아키텍처
intro에서 산출물은 테스트 스위트라고 짚었습니다. 여기서는 그 스위트가 디렉토리에서 어떻게 생겼는지, 어떤 규칙이 AI가 임의로 구조를 흐리지 못하게 막는지를 봅니다. POM과 fixtures 조합, 트랙 분리, 시나리오와 테스트의 1:1, 그리고 그걸 세우고 채우고 검증하는 세 에이전트.
디렉토리 구조
섹션 제목: “디렉토리 구조”트랙은 디렉토리부터 갈립니다. 선택 안 한 트랙은 /6-cleanup-residue가 지우므로, fork 직후 모든 디렉토리가 있다가 결정 뒤 정리됩니다.
<project>/├── tests/│ ├── web/ ← Playwright│ │ ├── pages/ ← Page Object (로케이터 + 동작)│ │ ├── fixtures/ ← test.extend 픽스처 + storageState setup│ │ ├── specs/ ← <flow>.spec.ts (시나리오 1개 = 1 spec)│ │ └── utils/│ ├── electron/ ← Playwright _electron│ │ ├── specs/│ │ └── helpers/ ← 메인 프로세스 evaluate, dialog/menu/tray stub│ └── mobile/ ← Maestro 또는 Detox│ ├── flows/ ← Maestro .yml (또는 Detox e2e/)│ └── helpers/├── playwright.config.ts ← web/electron 트랙├── .detoxrc.js ← mobile=detox 선택 시├── .maestro/ ← mobile=maestro 선택 시(또는 tests/mobile/flows)├── .github/workflows/e2e.yml ← implement-ci-workflow 산출├── docs/design/e2e-spec.md ← 설계 SSOT (SUT·플로우·도구·환경·CI)└── .env.test.example ← 테스트 환경변수 키 목록 (실키 0건)로케이터는 pages/의 Page Object 클래스 안에만 둡니다. spec 파일에 셀렉터를 흩으면 SUT의 DOM이 한 번 바뀔 때 따라가야 할 자리를 잃습니다.
POM + fixtures
섹션 제목: “POM + fixtures”2026 권장 조합입니다. fixtures가 setup과 teardown, 인증을 관리하고, Page Object가 페이지 상호작용을 캡슐화합니다. 둘의 책임이 갈립니다.
fixtures/:test.extend로 로그인된 페이지나 준비된 데이터를 테스트에 주입합니다. web의auth.setup.ts는 setup project로 한 번 로그인해storageState를 저장하고, 다른 project가dependencies: ['setup']으로 그 상태를 재사용합니다.pages/:LoginPage,DashboardPage같은 클래스. 로케이터와 그 페이지에서 할 수 있는 동작을 담습니다. spec은 이 클래스의 메서드만 부릅니다.
인증을 매 테스트 UI로 다시 밟지 않는 게 핵심입니다. 매번 로그인하면 느리고 flaky합니다. web은 storageState, mobile은 사전 로그인 subflow, electron은 세션 주입으로 1회 로그인 후 재사용합니다. 전략은 analyze-and-design에서, 트랙별 구현은 tracks에서 봅니다.
트랙 분리와 시나리오 1:1
섹션 제목: “트랙 분리와 시나리오 1:1”web, electron, mobile은 디렉토리뿐 아니라 config와 CI 잡도 분리됩니다. 공유하는 건 utils/의 트랙 무관 유틸뿐이고, 트랙 간 공유는 최소로 둡니다. electron은 단일 인스턴스라 workers: 1로 도는데 web은 fullyParallel: true로 도니까, 한 config에 섞으면 서로의 가정이 깨집니다.
테스트 범위의 SSOT는 docs/design/e2e-spec.md §2입니다. 거기 적힌 크리티컬 플로우 한 줄이 테스트 한 개(또는 한 spec)로 변환됩니다. 스펙에 없는 임의 테스트를 늘리지 않습니다. AI에게 맡기면 커버리지를 채우려고 스펙 밖 케이스를 발명하는데, 그 자리가 유지보수 비용이 됩니다.
Phase 흐름과 세 에이전트
섹션 제목: “Phase 흐름과 세 에이전트”워크플로우는 Atomic Phase입니다. /start가 진입 라우터고, stage를 감지해 호흡을 정하고 첫 phase부터 순차 실행합니다.
graph LR start["프로젝트 시작<br/>/start"] --> pace["/1-pace"] pace --> setup["/2-setup-base"] setup --> analyze["/3-analyze-target"] analyze --> design["/4-design-suite"] design --> impl["/5-implement-suite"] impl --> cleanup["/6-cleanup-residue"] cleanup --> run["/run-suite"] run --> review["/review-e2e"] review -->|changes_requested| impl/review-e2e가 통과 못 하면 그 트랙의 implement-*로 돌아갑니다. 이 루프는 iteration 두 번까지입니다.
Claude Code에서는 이 흐름의 무거운 자리를 세 서브에이전트가 별도 컨텍스트에서 맡습니다.
graph TB spec["e2e-spec.md §2<br/>크리티컬 플로우"] --> architect["e2e-architect<br/>골격 + 도구 배선 (1회)"] architect --> builder["e2e-builder<br/>POM·픽스처·spec·CI 구현"] builder --> reviewer["e2e-reviewer<br/>6차원 검증"] reviewer -->|changes_requested| builder reviewer -->|passed| done["통과"]
auth["인증 재사용<br/>storageState / subflow / 세션 주입"] -.공유.- buildere2e-architect: 디렉토리,playwright.config.ts,.detoxrc.js또는.maestro/, CI 골격을 한 번 세웁니다. 본문은 비우고 뼈대까지.e2e-builder: 골격에 실제 플로우와 POM, 픽스처를 채웁니다.implement-web-suite,implement-electron-suite,implement-mobile-suite,implement-auth-fixtures,implement-ci-workflow가 실제 도구입니다.e2e-reviewer: 6차원으로 검증만 합니다. 코드는 고치지 않습니다. 고치는 건 builder의 몫이라 검증자와 수정자가 갈립니다.
세 에이전트가 별도 컨텍스트로 도는 이유는 메인 컨텍스트를 보호하기 위해서입니다. 트랙별 구현 디테일이 메인 대화에 쌓이면 결정 맥락이 묻힙니다. 산출물은 파일 경로로 핸드오프하고 노트만 .claude/state/builder-<track>.md에 남깁니다.
ADR
섹션 제목: “ADR”되돌리기 비싼 결정은 docs/adr/에 한 장씩 쌓습니다. 추천 외 도구를 고른 자리, 예를 들어 web에서 Playwright 대신 Cypress, mobile에서 Maestro 대신 Detox를 고른 근거가 여기 들어갑니다. 코드는 무엇을 했는지를, ADR은 왜 그랬는지를 들고 있습니다. 어떤 결정에 ADR이 붙는지는 analyze-and-design에서 봅니다.
다음 섹션은 tracks입니다. web의 Playwright config와 Supabase localStorage, Stripe cross-origin 함정, electron의 메인 프로세스 stub, mobile의 Maestro 선언형 플로우와 타겟 매트릭스를 트랙별로 봅니다.