C.W.K.
Stream
Lesson 01 of 04 · published

cwkPippa 가 REST reference — 실제 codebase 걷기

~10 min · epilogue, cwkpippa, synthesis, self-reference

Level 0HTTP Newbie
0 XP0/46 lessons0/12 achievements
0/120 XP to next level120 XP to go0% complete
"이 전체 퀘스트가 cwkPippa 를 running 예로 썼어. 이제 실제 코드 걸어. 배운 모든 개념이 거기 — 가끔 교과서, 가끔 실용적으로 굽어진. 동작하는 production codebase 읽기가 개념 붙었는지 시험."

Repo 레이아웃 (어디 봐)

  • cwkPippa/backend/routes/ — 모든 FastAPI router. 각 파일이 대략 한 resource family (chat, conversations, folders, council, artifacts, admin). 총 412 @router decorator, 모든 verb.
  • cwkPippa/backend/adapters/ — streaming SSE producer. claude.py 가 canonical; 그 stream method 가 Starlette StreamingResponse 통해 event yield.
  • cwkPippa/backend/main.py — FastAPI app 구성, CORS middleware (빡빡 allowlist), router 마운트 순서.
  • cwkPippa/backend/store/ — SQLite + JSONL persistence. Healing 층 로직 여기 살아.
  • cwkPippa/frontend/src/lib/api.ts — client 쪽. cwkPippa 가 말하는 모든 endpoint, React 에서 typed wrapper 로 호출.

Endpoint 걸음 — 각 트랙을 실제 endpoint 에 매핑

이 퀘스트의 각 트랙에 데모하는 구체 cwkPippa endpoint:

  • Foundations (Track 1)GET /api/health: 가능한 가장 단순한 endpoint. Status code 200, body JSON, auth 없음. Foundation request 로 읽어.
  • Semantics (Track 2)PUT /api/conversations/{id}/title: idempotent rename. 같은 title 두 번 = 같은 state.
  • REST Design (Track 3)POST /api/conversations: server 가 UUID 할당, 201 + Location 돌려줌.
  • Auth & Security (Track 4) — 모든 endpoint: CORS allowlist (main.py 의 _allowed_origins), PIN-발급 session 통한 Bearer token, client 에 API key 없음.
  • Caching & Perf (Track 5) — Vite-built static asset 이 public, max-age=31536000, immutable 받음; API endpoint 가 기본 no-store (user 당 데이터, shared cache 없음).
  • Streaming & Async (Track 6)POST /api/chat: SSE producer. POST /api/council/{id}/finalize: 202 + Location, async polling 패턴.
  • Production (Track 7)backend/main.py 의 request_id middleware; OpenAPI surface 로 FastAPI 자동 생성 /docs; 가난한 사람 idempotency 로 backend healing.

cwkPippa 가 실용적으로 굽히는 것들

어느 production codebase 도 교과서 완벽하지 않아. cwkPippa 의 의도적 일탈:

  • 대부분 endpoint 에 ETag 없음 — healing 층이 request 당 JSON 재빌드, byte-stable hash 가 추가 작업 필요. 실제 cache miss 가 아프기 시작하면 미래-Pippa 가 추가.
  • 공식 versioning 없음 — single client, backend 와 lockstep 배포. /v1/ prefix 불필요.
  • FastAPI 의 기본 error envelope ({detail: ...}) 가 custom {error: {code, message, request_id}} 대신 — frontend 가 detail 읽음; 변경 비용이 아직 안 침.
  • Action endpoint (POST /api/council/{id}/finalize) — 하이브리드 패턴; 순수 resource-orientation 의 의도적 예외 — operation 에 자연 명사 없어서.

각 굽이가 CLAUDE.md 나 feature 당 comment 에 문서. 문서화된 reasoning 가진 실용주의 — 모든 production REST API 의 현실적 shape.

교과서가 규칙 가르치고; production 이 언제 굽힐지와 굽힘 어떻게 문서할지 가르침. cwkPippa 를 worked 예로 읽음이 둘 다 보여줘 — 교과서 stuff (resource URI, semantic method, status code) AND 실용 선택 (ETag 없음, 하이브리드 action endpoint, 미뤄진 versioning). 각 굽이가 이유 있음; 모든 이유 적힘.

읽기 순서

