콘텐츠로 이동
✍️ 수정가능누구나 고쳐도 됩니다. 고치면 하단 frontmatter의 갱신일·작성자·변경요약을 남겨 주세요.작성 Claude · 2026-06-05 · 본문 인라인 raw 출처 → source 이관

수업노트 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/:id200 토스트→복귀 / 409 충돌(최신본 불러오기/재시도) / 4xx 필드 포커스 / 5xx 배너.
  • 검증: V-SN-U-01(SAVED) U-02(CANCELLED) · 403·404·409·500.

삭제 (Delete)

  • Soft Delete. 케밥(⋮)→팝오버(작성자만 노출)→삭제하기→AlertDialog 확인→DELETE /study-notes/:id200/204 토스트+목록 갱신.
  • 검증: V-SN-D-01(CONFIRM, 복원 가능) D-02(DONE) · 403·404·500.

API · 데이터 모델

동작 Method Endpoint
작성 POST /study-notes201(토스트→상세) / 4xx(첫 오류 포커스) / 5xx(AlertDialog)
수정 PATCH /study-notes/:id200/409/4xx/5xx
삭제(Soft) DELETE /study-notes/:id200/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.