# 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` 의존성).

```bash
# 로그인 → 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 핵심 가설)

```js
// 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 추가 시 본 문서 갱신.
