Skip to content

Latest commit

Β 

History

History
1202 lines (958 loc) Β· 34.4 KB

File metadata and controls

1202 lines (958 loc) Β· 34.4 KB

μ±„νŒ… API

μ‹€μ‹œκ°„ μ±„νŒ… κΈ°λŠ₯의 REST APIμž…λ‹ˆλ‹€. μ±„νŒ…λ°© 관리, λ©”μ‹œμ§€ μ†‘μˆ˜μ‹ , 파일 μ—…λ‘œλ“œ/λ‹€μš΄λ‘œλ“œ, μ‚¬μš©μž 검색 κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. λͺ¨λ“  μ—”λ“œν¬μΈνŠΈλŠ” isChatEnabled 미듀웨어λ₯Ό 톡해 μ•„μΉ΄λ°λ―Έμ˜ μ±„νŒ… ν™œμ„±ν™” μ—¬λΆ€λ₯Ό ν™•μΈν•©λ‹ˆλ‹€.

라우트 파일: backend/src/routes/chats.js 컨트둀러 파일: backend/src/controllers/chats.js λͺ¨λΈ 파일: backend/src/models/ChatRoom.js, backend/src/models/ChatMessage.js, backend/src/models/ChatFile.js


μ—”λ“œν¬μΈνŠΈ μš”μ•½

λ©”μ„œλ“œ 경둜 μ„€λͺ… κΆŒν•œ
POST /api/chats/rooms μ±„νŒ…λ°© 생성 isLoggedIn + isChatEnabled
GET /api/chats/rooms μ±„νŒ…λ°© λͺ©λ‘ 쑰회 isLoggedIn + isChatEnabled
GET /api/chats/rooms/:roomId μ±„νŒ…λ°© 상세 쑰회 isLoggedIn + isChatEnabled
PUT /api/chats/rooms/:roomId μ±„νŒ…λ°© μˆ˜μ • isLoggedIn + isChatEnabled
DELETE /api/chats/rooms/:roomId μ±„νŒ…λ°© λ‚˜κ°€κΈ°/μ‚­μ œ isLoggedIn + isChatEnabled
DELETE /api/chats/rooms/:roomId/creator μ±„νŒ…λ°© μ‚­μ œ (λ°©μž₯ μ „μš©) isLoggedIn + isChatEnabled
POST /api/chats/rooms/:roomId/participants μ°Έκ°€μž μΆ”κ°€ isLoggedIn + isChatEnabled
DELETE /api/chats/rooms/:roomId/participants/:participantId μ°Έκ°€μž 제거 isLoggedIn + isChatEnabled
POST /api/chats/rooms/:roomId/messages λ©”μ‹œμ§€ 전솑 isLoggedIn + isChatEnabled
GET /api/chats/rooms/:roomId/messages λ©”μ‹œμ§€ λͺ©λ‘ 쑰회 isLoggedIn + isChatEnabled
PUT /api/chats/rooms/:roomId/read 읽음 처리 isLoggedIn + isChatEnabled
POST /api/chats/rooms/:roomId/upload 파일 μ—…λ‘œλ“œ isLoggedIn + isChatEnabled
GET /api/chats/files λ‚΄ 파일 λͺ©λ‘ 쑰회 isLoggedIn + isChatEnabled
DELETE /api/chats/files/:fileId 파일 μ‚­μ œ isLoggedIn + isChatEnabled
GET /api/chats/files/:fileId/signed λ‹€μš΄λ‘œλ“œ URL 쑰회 isLoggedIn + isChatEnabled
GET /api/chats/users μ‚¬μš©μž 검색 isLoggedIn + isChatEnabled

μ±„νŒ…λ°© 생성

μƒˆλ‘œμš΄ μ±„νŒ…λ°©μ„ μƒμ„±ν•©λ‹ˆλ‹€. 1:1 μ±„νŒ…(direct)의 경우 λ™μΌν•œ μ°Έκ°€μž μ‘°ν•©μ˜ μ±„νŒ…λ°©μ΄ 이미 μ‘΄μž¬ν•˜λ©΄ κΈ°μ‘΄ μ±„νŒ…λ°©μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.

POST /api/chats/rooms

κΆŒν•œ: isLoggedIn + isChatEnabled

μš”μ²­ λ³Έλ¬Έ

ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
type string O μ±„νŒ…λ°© μœ ν˜• ("direct" | "group")
participants object[] O μ°Έκ°€μž λͺ©λ‘ (ν˜„μž¬ μ‚¬μš©μž μ œμ™Έ)
participants[].user string O μ°Έκ°€μž ObjectId
participants[].userId string O μ°Έκ°€μž μ‚¬μš©μž ID
participants[].userName string O μ°Έκ°€μž 이름
participants[].profile string X μ°Έκ°€μž ν”„λ‘œν•„ 이미지 URL
name string κ·Έλ£Ή μ‹œ O μ±„νŒ…λ°© 이름 (κ·Έλ£Ή μ±„νŒ… μ „μš©)

μ°Έκ³ : direct μ±„νŒ… μ‹œ participants λ°°μ—΄μ—λŠ” μ •ν™•νžˆ 1λͺ…μ˜ μ°Έκ°€μžλ§Œ 포함해야 ν•©λ‹ˆλ‹€. ν˜„μž¬ λ‘œκ·ΈμΈν•œ μ‚¬μš©μžλŠ” μžλ™μœΌλ‘œ μ°Έκ°€μžμ— μΆ”κ°€λ©λ‹ˆλ‹€.

μš”μ²­ μ˜ˆμ‹œ (1:1 μ±„νŒ…)

{
  "type": "direct",
  "participants": [
    {
      "user": "507f1f77bcf86cd799439011",
      "userId": "user01",
      "userName": "홍길동"
    }
  ]
}

μš”μ²­ μ˜ˆμ‹œ (κ·Έλ£Ή μ±„νŒ…)

{
  "type": "group",
  "name": "ν”„λ‘œμ νŠΈ 회의방",
  "participants": [
    {
      "user": "507f1f77bcf86cd799439011",
      "userId": "user01",
      "userName": "홍길동"
    },
    {
      "user": "507f1f77bcf86cd799439012",
      "userId": "user02",
      "userName": "κΉ€μ² μˆ˜",
      "profile": "https://example.com/profile.jpg"
    }
  ]
}

응닡 (200) - μ‹ κ·œ 생성

