# Stack Template And WBS 이 문서는 `MudBlazor + ASP.NET Core 10 + Dapper + PostgreSQL 18.4 + API-first` 기준의 기본 템플릿과 작업 순서를 정의한다. 기준은 공식 문서로 확인한 다음 반영한다. ## Verified Assumptions - MudBlazor는 static rendering을 지원하지 않는다. MudBlazor를 쓰는 화면은 interactive render mode가 필요하다. - Blazor Web App은 static rendering과 interactive rendering을 구분한다. - Interactive WebAssembly 컴포넌트는 `.Client` 프로젝트에 두는 것이 공식 구조다. - ASP.NET Core 10은 `Microsoft.AspNetCore.OpenApi` 기반 OpenAPI 문서 생성을 지원한다. - PostgreSQL 18.4는 2026-05-14 릴리스이며, 18.x 내 minor upgrade는 dump/restore가 필요하지 않다. - Dapper는 SQL 중심의 micro ORM으로 repository layer에 맞는다. - DTO 검증은 `DataAnnotations`를 기본으로 하고, 표현력이 부족한 경우에만 FluentValidation을 보완으로 둔다. - Blazor UI의 화면 상태는 MVVM 스타일 ViewModel로 분리한다. ## Target Template | 영역 | 권장 방식 | 비고 | | --- | --- | --- | | Public Home | Static SSR + 필요한 부분만 Interactive WebAssembly | 초기 로딩과 SEO 우선 | | Login | Static SSR 또는 Razor Page form | MudBlazor 의존 금지 | | Home/Dashboard | Interactive WebAssembly + MudBlazor | 사용자 인터랙션 중심 | | Admin CRUD | Interactive WebAssembly + API-first | BrowserClient 경유 | | API | Minimal API 또는 Controller + OpenAPI | 계약 우선 | | Persistence | Dapper + `NpgsqlDataSource` singleton | connection pool 직접 관리 금지 | | Auth | 브라우저는 HttpOnly Secure Cookie 우선, 외부 클라이언트만 JWT | localStorage 저장 금지 | 현재 저장소 기준 예외: - 포털 로그인은 이미 Razor Page SSR로 구현돼 있다. - 관리자 로그인은 아직 Interactive WebAssembly 경로를 사용한다. - 따라서 본 템플릿의 로그인 SSR 기준은 포털/공개 사용자 흐름에 우선 적용하고, 관리자 로그인은 별도 마이그레이션 WBS로 분리한다. ## Authentication Rules - 브라우저 사용자 흐름은 SSR 로그인 form으로 시작한다. - 서버는 자격 증명을 검증한 뒤 HttpOnly + Secure + SameSite cookie를 발급한다. - 같은 origin에서 WebAssembly 화면은 쿠키 기반 API 호출을 우선 사용한다. - JWT는 외부 API 클라이언트, 모바일, 파트너용으로만 분리한다. - 토큰 원문은 로그에 남기지 않는다. ## Render Mode Rules - `/account/login` 은 Static SSR 또는 Razor Page로 구현한다. - `/` 또는 홈 대시는 Interactive WebAssembly로 구현한다. - MudBlazor 컴포넌트는 interactive render mode가 없는 페이지에 두지 않는다. - 로그인 화면에서 `MudButton`, `MudTextField`, `MudDialog`, `MudSnackbar` 같은 interactive 의존은 금지한다. ## Architecture Skeleton ```text src/ TaxBaik.Web/ # Host, SSR shell, auth, API, OpenAPI TaxBaik.Web.Client/ # Interactive WebAssembly UI TaxBaik.Contracts/ # DTO, request/response, validation contracts TaxBaik.Application/ # Use cases, interfaces, policies TaxBaik.Infrastructure/ # Dapper repositories, external integrations TaxBaik.Migrations/ # SQL migration scripts tests/ TaxBaik.UnitTests/ TaxBaik.ApiTests/ TaxBaik.Playwright/ scripts/ smoke/ deploy/ evidence/ ``` ## Roadmap | Phase | Goal | Exit Criteria | | --- | --- | --- | | P0 Baseline | 공식 전제와 템플릿 기준 고정 | 본 문서와 `ENGINEERING_HARNESS.md`가 `INDEX.md`에 연결 | | P1 Local Verify | 로컬 빌드/테스트/증빙 먼저 통과 | 로컬 `dotnet build`, unit, Playwright 1차 통과 | | P2 CI Deploy | CI 배포와 중간 smoke 통과 | 배포 workflow success | | P3 Domain Verify | 실제 도메인 최종 검증 | `https://www.taxbaik.com/taxbaik` 기준 브라우저 E2E 성공 | | P1 Shell | SSR login / interactive home / API host 분리 | 로그인 SSR, 홈 WASM, API 계약 분리 확인 | | P2 Auth | Cookie/JWT 이중 경로 정착 | 브라우저 cookie, 외부 JWT 경로 분리 완료 | | P3 Data | Dapper + PostgreSQL 18.4 안정화 | repository, migration, index, connection 규칙 확정 | | P4 Verify | Playwright와 데이터 증빙 자동화 | 화면 캡처, DOM 캡처, 실제 데이터 비교 통과 | | P5 Operate | 배포/장애/FAQ 표준화 | CI/CD, smoke, rollback, incident FAQ 정착 | ## Detailed WBS WBS 항목은 다음 데이터가 모두 있어야 완료다. - 변경 diff 링크 또는 파일명 - 로컬 빌드 결과 - 로컬 Playwright 결과 - Playwright 시나리오 이름 - 화면 캡처 파일 경로 - DOM 캡처 파일 경로 - 기대값과 실제값 비교 결과 - CI 배포 결과 - 실제 도메인 최종 검증 결과 - CI 또는 배포 로그 링크 | ID | 작업 | 산출물 | 완료 데이터 정의 | | --- | --- | --- | --- | | P0-01 | 공식 전제 검증 문서화 | Verified Assumptions | MudBlazor static rendering 비지원, Blazor render mode, OpenAPI, PostgreSQL 18.4, Dapper 근거 링크 | | P0-02 | 엔지니어링 하네스 반영 | `ENGINEERING_HARNESS.md` | 완료 정의에 build + Playwright + screenshot + DOM + data proof 포함 | | P0-03 | 인덱스 연결 | `INDEX.md` | 새 템플릿 문서가 canonical list에 포함 | | P1-01 | 솔루션 구조 확정 | `src/`, `tests/`, `scripts/` tree | 호스트/클라이언트/계약/애플리케이션/인프라 분리 확인 | | P1-02 | 로그인 SSR 구현 가이드 | `/account/login` 기준 | static SSR form, antiforgery, cookie issuance 흐름 문서화 | | P1-03 | 홈 WASM 가이드 | `/` 또는 dashboard | interactive WebAssembly + MudBlazor 사용 경계 문서화 | | P1-04 | 관리자 로그인 마이그레이션 분리 | `/admin/login` 또는 equivalent | 현재 WASM 로그인과 목표 SSR 경계를 문서화하고 후속 WBS로 분리 | | P1-05 | API-first 계약 정의 | `/api/v1/*` | DTO, OpenAPI, ProblemDetails, auth policy 정의 | | P1-06 | DTO/MVVM 규칙 확정 | 모든 Blazor form/list | DTO는 DataAnnotations, UI는 ViewModel, 보완 검증은 FluentValidation | | P2-01 | Cookie auth 템플릿 | auth middleware | HttpOnly/Secure/SameSite settings, 401/403 behavior 확인 | | P2-02 | JWT 분리 템플릿 | external auth endpoint | refresh rotation, revocation, expiry, no localStorage rule | | P2-03 | CSRF/antiforgery 검증 | login POST flow | token present, POST accepted, stale tab failure case documented | | P3-01 | Dapper repository pattern | singleton `NpgsqlDataSource` | open-conn-per-method, transaction short-lived, query mapping test | | P3-02 | PostgreSQL 18.4 migration policy | SQL scripts | versioned migrations, restore drill evidence | | P3-03 | schema/index baseline | core tables | PK/FK/unique/check/index list and explain output | | P4-01 | Playwright user journeys | login/home/admin scenario suite | each test has screenshot, DOM snapshot, assert on real data | | P4-02 | evidence capture harness | scripts/evidence | screenshot + DOM + response capture persisted per run | | P4-03 | build gate | CI/local build | 로컬 `dotnet build` warning/error zero evidence | | P5-01 | deployment smoke | deploy workflow | CI 배포 success + 실제 도메인 smoke success | | P5-02 | incident FAQ | docs FAQ section | common failure, root cause, and recovery steps documented | ## Playwright Evidence Standard - 시나리오는 실제 사용자 관점이어야 한다. - 버튼 클릭, 입력, 저장, 조회 같은 동작을 포함해야 한다. - 결과는 화면 캡처만으로 끝내지 않고 DOM 캡처를 함께 남긴다. - API 응답 또는 화면 텍스트를 기준으로 기대값과 실제값을 assert한다. - 실패 시에는 어떤 데이터가 달랐는지 로그로 남긴다. - 최종 완료 검증은 `https://www.taxbaik.com/taxbaik` 도메인에서 수행한다. IP 직결 주소는 로컬/임시 점검용으로만 쓴다. ## Deployment and Trouble FAQ ### Q1. 로그인 화면에 MudBlazor를 쓰면 안 되나? Static SSR 로그인이라면 쓰지 않는 것이 맞다. MudBlazor는 static rendering을 지원하지 않으므로 login은 HTML form 또는 Razor Page가 안전하다. ### Q2. 브라우저 앱에 JWT를 localStorage에 저장해도 되나? 피해야 한다. 브라우저 사용자 인증은 HttpOnly cookie가 기본이고, JWT는 외부 API 클라이언트용으로 분리한다. ### Q3. WebAssembly 홈에서 cookie 인증 API 호출이 복잡한가? same-origin이면 단순하다. cross-origin이면 CORS, SameSite, credentials 정책이 추가되어 장애 포인트가 늘어난다. ### Q4. Dapper를 쓰면 ORM의 변경 추적이 없는데 괜찮나? 이 구조는 조회와 명령을 분리하는 쪽에 맞는다. SQL을 명시적으로 관리하고 repository 테스트와 migration으로 정합성을 유지한다. ### Q5. PostgreSQL 18.4로 업그레이드할 때 dump/restore가 필요한가? 같은 18.x minor 업그레이드는 dump/restore가 필요하지 않다. 다만 운영 적용 전 staging restore drill은 필수다. ## Stop Conditions - MudBlazor를 static rendering 화면에 억지로 넣는 시도는 중단한다. - 로그인 SSR과 WASM home 경계를 흐리는 구현은 중단한다. - 관리자 로그인 WASM을 즉시 제거하지 말고, 먼저 migration WBS와 대체 SSR 경로를 정의한다. - JWT를 브라우저 저장소에 넣는 설계는 중단한다. - 완료 데이터 정의가 없는 WBS는 완료로 보지 않는다.