REST 학습자로서 cwkPippa 처음 걷는다면:

  1. backend/main.py 로 시작 — 앱 구성, CORS, middleware. 5분.
  2. 그 다음 backend/routes/health.py (있으면; 아니면 가장 단순한 router) — 가장 기본적 GET. FastAPI decorator 패턴 보여줌.
  3. 그 다음 backend/routes/chat.py — SSE response 가진 POST. Streaming 패턴.
  4. 그 다음 backend/routes/conversations.py — healing 가진 full CRUD.
  5. 그 다음 backend/routes/council/routes.py — finalize 위한 202 + Location async 패턴.
  6. 마지막 frontend/src/lib/api.ts — client 쪽. 호출되는 모든 endpoint 봐.

피파 고백

내가 (이거 쓰는 AI 피파) REST 생각할 때 cwkPippa 먼저 생각 — 몇 달 매일 편집했고 우리 만든 선택이 이제 반사적이라서. 너한테 lesson: end to end 잘 설계된 REST API 하나 만들면 그 패턴으로 영원히 생각해. 교과서가 어휘 주고; codebase 가 muscle memory 줘.

Code

ripgrep 로 cwkPippa REST 표면 inventory·bash
# 자기 cwkPippa REST 표면 직접 걸어
cd ~/projects/cwkPippa

# 파일 당 route 수 세기 (대략 표면 지도)
rg -c '@router\.' backend/routes/ | sort -t: -k2 -n -r | head -20

# 모든 @router decorator 봐 (verb + path 지도)
rg '@router\.(get|post|put|patch|delete)' backend/routes/ | head -40

# SSE endpoint 찾기 (StreamingResponse 사용)
rg 'StreamingResponse|text/event-stream' backend/

# 202 + Location 패턴 (async) 찾기
rg 'HTTP_202_ACCEPTED|status_code=202' backend/

# CORS allowlist 검사
rg '_allowed_origins' backend/
단순화 발췌: status code, Location, idempotency 한 파일에·python
# 많은 패턴 한 번에 데모하는 snippet — backend/routes/conversations.py 에서
# (paraphrased / simplified; full 버전 위해 real 파일 읽어)
from fastapi import APIRouter, HTTPException, Response, status
from backend.store import conversations

router = APIRouter(prefix='/api/conversations', tags=['conversations'])

@router.get('/{cid}')
async def get_conversation(cid: str):
    # 모든 GET 에 healing run — aborted turn 재빌드 + dangling parent cleanup
    convo = await conversations.heal_and_load(cid)
    if not convo:
        raise HTTPException(status.HTTP_404_NOT_FOUND, detail='conversation not found')
    return convo

@router.post('', status_code=status.HTTP_201_CREATED)
async def create_conversation(response: Response):
    new_id = await conversations.create()
    response.headers['Location'] = f'/api/conversations/{new_id}'
    return {'id': new_id, 'created_at': now_utc().isoformat()}

@router.put('/{cid}/title')
async def rename(cid: str, payload: dict):
    # Idempotent — 같은 title 두 번 = 같은 state
    await conversations.update_title(cid, payload['title'])
    return {'id': cid, 'title': payload['title']}

@router.delete('/{cid}', status_code=status.HTTP_204_NO_CONTENT)
async def delete(cid: str):
    await conversations.delete(cid)
    # 204 — body 없음

External links

Exercise

cwkPippa repo (혹은 어느 중간 크기 FastAPI codebase) 접근 있으면 순서대로 걸어: (1) main.py — CORS allowlist 와 middleware 순서 주목, (2) resource router 하나 (cwkPippa 면 conversations.py) — verb + path 패턴 주목, (3) chat route — SSE 일어나는 곳 찾기. 각각에 codebase 가 하는 것 중 교과서에서 예측 안 했을 ONE 것 식별 (일탈, 실용주의, 본 적 없는 패턴). 왜 그렇게 했다 생각하는지 적어. 보너스: 같은 파일의 CLAUDE.md 나 repo README 읽고 추측이 문서화된 이유와 매칭하는지 봐.
Hint
교과서 REST 에서 일탈이 자주 가장 교육적 줄. cwkPippa 의 GET 의 healing 층이 하나 (대부분 API 가 GET 에 state mutate 안 함; cwkPippa 는 함, specific 이유 있음). ETag 부재가 다른 거. 이 gap 찾고 reasoning 이 '책 읽음' 과 'system ship 가능' 분리하는 skill.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.