{
  "room": {
    "_id": "60a1b2c3d4e5f6789012abcd",
    "type": "group",
    "name": "ν”„λ‘œμ νŠΈ 회의방",
    "creator": "507f1f77bcf86cd799439000",
    "creatorId": "admin01",
    "creatorName": "κ΄€λ¦¬μž",
    "participants": [
      {
        "user": "507f1f77bcf86cd799439000",
        "userId": "admin01",
        "userName": "κ΄€λ¦¬μž",
        "joinedAt": "2024-01-15T09:00:00.000Z"
      },
      {
        "user": "507f1f77bcf86cd799439011",
        "userId": "user01",
        "userName": "홍길동",
        "joinedAt": "2024-01-15T09:00:00.000Z"
      },
      {
        "user": "507f1f77bcf86cd799439012",
        "userId": "user02",
        "userName": "κΉ€μ² μˆ˜",
        "profile": "https://example.com/profile.jpg",
        "joinedAt": "2024-01-15T09:00:00.000Z"
      }
    ],
    "isActive": true,
    "createdAt": "2024-01-15T09:00:00.000Z",
    "updatedAt": "2024-01-15T09:00:00.000Z"
  }
}

응닡 (200) - κΈ°μ‘΄ 1:1 μ±„νŒ…λ°© λ°˜ν™˜

{
  "room": {
    "_id": "60a1b2c3d4e5f6789012abcd",
    "type": "direct",
    "participants": [
      {
        "user": "507f1f77bcf86cd799439000",
        "userId": "admin01",
        "userName": "κ΄€λ¦¬μž",
        "joinedAt": "2024-01-14T10:00:00.000Z"
      },
      {
        "user": "507f1f77bcf86cd799439011",
        "userId": "user01",
        "userName": "홍길동",
        "joinedAt": "2024-01-14T10:00:00.000Z"
      }
    ],
    "isActive": true,
    "createdAt": "2024-01-14T10:00:00.000Z",
    "updatedAt": "2024-01-14T10:00:00.000Z"
  },
  "existing": true
}

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
400 FIELD_REQUIRED(type) type ν•„λ“œ λˆ„λ½
400 FIELD_REQUIRED(participants) participants ν•„λ“œ λˆ„λ½ λ˜λŠ” 빈 λ°°μ—΄
400 FIELD_INVALID(participants) 1:1 μ±„νŒ… μ‹œ μ°Έκ°€μžκ°€ 1λͺ…이 μ•„λ‹Œ 경우

μ±„νŒ…λ°© λͺ©λ‘ 쑰회

ν˜„μž¬ μ‚¬μš©μžκ°€ μ°Έκ°€ 쀑인 ν™œμ„± μ±„νŒ…λ°© λͺ©λ‘μ„ μ‘°νšŒν•©λ‹ˆλ‹€. λ§ˆμ§€λ§‰ λ©”μ‹œμ§€ μ‹œκ°„ κΈ°μ€€ λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ μ •λ ¬λ©λ‹ˆλ‹€.

GET /api/chats/rooms

κΆŒν•œ: isLoggedIn + isChatEnabled

응닡 (200)

{
  "rooms": [
    {
      "_id": "60a1b2c3d4e5f6789012abcd",
      "type": "group",
      "name": "ν”„λ‘œμ νŠΈ 회의방",
      "creator": "507f1f77bcf86cd799439000",
      "creatorId": "admin01",
      "creatorName": "κ΄€λ¦¬μž",
      "participants": [
        {
          "user": "507f1f77bcf86cd799439000",
          "userId": "admin01",
          "userName": "κ΄€λ¦¬μž",
          "joinedAt": "2024-01-15T09:00:00.000Z",
          "lastReadAt": "2024-01-15T12:00:00.000Z"
        },
        {
          "user": "507f1f77bcf86cd799439011",
          "userId": "user01",
          "userName": "홍길동",
          "joinedAt": "2024-01-15T09:00:00.000Z"
        }
      ],
      "lastMessage": {
        "content": "회의 μ‹œκ°„μ΄ λ³€κ²½λ˜μ—ˆμŠ΅λ‹ˆλ‹€.",
        "sender": "507f1f77bcf86cd799439000",
        "senderName": "κ΄€λ¦¬μž",
        "sentAt": "2024-01-15T12:00:00.000Z"
      },
      "isActive": true,
      "settings": {
        "allowInvites": true,
        "allowChat": true
      },
      "createdAt": "2024-01-15T09:00:00.000Z",
      "updatedAt": "2024-01-15T12:00:00.000Z"
    },
    {
      "_id": "60a1b2c3d4e5f6789012abce",
      "type": "direct",
      "participants": [
        {
          "user": "507f1f77bcf86cd799439000",
          "userId": "admin01",
          "userName": "κ΄€λ¦¬μž",
          "joinedAt": "2024-01-14T10:00:00.000Z"
        },
        {
          "user": "507f1f77bcf86cd799439012",
          "userId": "user02",
          "userName": "κΉ€μ² μˆ˜",
          "joinedAt": "2024-01-14T10:00:00.000Z"
        }
      ],
      "lastMessage": {
        "content": "μ•ˆλ…•ν•˜μ„Έμš”!",
        "sender": "507f1f77bcf86cd799439012",
        "senderName": "κΉ€μ² μˆ˜",
        "sentAt": "2024-01-14T15:30:00.000Z"
      },
      "isActive": true,
      "createdAt": "2024-01-14T10:00:00.000Z",
      "updatedAt": "2024-01-14T15:30:00.000Z"
    }
  ]
}

μ±„νŒ…λ°© 상세 쑰회

νŠΉμ • μ±„νŒ…λ°©μ˜ 상세 정보λ₯Ό μ‘°νšŒν•©λ‹ˆλ‹€. μ±„νŒ…λ°© μ°Έκ°€μžλ§Œ μ‘°νšŒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

GET /api/chats/rooms/:roomId

κΆŒν•œ: isLoggedIn + isChatEnabled

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
roomId string μ±„νŒ…λ°© ObjectId

응닡 (200)

