Files
Hyungi Ahn 477be3892a docs(events): PR-1 → PR-2 quickref — API contract + 5초 행동 기록 UX 가이드
PR-2 (frontend UI MVP) 진입 전 reference doc. plan: beszel-tingly-sloth.md v6.

내용:
- JWT 인증 flow (curl 예시)
- 9 endpoint 표 (Create/List/Detail + 4 Lifecycle + 3 View)
- kind / status enum 의미 + UI 분기 hint
- 빠른 행동 기록 5초 UX (PR-2 핵심 가설)
- PR-2 smoke 로 자연 검증할 5건 (PR-1 closure 의 deferred 항목)
- events_history 조회 endpoint 미존재 (필요 시 PR-2 에서 추가)

authoritative API contract = /openapi.json. 본 doc 은 frontend cheat sheet.
2026-05-11 07:50:33 +09:00

4.6 KiB

events API quickref (PR-1 → PR-2 frontend reference)

Plan: ~/.claude/plans/beszel-tingly-sloth.md v6 PR-1 closure: 2026-05-11, schema + endpoint registration 검증 완료. JWT 의존 HTTP behavior 는 PR-2 UI smoke 로 자연 검증. Authoritative contract: GET /openapi.json (자동 생성). 본 문서는 frontend 개발자용 cheat sheet.

인증

모든 events endpoint = JWT Bearer (기존 get_current_user 의존성).

# 로그인 → access_token
TOKEN=$(curl -s -X POST https://document.hyungi.net/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"<USERNAME>","password":"<PASSWORD>","totp_code":"<TOTP_IF_ENABLED>"}' \
  | jq -r .access_token)

# events 호출
curl -H "Authorization: Bearer $TOKEN" https://document.hyungi.net/api/events/today

Frontend (SvelteKit 5) 는 기존 lib/api.ts 의 fetch wrapper (JWT 자동 첨부) 그대로 사용.

9 endpoint

Create / List / Detail

Method Path 용도
POST /api/events/ 생성. kind=task/calendar_event/activity_log. activity_log 면 status=done + ended_at=now() default.
GET /api/events/ 목록. ?kind&status&from&to&project_tag&source&page&page_size. Upcoming = ?from=now&to=now+7d&status=scheduled,next,deferred.
GET /api/events/{id} 상세.
PATCH /api/events/{id} edit. 허용: title/description/시간 7필드/priority/project_tag/tags/memo_document_id. 금지 (422): status/completed_at/cancelled_at/defer_until/source/source_ref/raw_metadata/user_id/created_by. 시간 필드 변경 시 reschedule history 자동.

Lifecycle (각 호출당 events_history 1 row 자동)

Method Path 효과
POST /api/events/{id}/complete status=done + completed_at=now()
POST /api/events/{id}/cancel status=cancelled + cancelled_at=now()
POST /api/events/{id}/defer body {defer_until: ISO} → status=deferred + defer_until 설정
POST /api/events/{id}/reactivate task → inbox, calendar_event → scheduled, activity_log → 400 거부

View

Method Path 정책
GET /api/events/today ?timezone=Asia/Seoul (default). due_at/start_at/started_at 이 오늘이고 status ∈ {inbox, next, scheduled, in_progress} 또는 (deferred AND defer_until <= now).
GET /api/events/inbox status=inbox 만.
GET /api/events/activity ?from&to. kind=activity_log + status=done 만. Today 와 분리.

kind / status 의미 (UI 분기 가이드)

kind 주요 시간 필드 default status UI hint
task due_at (start_at/end_at optional, "14:00 전화" 같은 시각 task 허용) inbox 체크박스 + 마감일 표시
calendar_event start_at (필수) + end_at (optional) scheduled 캘린더 일정 카드
activity_log started_at OR ended_at (둘 다 NULL 금지) done "방금 한 일" 입력 / Activity 타임라인
status 의미
inbox 아직 정리 안 됨
next 다음 행동으로 선정 (시간 미정)
scheduled 시간/날짜 잡힘
in_progress 진행 중
done 완료
cancelled 취소
deferred defer_until 까지 숨김

빠른 행동 기록 5초 UX (PR-2 핵심 가설)

// 1입력 필드 → Enter → POST /api/events
api.post('/api/events/', {
  kind: 'activity_log',
  title: '<사용자 입력>'
  // status/started_at/ended_at/completed_at 모두 server-side default
})

→ status=done + started_at=ended_at=completed_at=now() 자동 → Activity 탭 즉시 반영 + 새로고침 유지.

검증되지 않은 HTTP behavior 항목 (PR-2 smoke 시 닫기)

PR-1 closure 시 schema/endpoint registration 만 자동 검증. 아래 5건은 frontend 호출하며 자연 검증:

  1. POST /api/events kind=activity_log + title only → status=done + 시간 default 채워짐
  2. POST /api/events/{id}/complete 호출 → events_history row 1건 (change_kind=complete) 자동 생성
  3. PATCH /api/events/{id} 시간 필드 변경 → reschedule history 자동
  4. PATCH /api/events/{id} 금지 필드 (status 등) 시도 → 422 응답 (Pydantic extra=forbid)
  5. GET /api/events/today?timezone=Asia/Seoul → 오늘 (KST 기준) 항목만 반환, deferred 는 defer_until ≤ now 조건 만족 시만

events_history 조회 (PR-2 history timeline)

PR-1 에는 history 조회 endpoint 없음. PR-2 시 상세 페이지 timeline 필요하면 GET /api/events/{id}/history 신규 추가 (간단 — events_history 테이블 ORDER BY changed_at). 별 endpoint 추가 시 본 문서 갱신.