"이 Quest 의 패턴이 교과서 아냐. 실제 frontend 빌드할 때 손 뻗는 거. 모양 보여줄게."
Pippa-style frontend 의 모양
cwkPippa 가 나 돌리는 codebase — React 19 + Vite + TypeScript, frontend 대략 30,000 줄. Layout 이 관례적, 패턴이 너가 배운 거. 이 Quest 가 가르치는 방식으로 조직된 frontend 의 conceptual 구조:
frontend/
├── src/
│ ├── App.tsx # top-level component, state 들어 올려진 곳
│ ├── main.tsx # React mount point
│ ├── components/ # 영역별로 그룹화된 UI component
│ │ ├── chat/ # chat-specific
│ │ ├── sidebar/ # conversation list
│ │ ├── council/ # Family Council UI
│ │ ├── admin/ # admin panel
│ │ └── settings/ # configuration UI
│ ├── hooks/ # custom hook (useChat, useCouncil, …)
│ ├── lib/ # api, helper, utility
│ ├── types/ # 공유 타입 (BrainName, Conversation, …)
│ └── version.ts # 버전 상수
본 패턴, 야생에서
Literal-union 타입을 enum-by-convention 으로. 공유 types.ts 가 type BrainName = 'claude' | 'codex' | 'gemini' | 'ollama' 정의. 4개 brain. 모든 참조 체크; 모든 typo 가 컴파일 실패.
Streaming event 용 discriminated union. 각 SSE event 가 type 필드 가짐; 모양의 나머지가 그것에 의존. type 에 narrow 하면 event-specific 필드 접근.
Tuple 반환하는 custom hook. useChat() 가 [messages, sendMessage, status] 반환 — destructure-friendly, useState-shaped.
Strict mode throughout. 첫날부터 "strict": true. Narrowly-justified 자리 외에 any zero.
이런 frontend walk 하는 법
레시피가 손에 있는 어떤 well-typed TS frontend 든 transfer — 너의 자기 프로젝트, 기여하는 open-source 앱, 또는 존중하는 reference codebase. 이 순서로 읽어:
- 공유 타입 파일 — 보통
types/또는types.ts. 이것들 읽으면 시스템이 뭔지 알아. - API client —
lib/api.ts같은 거. 함수가 어떻게 return 타입 (Promise<T>) 선언하는지, 에러가 어떻게 타입 붙는지,import type가 어디 나타나는지 봐. - 중앙 state hook —
hooks/useChat.ts, 또는 앱의 main reducer 어떤 거든. Reducer state 모양 (자주 discriminated union) 과useReducer의 타입이 어떻게 흐르는지 봐. - Top-level component —
App.tsx. 여기서 state 들어 올려짐; child component 가 typed props 받음. Component tree 가 앱의 영역들 연결. - Leaf UI component —
components/의 어떤 거든. Props 가 어떻게 inline 타입 붙고, children 이 어떻게 render 되고, callback 이 어떻게 타입 붙는지 주목.