{
  "room": {
    "_id": "60a1b2c3d4e5f6789012abcd",
    "type": "group",
    "name": "ν”„λ‘œμ νŠΈ 회의방",
    "creator": "507f1f77bcf86cd799439000",
    "creatorId": "admin01",
    "creatorName": "κ΄€λ¦¬μž",
    "participants": [
      {
        "user": "507f1f77bcf86cd799439000",
        "userId": "admin01",
        "userName": "κ΄€λ¦¬μž",
        "joinedAt": "2024-01-15T09:00:00.000Z",
        "lastReadAt": "2024-01-15T12:00:00.000Z"
      }
    ],
    "lastMessage": {
      "content": "회의 μ‹œκ°„μ΄ λ³€κ²½λ˜μ—ˆμŠ΅λ‹ˆλ‹€.",
      "sender": "507f1f77bcf86cd799439000",
      "senderName": "κ΄€λ¦¬μž",
      "sentAt": "2024-01-15T12:00:00.000Z"
    },
    "isActive": true,
    "settings": {
      "allowInvites": true,
      "allowChat": true
    },
    "createdAt": "2024-01-15T09:00:00.000Z",
    "updatedAt": "2024-01-15T12:00:00.000Z"
  }
}

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
403 PERMISSION_DENIED μ±„νŒ…λ°© μ°Έκ°€μžκ°€ μ•„λ‹Œ 경우
404 __NOT_FOUND(room) μ±„νŒ…λ°©μ„ 찾을 수 μ—†μŒ

μ±„νŒ…λ°© μˆ˜μ •

κ·Έλ£Ή μ±„νŒ…λ°©μ˜ 이름 λ˜λŠ” 섀정을 λ³€κ²½ν•©λ‹ˆλ‹€. 이름은 λͺ¨λ“  μ°Έκ°€μžκ°€ λ³€κ²½ν•  수 μžˆμœΌλ‚˜, μ„€μ •(settings)은 λ°©μž₯만 λ³€κ²½ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

PUT /api/chats/rooms/:roomId

κΆŒν•œ: isLoggedIn + isChatEnabled

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
roomId string μ±„νŒ…λ°© ObjectId

μš”μ²­ λ³Έλ¬Έ

ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
name string X μƒˆ μ±„νŒ…λ°© 이름 (κ·Έλ£Ή μ±„νŒ… μ „μš©, λͺ¨λ“  μ°Έκ°€μž λ³€κ²½ κ°€λŠ₯)
settings object X μ±„νŒ…λ°© μ„€μ • (λ°©μž₯만 λ³€κ²½ κ°€λŠ₯)
settings.allowInvites boolean X 일반 μ°Έκ°€μžμ˜ μ΄ˆλŒ€ ν—ˆμš© μ—¬λΆ€
settings.allowChat boolean X 일반 μ°Έκ°€μžμ˜ λ©”μ‹œμ§€ 전솑 ν—ˆμš© μ—¬λΆ€

μš”μ²­ μ˜ˆμ‹œ

{
  "name": "ν”„λ‘œμ νŠΈ 회의방 (μˆ˜μ •)",
  "settings": {
    "allowInvites": false,
    "allowChat": true
  }
}

응닡 (200)

{
  "room": {
    "_id": "60a1b2c3d4e5f6789012abcd",
    "type": "group",
    "name": "ν”„λ‘œμ νŠΈ 회의방 (μˆ˜μ •)",
    "settings": {
      "allowInvites": false,
      "allowChat": true
    },
    "participants": [ ... ],
    "isActive": true,
    "createdAt": "2024-01-15T09:00:00.000Z",
    "updatedAt": "2024-01-15T14:00:00.000Z"
  }
}

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
403 PERMISSION_DENIED μ±„νŒ…λ°© μ°Έκ°€μžκ°€ μ•„λ‹Œ 경우
404 __NOT_FOUND(room) μ±„νŒ…λ°©μ„ 찾을 수 μ—†μŒ

μ±„νŒ…λ°© λ‚˜κ°€κΈ°/μ‚­μ œ

μ±„νŒ…λ°©μ„ λ‚˜κ°€κ±°λ‚˜ μ‚­μ œν•©λ‹ˆλ‹€. μœ ν˜•μ— 따라 λ™μž‘μ΄ λ‹€λ¦…λ‹ˆλ‹€.

  • 1:1 μ±„νŒ… (direct): μ†Œν”„νŠΈ μ‚­μ œ (isActive = false)
  • κ·Έλ£Ή μ±„νŒ… (group): μ°Έκ°€μž λͺ©λ‘μ—μ„œ ν˜„μž¬ μ‚¬μš©μž 제거. μ°Έκ°€μžκ°€ 0λͺ…이 되면 μ†Œν”„νŠΈ μ‚­μ œ
DELETE /api/chats/rooms/:roomId

κΆŒν•œ: isLoggedIn + isChatEnabled

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
roomId string μ±„νŒ…λ°© ObjectId

응닡 (200)

{}

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
403 PERMISSION_DENIED μ±„νŒ…λ°© μ°Έκ°€μžκ°€ μ•„λ‹Œ 경우
404 __NOT_FOUND(room) μ±„νŒ…λ°©μ„ 찾을 수 μ—†μŒ

μ±„νŒ…λ°© μ‚­μ œ (λ°©μž₯ μ „μš©)

λ°©μž₯이 μ±„νŒ…λ°©μ„ κ°•μ œ μ‚­μ œν•©λ‹ˆλ‹€. μ†Œν”„νŠΈ μ‚­μ œ(isActive = false) 처리되며, λͺ¨λ“  μ°Έκ°€μžμ—κ²Œ room_deleted μ†ŒμΌ“ μ΄λ²€νŠΈκ°€ λ°œμ†‘λ©λ‹ˆλ‹€.

DELETE /api/chats/rooms/:roomId/creator

κΆŒν•œ: isLoggedIn + isChatEnabled (λ°©μž₯만 κ°€λŠ₯)

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
roomId string μ±„νŒ…λ°© ObjectId

응닡 (200)

{}

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
403 PERMISSION_DENIED λ°©μž₯이 μ•„λ‹Œ 경우
404 __NOT_FOUND(room) μ±„νŒ…λ°©μ„ 찾을 수 μ—†μŒ

WebSocket 이벀트

이벀트 λŒ€μƒ νŽ˜μ΄λ‘œλ“œ
room_deleted λͺ¨λ“  μ°Έκ°€μž { room, deletedBy }

μ°Έκ°€μž μΆ”κ°€

κ·Έλ£Ή μ±„νŒ…λ°©μ— μƒˆλ‘œμš΄ μ°Έκ°€μžλ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€. 이미 μ°Έκ°€ 쀑인 μ‚¬μš©μžλŠ” 쀑볡 μΆ”κ°€λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. allowInvitesκ°€ false인 경우 λ°©μž₯만 μ΄ˆλŒ€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

