μ€μκ° μ±ν
κΈ°λ₯μ 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)μ κ²½μ° λμΌν μ°Έκ°μ μ‘°ν©μ μ±ν
λ°©μ΄ μ΄λ―Έ μ‘΄μ¬νλ©΄ κΈ°μ‘΄ μ±ν
λ°©μ λ°νν©λλ€.
κΆν : 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λͺ
μ΄ μλ κ²½μ°
νμ¬ μ¬μ©μκ° μ°Έκ° μ€μΈ νμ± μ±ν
λ°© λͺ©λ‘μ μ‘°νν©λλ€. λ§μ§λ§ λ©μμ§ μκ° κΈ°μ€ λ΄λ¦Όμ°¨μμΌλ‘ μ λ ¬λ©λλ€.
κΆν : isLoggedIn + isChatEnabled
{
"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
{
"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
}
}
{
"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
μν μ½λ
λ©μμ§
μ€λͺ
403
PERMISSION_DENIED
μ±ν
λ°© μ°Έκ°μκ° μλ κ²½μ°
404
__NOT_FOUND(room)
μ±ν
λ°©μ μ°Ύμ μ μμ
μ±ν
λ°© μμ (λ°©μ₯ μ μ©)
λ°©μ₯μ΄ μ±ν
λ°©μ κ°μ μμ ν©λλ€. μννΈ μμ (isActive = false) μ²λ¦¬λλ©°, λͺ¨λ μ°Έκ°μμκ² room_deleted μμΌ μ΄λ²€νΈκ° λ°μ‘λ©λλ€.
DELETE /api/chats/rooms/:roomId/creator
κΆν : isLoggedIn + isChatEnabled (λ°©μ₯λ§ κ°λ₯)
νλΌλ―Έν°
νμ
μ€λͺ
roomId
string
μ±ν
λ°© ObjectId
μν μ½λ
λ©μμ§
μ€λͺ
403
PERMISSION_DENIED
λ°©μ₯μ΄ μλ κ²½μ°
404
__NOT_FOUND(room)
μ±ν
λ°©μ μ°Ύμ μ μμ
μ΄λ²€νΈ
λμ
νμ΄λ‘λ
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" : " μ΄μν¬"
}
]
}
{
"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)
μ±ν
λ°©μ μ°Ύμ μ μμ
μ΄λ²€νΈ
λμ
νμ΄λ‘λ
participants_added
λͺ¨λ μ°Έκ°μ
{ room, newParticipants, addedBy }
κ·Έλ£Ή μ±ν
λ°©μμ μ°Έκ°μλ₯Ό κ°μ μ κ±°ν©λλ€. λ°©μ₯λ§ μ¬μ©ν μ μμΌλ©°, μκΈ° μμ μ μ κ±°ν μ μμ΅λλ€ (λμ μ±ν
λ°© λκ°κΈ°λ₯Ό μ¬μ©).
DELETE /api/chats/rooms/:roomId/participants/:participantId
κΆν : isLoggedIn + isChatEnabled (λ°©μ₯λ§ κ°λ₯)
νλΌλ―Έν°
νμ
μ€λͺ
roomId
string
μ±ν
λ°© ObjectId
participantId
string
μ κ±°ν μ°Έκ°μμ user ObjectId
{
"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)
ν΄λΉ μ°Έκ°μλ₯Ό μ°Ύμ μ μμ
μ΄λ²€νΈ
λμ
νμ΄λ‘λ
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"
}
}
{
"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)
μ±ν
λ°©μ μ°Ύμ μ μμ
μ΄λ²€νΈ
λμ
νμ΄λ‘λ
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
{
"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
μν μ½λ
λ©μμ§
μ€λͺ
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
{
"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λ‘ μλ λ³νλ©λλ€.
κΆν : isLoggedIn + isChatEnabled
νλΌλ―Έν°
νμ
νμ
μ€λͺ
fileType
string
X
νμΌ μ ν νν° ("image" | "file")
limit
number
X
μ‘°νν νμΌ μ (κΈ°λ³Έκ°: 20)
before
string
X
μ΄ μκ° μ΄μ μ νμΌ μ‘°ν (ISO 8601 νμ, 컀μ νμ΄μ§λ€μ΄μ
)
GET /api/chats/files?fileType=image&limit=10
{
"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
μν μ½λ
λ©μμ§
μ€λͺ
403
PERMISSION_DENIED
νμΌ μμ μκ° μλ κ²½μ°
404
__NOT_FOUND(file)
νμΌμ μ°Ύμ μ μμ
νμΌμ λ€μ΄λ‘λμ© Pre-Signed URLμ μμ±ν©λλ€. νμΌ μμ μ λλ ν΄λΉ νμΌμ΄ 곡μ λ μ±ν
λ°©μ μ°Έκ°μκ° μ κ·Όν μ μμ΅λλ€. URL μ ν¨ μκ°μ 5λΆμ
λλ€.
GET /api/chats/files/:fileId/signed
κΆν : isLoggedIn + isChatEnabled
νλΌλ―Έν°
νμ
μ€λͺ
fileId
string
νμΌ ObjectId
{
"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μΌλ‘ κ²μνλ©°, νκ΅λ³ νν°λ§μ΄ κ°λ₯ν©λλ€. νμ¬ λ‘κ·ΈμΈν μ¬μ©μλ κ²°κ³Όμμ μ μΈλ©λλ€.
κΆν : isLoggedIn + isChatEnabled
νλΌλ―Έν°
νμ
νμ
μ€λͺ
q
string
X
κ²μμ΄ (userId λλ userName λμλ¬Έμ λ¬΄κ΄ λΆλΆ μΌμΉ)
sid
string
X
νκ΅ ObjectIdλ‘ νν°λ§
GET /api/chats/users?q=νκΈΈ&sid=507f1f77bcf86cd799439099
{
"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 }
νλ
νμ
νμ
κΈ°λ³Έκ°
μ€λͺ
_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
μλ
-
μμ μκ°
νλ
νμ
νμ
μ€λͺ
user
ObjectId
O
μ¬μ©μ ObjectId
userId
string
O
μ¬μ©μ ID
userName
string
O
μ¬μ©μ μ΄λ¦
profile
string
X
νλ‘ν μ΄λ―Έμ§ URL
joinedAt
Date
X
μ°Έκ° μκ° (κΈ°λ³Έ: νμ¬ μκ°)
lastReadAt
Date
X
λ§μ§λ§ μ½μ μκ°
νλ
νμ
μ€λͺ
content
string
λ©μμ§ λ΄μ© (μ΅λ 100μ)
sender
ObjectId
λ°μ μ ObjectId
senderName
string
λ°μ μ μ΄λ¦
sentAt
Date
μ μ‘ μκ°
νλ
νμ
κΈ°λ³Έκ°
μ€λͺ
allowInvites
boolean
true
μΌλ° μ°Έκ°μμ μ΄λ νμ© μ¬λΆ
allowChat
boolean
true
μΌλ° μ°Έκ°μμ λ©μμ§ μ μ‘ νμ© μ¬λΆ
νλ
νμ
νμ
κΈ°λ³Έκ°
μ€λͺ
_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
μλ
-
μμ μκ°
νλ
νμ
μ€λͺ
url
string
νμΌ URL (μλͺ
URL)
fileName
string
νμΌ μ΄λ¦
fileSize
number
νμΌ ν¬κΈ° (λ°μ΄νΈ)
mimeType
string
MIME νμ
key
string
S3 ν€ (μλͺ
URL μμ±μ©)
νλ
νμ
μ€λͺ
user
ObjectId
μ½μ μ¬μ©μ ObjectId
readAt
Date
μ½μ μκ°
νλ
νμ
νμ
κΈ°λ³Έκ°
μ€λͺ
_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
μ¬μ©μ κ²μ