자료실 자료를 사용자가 명시적으로 "1회독 완료" 클릭 시 +1 누적.
detail 진입 자동 카운트 ❌. append-only 로그.
데이터:
- migrations 174~176: document_reads 테이블 + 인덱스 2개 (단일 statement 분할)
ORM:
- app/models/document_read.py: DocumentRead (user_id, document_id, read_at)
API (app/api/document_reads.py, /api/documents prefix):
- POST /api/documents/{id}/read — 회독 +1
- GET /api/documents/{id}/read-stats — {read_count, last_read_at}
- DELETE /api/documents/{id}/read/last — 현재 사용자의 그 문서 마지막 1건만
· ownership: WHERE user_id=current_user.id AND document_id=:doc_id
· documents 에 user_id 부재 (single-user). multi-user 전환 시 ownership
check 추가 필요 — 코드 주석 명시.
응답 확장:
- DocumentResponse: read_count(default 0), last_read_at(default None)
- /api/documents/library: 페이지 N건 한정 LEFT JOIN 으로 read 통계 매핑 (N+1 회피)
- /api/library/tree CategoryTreeNode: unread_count 추가
· 기존 path_docs 가 ancestor 누적 구조라 그대로 활용 — 하위 경로 합산 자동
규칙 (사용자 명시 — 변경 금지):
· 같은 날 여러 번 클릭 → 각각 별개 회독
· 실수 클릭 취소 = DELETE /read/last
· documents 에 read_count 컬럼 추가 ❌, 로그 기반 COUNT(*) 만
plan: ~/.claude/plans/scalable-chasing-stonebraker.md
브랜치: feature/library-reads (손글씨 트랙과 분리)
library_categories 테이블 추가로 빈 카테고리 생성 가능.
CRUD API (생성/leaf rename/leaf delete) + 트리 머지 엔드포인트.
사이드바 트리에 컨텍스트 메뉴 (추가/이름변경/삭제).
LibraryPathEditor를 카테고리 기반 flat selector로 전환.
미분류는 시스템 분류로 보호 (삭제/이름변경 불가).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>