POST /api/chats/rooms/:roomId/participants

κΆŒν•œ: isLoggedIn + isChatEnabled

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
roomId string μ±„νŒ…λ°© ObjectId

μš”μ²­ λ³Έλ¬Έ

ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
participants object[] O μΆ”κ°€ν•  μ°Έκ°€μž λͺ©λ‘
participants[].user string O μ°Έκ°€μž ObjectId
participants[].userId string O μ°Έκ°€μž μ‚¬μš©μž ID
participants[].userName string O μ°Έκ°€μž 이름
participants[].profile string X μ°Έκ°€μž ν”„λ‘œν•„ 이미지 URL

μš”μ²­ μ˜ˆμ‹œ

{
  "participants": [
    {
      "user": "507f1f77bcf86cd799439013",
      "userId": "user03",
      "userName": "이영희"
    }
  ]
}

응닡 (200)

{
  "room": {
    "_id": "60a1b2c3d4e5f6789012abcd",
    "type": "group",
    "name": "ν”„λ‘œμ νŠΈ 회의방",
    "participants": [
      {
        "user": "507f1f77bcf86cd799439000",
        "userId": "admin01",
        "userName": "κ΄€λ¦¬μž",
        "joinedAt": "2024-01-15T09:00:00.000Z"
      },
      {
        "user": "507f1f77bcf86cd799439011",
        "userId": "user01",
        "userName": "홍길동",
        "joinedAt": "2024-01-15T09:00:00.000Z"
      },
      {
        "user": "507f1f77bcf86cd799439013",
        "userId": "user03",
        "userName": "이영희",
        "joinedAt": "2024-01-15T14:30:00.000Z"
      }
    ],
    "isActive": true,
    "createdAt": "2024-01-15T09:00:00.000Z",
    "updatedAt": "2024-01-15T14:30:00.000Z"
  }
}

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
400 FIELD_REQUIRED(participants) participants ν•„λ“œ λˆ„λ½ λ˜λŠ” 빈 λ°°μ—΄
400 FIELD_INVALID(room.type) 1:1 μ±„νŒ…λ°©μ— μ°Έκ°€μž μΆ”κ°€ μ‹œλ„
403 PERMISSION_DENIED μ°Έκ°€μžκ°€ μ•„λ‹ˆκ±°λ‚˜, allowInvites=falseμ—μ„œ λ°©μž₯이 μ•„λ‹Œ 경우
404 __NOT_FOUND(room) μ±„νŒ…λ°©μ„ 찾을 수 μ—†μŒ

WebSocket 이벀트

이벀트 λŒ€μƒ νŽ˜μ΄λ‘œλ“œ
participants_added λͺ¨λ“  μ°Έκ°€μž { room, newParticipants, addedBy }

μ°Έκ°€μž 제거

κ·Έλ£Ή μ±„νŒ…λ°©μ—μ„œ μ°Έκ°€μžλ₯Ό κ°•μ œ μ œκ±°ν•©λ‹ˆλ‹€. λ°©μž₯만 μ‚¬μš©ν•  수 있으며, 자기 μžμ‹ μ€ μ œκ±°ν•  수 μ—†μŠ΅λ‹ˆλ‹€ (λŒ€μ‹  μ±„νŒ…λ°© λ‚˜κ°€κΈ°λ₯Ό μ‚¬μš©).

DELETE /api/chats/rooms/:roomId/participants/:participantId

κΆŒν•œ: isLoggedIn + isChatEnabled (λ°©μž₯만 κ°€λŠ₯)

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
roomId string μ±„νŒ…λ°© ObjectId
participantId string μ œκ±°ν•  μ°Έκ°€μžμ˜ user ObjectId

응닡 (200)

{
  "room": {
    "_id": "60a1b2c3d4e5f6789012abcd",
    "type": "group",
    "name": "ν”„λ‘œμ νŠΈ 회의방",
    "participants": [
      {
        "user": "507f1f77bcf86cd799439000",
        "userId": "admin01",
        "userName": "κ΄€λ¦¬μž",
        "joinedAt": "2024-01-15T09:00:00.000Z"
      }
    ],
    "isActive": true,
    "createdAt": "2024-01-15T09:00:00.000Z",
    "updatedAt": "2024-01-15T15:00:00.000Z"
  }
}

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
400 FIELD_INVALID(room.type) 1:1 μ±„νŒ…λ°©μ—μ„œ μ°Έκ°€μž 제거 μ‹œλ„
400 FIELD_INVALID(participantId) 자기 μžμ‹ μ„ μ œκ±°ν•˜λ €λŠ” 경우
403 PERMISSION_DENIED λ°©μž₯이 μ•„λ‹Œ 경우
404 __NOT_FOUND(room) μ±„νŒ…λ°©μ„ 찾을 수 μ—†μŒ
404 __NOT_FOUND(participant) ν•΄λ‹Ή μ°Έκ°€μžλ₯Ό 찾을 수 μ—†μŒ

WebSocket 이벀트

이벀트 λŒ€μƒ νŽ˜μ΄λ‘œλ“œ
participant_removed 제거된 μ‚¬μš©μž + 남은 μ°Έκ°€μž { room, removedUserId, removedBy }

λ©”μ‹œμ§€ 전솑

μ±„νŒ…λ°©μ— λ©”μ‹œμ§€λ₯Ό μ „μ†‘ν•©λ‹ˆλ‹€. 전솑 μ‹œ μ±„νŒ…λ°©μ˜ lastMessageκ°€ μžλ™ κ°±μ‹ λ˜λ©°, λ°œμ‹ μžμ˜ 읽음 μ²˜λ¦¬κ°€ μžλ™μœΌλ‘œ μˆ˜ν–‰λ©λ‹ˆλ‹€. κ·Έλ£Ή μ±„νŒ…μ—μ„œ allowChat이 false인 경우 λ°©μž₯만 λ©”μ‹œμ§€λ₯Ό 보낼 수 μžˆμŠ΅λ‹ˆλ‹€.

POST /api/chats/rooms/:roomId/messages

κΆŒν•œ: isLoggedIn + isChatEnabled

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
roomId string μ±„νŒ…λ°© ObjectId

