μλ¦Ό(Notification) λ° μλ¦Ό μ€μ (NotificationSetting) APIμ λλ€. μλ¦Όμ μμ±, μ‘°ν, νμΈ(μ½μ), μμ μ μλ¦Ό μ νλ³ μμ μ€μ μ κ΄λ¦¬ν©λλ€.
λΌμ°νΈ νμΌ:
backend/src/routes/notifications.js컨νΈλ‘€λ¬ νμΌ:backend/src/controllers/notifications.jsλͺ¨λΈ νμΌ:backend/src/models/Notification.js,backend/src/models/NotificationSetting.js
| λ©μλ | κ²½λ‘ | μ€λͺ | κΆν |
|---|---|---|---|
POST |
/api/notifications |
μλ¦Ό μμ± | isLoggedIn (admin|manager λλ νμ± λ±λ‘μ΄ μλ teacher) |
GET |
/api/notifications |
μλ¦Ό λͺ©λ‘ μ‘°ν | isLoggedIn |
GET |
/api/notifications/:_id |
μλ¦Ό μμΈ μ‘°ν | isLoggedIn (λ³ΈμΈ μμ ) |
PUT |
/api/notifications/:_id/check |
μλ¦Ό νμΈ | isLoggedIn (λ³ΈμΈ μμ ) |
DELETE |
/api/notifications/:_id |
μλ¦Ό μμ | isLoggedIn (λ³ΈμΈ μμ ) |
PUT |
/api/notifications/bulk-check |
μλ¦Ό μΌκ΄ νμΈ | isLoggedIn |
GET |
/api/notifications/settings |
μλ¦Ό μ€μ μ‘°ν | isLoggedIn |
PUT |
/api/notifications/settings |
μλ¦Ό μ€μ μμ | isLoggedIn |
GET |
/api/notifications/push/vapid-public-key |
Web Push VAPID 곡κ°ν€ | isLoggedIn |
POST |
/api/notifications/push/subscribe |
Web Push ꡬλ λ±λ‘ | isLoggedIn |
DELETE |
/api/notifications/push/subscribe |
Web Push ꡬλ ν΄μ | isLoggedIn |
POST |
/api/notifications/push/test |
Web Push ν μ€νΈ λ°μ‘ | isLoggedIn |
μλ¦Όμ μμ±νμ¬ μ§μ λ μ¬μ©μλ€μκ² λ°μ‘ν©λλ€. μμ μλ³λ‘ received νμ
μλ¦Όμ΄, λ°μ μμκ²λ sent νμ
μλ¦Όμ΄ μμ±λ©λλ€. μμ± ν Socket.ioλ₯Ό ν΅ν΄ μμ μμκ² μ€μκ° μλ¦Ό μ΄λ²€νΈ(listen)κ° μ μ‘λ©λλ€.
POST /api/notifications
κΆν: isLoggedIn - admin λλ managerλ νμ νμ©, κ·Έ μΈ μ¬μ©μλ νμ±νλ teacher λ±λ‘μ΄ μμ΄μΌ ν¨
| νλ | νμ | νμ | μ€λͺ |
|---|---|---|---|
toUserList |
object[] |
O | μμ μ λͺ©λ‘ |
toUserList[].user |
string |
O | μμ μ ObjectId |
toUserList[].userId |
string |
O | μμ μ μ¬μ©μ ID |
toUserList[].userName |
string |
O | μμ μ μ΄λ¦ |
title |
string |
O | μλ¦Ό μ λͺ© |
description |
string |
O | μλ¦Ό λ΄μ© |
category |
string |
X | μλ¦Ό μΉ΄ν κ³ λ¦¬ |
{
"toUserList": [
{
"user": "507f1f77bcf86cd799439011",
"userId": "student01",
"userName": "νκΈΈλ"
},
{
"user": "507f1f77bcf86cd799439012",
"userId": "student02",
"userName": "κΉμ² μ"
}
],
"title": "μμ
μλ΄",
"description": "λ΄μΌ μ€ν 3μμ 보좩 μμ
μ΄ μμ΅λλ€.",
"category": "μμ
"
}{
"notifications": [
{
"_id": "507f1f77bcf86cd799439101",
"type": "received",
"user": "507f1f77bcf86cd799439011",
"userId": "student01",
"userName": "νκΈΈλ",
"fromUser": "507f1f77bcf86cd799439099",
"fromUserId": "teacher01",
"fromUserName": "λ°μ μ",
"checked": false,
"category": "μμ
",
"title": "μμ
μλ΄",
"description": "λ΄μΌ μ€ν 3μμ 보좩 μμ
μ΄ μμ΅λλ€.",
"notificationType": "direct",
"autoDeleteOnCheck": true,
"date": "2024-03-15T09:00:00.000Z",
"createdAt": "2024-03-15T09:00:00.000Z",
"updatedAt": "2024-03-15T09:00:00.000Z"
},
{
"_id": "507f1f77bcf86cd799439102",
"type": "received",
"user": "507f1f77bcf86cd799439012",
"userId": "student02",
"userName": "κΉμ² μ",
"fromUser": "507f1f77bcf86cd799439099",
"fromUserId": "teacher01",
"fromUserName": "λ°μ μ",
"checked": false,
"category": "μμ
",
"title": "μμ
μλ΄",
"description": "λ΄μΌ μ€ν 3μμ 보좩 μμ
μ΄ μμ΅λλ€.",
"notificationType": "direct",
"autoDeleteOnCheck": true,
"date": "2024-03-15T09:00:00.000Z",
"createdAt": "2024-03-15T09:00:00.000Z",
"updatedAt": "2024-03-15T09:00:00.000Z"
},
{
"_id": "507f1f77bcf86cd799439103",
"type": "sent",
"user": "507f1f77bcf86cd799439099",
"userId": "teacher01",
"userName": "λ°μ μ",
"toUserList": [
{
"user": "507f1f77bcf86cd799439011",
"userId": "student01",
"userName": "νκΈΈλ"
},
{
"user": "507f1f77bcf86cd799439012",
"userId": "student02",
"userName": "κΉμ² μ"
}
],
"category": "μμ
",
"title": "μμ
μλ΄",
"description": "λ΄μΌ μ€ν 3μμ 보좩 μμ
μ΄ μμ΅λλ€.",
"notificationType": "direct",
"autoDeleteOnCheck": true,
"date": "2024-03-15T09:00:00.000Z",
"createdAt": "2024-03-15T09:00:00.000Z",
"updatedAt": "2024-03-15T09:00:00.000Z"
}
]
}| μν μ½λ | λ©μμ§ | μ€λͺ |
|---|---|---|
400 |
FIELD_REQUIRED({νλλͺ
}) |
νμ νλ λλ½ (toUserList, title, description, user, userId, userName) |
403 |
PERMISSION_DENIED |
admin/managerκ° μλκ³ νμ± teacher λ±λ‘μ΄ μλ κ²½μ° |
λ‘κ·ΈμΈν μ¬μ©μμ μλ¦Ό λͺ©λ‘μ μ‘°νν©λλ€. μ±λ₯μ μν΄ description νλλ μλ΅μμ μ μΈλ©λλ€.
GET /api/notifications
κΆν: isLoggedIn
| νλΌλ―Έν° | νμ | νμ | μ€λͺ |
|---|---|---|---|
type |
string |
O | "received" (λ°μ μλ¦Ό) λλ "sent" (λ³΄λΈ μλ¦Ό) |
checked |
string |
X | "true" λλ "false" - νμΈ μ¬λΆλ‘ νν°λ§ |
{
"notifications": [
{
"_id": "507f1f77bcf86cd799439101",
"type": "received",
"user": "507f1f77bcf86cd799439011",
"userId": "student01",
"userName": "νκΈΈλ",
"fromUser": "507f1f77bcf86cd799439099",
"fromUserId": "teacher01",
"fromUserName": "λ°μ μ",
"checked": false,
"category": "μμ
",
"title": "μμ
μλ΄",
"notificationType": "direct",
"autoDeleteOnCheck": true,
"date": "2024-03-15T09:00:00.000Z",
"createdAt": "2024-03-15T09:00:00.000Z",
"updatedAt": "2024-03-15T09:00:00.000Z"
}
]
}μ°Έκ³ :
descriptionνλλ λͺ©λ‘ μ‘°ν μ μ±λ₯ μ΅μ νλ₯Ό μν΄ μ μΈλ©λλ€. μμΈ λ΄μ©μ΄ νμνλ©΄ κ°λ³ μλ¦Ό μμΈ μ‘°ν APIλ₯Ό μ¬μ©νμΈμ.
| μν μ½λ | λ©μμ§ | μ€λͺ |
|---|---|---|
400 |
FIELD_REQUIRED(type) |
type 쿼리 νλΌλ―Έν° λλ½ |
μλ¦Όμ μμΈ μ 보λ₯Ό μ‘°νν©λλ€. description νλλ₯Ό ν¬ν¨ν μ 체 λ°μ΄ν°λ₯Ό λ°νν©λλ€.
GET /api/notifications/:_id
κΆν: isLoggedIn (λ³ΈμΈ μμ μλ¦Όλ§ μ‘°ν κ°λ₯)
| νλΌλ―Έν° | νμ | μ€λͺ |
|---|---|---|
_id |
string |
μλ¦Ό ObjectId |
{
"notification": {
"_id": "507f1f77bcf86cd799439101",
"type": "received",
"user": "507f1f77bcf86cd799439011",
"userId": "student01",
"userName": "νκΈΈλ",
"fromUser": "507f1f77bcf86cd799439099",
"fromUserId": "teacher01",
"fromUserName": "λ°μ μ",
"checked": false,
"category": "μμ
",
"title": "μμ
μλ΄",
"description": "λ΄μΌ μ€ν 3μμ 보좩 μμ
μ΄ μμ΅λλ€.",
"notificationType": "direct",
"relatedEntity": {
"type": "enrollment",
"id": "507f1f77bcf86cd799439201"
},
"autoDeleteOnCheck": true,
"date": "2024-03-15T09:00:00.000Z",
"createdAt": "2024-03-15T09:00:00.000Z",
"updatedAt": "2024-03-15T09:00:00.000Z"
}
}| μν μ½λ | λ©μμ§ | μ€λͺ |
|---|---|---|
403 |
PERMISSION_DENIED |
λ³ΈμΈ μμ κ° μλ μλ¦Ό μ‘°ν μλ |
404 |
NOTIFICATION_NOT_FOUND |
μλ¦Όμ μ°Ύμ μ μμ |
μλ¦Όμ νμΈ(μ½μ) μ²λ¦¬ν©λλ€. autoDeleteOnCheckκ° trueμΈ νλ°μ± μλ¦Όμ νμΈ μ μλμΌλ‘ μμ λλ©°, falseμΈ μλ¦Όμ checkedκ° trueλ‘ λ³κ²½λ©λλ€.
PUT /api/notifications/:_id/check
κΆν: isLoggedIn (λ³ΈμΈ μμ μλ¦Όλ§ νμΈ κ°λ₯)
| νλΌλ―Έν° | νμ | μ€λͺ |
|---|---|---|
_id |
string |
μλ¦Ό ObjectId |
{}| μν μ½λ | λ©μμ§ | μ€λͺ |
|---|---|---|
403 |
PERMISSION_DENIED |
λ³ΈμΈ μμ κ° μλ μλ¦Ό νμΈ μλ |
404 |
NOTIFICATION_NOT_FOUND |
μλ¦Όμ μ°Ύμ μ μμ |
μλ¦Όμ μμ ν©λλ€.
DELETE /api/notifications/:_id
κΆν: isLoggedIn (λ³ΈμΈ μμ μλ¦Όλ§ μμ κ°λ₯)
| νλΌλ―Έν° | νμ | μ€λͺ |
|---|---|---|
_id |
string |
μλ¦Ό ObjectId |
{}| μν μ½λ | λ©μμ§ | μ€λͺ |
|---|---|---|
403 |
PERMISSION_DENIED |
λ³ΈμΈ μμ κ° μλ μλ¦Ό μμ μλ |
404 |
NOTIFICATION_NOT_FOUND |
μλ¦Όμ μ°Ύμ μ μμ |
λ‘κ·ΈμΈν μ¬μ©μμ λ―ΈνμΈ μμ μλ¦Όμ μΌκ΄ νμΈ μ²λ¦¬ν©λλ€. autoDeleteOnCheckκ° trueμΈ νλ°μ± μλ¦Όμ μμ λκ³ , λΉνλ°μ± μλ¦Όμ checkedκ° trueλ‘ λ³κ²½λ©λλ€.
PUT /api/notifications/bulk-check
κΆν: isLoggedIn
{
"checkedCount": 5,
"deletedCount": 3
}| νλ | νμ | μ€λͺ |
|---|---|---|
checkedCount |
number |
νμΈ μ²λ¦¬λ λΉνλ°μ± μλ¦Ό μ |
deletedCount |
number |
μμ λ νλ°μ± μλ¦Ό μ |
λ‘κ·ΈμΈν μ¬μ©μμ μλ¦Ό μμ μ€μ μ μ‘°νν©λλ€. μ€μ μ΄ μ‘΄μ¬νμ§ μμΌλ©΄ κΈ°λ³Έκ°μΌλ‘ μλ μμ±λ©λλ€.
GET /api/notifications/settings
κΆν: isLoggedIn
{
"settings": {
"classInvitation": true,
"classCancellation": true,
"classApproval": true,
"classApprovalCancel": true,
"scheduleStart": true,
"newPost": true,
"directMessage": true,
"soundEnabled": true,
"reminder": true,
"eventReminderDefault": 15
}
}μλ¦Ό μμ μ€μ μ μμ ν©λλ€. μ λ¬λ νλλ§ λ³κ²½λλ©°, λ―Έμ λ¬ νλλ κΈ°μ‘΄ κ°μ΄ μ μ§λ©λλ€.
PUT /api/notifications/settings
κΆν: isLoggedIn
| νλ | νμ | νμ | μ€λͺ |
|---|---|---|---|
classInvitation |
boolean |
X | μμ μ΄λ μλ¦Ό μμ μ¬λΆ |
classCancellation |
boolean |
X | μμ μ΄λ μ·¨μ μλ¦Ό μμ μ¬λΆ |
classApproval |
boolean |
X | μμ μΉμΈ μλ¦Ό μμ μ¬λΆ |
classApprovalCancel |
boolean |
X | μμ μΉμΈ μ·¨μ μλ¦Ό μμ μ¬λΆ |
scheduleStart |
boolean |
X | μΌμ μμ μλ¦Ό μμ μ¬λΆ |
newPost |
boolean |
X | μ κ²μκΈ μλ¦Ό μμ μ¬λΆ |
directMessage |
boolean |
X | μ§μ λ©μμ§ μλ¦Ό μμ μ¬λΆ |
{
"classInvitation": true,
"classCancellation": false,
"directMessage": true
}{
"settings": {
"classInvitation": true,
"classCancellation": false,
"classApproval": true,
"classApprovalCancel": true,
"scheduleStart": true,
"newPost": true,
"directMessage": true,
"soundEnabled": true,
"reminder": true,
"eventReminderDefault": 15
}
}| νλ | νμ | νμ | κΈ°λ³Έκ° | μ€λͺ |
|---|---|---|---|---|
_id |
ObjectId |
- | μλμμ± | κ³ μ μλ³μ |
type |
string |
O | - | "sent" (λ°μ ) λλ "received" (μμ ) |
user |
ObjectId |
O | - | μλ¦Ό μμ μ (λ°μ μ λλ μμ μ) |
userId |
string |
O | - | μμ μ μ¬μ©μ ID |
userName |
string |
O | - | μμ μ μ΄λ¦ |
toUserList |
object[] |
X | - | type=sentμΌ λ μμ μ λͺ©λ‘ |
fromUser |
ObjectId |
X | - | type=receivedμΌ λ λ°μ μ ObjectId |
fromUserId |
string |
X | - | type=receivedμΌ λ λ°μ μ μ¬μ©μ ID |
fromUserName |
string |
X | - | type=receivedμΌ λ λ°μ μ μ΄λ¦ |
checked |
boolean |
X | false |
type=receivedμΌ λ νμΈ μ¬λΆ |
category |
string |
X | - | μλ¦Ό μΉ΄ν κ³ λ¦¬ |
title |
string |
O | - | μλ¦Ό μ λͺ© |
description |
string |
X | - | μλ¦Ό λ΄μ© |
date |
Date |
X | μλμ€μ | insertMany μ UTC μκ°μΌλ‘ μλ μ€μ |
notificationType |
string |
X | "direct" |
μλ¦Ό μ ν (μλ μ°Έμ‘°) |
relatedEntity |
object |
X | - | κ΄λ ¨ μν°ν° μ 보 (type, id) |
autoDeleteOnCheck |
boolean |
X | true |
νμΈ μ μλ μμ μ¬λΆ (νλ°μ± μλ¦Ό) |
createdAt |
Date |
- | μλμμ± | μμ± μΌμ |
updatedAt |
Date |
- | μλμμ± | μμ μΌμ |
| μΈλ±μ€ | νλ | μμ± |
|---|---|---|
user_1_createdAt_-1 |
{ user: 1, createdAt: -1 } |
COMPOUND |
| κ° | μ€λͺ |
|---|---|
direct |
μ§μ λ°μ‘ μλ¦Ό (κΈ°λ³Έκ°) |
classInvitation |
μμ μ΄λ μλ¦Ό |
classCancellation |
μμ μ΄λ μ·¨μ μλ¦Ό |
classApproval |
μμ μΉμΈ μλ¦Ό |
classApprovalCancel |
μμ μΉμΈ μ·¨μ μλ¦Ό |
scheduleStart |
μΌμ μμ μλ¦Ό |
newPost |
μ κ²μκΈ μλ¦Ό |
reminder |
리λ§μΈλ μλ¦Ό |
| κ° | μ€λͺ |
|---|---|
enrollment |
μκ° λ±λ‘ |
syllabus |
κ°μ κ³ν |
calendarEvent |
μΊλ¦°λ μ΄λ²€νΈ |
post |
κ²μκΈ |
reminder |
리λ§μΈλ |
| νλ | νμ | νμ | κΈ°λ³Έκ° | μ€λͺ |
|---|---|---|---|---|
_id |
ObjectId |
- | μλμμ± | κ³ μ μλ³μ |
user |
ObjectId |
O | - | μ¬μ©μ ObjectId (UNIQUE) |
userId |
string |
O | - | μ¬μ©μ ID |
userName |
string |
O | - | μ¬μ©μ μ΄λ¦ |
settings |
object |
X | κΈ°λ³Έκ° κ°μ²΄ | μλ¦Ό μ€μ (μλ μ°Έμ‘°) |
createdAt |
Date |
- | μλμμ± | μμ± μΌμ |
updatedAt |
Date |
- | μλμμ± | μμ μΌμ |
| νλ | νμ | κΈ°λ³Έκ° | μ€λͺ |
|---|---|---|---|
classInvitation |
boolean |
true |
μμ μ΄λ μλ¦Ό |
classCancellation |
boolean |
true |
μμ μ΄λ μ·¨μ μλ¦Ό |
classApproval |
boolean |
true |
μμ μΉμΈ μλ¦Ό |
classApprovalCancel |
boolean |
true |
μμ μΉμΈ μ·¨μ μλ¦Ό |
scheduleStart |
boolean |
true |
μΌμ μμ μλ¦Ό |
newPost |
boolean |
true |
μ κ²μκΈ μλ¦Ό |
directMessage |
boolean |
true |
μ§μ λ©μμ§ μλ¦Ό |
soundEnabled |
boolean |
true |
μλ¦Όμ νμ±ν |
reminder |
boolean |
true |
리λ§μΈλ μλ¦Ό |
eventReminderDefault |
number |
15 |
μ΄λ²€νΈ 리λ§μΈλ κΈ°λ³Έκ° (λΆ) |
autoDeleteOnCheckκ° trueμΈ μλ¦Όμ νμΈ μ λ°μ΄ν°λ² μ΄μ€μμ μμ λ©λλ€. κΈ°λ³Έκ°μ΄ trueμ΄λ―λ‘ λλΆλΆμ μλ¦Όμ νμΈ ν μλ μμ λ©λλ€. μꡬμ μΌλ‘ 보κ΄ν΄μΌ νλ μλ¦Όμ μμ± μ autoDeleteOnCheck: falseλ‘ μ€μ ν©λλ€.
μλ¦Ό μμ± μ Socket.ioλ₯Ό ν΅ν΄ μμ μμκ² μ€μκ°μΌλ‘ μλ¦Ό μ΄λ²€νΈκ° μ μ‘λ©λλ€. κ° μ¬μ©μλ {academyId}/{userId} νμμ λ£Έμ μ μνλ©°, listen μ΄λ²€νΈλ‘ "update notifications" λ©μμ§λ₯Ό μμ ν©λλ€.
sendAutoNotification μλΉμ€λ₯Ό ν΅ν΄ λ°μ‘λλ μλ μλ¦Όμ μμ μμ μλ¦Ό μ€μ μ νμΈνμ¬, ν΄λΉ notificationTypeμ λΉνμ±νν μ¬μ©μμκ²λ μλ¦Όμ΄ λ°μ‘λμ§ μμ΅λλ€.
| ν¨μλͺ | λ©μλ | κ²½λ‘ | μ€λͺ |
|---|---|---|---|
CNotification |
POST | /api/notifications |
μλ¦Ό μμ± |
RNotifications |
GET | /api/notifications |
μλ¦Ό λͺ©λ‘ μ‘°ν |
RNotification |
GET | /api/notifications/:_id |
μλ¦Ό μμΈ μ‘°ν |
UCheckNotification |
PUT | /api/notifications/:_id/check |
μλ¦Ό νμΈ |
DNotification |
DELETE | /api/notifications/:_id |
μλ¦Ό μμ |
UBulkCheckNotifications |
PUT | /api/notifications/bulk-check |
μλ¦Ό μΌκ΄ νμΈ |
RNotificationSettings |
GET | /api/notifications/settings |
μλ¦Ό μ€μ μ‘°ν |
UNotificationSettings |
PUT | /api/notifications/settings |
μλ¦Ό μ€μ μμ |