수업노트 FRD¶
수업노트(StudyNote)의 작성·조회·수정·삭제를 어떻게 구현하는지 정리한다. 강사·학생·보호자가 남기는 학습 기록을 스터디룸 컨텍스트 안에서 관리하며(개인 대시보드와는 분리), 라우팅은 /study-rooms/{publicId}/study-notes를 쓴다. 상위 기획은 prd에 있고, 거기서 구성요소·공개범위·그룹화가 바뀌면 아래 API·데이터 절을 맞춘다.
Spec Out (MVP 범위 밖)¶
예약 게시, 작성 템플릿, 임시저장/자동저장, 에디터 고급(헤딩/링크/이미지/표/수식/멘션), 첨부 업로드, 외부 공유 링크, 좋아요/댓글, 조회수 노출(집계는 BE만), 버전 히스토리 UI, Export, 열람자 통계, 아카이브 자동화.
기술 접근 · 아키텍처¶
도메인 구성요소¶
| 구성요소(* 필수) | 제약 |
|---|---|
| 제목* | 30~80자(문서 간 상이; FRD 30자, FDD maxlength=80) |
| 날짜* | default 작성일시 |
| 내용* | 3,000자, TipTap |
| 공개 범위* | 나만보기 / 특정학생(default) / 스터디룸 / 전체(스터디룸 비공개면 선택 불가) |
| 조회수* | 게시글당 뷰카운트(가능 시 동일 IP 1일 1회, F5 연타 미카운트 수준; 구현 3일+ 시 단순 카운트) |
기획 4종 중 특정학생·스터디룸은 각각 학생만 / 학생+보호자(default) 하위 선택을 가진다. 특정학생의 대상 default=스터디룸 학생, max 100명(추후 BM max 30 후 결제 확장). 도메인은 이를 6단계 enum으로 전개: TEACHER_ONLY / SPECIFIC_STUDENTS_ONLY / SPECIFIC_STUDENTS_AND_PARENTS / STUDY_ROOM_STUDENTS_ONLY / STUDY_ROOM_STUDENTS_AND_PARENTS / PUBLIC (→ teaching-note).
기타 정책: 사용자당 5,000개·스터디룸당 1,000개. 회원 탈퇴 시 자동 삭제 안 됨. 동적 항목(수정 시 참조 항목 일괄 업데이트). 학부모는 연결 학생에 종속.
작성 (Create)¶
- 경로
/study-rooms/{publicId}/study-notes/new. 강사(Author)만. 제출 시 1회 API. - UI: 제목(
maxlength=80) · TipTap 본문 · 공개범위 RadioGroup · 대상학생 MultiSelect(Chip,TARGET일 때 필수) · 보호자공개 Switch(isGuardianVisible). - 검증:
V-SN-C-01(제목 EMPTY)02(제목 MAX)03(본문 EMPTY)04(공개범위 필수)05(대상 필수)06(보호자 플래그).500글로벌.
조회 (List + Detail)¶
- 목록
/study-rooms/{publicId}/study-notes: 좌측 상세 / 우측 목록 SPA. 검색(제목/작성자)·정렬(최신 default/오래된/제목/조회수)·필터(공개범위/내 글만/대상학생)·페이지네이션. URL 쿼리 동기화(?page&size&sort&keyword&visibility&targetStudentId&onlyMine). - 상세
.../study-notes/:noteId: 헤더(제목/작성자/메타/가시성 아이콘)·CTA(수정·삭제=작성자, 질문하기=학생·보호자)·TipTap Viewer(XSS Safe)·대상학생 Chip(TARGET만)·과제/메모 섹션. - 비회원
/login, 비멤버/dashboard리디렉션. 가시성·isGuardianVisible에 따라 열람 제한. - 검증:
V-SN-R-01(빈 목록)R-02(결과없음) ·403(FORBIDDEN)404(NOT_FOUND)500.
그룹화¶
- 그룹 구성: 소속 스터디룸(필수) · 그룹명(필수 1~15자) · 하위 노트 0~제한없음.
- 정책: 교사만 생성. 그룹:노트 = 1:N. 생성 시 최소 1개 로그 선택. 그룹명 수정 시 참조 데이터 동적 갱신. 그룹 삭제(해제)해도 노트 보존. 작성 화면 그룹 UI는 스터디룸 선택 상태에서만 노출. (3차 스프린트 — 추후 수업노트 태그 기능으로 디벨롭.)
수정 (Update)¶
- 경로
.../study-notes/:noteId/edit. 작성자 본인만. 상세 GET 프리필. PATCH /study-notes/:id→200토스트→복귀 /409충돌(최신본 불러오기/재시도) /4xx필드 포커스 /5xx배너.- 검증:
V-SN-U-01(SAVED)U-02(CANCELLED) ·403·404·409·500.
삭제 (Delete)¶
- Soft Delete. 케밥(⋮)→팝오버(작성자만 노출)→
삭제하기→AlertDialog 확인→DELETE /study-notes/:id→200/204토스트+목록 갱신. - 검증:
V-SN-D-01(CONFIRM, 복원 가능)D-02(DONE) ·403·404·500.
API · 데이터 모델¶
| 동작 | Method | Endpoint |
|---|---|---|
| 작성 | POST |
/study-notes → 201(토스트→상세) / 4xx(첫 오류 포커스) / 5xx(AlertDialog) |
| 수정 | PATCH |
/study-notes/:id → 200/409/4xx/5xx |
| 삭제(Soft) | DELETE |
/study-notes/:id → 200/204/403/404/500 |
권한 × 공개범위 매트릭스 (FDD §1.2)
| Role \ Visibility | PRIVATE | ROOM_ONLY | TARGET | PUBLIC |
|---|---|---|---|---|
| 강사(Author) | 본인 O, 수정/삭제 O | O | O | O |
| 학생(Member) | X | O | 대상 포함 시 O | O |
| 보호자(Guardian) | X | 공개허용 시 O | 대상 학생 보호자 & 공개허용 시 O | O |
접근권한 구현(개발 메모): 모두공개=매핑테이블 없이 조인 없이 조회 / 특정학생=
수업로그_학생매핑 조인.
관련 엔티티: TeachingNote / TeachingNoteGroup / TeachingNoteStudent(특정 학생 매핑) / TeachingNoteImage(S3). 도메인 코드 매핑은 teaching-note. Request/Response 예시·일부 Status Code는 원본 미작성.
트래킹: note_create_open/submit/success/fail_4xx/fail_5xx, note_list_view/filter_change/item_click/dashboard_open_all/empty_view, note_detail_view/hw_toggle/target_open/forbidden_view, note_update_open/submit/success/conflict/fail, note_kebab_open/delete_click/confirm/success/fail.
의존성 · 영향 범위¶
- 도메인 teaching-note(엔티티·6단계 visibility·매핑테이블)·studyroom(소속 룸·멤버 권한). 질문하기는 QnA 연계.
- 공개범위 6단계 enum은 teaching-note가 SSOT — 변경 시 동기화.
테스트 계획¶
- 권한×공개범위 매트릭스(강사/학생/보호자 × PRIVATE/ROOM_ONLY/TARGET/PUBLIC) 단언,
isGuardianVisible분기. - CRUD 검증코드(
V-SN-*)·수정 충돌(409)·Soft Delete 복원, 비회원/비멤버 리디렉션, 제한(5,000/1,000) 경계 → qa-playbook.
작업 분해 (이슈 링크)¶
- 작성/조회/수정/삭제 API + 검증·트래킹, 6단계 visibility 권한 게이트, 그룹화 CRUD, 대상학생 매핑테이블, 좌상세/우목록 SPA·URL 쿼리 동기화.
- 팔로우업: 작성 횟수 기반 선생님 브랜드 강화, 노트 기반 학생 질문 게시 연계, 특정 학생 읽음 확인, 각 노트별 숙제 기능. 이슈 링크는 status.