μš”μ²­ λ³Έλ¬Έ

ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
content string O λ©”μ‹œμ§€ λ‚΄μš©
messageType string X λ©”μ‹œμ§€ μœ ν˜• ("text" | "image" | "file" | "system"). κΈ°λ³Έκ°’: "text"
attachment object 이미지/파일 μ‹œ O 첨뢀 파일 정보
attachment.url string O 파일 URL
attachment.fileName string O 파일 이름
attachment.fileSize number O 파일 크기 (λ°”μ΄νŠΈ)
attachment.mimeType string O MIME νƒ€μž…
attachment.key string O S3 ν‚€ (μ„œλͺ… URL μƒμ„±μš©)

μš”μ²­ μ˜ˆμ‹œ (ν…μŠ€νŠΈ λ©”μ‹œμ§€)

{
  "content": "μ•ˆλ…•ν•˜μ„Έμš”!"
}

μš”μ²­ μ˜ˆμ‹œ (이미지 λ©”μ‹œμ§€)

{
  "content": "이미지λ₯Ό λ³΄λƒˆμŠ΅λ‹ˆλ‹€.",
  "messageType": "image",
  "attachment": {
    "url": "https://s3.example.com/chat/image.png",
    "fileName": "image.png",
    "fileSize": 1048576,
    "mimeType": "image/png",
    "key": "chat/rooms/60a1b2c3/image.png"
  }
}

μš”μ²­ μ˜ˆμ‹œ (파일 λ©”μ‹œμ§€)

{
  "content": "νŒŒμΌμ„ λ³΄λƒˆμŠ΅λ‹ˆλ‹€.",
  "messageType": "file",
  "attachment": {
    "url": "https://s3.example.com/chat/report.pdf",
    "fileName": "report.pdf",
    "fileSize": 2097152,
    "mimeType": "application/pdf",
    "key": "chat/rooms/60a1b2c3/report.pdf"
  }
}

응닡 (200)

{
  "message": {
    "_id": "60b1c2d3e4f5a6789012bcde",
    "room": "60a1b2c3d4e5f6789012abcd",
    "sender": "507f1f77bcf86cd799439000",
    "senderId": "admin01",
    "senderName": "κ΄€λ¦¬μž",
    "content": "μ•ˆλ…•ν•˜μ„Έμš”!",
    "messageType": "text",
    "readBy": [
      {
        "user": "507f1f77bcf86cd799439000",
        "readAt": "2024-01-15T12:00:00.000Z"
      }
    ],
    "isDeleted": false,
    "createdAt": "2024-01-15T12:00:00.000Z",
    "updatedAt": "2024-01-15T12:00:00.000Z"
  }
}

μ°Έκ³ : lastMessage.contentλŠ” 이미지 λ©”μ‹œμ§€μ˜ 경우 "[이미지]", 파일 λ©”μ‹œμ§€μ˜ 경우 "[파일] {파일λͺ…}" 으둜 μ €μž₯λ©λ‹ˆλ‹€. ν…μŠ€νŠΈ λ©”μ‹œμ§€λŠ” μ΅œλŒ€ 100μžκΉŒμ§€ μ €μž₯λ©λ‹ˆλ‹€.

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
400 FIELD_REQUIRED(content) λ©”μ‹œμ§€ λ‚΄μš© λˆ„λ½
400 FIELD_REQUIRED(attachment) 이미지/파일 λ©”μ‹œμ§€μ—μ„œ 첨뢀 파일 λˆ„λ½
403 PERMISSION_DENIED μ°Έκ°€μžκ°€ μ•„λ‹ˆκ±°λ‚˜, allowChat=falseμ—μ„œ λ°©μž₯이 μ•„λ‹Œ 경우
404 __NOT_FOUND(room) μ±„νŒ…λ°©μ„ 찾을 수 μ—†μŒ

WebSocket 이벀트

이벀트 λŒ€μƒ νŽ˜μ΄λ‘œλ“œ
new_message λ°œμ‹ μžλ₯Ό μ œμ™Έν•œ λͺ¨λ“  μ°Έκ°€μž { room, roomType, message }

λ©”μ‹œμ§€ λͺ©λ‘ 쑰회

μ±„νŒ…λ°©μ˜ λ©”μ‹œμ§€λ₯Ό μ‘°νšŒν•©λ‹ˆλ‹€. μ»€μ„œ 기반 νŽ˜μ΄μ§€λ„€μ΄μ…˜μ„ μ§€μ›ν•˜λ©°, μ‹œκ°„μˆœ(였래된 순)으둜 μ •λ ¬ν•˜μ—¬ λ°˜ν™˜ν•©λ‹ˆλ‹€. μ‚­μ œλœ λ©”μ‹œμ§€λŠ” μ œμ™Έλ©λ‹ˆλ‹€. 첨뢀 파일 URL은 1μ‹œκ°„ μœ νš¨ν•œ μ„œλͺ… URL둜 μžλ™ λ³€ν™˜λ©λ‹ˆλ‹€.

GET /api/chats/rooms/:roomId/messages

κΆŒν•œ: isLoggedIn + isChatEnabled

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
roomId string μ±„νŒ…λ°© ObjectId

쿼리 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… ν•„μˆ˜ μ„€λͺ…
limit number X μ‘°νšŒν•  λ©”μ‹œμ§€ 수 (κΈ°λ³Έκ°’: 50)
before string X 이 μ‹œκ°„ μ΄μ „μ˜ λ©”μ‹œμ§€ 쑰회 (ISO 8601 ν˜•μ‹, μ»€μ„œ νŽ˜μ΄μ§€λ„€μ΄μ…˜)

μš”μ²­ μ˜ˆμ‹œ

GET /api/chats/rooms/60a1b2c3d4e5f6789012abcd/messages?limit=20&before=2024-01-15T12:00:00.000Z

응닡 (200)

