Notification 모듈
학원 운영에 필요한 문자(SMS) 발송, 메시지 이력 관리, 재사용 가능한 문자 템플릿 관리를 담당하는 모듈입니다.
모듈 개요
| 항목 | 내용 |
|---|---|
| Gradle 서브프로젝트 | modules/notification |
| 베이스 패키지 | com.lumie.notification |
| 데이터베이스 | PostgreSQL (멀티테넌트 RLS, sms_messages / sms_templates 테이블) |
| 내부 의존 | StudentService, ClassService, StaffService |
현재 SMS 실제 발송은 mock 처리(
message.markAsSent())됩니다. 실 발송 어댑터는 추후adapter/out/external/에 추가됩니다.
주요 책임
- 개별 수신자 또는 반 전체 학생에게 문자 발송
- 발송 이력(수신자 목록, 상태, 성공/실패 수) 저장
- 재사용 문자 템플릿 생성·수정·삭제
Idempotency-Key헤더를 통한 중복 발송 방지
도메인 모델
SmsMessage 엔티티
@Entity
@Table(name = "sms_messages")
public class SmsMessage extends TenantScopedEntity {
Long id;
Long senderId; // 발신 직원 ID
RecipientType recipientType; // STUDENT | PARENT | CUSTOM
List<Recipient> recipients; // 수신자 목록 (JSONB)
String title;
String content;
Long templateId; // 사용한 템플릿 ID (선택)
Instant sentAt;
SmsStatus status; // PENDING | SENT | FAILED | PARTIAL
int successCount;
int failCount;
}
Recipient 값 객체
public record Recipient(
String phone, // 수신 전화번호
String name, // 수신자 이름
Long studentId // 학생 ID (학생 수신 시)
) {}
SmsTemplate 엔티티
@Entity
@Table(name = "sms_templates")
public class SmsTemplate extends TenantScopedEntity {
Long id; @Version Long version;
String name;
String content;
TemplateCategory category; // GENERAL | ATTENDANCE | PAYMENT | EXAM | CUSTOM
}
SmsStatus
| 값 | 의미 |
|---|---|
PENDING | 발송 대기 |
SENT | 전체 발송 성공 |
FAILED | 전체 발송 실패 |
PARTIAL | 일부 성공·일부 실패 |
RecipientType
| 값 | 의미 |
|---|---|
STUDENT | 학생 |
PARENT | 학부모 |
CUSTOM | 직접 입력 |
REST API
문자 발송 API — 기본 경로: /v1/sms
| 메서드 | 경로 | 설명 |
|---|---|---|
POST | /v1/sms/send | 문자 발송 (Idempotency-Key 지원, 201 Created) |
POST | /v1/sms/send/class/\{classId\} | 반 전체 학생에게 문자 발송 (Idempotency-Key 지원) |
GET | /v1/sms/history | 발송 이력 조회 (status, recipientType, 검색, 페이지) |
GET | /v1/sms/history/\{id\} | 특정 발송 이력 상세 |
POST /v1/sms/send 요청 예시
{
"senderId": 1,
"recipientType": "STUDENT",
"recipients": [
{ "phone": "010-1234-5678", "name": "김학생", "studentId": 42 }
],
"title": "수업 안내",
"content": "내일 수업은 오후 3시에 진행됩니다.",
"templateId": null
}
POST /v1/sms/send/class/\{classId\} 요청 예시
{
"senderId": 1,
"title": "수업 취소 안내",
"content": "금일 수업이 취소되었습니다.",
"templateId": null
}
ClassService.getEnrolledStudentIds() → StudentService.getStudentsByIds()를 통해 수신자 목록을 자동 구성합니다.
정렬 허용 필드
createdAt, sentAt, status
템플릿 API — 기본 경로: /v1/sms-templates
| 메서드 | 경로 | 설명 |
|---|---|---|
GET | /v1/sms-templates | 템플릿 목록 조회 (페이지) |
POST | /v1/sms-templates | 템플릿 생성 (201 Created) |
PATCH | /v1/sms-templates/\{id\} | 템플릿 수정 |
DELETE | /v1/sms-templates/\{id\} | 템플릿 삭제 |
내부 의존 (in-process 주입)
| 모듈 인터페이스 | 사용 목적 |
|---|---|
StaffService | 발신자(senderId) 검증 |
ClassService | 반 전체 발송 시 반 조회 및 수강생 ID 목록 획득 |
StudentService | 학생 전화번호·이름 조회 |
멀티테넌시
sms_messages 및 sms_templates 테이블 모두 tenant_id BIGINT NOT NULL + RLS 정책이 적용됩니다.
관련 문서
- Class 모듈 — 반 전체 발송 시 수강생 조회
- Student 모듈 — 학생 전화번호 조회
- Tuition 모듈 — 연체 알림 발송 연계 예정