Usecase: 솔로 개발자가 Authentication 기능 구축하기
혼자 일하는 개발자도 Superpowers 프로세스를 따르는 것만으로 완전하고 안전하며 충분한 테스트 커버리지를 갖춘 authentication 기능을 구축할 수 있습니다.
배경
여러분은 Todo App 프로젝트에서 혼자 작업하는 솔로 개발자입니다. 프로젝트에는 이미 CRUD todos, 필터, drag-and-drop, dark/light 테마 등 완전한 기능이 갖춰져 있지만 -- authentication 시스템이 전혀 없습니다. 앱을 여는 사람이면 누구나 모든 todos를 볼 수 있습니다. 새로운 요구사항은 다음과 같습니다:
- 사용자 등록 (register) 추가
- 이메일 + 비밀번호로 로그인 (login) 추가
- 앱 접근 보호 (login gate) -- 로그인하지 않으면 접근 불가
- 전체 기능에 대한 테스트 작성
프로젝트에는 auth 시스템이 없습니다. 코드를 리뷰해줄 사람이 없습니다. 처음부터 끝까지 혼자 작업합니다.
기술 스택:
- React 19 + TypeScript + Vite
- Tailwind CSS + shadcn/ui
- localStorage (백엔드 없음)
- Vitest + Testing Library (테스팅)
- Web Crypto API (SHA-256 비밀번호 해싱)
배울 수 있는 것
이 가이드에서는 Superpowers의 다섯 가지 핵심 기술을 적용합니다:
- Brainstorming & Design -- 코드 작성 전 설계
- Writing Plans -- 작업을 명확한 task로 분할
- TDD -- 테스트 먼저 작성, 구현은 그 다음
- 실행 & Subagents -- 병렬 dispatch로 속도 향상
- Debugging & Verification -- 실제 증거로 결과 검증
최종 목표: 39개 테스트 케이스가 모두 통과하는 완전한 authentication 시스템을, 철저히 규율 있는 프로세스로 구축하는 것입니다.
단계별 실습
1단계: Auth 디자인 브레인스토밍
코드를 한 줄도 작성하기 전에, 브레인스토밍부터 시작합니다. 브레인스토밍 skill을 호출합니다:
/superpowers:brainstorming "Todo 프로젝트에 authentication을 추가해야 합니다. 코드를 작성하기 전에 브레인스토밍을 해봅시다."
AI는 먼저 코드베이스를 탐색하여 현재 기술 스택 (React 19, TypeScript, Vite, Tailwind, shadcn/ui, localStorage)을 파악한 후, 하나씩 질문을 시작합니다:
질문 1: "authentication은 어떤 목적으로 필요하신가요?"
- A) 앱 접근 보호 (login gate)만 -- 데이터는 여전히 localStorage에 저장, 같은 브라우저의 각 사용자가 동일한 데이터를 봄
- B) 사용자별 개별 데이터 -- 사용자별 todos 저장을 위한 백엔드/데이터베이스 필요
- C) 학습 목적의 단순한 login/register 흐름 데모
A) Login gate를 선택합니다 -- 접근 보호만 필요하고, 데이터는 localStorage에 유지합니다.
질문 2: "어떤 로그인 방식을 사용하고 싶으신가요?"
- A) Email + Password (login/register 폼 직접 구축)
- B) Social login (Google, GitHub...) -- Firebase Auth, Supabase Auth, Auth0 사용
- C) 둘 다
A) Email + Password를 선택합니다 -- 직접 구축, 외부 의존성 없음.
질문 3: "Register (신규 계정 생성) 기능이 필요하신가요?"
- A) Register + Login 둘 다 필요 -- 사용자가 새 계정 생성, localStorage에 저장
- B) Login만 -- mock/하드코딩된 계정 사용
A) Register + Login 둘 다 필요를 선택합니다.
질문 4: "비밀번호 찾기 기능이 필요하신가요?"
- A) 필요 -- reset password 폼 표시 (mock)
- B) 불필요 -- 간단하게 유지
B) 불필요를 선택합니다 -- Login + Register만으로 간단하게 유지.
질문 5: "UI적으로, Login/Register 페이지를 어떻게 만들고 싶으신가요?"
- A) 별도 페이지 (full page) -- 로그인하지 않으면 login 페이지로 리다이렉트
- B) Modal/Dialog -- 현재 앱 위에 오버레이 표시
- C) 제안해 주세요
A) 별도 페이지를 선택합니다.
충분한 정보를 수집한 후, AI는 3가지 접근 방식을 제시합니다:
## Approach A: React Context + localStorage (권장)
- AuthContext로 로그인 상태 관리
- Users를 localStorage에 저장 (email + Web Crypto API로 해시된 password)
- 간단한 wrapper 컴포넌트로 Protected route 구현
- Login/Register는 full-page, 인증되면 App 렌더링
- 장점: 간단, 추가 의존성 없음, 현재 아키텍처에 적합
- 단점: 실제 라우팅 없음 (조건부 렌더링만)
## Approach B: React Router + Context
- react-router-dom을 추가하여 실제 라우팅 (/login, /register, /)
- 장점: URL 기반 네비게이션, 이후 페이지 추가 용이
- 단점: 간단한 앱에 추가 의존성, 더 복잡
## Approach C: TanStack Router + Context
- React용 Type-safe 라우팅
- 장점: Type-safe, 현대적
- 단점: 현재 범위에 과도
## 권장
Approach A. 현재 프로젝트는 single-page app이며 라우팅이 없습니다.
2개 페이지 (login + app)만을 위해 라우터를 추가하는 것은 과도합니다.
AuthContext를 이용한 조건부 렌더링이 충분하며 프로젝트를 간단하게 유지합니다.
Approach A에 동의합니다. AI는 각 부분에 대한 상세 설계를 계속 제시합니다:
Part 1 -- Architecture & Data Model:
User type:
- id: string (crypto.randomUUID)
- email: string
- passwordHash: string (SHA-256 via Web Crypto API)
- createdAt: string
AuthContext provides:
- user: User | null
- isAuthenticated: boolean
- isLoading: boolean
- login(email, password) → success/error
- register(email, password) → success/error
- logout()
localStorage keys:
- todo-app-users — 등록된 사용자 배열
- todo-app-session — 현재 세션의 사용자 ID
- todo-app-todos — 유지 (모든 사용자 간 공유)
Part 2 -- Component Structure:
<StrictMode>
<AuthProvider>
<App>
├── isLoading = true → Loading indicator
│
├── isAuthenticated = false → <AuthPage>
│ ├── <LoginForm />
│ └── <RegisterForm />
│
└── isAuthenticated = true → <TodoApp>
├── <Header> (+ logout 버튼, 사용자 이메일)
├── <FilterBar>
├── <TodoInput>
├── <TodoList>
└── <EditTodoDialog>
</App>
</AuthProvider>
</StrictMode>
Part 3 -- UI Design: AI가 visual companion을 통해 브라우저에서 직접 2개의 목업을 보여줍니다: Centered Card vs Split Layout. Split Layout을 선택합니다 -- 화면을 반으로 나누어, 왼쪽은 브랜딩, 오른쪽은 폼.
Part 4 -- Validation & Error Handling:
- Register: 이메일 형식, 이메일 중복, 비밀번호 6-128자, confirm password 일치
- Login: 이메일/비밀번호 비어있지 않음, 틀리면 toast error 표시 (기존 Sonner 사용)
- Session: 앱 마운트 시 확인, 사용자 ID가 유효하지 않으면 자동 로그아웃
Part 5 -- Testing Strategy: Vitest + Testing Library, storage 테스트를 위한 localStorage mock.
AI가 디자인 spec을 docs/superpowers/specs/2026-03-18-authentication-design.md에 작성하고 자동 spec 리뷰 3라운드를 실행합니다 -- 7개 이슈 발견 (loading state 누락, password max length 누락, stale session handling 누락 등) 후 plan 작성으로 넘어가기 전에 모두 수정합니다.
Superpowers 참고: 자동 spec 리뷰는 프로세스의 중요한 부분입니다. AI가 code-reviewer agent를 dispatch하여 승인 전에 spec을 리뷰합니다. 이를 통해 spec의 누락을 방지합니다. 자세한 내용은 Brainstorming을 참조하세요.
2단계: Superpowers가 상세 Plan 작성
승인된 디자인 spec을 기반으로, AI가 writing-plans skill을 호출하여 작업을 8개 task로 분할합니다:
## Plan: Authentication Implementation
### Task 1: Hash Utility
- 파일: src/lib/hash.ts, src/lib/hash.test.ts
- Web Crypto API를 이용한 SHA-256 해싱
- 검증: npx vitest run src/lib/hash.test.ts
### Task 2: Auth Storage
- 파일: src/lib/auth-storage.ts, src/lib/auth-storage.test.ts
- localStorage에서 사용자 CRUD + 세션 관리
- 검증: npx vitest run src/lib/auth-storage.test.ts
### Task 3: Auth Context
- 파일: src/contexts/auth-context.tsx, src/contexts/auth-context.test.tsx
- AuthProvider + useAuth hook
- Login, register, logout, session restore, isLoading, stale session
- 검증: npx vitest run src/contexts/auth-context.test.tsx
### Task 4: Login Form
- 파일: src/components/login-form.tsx, src/components/login-form.test.tsx
- 폼 유효성 검사, 제출, 오류 표시
- 검증: npx vitest run src/components/login-form.test.tsx
### Task 5: Register Form
- 파일: src/components/register-form.tsx, src/components/register-form.test.tsx
- 유효성 검사, 이메일 중복, 비밀번호 과다 길이, 제출
- 검증: npx vitest run src/components/register-form.test.tsx
### Task 6: Auth Page
- 파일: src/components/auth-page.tsx
- Split layout 컨테이너, login/register 간 전환
- 별도 테스트 불필요 (form tests + auth-context tests에서 커버)
### Task 7: Wire Up
- 수정: src/main.tsx, src/App.tsx, src/components/header.tsx
- App을 AuthProvider로 감싸기, 조건부 렌더링, logout 버튼
- 검증: npx tsc --noEmit && npx vitest run
### Task 8: Smoke Test
- 전체 테스트 스위트 + TypeScript 체크 실행
- 검증: npx tsc --noEmit && npx vitest run
각 task에는 구체적인 파일, 구체적인 검증 명령, plan에 미리 작성된 상세 테스트 코드가 있습니다.
Plan도 자동 리뷰 2라운드를 거칩니다 -- 이슈 발견 (테스트 환경을 위한 crypto.subtle polyfill 누락, stale session 테스트 케이스 누락, password > 128자 테스트 누락 등) 후 모두 수정합니다.
Superpowers 참고: 실제 plan에는 각 테스트 파일과 구현 파일의 전체 코드가 포함되어 있으며, 각 단계에
- [ ]체크박스 형식을 사용합니다. 자세한 내용은 Writing Plans를 참조하세요.
AI가 질문합니다:
"Plan이 8개 task로 완성되었습니다. Subagent-Driven (병렬)으로 실행할까요, Inline Execution (순차)으로 실행할까요?"
Subagent-Driven을 선택합니다 -- 여러 agent를 병렬로 dispatch하여 속도를 높입니다.
3단계: Subagent-Driven Development로 구현
AI는 subagent-driven-development skill을 사용하여 plan을 실행합니다. 각 task를 순차적으로 수행하는 대신, AI가 task 간 의존성을 분석하고 가능한 경우 병렬로 dispatch합니다.
Batch 1: Task 1 + Task 2 (병렬)
Task 1 (Hash Utility)과 Task 2 (Auth Storage)는 서로 의존하지 않으므로, 2개의 별도 agent에 병렬로 dispatch됩니다:
| Agent | Task | 테스트 케이스 | 결과 |
|---|---|---|---|
| Agent 1 | Hash Utility (hash.ts + hash.test.ts) | 3개 테스트: hash 일관성, 다른 입력 → 다른 해시, hex 문자열 반환 | 3/3 PASS |
| Agent 2 | Auth Storage (auth-storage.ts + auth-storage.test.ts) | 6개 테스트: get/save users, add user, find by email, session CRUD, user validation | 6/6 PASS |
두 agent 완료 후, AI가 테스트를 검증하고 커밋합니다:
git commit -m "feat: add SHA-256 password hashing utility"
git commit -m "feat: add auth storage with user and session management"
Batch 2: Task 3 + Task 4/5 (병렬)
Task 3 (Auth Context)은 Task 1+2가 필요하지만, Task 4 (Login Form)와 Task 5 (Register Form)는 props interface만 필요하므로 병렬 실행이 가능합니다:
| Agent | Task | 테스트 케이스 | 결과 |
|---|---|---|---|
| Agent 3 | Auth Context (auth-context.tsx + test) | 6개 테스트: initial state, register + auto-login, login after register, session restore, logout, stale session cleanup | 6/6 PASS |
| Agent 4 | Login + Register Forms | 12개 테스트: validation, submit, error display, duplicate email, password too long | 12/12 PASS |
검증 후 커밋:
git commit -m "feat: add AuthContext with login, register, session management"
git commit -m "feat: add login and register form components"
Batch 3: Task 6 + Task 7 (순차, inline)
Task 6 (Auth Page)과 Task 7 (Wire Up)은 작고 서로 의존하므로 AI가 직접 구현합니다:
auth-page.tsx생성 -- split layout 컨테이너main.tsx수정 -- App을<AuthProvider>로 감싸기App.tsx수정 -- AuthPage / TodoApp 조건부 렌더링 + loading stateheader.tsx수정 -- 사용자 이메일 + logout 버튼 추가
git commit -m "feat: add AuthPage with split layout"
git commit -m "feat: wire up authentication — AuthProvider, conditional render, header logout"
각 task의 TDD 프로세스: 각 agent는 모두 다음 사이클을 따릅니다: 테스트 먼저 작성 (RED) → 최소한의 코드 구현 (GREEN) → 테스트 PASS 확인 → 커밋. 자세한 내용은 TDD를 참조하세요.
4단계: Verification -- 전체 검증
plan의 8개 task가 모두 완료되었습니다. 이제 Task 8: Smoke Test -- 전체 검증을 실행합니다.
TypeScript Check
npx tsc --noEmit
# (출력 없음) — 깨끗, 오류 없음
Full Test Suite
npx vitest run
✓ src/lib/hash.test.ts (3 tests)
✓ src/lib/auth-storage.test.ts (6 tests)
✓ src/contexts/auth-context.test.tsx (6 tests)
✓ src/components/login-form.test.tsx (5 tests)
✓ src/components/register-form.test.tsx (7 tests)
... (프로젝트의 다른 테스트 파일들)
Test Files 8 passed
Tests 39 passed
Git Log -- 깔끔한 7개 커밋
6b92624 feat: wire up authentication — AuthProvider, conditional render, header logout
37d68f1 feat: add AuthPage with split layout
... feat: add login and register form components
... feat: add AuthContext with login, register, session management
... feat: add auth storage with user and session management
878af65 feat: add SHA-256 password hashing utility
cc6e2f9 initial: todo app before authentication
39/39 테스트 PASS. TypeScript 깨끗. 7개 커밋. 이것은 실제 증거를 기반으로 한 유효한 선언입니다.
결과
전체 프로세스를 완료한 후, 다음과 같은 결과물을 얻게 됩니다:
완전한 Authentication 기능:
- Login 페이지 -- 이메일 + 비밀번호로 로그인
- Register 페이지 -- 완전한 유효성 검사를 갖춘 신규 계정 등록
- Login gate -- 로그인하지 않으면 앱에 접근 불가
- Logout -- 헤더에 logout 버튼, 사용자 이메일 표시
- Session persistence -- 페이지 새로고침 후에도 로그인 상태 유지
39개 테스트 케이스 100% 통과 범위:
- Utility 계층: hash 함수, localStorage CRUD
- Context 계층: login/register 흐름, session restore, stale session cleanup
- UI 계층: 폼 유효성 검사, 오류 표시, 제출 처리
- Edge cases: 이메일 중복, 비밀번호 과다 길이 (>128자), session invalid
새 파일 구조:
src/
contexts/
auth-context.tsx ← AuthProvider + useAuth hook
components/
auth-page.tsx ← Split layout 컨테이너
login-form.tsx ← 로그인 폼
register-form.tsx ← 등록 폼
lib/
hash.ts ← SHA-256 헬퍼
auth-storage.ts ← localStorage에서 사용자 CRUD + 세션
수정된 파일:
src/main.tsx ← App을 AuthProvider로 감싸기
src/App.tsx ← auth/todo 조건부 렌더링 + loading state
src/components/header.tsx ← 이메일 + logout 버튼 추가
핵심 포인트
1. 솔로 개발자도 프로세스가 필요합니다
코드를 리뷰해줄 사람이 없을 때, Superpowers 프로세스는 "가상 동료" 역할을 합니다. 브레인스토밍은 코드 작성 전에 충분히 생각하도록 강제합니다. TDD는 구현 전에 테스트를 작성하도록 강제합니다. Verification은 완료를 선언하기 전에 모든 것이 동작함을 증명하도록 강제합니다.
프로세스 없이 솔로 개발자는 함정에 빠지기 쉽습니다: 즉흥적으로 코드를 작성하고, 테스트 없이, 검증하지 않고 "완료"를 선언하는 것.
2. 사전 브레인스토밍이 over-engineering을 방지합니다
브레인스토밍 단계에서 AI는 React Router와 TanStack Router도 제안했습니다. 하지만 처음부터 요구사항을 명확히 했기 때문에 (login gate, single-page app, 백엔드 없음), 가장 간단한 방안인 React Context + localStorage + 조건부 렌더링을 선택했습니다.
브레인스토밍이 없었다면, 많은 개발자가 "확실히 하기 위해" 자동으로 라우터, 백엔드, 데이터베이스를 추가했을 것입니다. 결과적으로 아직 필요하지 않은 기능에 3배의 시간을 소비하게 됩니다.
3. 자동 spec 리뷰가 허점을 발견합니다
3라운드의 spec 리뷰가 놓칠 수 있었던 7가지 이슈를 발견했습니다: loading state 누락 (새로고침 시 AuthPage 깜빡임), password max length 누락 (DoS 위험), stale session handling 누락... 이러한 허점들은 코드 한 줄 작성하기 전에 수정되었습니다.
4. Subagent-Driven Development가 속도를 크게 향상시킵니다
8개 task를 순차적으로 구현하는 대신, AI가 병렬로 dispatch합니다: Task 1+2 동시에, Task 3 + Task 4/5 동시에. 병렬 처리 덕분에 전체 구현 시간이 크게 단축됩니다.
5. 상세한 plan이 방향을 잃지 않게 해줍니다
8개의 명확한 task가 있고, 각 task에 코드가 plan에 미리 준비되어 있으므로, 다음에 무엇을 해야 하는지 항상 알 수 있습니다. "다음에 뭘 해야 하지?"라고 고민하는 순간이 없습니다.
솔로 개발자에게 이것은 특히 중요합니다. 혼자 일할 때는 산만해지거나 프로젝트의 여러 부분 사이를 왔다 갔다 하기 쉽습니다.
6. 39개 테스트 케이스가 자동 "리뷰어"입니다
각 테스트 케이스는 명확한 assertion입니다. 코드를 변경할 때 -- 리팩토링, 새 기능 추가, 버그 수정 -- 무엇이 깨졌는지 즉시 알 수 있습니다. 39개 테스트는 몇 초 만에 실행됩니다. 어떤 수동 테스트보다 빠릅니다.
7. Verification gate가 실제로 완료되지 않았을 때 "완료" 선언을 방지합니다
테스트를 실행하지 않고 "완료"라고 말한 적이 몇 번이나 있나요? AI가 출력을 보여주지 않고 "구현 완료"라고 말한 적이 몇 번이나 있나요?
최종 smoke test -- TypeScript 깨끗 + 39/39 테스트 통과 -- 는 잘못된 선언 가능성을 완전히 제거합니다. 터미널에 실제 증거가 있을 때만 "완료"라고 말할 수 있습니다.
솔로 개발자라고 해서 규율 없이 일하는 것은 아닙니다. Superpowers는 큰 팀도 존중해야 하는 프로세스를 제공합니다: 코드 전에 브레인스토밍, 실행 전에 plan, 구현 전에 테스트, 승인 전에 자동 리뷰, 선언 전에 검증. 좋은 프로세스를 가진 한 사람은 프로세스가 없는 사람을 항상 이길 것입니다 -- 경험에 관계없이.