{
  "messages": [
    {
      "_id": "60b1c2d3e4f5a6789012bcd1",
      "room": "60a1b2c3d4e5f6789012abcd",
      "sender": "507f1f77bcf86cd799439011",
      "senderId": "user01",
      "senderName": "홍길동",
      "content": "μ•ˆλ…•ν•˜μ„Έμš”!",
      "messageType": "text",
      "readBy": [
        {
          "user": "507f1f77bcf86cd799439011",
          "readAt": "2024-01-15T11:00:00.000Z"
        }
      ],
      "isDeleted": false,
      "createdAt": "2024-01-15T11:00:00.000Z",
      "updatedAt": "2024-01-15T11:00:00.000Z"
    },
    {
      "_id": "60b1c2d3e4f5a6789012bcd2",
      "room": "60a1b2c3d4e5f6789012abcd",
      "sender": "507f1f77bcf86cd799439000",
      "senderId": "admin01",
      "senderName": "κ΄€λ¦¬μž",
      "content": "이미지λ₯Ό λ³΄λƒˆμŠ΅λ‹ˆλ‹€.",
      "messageType": "image",
      "attachment": {
        "url": "https://signed-url.example.com/chat/image.png?signature=...",
        "fileName": "image.png",
        "fileSize": 1048576,
        "mimeType": "image/png",
        "key": "chat/rooms/60a1b2c3/image.png"
      },
      "readBy": [
        {
          "user": "507f1f77bcf86cd799439000",
          "readAt": "2024-01-15T11:30:00.000Z"
        }
      ],
      "isDeleted": false,
      "createdAt": "2024-01-15T11:30:00.000Z",
      "updatedAt": "2024-01-15T11:30:00.000Z"
    }
  ]
}

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
403 PERMISSION_DENIED μ±„νŒ…λ°© μ°Έκ°€μžκ°€ μ•„λ‹Œ 경우
404 __NOT_FOUND(room) μ±„νŒ…λ°©μ„ 찾을 수 μ—†μŒ

읽음 처리

μ±„νŒ…λ°©μ˜ ν˜„μž¬ μ‚¬μš©μž μ°Έκ°€μž μ •λ³΄μ—μ„œ lastReadAt을 ν˜„μž¬ μ‹œκ°„μœΌλ‘œ κ°±μ‹ ν•©λ‹ˆλ‹€.

PUT /api/chats/rooms/:roomId/read

κΆŒν•œ: isLoggedIn + isChatEnabled

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
roomId string μ±„νŒ…λ°© ObjectId

응닡 (200)

{}

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
403 PERMISSION_DENIED μ±„νŒ…λ°© μ°Έκ°€μžκ°€ μ•„λ‹Œ 경우
404 __NOT_FOUND(room) μ±„νŒ…λ°©μ„ 찾을 수 μ—†μŒ

파일 μ—…λ‘œλ“œ

μ±„νŒ…λ°©μ— νŒŒμΌμ„ μ—…λ‘œλ“œν•©λ‹ˆλ‹€. multipart/form-data ν˜•μ‹μœΌλ‘œ μ „μ†‘ν•˜λ©°, chatMulter 미듀웨어λ₯Ό 톡해 S3에 μ €μž₯λ©λ‹ˆλ‹€. μ—…λ‘œλ“œλœ νŒŒμΌμ€ ChatFile μ»¬λ ‰μ…˜μ— κΈ°λ‘λ©λ‹ˆλ‹€.

POST /api/chats/rooms/:roomId/upload

κΆŒν•œ: isLoggedIn + isChatEnabled

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
roomId string μ±„νŒ…λ°© ObjectId

μš”μ²­ λ³Έλ¬Έ (multipart/form-data)

ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
file File O μ—…λ‘œλ“œν•  파일

파일 크기 μ œν•œ: 이미지 파일 μ΅œλŒ€ 10MB, 일반 파일 μ΅œλŒ€ 20MB

응닡 (200)

{
  "attachment": {
    "url": "https://s3.example.com/chat/rooms/60a1b2c3/document.pdf",
    "fileName": "document.pdf",
    "fileSize": 2097152,
    "mimeType": "application/pdf",
    "key": "chat/rooms/60a1b2c3/document.pdf"
  }
}

μ°Έκ³ : μ‘λ‹΅μœΌλ‘œ 받은 attachment 객체λ₯Ό κ·ΈλŒ€λ‘œ λ©”μ‹œμ§€ 전솑 API의 attachment ν•„λ“œμ— μ „λ‹¬ν•˜μ—¬ 파일 λ©”μ‹œμ§€λ₯Ό 전솑할 수 μžˆμŠ΅λ‹ˆλ‹€.

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
400 FIELD_REQUIRED(file) 파일 미첨뢀
403 PERMISSION_DENIED μ°Έκ°€μžκ°€ μ•„λ‹ˆκ±°λ‚˜, allowChat=falseμ—μ„œ λ°©μž₯이 μ•„λ‹Œ 경우
404 __NOT_FOUND(room) μ±„νŒ…λ°©μ„ 찾을 수 μ—†μŒ
409 LIMIT_FILE_SIZE 파일 크기 초과
409 INVALID_FILE_TYPE ν—ˆμš©λ˜μ§€ μ•Šμ€ 파일 ν˜•μ‹

λ‚΄ 파일 λͺ©λ‘ 쑰회

ν˜„μž¬ μ‚¬μš©μžκ°€ μ—…λ‘œλ“œν•œ μ±„νŒ… 파일 λͺ©λ‘μ„ μ‘°νšŒν•©λ‹ˆλ‹€. μ»€μ„œ 기반 νŽ˜μ΄μ§€λ„€μ΄μ…˜μ„ μ§€μ›ν•˜λ©°, 파일 URL은 1μ‹œκ°„ μœ νš¨ν•œ μ„œλͺ… URL둜 μžλ™ λ³€ν™˜λ©λ‹ˆλ‹€.

GET /api/chats/files

κΆŒν•œ: isLoggedIn + isChatEnabled

쿼리 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… ν•„μˆ˜ μ„€λͺ…
fileType string X 파일 μœ ν˜• ν•„ν„° ("image" | "file")
limit number X μ‘°νšŒν•  파일 수 (κΈ°λ³Έκ°’: 20)
before string X 이 μ‹œκ°„ μ΄μ „μ˜ 파일 쑰회 (ISO 8601 ν˜•μ‹, μ»€μ„œ νŽ˜μ΄μ§€λ„€μ΄μ…˜)

μš”μ²­ μ˜ˆμ‹œ

GET /api/chats/files?fileType=image&limit=10

응닡 (200)

