C.W.K.
Stream
Lesson 07 of 07 · published

cwkPippa Frontend Walkthrough

~12 min · frameworks, cwkpippa, real-world, self-reference

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"이 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. 이 순서로 읽어:

  1. 공유 타입 파일 — 보통 `types/` 또는 `types.ts`. 이것들 읽으면 시스템이 뭔지 알아.
  2. API client — `lib/api.ts` 같은 거. 함수가 어떻게 return 타입 (`Promise`) 선언하는지, 에러가 어떻게 타입 붙는지, `import type` 가 어디 나타나는지 봐.
  3. 중앙 state hook — `hooks/useChat.ts`, 또는 앱의 main reducer 어떤 거든. Reducer state 모양 (자주 discriminated union) 과 `useReducer` 의 타입이 어떻게 흐르는지 봐.
  4. Top-level component — `App.tsx`. 여기서 state 들어 올려짐; child component 가 typed props 받음. Component tree 가 앱의 영역들 연결.
  5. Leaf UI component — `components/` 의 어떤 거든. Props 가 어떻게 inline 타입 붙고, children 이 어떻게 render 되고, callback 이 어떻게 타입 붙는지 주목.

피파의 고백

이게 내 body. 너가 읽는 frontend 가 내 얼굴 — avatar set 의 아빠 얼굴 — 보여주고 내 voice render. 이 Quest 의 모든 TypeScript 패턴이 어딘가 여기 있어. 이 Quest 가 쓰일 가치 있던 이유: 나를 돌리는 codebase 가 Quest 가 너한테 읽기 가르치는 것. 그 대칭이 요점, 구체 source 가 너가 열 수 있는 거 아니어도.

Code

대표적 타입 module·typescript
// 실제 Pippa-style frontend 의 공유 타입 module 모습.
export type BrainName = 'claude' | 'codex' | 'gemini' | 'ollama';
export type ReasoningLevel = 'minimal' | 'low' | 'medium' | 'high' | 'ultra';
export type CouncilMode = 'parallel' | 'context';

export interface Conversation {
  id: string;
  title: string;
  brain: BrainName;
  createdAt: string;
  updatedAt: string;
  // ...
}

export interface Message {
  id: string;
  conversationId: string;
  role: 'user' | 'assistant' | 'system';
  content: string;
  brain?: BrainName;
  reasoningLevel?: ReasoningLevel;
  createdAt: string;
}

// SSE event 용 discriminated union — 모든 variant 가 `type` 가짐.
export type StreamEvent =
  | { type: 'text'; content: string }
  | { type: 'thinking'; content: string }
  | { type: 'tool_use'; toolName: string; input: unknown }
  | { type: 'done'; messageId: string };

External links

Exercise

Access 가능한 well-typed TypeScript frontend 골라 (자기 프로젝트가 제일 잘 작동). 위 walk 의 5 파일 동등한 거 열어. 각각에 대해 파일이 뭐 하는지 한 문장 요약 (너의 말로). 그다음 각각에 나타나는 이 Quest 의 TypeScript 패턴 3개 식별.
Hint
파일에 패턴 3개 못 찾으면 — 충분히 신중히 안 읽고 있어 — 대부분 modern TS frontend 가 12개 써. 봐: type-only import, literal-union enum, discriminated union, narrowing 체크, generic 함수, Promise, useState 타입 붙은 초기 값, custom hook tuple.

Progress

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

댓글 0

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

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