{
  "files": [
    {
      "_id": "60c1d2e3f4a5b6789012cdef",
      "user": "507f1f77bcf86cd799439000",
      "userId": "admin01",
      "room": "60a1b2c3d4e5f6789012abcd",
      "message": "60b1c2d3e4f5a6789012bcde",
      "fileName": "screenshot.png",
      "fileSize": 524288,
      "mimeType": "image/png",
      "key": "chat/rooms/60a1b2c3/screenshot.png",
      "url": "https://signed-url.example.com/chat/screenshot.png?signature=...",
      "fileType": "image",
      "isDeleted": false,
      "createdAt": "2024-01-15T11:30:00.000Z",
      "updatedAt": "2024-01-15T11:30:00.000Z"
    },
    {
      "_id": "60c1d2e3f4a5b6789012cdf0",
      "user": "507f1f77bcf86cd799439000",
      "userId": "admin01",
      "room": "60a1b2c3d4e5f6789012abcd",
      "fileName": "photo.jpg",
      "fileSize": 1048576,
      "mimeType": "image/jpeg",
      "key": "chat/rooms/60a1b2c3/photo.jpg",
      "url": "https://signed-url.example.com/chat/photo.jpg?signature=...",
      "fileType": "image",
      "isDeleted": false,
      "createdAt": "2024-01-15T10:00:00.000Z",
      "updatedAt": "2024-01-15T10:00:00.000Z"
    }
  ]
}

파일 μ‚­μ œ

μ—…λ‘œλ“œν•œ νŒŒμΌμ„ μ†Œν”„νŠΈ μ‚­μ œν•©λ‹ˆλ‹€. 파일 μ†Œμœ μžλ§Œ μ‚­μ œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

DELETE /api/chats/files/:fileId

κΆŒν•œ: isLoggedIn + isChatEnabled

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
fileId string 파일 ObjectId

응닡 (200)

{}

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
403 PERMISSION_DENIED 파일 μ†Œμœ μžκ°€ μ•„λ‹Œ 경우
404 __NOT_FOUND(file) νŒŒμΌμ„ 찾을 수 μ—†μŒ

λ‹€μš΄λ‘œλ“œ URL 쑰회

파일의 λ‹€μš΄λ‘œλ“œμš© Pre-Signed URL을 μƒμ„±ν•©λ‹ˆλ‹€. 파일 μ†Œμœ μž λ˜λŠ” ν•΄λ‹Ή 파일이 곡유된 μ±„νŒ…λ°©μ˜ μ°Έκ°€μžκ°€ μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€. URL 유효 μ‹œκ°„μ€ 5λΆ„μž…λ‹ˆλ‹€.

GET /api/chats/files/:fileId/signed

κΆŒν•œ: isLoggedIn + isChatEnabled

경둜 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… μ„€λͺ…
fileId string 파일 ObjectId

응닡 (200)

{
  "preSignedUrl": "https://s3.example.com/chat/rooms/60a1b2c3/document.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=300&...",
  "expiryDate": "2024-01-15T12:05:00.000Z"
}

μ—λŸ¬ 응닡

μƒνƒœ μ½”λ“œ λ©”μ‹œμ§€ μ„€λͺ…
403 PERMISSION_DENIED 파일 μ†Œμœ μžλ„ μ•„λ‹ˆκ³  μ±„νŒ…λ°© μ°Έκ°€μžλ„ μ•„λ‹Œ 경우
404 __NOT_FOUND(file) νŒŒμΌμ„ 찾을 수 μ—†κ±°λ‚˜ μ‚­μ œλœ 경우

μ‚¬μš©μž 검색

μ±„νŒ… κ°€λŠ₯ν•œ μ‚¬μš©μžλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€. userId λ˜λŠ” userName으둜 κ²€μƒ‰ν•˜λ©°, 학ꡐ별 필터링이 κ°€λŠ₯ν•©λ‹ˆλ‹€. ν˜„μž¬ λ‘œκ·ΈμΈν•œ μ‚¬μš©μžλŠ” κ²°κ³Όμ—μ„œ μ œμ™Έλ©λ‹ˆλ‹€.

GET /api/chats/users

κΆŒν•œ: isLoggedIn + isChatEnabled

쿼리 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… ν•„μˆ˜ μ„€λͺ…
q string X 검색어 (userId λ˜λŠ” userName λŒ€μ†Œλ¬Έμž 무관 λΆ€λΆ„ 일치)
sid string X 학ꡐ ObjectId둜 필터링

μš”μ²­ μ˜ˆμ‹œ

GET /api/chats/users?q=홍길&sid=507f1f77bcf86cd799439099

응닡 (200)

{
  "users": [
    {
      "_id": "507f1f77bcf86cd799439011",
      "userId": "user01",
      "userName": "홍길동",
      "profile": "https://example.com/profile.jpg",
      "schools": [
        {
          "school": "507f1f77bcf86cd799439099"
        }
      ]
    }
  ]
}

μ°Έκ³ : μ΅œλŒ€ 20λͺ…κΉŒμ§€ λ°˜ν™˜λ©λ‹ˆλ‹€.


WebSocket 이벀트 μš”μ•½

μ±„νŒ… APIλŠ” μ‹€μ‹œκ°„ 톡신을 μœ„ν•΄ Socket.io 이벀트λ₯Ό λ°œμƒμ‹œν‚΅λ‹ˆλ‹€. 각 μ‚¬μš©μžλŠ” chat:{academyId}:{userId} ν˜•μ‹μ˜ 룸에 μ°Έκ°€ν•˜μ—¬ 이벀트λ₯Ό μˆ˜μ‹ ν•©λ‹ˆλ‹€.

이벀트 λ°œμƒ μ‹œμ  νŽ˜μ΄λ‘œλ“œ
new_message λ©”μ‹œμ§€ 전솑 μ‹œ (λ°œμ‹ μž μ œμ™Έ) { room, roomType, message }
participants_added μ°Έκ°€μž μΆ”κ°€ μ‹œ { room, newParticipants, addedBy }
participant_removed μ°Έκ°€μž 제거 μ‹œ { room, removedUserId, removedBy }
room_deleted λ°©μž₯이 μ±„νŒ…λ°© μ‚­μ œ μ‹œ { room, deletedBy }

데이터 λͺ¨λΈ

ChatRoom

ν•„λ“œ νƒ€μž… ν•„μˆ˜ κΈ°λ³Έκ°’ μ„€λͺ…
_id ObjectId μžλ™ - 고유 ID
type string O - "direct" | "group"
name string X - μ±„νŒ…λ°© 이름 (κ·Έλ£Ή μ „μš©)
creator ObjectId X - λ°©μž₯ ObjectId
creatorId string X - λ°©μž₯ μ‚¬μš©μž ID
creatorName string X - λ°©μž₯ 이름
participants TChatParticipant[] O - μ°Έκ°€μž λͺ©λ‘
lastMessage TLastMessage X - λ§ˆμ§€λ§‰ λ©”μ‹œμ§€ 미리보기
isActive boolean X true ν™œμ„± μƒνƒœ
settings TChatRoomSettings X - μ±„νŒ…λ°© μ„€μ •
createdAt Date μžλ™ - 생성 μ‹œκ°„
updatedAt Date μžλ™ - μˆ˜μ • μ‹œκ°„

TChatParticipant

ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
user ObjectId O μ‚¬μš©μž ObjectId
userId string O μ‚¬μš©μž ID
userName string O μ‚¬μš©μž 이름
profile string X ν”„λ‘œν•„ 이미지 URL
joinedAt Date X μ°Έκ°€ μ‹œκ°„ (κΈ°λ³Έ: ν˜„μž¬ μ‹œκ°„)
lastReadAt Date X λ§ˆμ§€λ§‰ 읽음 μ‹œκ°„

TLastMessage

ν•„λ“œ νƒ€μž… μ„€λͺ…
content string λ©”μ‹œμ§€ λ‚΄μš© (μ΅œλŒ€ 100자)
sender ObjectId λ°œμ‹ μž ObjectId
senderName string λ°œμ‹ μž 이름
sentAt Date 전솑 μ‹œκ°„

TChatRoomSettings

ν•„λ“œ νƒ€μž… κΈ°λ³Έκ°’ μ„€λͺ…
allowInvites boolean true 일반 μ°Έκ°€μžμ˜ μ΄ˆλŒ€ ν—ˆμš© μ—¬λΆ€
allowChat boolean true 일반 μ°Έκ°€μžμ˜ λ©”μ‹œμ§€ 전솑 ν—ˆμš© μ—¬λΆ€

ChatMessage

ν•„λ“œ νƒ€μž… ν•„μˆ˜ κΈ°λ³Έκ°’ μ„€λͺ…
_id ObjectId μžλ™ - 고유 ID
room ObjectId O - μ±„νŒ…λ°© ObjectId
sender ObjectId O - λ°œμ‹ μž ObjectId
senderId string O - λ°œμ‹ μž μ‚¬μš©μž ID
senderName string O - λ°œμ‹ μž 이름
content string O - λ©”μ‹œμ§€ λ‚΄μš©
messageType string X "text" "text" | "image" | "file" | "system"
attachment TAttachment X - 첨뢀 파일 정보
readBy TReadBy[] X - 읽은 μ‚¬μš©μž λͺ©λ‘
isDeleted boolean X false μ†Œν”„νŠΈ μ‚­μ œ μ—¬λΆ€
createdAt Date μžλ™ - 생성 μ‹œκ°„
updatedAt Date μžλ™ - μˆ˜μ • μ‹œκ°„

TAttachment

ν•„λ“œ νƒ€μž… μ„€λͺ…
url string 파일 URL (μ„œλͺ… URL)
fileName string 파일 이름
fileSize number 파일 크기 (λ°”μ΄νŠΈ)
mimeType string MIME νƒ€μž…
key string S3 ν‚€ (μ„œλͺ… URL μƒμ„±μš©)

TReadBy

ν•„λ“œ νƒ€μž… μ„€λͺ…
user ObjectId 읽은 μ‚¬μš©μž ObjectId
readAt Date 읽은 μ‹œκ°„

ChatFile

ν•„λ“œ νƒ€μž… ν•„μˆ˜ κΈ°λ³Έκ°’ μ„€λͺ…
_id ObjectId μžλ™ - 고유 ID
user ObjectId O - μ—…λ‘œλ” ObjectId
userId string O - μ—…λ‘œλ” μ‚¬μš©μž ID
room ObjectId O - μ±„νŒ…λ°© ObjectId
message ObjectId X - μ—°κ΄€ λ©”μ‹œμ§€ ObjectId
fileName string O - 원본 파일 이름
fileSize number O - 파일 크기 (λ°”μ΄νŠΈ)
mimeType string O - MIME νƒ€μž…
key string O - S3 ν‚€
url string O - 파일 URL
fileType string O - "image" | "file"
isDeleted boolean X false μ†Œν”„νŠΈ μ‚­μ œ μ—¬λΆ€
createdAt Date μžλ™ - 생성 μ‹œκ°„
updatedAt Date μžλ™ - μˆ˜μ • μ‹œκ°„

ν”„λ‘ νŠΈμ—”λ“œ API ν•¨μˆ˜ (useAPIv2)

ν•¨μˆ˜λͺ… λ©”μ„œλ“œ 경둜 μ„€λͺ…
CChatRoom POST /api/chats/rooms μ±„νŒ…λ°© 생성
RChatRooms GET /api/chats/rooms μ±„νŒ…λ°© λͺ©λ‘ 쑰회
RChatRoom GET /api/chats/rooms/:roomId μ±„νŒ…λ°© 상세 쑰회
UChatRoom PUT /api/chats/rooms/:roomId μ±„νŒ…λ°© μˆ˜μ •
DChatRoom DELETE /api/chats/rooms/:roomId μ±„νŒ…λ°© λ‚˜κ°€κΈ°/μ‚­μ œ
CChatRoomParticipants POST /api/chats/rooms/:roomId/participants μ°Έκ°€μž μΆ”κ°€
DChatRoomParticipant DELETE /api/chats/rooms/:roomId/participants/:participantId μ°Έκ°€μž 제거
CChatMessage POST /api/chats/rooms/:roomId/messages λ©”μ‹œμ§€ 전솑
RChatMessages GET /api/chats/rooms/:roomId/messages λ©”μ‹œμ§€ λͺ©λ‘ 쑰회
UChatRoomRead PUT /api/chats/rooms/:roomId/read 읽음 처리
CChatFileUpload POST /api/chats/rooms/:roomId/upload 파일 μ—…λ‘œλ“œ
RChatFiles GET /api/chats/files λ‚΄ 파일 λͺ©λ‘ 쑰회
DChatFile DELETE /api/chats/files/:fileId 파일 μ‚­μ œ
RChatFileSignedUrl GET /api/chats/files/:fileId/signed λ‹€μš΄λ‘œλ“œ URL 쑰회
RChatUsers GET /api/chats/users μ‚¬μš©μž 검색