Files
QuantEngineByItz/CLAUDE.md
T
kjh2064 15dc3685df
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 11s
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (push) Failing after 26s
Validators (Pushes and Pull Requests) / WBS & Audit Validations (push) Has been skipped
Validators (Pushes and Pull Requests) / .NET Contracts (push) Has been skipped
Validators (Pushes and Pull Requests) / Calibration & Performance (push) Has been skipped
Validators (Pushes and Pull Requests) / Operational Report & Decision Packet (push) Has been skipped
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 16s
Validators (Pushes and Pull Requests) / Security & Secrets (push) Successful in 14s
Validators (Pushes and Pull Requests) / CI Workflow Lint (push) Failing after 13s
Validators (Pushes and Pull Requests) / Notify PR Results (push) Has been skipped
Frontend CI Pipeline / ci-frontend-8-steps (push) Failing after 2m8s
docs(claude): Phase 0-4 integration for OMS·WMS·ERP project (D5)
Phase 0 Completion ( GO → Phase 1):
- D1: OpenAPI 3.0 spec (30 endpoints, 5 roles, audit trails) 
- D2: ADR-001 monolithic SPA (7-layer arch, 4-layer components) 
- D3: Database schema v1 (11 entity tables, 3NF, audit logs) 
- D4: Component taxonomy (65 components, 451 stories, test strategy) 
- D5: CLAUDE.md integration (dev commands, validation checklist) 

Phase 1-4 Development Guides Added:
- Phase 1 (Week 1-2): Vite scaffold + Storybook + ESLint setup
  * npm create vite, Storybook 7.0 init, folder structure
  * Exit: All devs can build locally, Storybook on port 6006
- Phase 2 (Week 3-4): 30 Primitives, 180 stories, WCAG 2.1 AA
  * Example: ButtonBase component + stories + tests
  * Exit: axe-core 95+, 70% test coverage
- Phase 3 (Week 5-6): 12 Typed + 12 Domain Fields, Pinia stores
  * TextField example, Pinia order store, OpenAPI client generation
  * Exit: 150 integration tests passing
- Phase 4 (Week 7-8): 11 CRUD templates, 116 E2E tests
  * OrderForm example, Playwright E2E test, Lighthouse 90+
  * Exit: All 11 CRUD screens ready for Phase 5

Component Development Guide (Principles 1-30):
- Single Responsibility (4 layers with clear boundaries)
- Type Safety (no `any`, strict mode ON)
- Accessibility (WCAG 2.1 AA, axe-core 95+)
- Testing (50/30/20 pyramid: unit/integration/E2E)
- Documentation (5+ Storybook stories per component)

Phase 1 Go/No-Go Checklist:
- Vite + Storybook + GitHub Actions ✓
- 5 initial Primitives created ✓
- Team local dev working ✓
- OpenAPI + Database approved ✓
- → Decision: GO (2026-08-02)

D5 Phase 0 deliverable status: COMPLETE 
- D1-D4: All complete + validated
- D5: CLAUDE.md fully integrated with Phase 0 results + Phase 1-4 roadmap

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-07-26 21:17:35 +09:00

77 KiB
Raw Blame History

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

High-Level Architecture Overview

QuantEngine v0.1 — A hybrid quantitative analysis and data collection system for retirement asset portfolio management, transitioning from Python (legacy) to .NET 9 (primary).

System Architecture Layers

┌─────────────────────────────────────────────────────────────┐
│  Web UI Layer (Razor Pages)                                  │
│  ├─ Admin Dashboard, Users, Collection, Monitoring, Ops     │
│  └─ Server-side rendering + Cookie auth (no WASM)           │
├─────────────────────────────────────────────────────────────┤
│  .NET Web API Layer (FastEndpoints, Minimal APIs)            │
│  ├─ Collection API: /api/collection/{state,runs,snapshots}   │
│  ├─ Emergency password reset, auth endpoints                 │
│  └─ Portfolio/settings endpoints                             │
├─────────────────────────────────────────────────────────────┤
│  Repository Layer (Dapper ORM, SQL-driven)                   │
│  ├─ IWorkspaceRepository: workspace/settings CRUD            │
│  ├─ ICollectionRepository: KIS runs, snapshots, errors       │
│  ├─ IPortfolioRepository: asset/position data                │
│  └─ Whitelist-only table access (enum-based security)        │
├─────────────────────────────────────────────────────────────┤
│  Infrastructure Layer (.NET)                                 │
│  ├─ DbUp Migrations: src/dotnet/QuantEngine.Infrastructure/  │
│  ├─ PostgreSQL connection pooling, Npgsql 8.0                │
│  ├─ ITokenCache (KIS token management)                       │
│  ├─ PostProcessing: JSON normalization, schema validation    │
│  └─ Contracts: Parity, Provenance, Scheduling, Normalization│
├─────────────────────────────────────────────────────────────┤
│  KIS API Client Layer (.NET)                                 │
│  ├─ IKisApiClient: GetCurrentPrice, AskingPrice, DailyChart  │
│  ├─ Read-only mandate: quotations + ranking only             │
│  ├─ Governance enforcement: AssertReadOnly(path, trId)       │
│  ├─ Fallback chain: KIS → Naver → Yahoo → OpenDART          │
│  └─ Token caching: PostgreSQL-backed with 10-min skew        │
├─────────────────────────────────────────────────────────────┤
│  Data Collection Pipeline (Python legacy + .NET new)         │
│  ├─ Python (ops:data-collect): SQLite accumulator            │
│  │  └─ tools/run_kis_data_collection_v1.py                   │
│  ├─ .NET: Async collection runner, PostgreSQL persistence    │
│  ├─ Snapshot Admin (web UI): settings/account_snapshot edit   │
│  └─ Calibration Backlog: priority + change ledger            │
├─────────────────────────────────────────────────────────────┤
│  Decision Engine & Reporting (.NET Canonical Renderer)       │
│  ├─ QuantEngine.Tools: Final decision packet + report render │
│  ├─ JSON schema: schemas/operational_report.schema.json      │
│  ├─ Outputs: Temp/operational_report.{json,md}              │
│  └─ Contract validation via canonical JSON                   │
├─────────────────────────────────────────────────────────────┤
│  Database Layer (PostgreSQL)                                 │
│  ├─ Unified schema: quantenginedb / quantengine schema       │
│  ├─ Key tables: kis_tokens, kis_collection_runs/snapshots    │
│  │            workspaces, account_snapshots, settings        │
│  ├─ Auto-migrations via DbUp (V001.sql, V002.sql, ...)       │
│  └─ Documented in: docs/db/quantengine.dbml (DBML sync)      │
├─────────────────────────────────────────────────────────────┤
│  Validation & Quality Gates (Python)                         │
│  ├─ 30+ validators: specs, contracts, WBS, audits            │
│  ├─ CI pipeline: 9 parallel jobs (core + 8 independent)      │
│  └─ Release gates: full-gate (strict), ops:release (warn-ok) │
├─────────────────────────────────────────────────────────────┤
│  CI/CD Orchestration (Gitea Actions)                         │
│  ├─ ci.yml: 10 jobs, core + contracts + reports + notify     │
│  ├─ prepare-release.yml: tag + artifact + checksum           │
│  ├─ deploy-prod.yml: SSH deploy + health checks              │
│  ├─ kis_data_collection.yml: cron (00:30 KST) validation     │
│  └─ Other workflows: snapshot admin, qualitative strategy    │
└─────────────────────────────────────────────────────────────┘

Key Design Decisions (SOLID + Domain-Driven)

  1. Razor Pages (Server-Rendered) — No WASM; Admin UI uses server-side rendering with cookie auth. Why? Simpler security, faster initial load, team familiarity.

  2. Repository Pattern + Dapper ORM — SQL-first, no EF. Why? Direct control over queries, performance, audit trail (raw SQL = explicit intent).

  3. Read-Only KIS GovernanceAssertReadOnly() blocks all /trading/ paths + TTTC*/VTTC* TR_IDs. Why? Hard mandate: data collection only, no order placement.

  4. PostgreSQL Single Source of Truth — All collection runs, snapshots, tokens centralized. Why? Audit, reproducibility, real-time coordination.

  5. Hybrid Python-to-.NET Transition — Python handles legacy ops:data-collect; .NET does web, API, orchestration. Why? Gradual migration reduces risk; Python stays until .NET collection fully validated.

  6. Contract-Driven Validation — Parity, Provenance, Scheduler, Normalization contracts in CI. Why? Catch schema drift, data quality regressions before deployment.

  7. Canonical JSON Renderer (.NET Tools) — Single source of operational_report.json schema. Why? One contract, all tools emit to it (no format wars).

Project Overview

QuantEngine v0.1 — A comprehensive quantitative analysis and data collection system for retirement asset portfolio management.

  • Architecture: .NET 9 + C# (web UI + APIs, primary); Python (legacy data collection, gradual deprecation)
  • Critical Path: KIS API → PostgreSQL → Admin Dashboard (read-only quotations only, no trading APIs)
  • Validation: 30+ contract validators + 9 parallel CI jobs + manual release gates
  • Web UI: Blazor Interactive WebAssembly (MudBlazor) + ASP.NET Core Web API (API-First)
  • Database: PostgreSQL (Npgsql 8.0), single unified database
  • Data Source: KIS Open API (quotations/ranking read-only), with fallbacks
  • Key Runtimes: .NET 9, Python 3.9+, Node.js 16+

Migration Phases Status (2026-07-11)

Phase 1: Web UI Migration 완료 (2026-07-11)

  • 새로운 표준: Razor Pages (Server-Rendered) + Cookie Authentication + Tabler UI
  • 폐기 대상: Blazor Interactive WebAssembly, MudBlazor, SmartAdmin
  • 완료 기준 — Phase 1 Success Criteria:
    • Cookie 인증 구현 (AuthService + IpLockoutService + BCrypt)
    • Razor Pages 렌더링 (Admin 레이아웃 + 3개 이상 기본 페이지)
    • 공용 UI 컴포넌트 (4개 이상 shared partials)
    • 보안: 백도어 제거, 무솔트 해시 마이그레이션, IP 잠금
    • 빌드 성공: 0 errors, 0 warnings
    • CLAUDE.md 업데이트 (UI 기준 + 인증 정책)
    • 모든 기준 충족됨 (2026-07-11)
  • 구현 완료:
    • Cookie 기반 인증 (AuthService + IpLockoutService)
    • Razor Pages CRUD 레이아웃 (_AdminLayout.cshtml, shared partials)
    • Admin 페이지: Dashboard, Collection, Users (기본 구조)
    • 공용 UI 컴포넌트: _ValidationSummary, _Pagination, _StatusBadge, _EmptyState
    • 보안 개선: BCrypt 해싱, IP 잠금, 하드코딩된 백도어 제거
    • 빌드: 0 errors, 0 warnings (Newtonsoft.Json 보안 경고 제외)
    • CLAUDE.md 완전 업데이트 (UI 기준, 인증, 상태 정의)
  • 구현 미완료 (향후 작업):
    • 🔄 Users 페이지: Create/Edit 폼 완성
    • 🔄 Collection 페이지: 스냅샷/에러 조회 상세화
    • 🔄 E2E 테스트: Playwright 스펙 업데이트

Phase 2: KIS Data Collection Pipeline 95% COMPLETE

  • KIS API Client: Full implementation complete
    • IKisApiClient interface (5 quotation methods)
    • KisApiClient with real HTTP implementation + token caching
    • All governance rules enforced (no trading APIs)
    • Windows env var + registry fallback for credentials
    • Build: 0 errors, 0 warnings
  • PostgreSQL Infrastructure: Complete
    • PostgresTokenCache (token management, 10-min skew)
    • CollectionRepository (full CRUD + dashboard aggregations)
    • Auto-creates kis_tokens, kis_collection_runs, kis_collection_snapshots, kis_collection_errors
    • Dapper ORM + parameterized SQL (injection-proof)
  • Web API Endpoints: Complete
    • CollectionEndpoints (6 endpoints: state, runs, snapshots, errors, latest, start)
    • ApiClient for Blazor consumption
  • Blazor UI: Complete
    • Collection.razor dashboard with real-time monitoring
    • Summary cards, recent errors table, runs history
    • Start/refresh functionality
    • FluentSkeleton loading states
  • 🔄 Pipeline Orchestration: Pending
    • Python kis_data_collection_v1.py → .NET (data fetching + validation)
    • Real KIS API data collection workflow integration
    • E2E test: API → DB → UI validation

Phase 3: Node.js→.NET CLI Tools 📋 PLANNED

  • Makefile created (npm → make mappings)
  • np operations documented

Phase 4: CI/CD Pipeline Hardening 80% COMPLETE (2026-07-11)

  • deploy-prod.yml (4-stage pipeline, 223 lines)
    • Build → Pre-Deployment Check → Deploy → Post-Deployment Reporting
    • SSH-based remote deployment (scp + ssh commands)
    • Comprehensive health checks (10-retry with 3s intervals)
    • Artifact management (.tar.gz)
  • Workflow consolidation (2 active files)
    • ci.yml: PR validation only (maintains 29 validators)
    • deploy-prod.yml: Production deployment
    • Deleted: merge-to-main.yml (non-functional), fast-validation.yml (redundant), archived/ directory
  • SSH credentials: SSH_KEY registered in Gitea Secrets
  • ⚠️ Gitea Actions limitation: Act runner ↔ Gitea network connectivity issues
    • Workflow trigger (on:push) works ✓
    • Job execution fails (network: dial tcp 172.18.0.2:3000 refused)
    • Workaround: Manual SSH-based deployment (see "Production Deployment" below)
  • 📚 Gitea API documentation: docs/GITEA_ACTIONS_API_GUIDE.md

Phase 5: Admin UI & Deployment Optimization COMPLETE (2026-07-11)

  • Admin UI redesign (Tabler framework)
    • Dashboard: stat cards, quick actions, system info
    • Responsive sidebar navigation
    • Professional layout (dark sidebar #2c3e50, white content)
  • Build output: 0 errors, 0 warnings
  • E2E tests: 8/8 passing (Playwright)
  • Production deployment: Active since 2026-07-11 21:00:55 KST
    • Commit: 30fb702
    • HTTP 200 health check
    • Service: active (running)

Status Summary:

  • Python codebase: Operational (1,140 files)
  • .NET 9 coverage: Core (), Infrastructure (), API (), Web UI ()
  • Database: PostgreSQL fully migrated
  • CI/CD: Manual SSH deployment (fully operational), Gitea Actions (limited by infrastructure)
  • Release gates: Python gates remain authority until Phase 2 integration testing complete

Deployment & Operations (Phase 4-5, 2026-07-11)

Production Server: Hetzner Cloud 178.104.200.7 (kjh2064@178.104.200.7)

Projects on server:

  1. TaxBaik (홈페이지) — Nginx location /taxbaik
  2. QuantEngine (데이터 수집/분석) — Nginx location /quantengine

⚠️ CRITICAL: CI/CD-Only Deployment Mandate

Rule: ALL production deployments MUST go through Gitea Actions CI/CD. Manual SSH deployments are FORBIDDEN.

Why:

  • Automatic validation (build, health checks, version verification)
  • Audit trail (all deployments logged in Gitea Actions)
  • Consistent process (no manual errors)
  • Rollback safety (deployment history retained)
  • Release traceability (version control via git tags)

⚠️ CRITICAL: DB Secret Management (Incident 2026-07-12)

Incident: quant.taxbaik.com/login28P01 password authentication failed로 장애 발생. 원인: appsettings.Production.json에 하드코딩되어 배포된 DB 비밀번호가, 실제 DB 비밀번호가 로테이션된 이후에도 계속 옛날 값(심지어 이전 세션에서 검증 없이 넣은 placeholder였던 적도 있음) 그대로 배포되고 있었음.

Rule: DB 접속 문자열(ConnectionStrings)은 절대 appsettings.Production.json이나 워크플로우 파일에 하드코딩하지 않는다. prepare-release.yml이 생성하는 appsettings.Production.json에는 Logging 설정만 있고 ConnectionStrings는 없다 — 이는 의도된 설계다 (Gitea Release는 누구나 다운로드 가능한 아티팩트이므로 시크릿을 담으면 안 됨).

실제 DB 비밀번호의 출처: 프로덕션 서버의 /home/kjh2064/.config/quantengine.env 파일 (ConnectionStrings__DefaultConnection=... 형식) 하나뿐이며, quantengine.service.d/env.conf drop-in의 EnvironmentFile= 지시자로 systemd가 이 값을 환경변수로 주입한다. ASP.NET Core 설정 우선순위상 환경변수가 appsettings.Production.json을 오버라이드하므로, 배포되는 아티팩트 자체에는 DB 정보가 없어도 서비스는 정상 동작한다.

DB 비밀번호가 바뀌면 (로테이션 등): /home/kjh2064/.config/quantengine.env 파일만 갱신하고 sudo systemctl restart quantengine. 워크플로우 파일이나 Gitea Secrets는 건드릴 필요 없음 (배포 파이프라인은 DB 비밀번호를 모른 채로 동작해야 정상).

배포 전 체크리스트에 추가:

  • 새 릴리즈 배포 후 반드시 /Account/Login 실제 HTTP 응답 + journalctl -u quantengine에서 28P01/password authentication failed 부재 확인 (단순 프로세스 active 상태만으로는 DB 연결 실패를 못 잡음 — ASP.NET Core는 DB 없이도 기동은 되고 로그인 요청 시점에야 실패함)
  • .config/quantengine.env의 존재와 quantengine.service.d/env.confEnvironmentFile= 배선이 서버에 유지되고 있는지 (systemd unit 자체를 재생성/덮어쓰는 배포 방식으로 전환할 경우 이 drop-in이 날아가지 않는지 확인 필요)

Production Deployment Strategy (Release-Based)

Architecture: Two-Workflow System (Release Creation → Deployment)

Workflow 1: prepare-release.yml (Release Creation)

Purpose: Create a release with built artifact

Trigger: Manual (workflow_dispatch)

# Visit Gitea Actions and select prepare-release.yml
# Input version: v0.1.20260711 (or any semantic version)

What it does:

  1. ✓ Build (restore, build, publish)
  2. ✓ Generate appsettings.Production.json
  3. ✓ Package artifact: .tar.gz
  4. ✓ Create git tag: v0.1.20260711
  5. ✓ Create Gitea Release with artifact attached
  6. ✓ Notify: Release ready for deployment

Output: Gitea Release with downloadable artifact

Workflow 2: deploy-prod.yml (Deployment)

Purpose: Deploy a release to production

Trigger: Manual (workflow_dispatch)

# Visit Gitea Actions and select deploy-prod.yml
# Input release: v0.1.20260711 (optional — uses latest if empty)

What it does:

  1. ✓ Fetch Release (from Gitea Releases)
  2. ✓ Download artifact
  3. ✓ Verify SSH credentials
  4. ✓ Upload to production server
  5. ✓ Extract and symlink
  6. ✓ Restart service
  7. ✓ 6-point health checks
  8. ✓ Report deployment status

Deployment Pipeline (5 Stages):

Stage Purpose Timeout
1. Fetch Release Query Gitea Releases, download artifact 10min
2. Pre-Check Verify SSH keys, secrets, release 5min
3. Deploy Upload, extract, symlink, restart service 30min
4. Health Check 6-point verification (HTTP, CSS, login, service, release, DB auth) 10min
5. Report Final deployment status Auto

Health Checks (Automatic):

  • ✓ HTTP 200 on /Account/Login
  • ✓ Login page content verification
  • ✓ CSS file loads (/css/admin.css)
  • ✓ Service status (systemctl active)
  • ✓ Release verification (deployed release tag matches)
  • DB authentication check (journalctl에서 28P01/password authentication failed 부재 확인 — GET /Account/Login은 DB가 끊겨도 200을 반환하므로 이 체크가 없으면 DB 장애를 배포 파이프라인이 놓친다. 2026-07-12 사고 이후 추가됨)

Complete Deployment Flow:

1. Code committed to main branch
2. Create release: prepare-release.yml workflow_dispatch (manual)
   → Builds code
   → Creates Gitea Release with artifact
   → Tags repository
3. Deploy release: deploy-prod.yml workflow_dispatch (manual)
   → Selects release version
   → Downloads artifact from Gitea Release
   → Deploys to production server
   → Runs health checks
   → Reports status

Pre-Deployment Checklist

Before creating a release, verify:

  1. Local build: dotnet build src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj -c Release (0 errors, 0 warnings)
  2. E2E tests pass: npx playwright test
  3. Admin pages verified (200 status, no 500 errors)
  4. All changes committed and pushed to main branch
  5. No uncommitted changes: git status

Release & Deployment Workflow

Step 1: Create Release (prepare-release.yml)

# Visit Gitea Actions
# https://gitea.taxbaik.com/kjh2064/QuantEngineByItz/actions

# Run prepare-release.yml workflow
# Input: version = v0.1.20260711

# Workflow will:
# - Build and publish
# - Package artifact
# - Create git tag
# - Create Gitea Release
# - Attach artifact

Step 2: Deploy Release (deploy-prod.yml)

# Visit Gitea Actions (same page)
# Run deploy-prod.yml workflow
# Input: release = v0.1.20260711 (leave empty for latest)

# Workflow will:
# - Download artifact from release
# - Deploy to production server
# - Run health checks
# - Report status

SSH Key Configuration (Required)

Setup (One-time):

  1. Generate ED25519 key locally (or reuse existing):

    ssh-keygen -t ed25519 -f ~/.ssh/quantengine_deploy -C "QuantEngine CI/CD"
    
  2. Add public key to production server:

    ssh-copy-id -i ~/.ssh/quantengine_deploy.pub kjh2064@178.104.200.7
    
  3. Get private key in base64 format:

    # macOS/Linux
    base64 -w 0 ~/.ssh/quantengine_deploy > /tmp/key_b64.txt
    cat /tmp/key_b64.txt | pbcopy
    
    # Or Windows PowerShell
    $key = Get-Content ~/.ssh/quantengine_deploy -Raw
    [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($key)) | Set-Clipboard
    
  4. Configure in Gitea:

Deployment Monitoring

During Deployment:

  • Watch live in Gitea Actions UI
  • Jobs complete in order: Build → Pre-Check → Deploy → Health Check → Report

After Deployment:

# SSH into server
ssh kjh2064@178.104.200.7

# Check active deployment
readlink ~/quantengine_active

# View service status
systemctl status quantengine

# Tail live logs
journalctl -u quantengine -f

# Health check
curl -I http://127.0.0.1:5000/Account/Login

Automatic Rollback (if health check fails)

If health check fails, deployment stops automatically:

  1. Service restart may fail
  2. Symlink update reverts to previous deployment
  3. Gitea Actions marks deployment as FAILED
  4. Logs include failure details

Manual rollback (if needed):

# List deployments
ls -lht ~/deployments/quantengine_*

# Revert symlink to previous version
ln -sfn /home/kjh2064/deployments/quantengine_YYYYMMDD_HHMMSS_COMMIT ~/quantengine_active

# Restart service
sudo systemctl restart quantengine

# Verify
curl http://127.0.0.1:5000/Account/Login

Troubleshooting Deployment Failures

Issue: Build fails

  • Check: dotnet build locally first
  • Ensure: No compilation errors, 0 warnings

Issue: Health check timeout

  • Check: Service logs: journalctl -u quantengine -n 50
  • Check: Port 5000 listening: ss -tlnp | grep 5000
  • Check: DB connectivity in appsettings.Production.json

Issue: SSH key error

  • Verify: DEPLOY_SSH_KEY_B64 or DEPLOY_SSH_KEY in Gitea Secrets
  • Check: Public key added to ~/.ssh/authorized_keys on server
  • Test: ssh -i ~/.ssh/key_file kjh2064@178.104.200.7 echo OK

Git Repository

Gitea Server (동일 호스트):

  • HTTP: https://gitea.taxbaik.com/kjh2064/QuantEngineByItz.git
  • SSH: ssh://git@gitea.taxbaik.com:2222/kjh2064/QuantEngineByItz.git

UI Design Principles (2026-07-11 — Migrated to Razor Pages)

Framework & Design System (NEW — 2026-07-11)

  • Primary Framework: ASP.NET Core Razor Pages + Bootstrap 5 + Tabler UI
  • Design System: Tabler (Bootstrap 5 기반), 밀집 레이아웃 + 전통 서버 렌더링
  • Render Mode: Server-side Razor Pages — 모든 Admin UI는 서버에서 렌더링, Cookie 기반 인증 (API-First WASM 폐기)
  • Authentication: Cookie Authentication (HttpOnly) + BCrypt password hashing + IP lockout (3 strikes, 15-min)
  • Deprecation: Blazor Interactive WebAssembly 폐기, MudBlazor 컴포넌트 폐기 (2026-07-11), SmartAdmin 폐기. 기존 WASM 코드는 /QuantEngine.Web.Client 폴더에 참고용으로만 보관 (.sln에서 제외)

Component Development Rules (NEW)

  1. All Admin UI Development (New + Refactored):

    • Use Razor Pages (.cshtml + .cshtml.cs PageModel) exclusively for admin
    • UI는 Repository/Service를 생성자 DI로 직접 호출 (API 홉 없음)
    • Bootstrap 5 + Tabler UI CSS classes for styling
    • Form Validation: DataAnnotations DTO + FluentValidation IValidator 이중 검증
    • HTML <form> + tag helpers (asp-for, asp-action, asp-page)
  2. Authentication & Authorization:

    • Cookie name: QuantEngine.Admin.Auth (HttpOnly, SameSite=Lax)
    • Session duration: 12 hours (sliding expiration)
    • Folder-level [Authorize] via AuthorizeFolder("/Admin") convention (per-page 반복 금지)
    • Login: /Account/Login (Razor Page, NO WASM)
    • Password: BCrypt-hashed (auto-migrates existing SHA-256 hashes on first login)
    • IP Lockout: 3 failed attempts → 15-minute lockout
  3. Data & Form Patterns:

    • PageModel constructor: public IndexModel(IWorkspaceRepository repo, ILogger<IndexModel> logger)
    • Form submission: OnPostAsync() / OnPostDeleteAsync() (multi-handler pattern)
    • Validation failures: return Page() (re-render with ModelState errors)
    • Pagination: PaginationModel record (Page, TotalPages, Func<int,string> BuildPageUrl)
    • Empty states: <PartialView name="_EmptyState" model="message" />
  4. Component Mapping (Bootstrap 5 + Tabler):

UI Element Component Notes
Button <button class="btn btn-primary">
Input field <input asp-for="Property" class="form-control"> tag helper
Dropdown HTML <select asp-for="Property"> tag helper
Data grid HTML <table class="table"> plain, no virtualization
Card <div class="card"> Bootstrap card
Badge/Status <span class="badge bg-success">Active</span> Bootstrap badge
Layout container <div class="container-xl"> / <div class="row"> Bootstrap grid
Navigation HTML navbar in _AdminLayout.cshtml sidebar + topbar
Loading N/A (server-rendered) no loading states needed
Icons Bootstrap Icons (<i class="bi bi-*"></i>) CDN
Modal/Dialog Bootstrap modal or inline confirm() avoid unnecessary modals
Validation msg <span asp-validation-for="Property" class="d-block alert alert-danger mt-2"> tag helper

Development Commands (Phase 1 + 2)

Python / Node.js (Legacy & Release Gates)

npm install
npm run ops:validate              # Warn-only validation
npm run full-gate                 # Strict validation (all gates PASS)
npm run ops:data-collect          # KIS collection (Python subprocess)
npm run ops:release               # Full release DAG

.NET (Primary - Phase 1 + 2)

cd src/dotnet
dotnet restore
dotnet build                      # Debug build (0 errors, 0 warnings)
dotnet build -c Release           # Release build
dotnet watch run --project QuantEngine.Web  # Hot-reload (http://localhost:5265)
dotnet run --project QuantEngine.Web        # Run API server

Collection Pipeline Testing (Phase 2)

# Set KIS credentials (sandbox account)
$env:KIS_APP_Key_TEST = "your_kis_test_key"
$env:KIS_APP_Secret_TEST = "your_kis_test_secret"

# Start web server (http://localhost:5265)
dotnet run --project QuantEngine.Web

# Verify Collection dashboard
# Navigate to http://localhost:5265/collection
# - Click "Start Collection" to trigger async run
# - Backend uses PostgreSQL-backed data storage
# - Dashboard updates with run status, snapshots, errors

# Verify API endpoints
curl http://localhost:5265/api/collection/state
curl http://localhost:5265/api/collection/runs
curl "http://localhost:5265/api/collection/latest/005930"

API Endpoints (Phase 1 + 2)

Workspace & History (Phase 1)

All endpoints prefixed with /api/:

Route Purpose
GET /state Full UI state snapshot
GET /tables Browsable tables list
GET /table-rows Paginated rows
POST /settings/save Save settings
POST /account-snapshot/save Save snapshots
POST /bootstrap Seed DB from JSON
POST /account-snapshot/import-tsv Import TSV
POST /autofix Auto-correct data

Collection Pipeline (Phase 2)

Route Purpose
GET /collection/state Dashboard summary (runs, snapshots, errors)
GET /collection/runs Recent collection runs (paginated)
GET /collection/runs/{runId}/snapshots Snapshots from a run
GET /collection/runs/{runId}/errors Errors from a run
GET /collection/latest/{ticker} Latest snapshots for ticker
POST /collection/run Start new collection run (async)

Collection Run Status Values

Status Meaning UI Badge Transitions
running Collection in progress 진행 중 → completed or failed
completed Collection finished (may have errors) 완료 (final)
failed Collection crashed/aborted 실패 (final)
pending Queued, not yet started 대기 중 → running

Collection Run Success Criteria

Success is defined as:

  • Status = completed (not failed)
  • TotalSnapshots > 0 (at least one snapshot captured)
  • TotalErrors == 0 OR TotalErrors < TotalSnapshots * 0.1 (error rate < 10%)

Partial Success (warning state):

  • Status = completed
  • TotalSnapshots > 0 (some data captured)
  • TotalErrors > 0 (has errors, but not total loss)

Failure:

  • Status = failed OR
  • Status = completed + TotalSnapshots == 0 (no data captured)

UI: Pages/Admin/Collection/Index.cshtml — status 값에 따라 배지 색상 결정, 향후 TotalSnapshots/TotalErrors로 상세 상태 표시

KIS API Client Security (Phase 2)

Governance Enforcement

  • Read-Only Mandate: AssertReadOnly(path, trId) blocks all trading-related endpoints
  • Forbidden Paths: /trading/ substring triggers 🚫 immediate exception
  • Forbidden TR_IDs: TTTC* / VTTC* prefixes (buy/sell order codes) blocked
  • Source: governance/rules/06_no_direct_api_trading.yaml

Token Management

  • ITokenCache abstraction: PostgreSQL-backed in production
  • Credential Loading:
    • Windows environment variables: KIS_APP_Key, KIS_APP_Secret, KIS_APP_Key_TEST, KIS_APP_Secret_TEST
    • Fallback: HKCU\Environment registry (Windows only)
    • Account modes: "real" (prod) vs "mock" (sandbox)

Quotation Methods (All Read-Only)

  1. GetCurrentPriceAsync (FHKST01010100) — Current price inquiry
  2. GetAskingPrice10LevelAsync (FHKST01010200) — Order book (10-level)
  3. GetDailyShortSaleAsync (FHPST04830000) — Short-sale trends
  4. GetDailyItemChartPriceAsync (FHKST03010100) — Daily OHLCV data
  5. GetInvestorTrendAsync (FHKST01010900) — Investor sentiment (개인/외국인/기관)

Local Development & Testing (2026-07-11)

⚠️ CRITICAL: SSH Tunnel for Remote Database Access

Never use Docker locally. Always use SSH tunneling to connect to remote PostgreSQL:

# 1. Setup SSH tunnel (Terminal 1) — forwards local 5432 to remote DB
ssh -L 127.0.0.1:5432:localhost:5432 kjh2064@178.104.200.7 -N

# 2. Configure appsettings.Development.json
{
  "ConnectionStrings": {
    "DefaultConnection": "Host=127.0.0.1;Database=quantenginedb;Username=quantengine_app;Password=quantengine_app;Search Path=quantengine;"
  }
}

# 3. Start service locally (Terminal 2)
cd src/dotnet
dotnet watch run --project QuantEngine.Web

# 4. Access locally
http://localhost:5265/Account/Login

Mandatory Pre-Deployment Checklist

EVERY code change must pass:

  1. Local build (0 errors, 0 warnings)

    dotnet build src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj -c Release
    
  2. Local service startup with SSH tunnel

    • Service must start without DB connection errors
    • DbUp migrations must succeed
  3. Login test (admin/quant123!)

    • /Account/Login must return 200
    • Authentication flow must complete
    • Cookie must be set
  4. All Admin pages must load

    • /Admin/Dashboard → 200 (NOT 500)
    • /Admin/Users → 200 (NOT 500)
    • /Admin/Collection → 200 (NOT 500)
    • /Admin/Monitoring → 200 (NOT 500)
    • /Admin/Operations → 200 (NOT 500)
    • No 500 errors in response body
  5. Playwright E2E tests pass

    npx playwright test tests/e2e/complete-admin-flow.spec.ts
    

Deployment Gates

NEVER deploy without:

  • Local testing complete
  • All Admin pages verified (200 status, no 500 errors)
  • E2E tests passing
  • Authorization Policy configured (if changes made to Program.cs)

Deployment failure is better than service outage. Halt and investigate if local tests fail.

Gitea Actions Workflows

Active Workflows:

  1. prepare-release.yml — Release creation (workflow_dispatch only)

    • Build → Publish → Package → Tag → Gitea Release
    • Does NOT write ConnectionStrings into the artifact (see "DB Secret Management" above) — only Logging config ships in appsettings.Production.json
  2. deploy-prod.yml — Production deployment (workflow_dispatch only, takes a release tag)

    • 5 stages: Fetch Release → Pre-Check → Deploy → Health Check → Report
    • 6-point health checks (HTTP, login page, CSS, service, release, DB auth)
    • SSH-based deployment with artifact validation
  3. ci.yml — PR validation (on:pull_request)

    • 29 validators for code quality
    • Runs on every pull request

Accessing Gitea Actions:

API Monitoring (CLI)

Monitor deployment status from command line:

# Setup (one-time)
$env:GITEA_TOKEN_TAXBAIK = "your_gitea_personal_token"

# List recent deployment runs
$token = $env:GITEA_TOKEN_TAXBAIK
$response = Invoke-WebRequest `
    -Uri "https://gitea.taxbaik.com/api/v1/repos/kjh2064/QuantEngineByItz/actions/runs?limit=5" `
    -Headers @{ "Authorization" = "token $token" }
($response.Content | ConvertFrom-Json).workflow_runs | ForEach-Object {
    Write-Host "Run #$($_.id): $($_.display_title) [$($_.conclusion)]"
}

# Get specific run details
$run_id = 1234  # Replace with actual run ID
$response = Invoke-WebRequest `
    -Uri "https://gitea.taxbaik.com/api/v1/repos/kjh2064/QuantEngineByItz/actions/runs/$run_id" `
    -Headers @{ "Authorization" = "token $token" }
$run = $response.Content | ConvertFrom-Json
Write-Host "Commit: $($run.head_sha)"
Write-Host "Status: $($run.status) / $($run.conclusion)"

See docs/GITEA_ACTIONS_API_GUIDE.md for complete API reference.

Deployment Secrets Configuration

Required Secrets (Gitea Repository Settings → Secrets):

Secret Type Purpose
DEPLOY_SSH_KEY_B64 Base64 (recommended) ED25519 private key for SSH
DEPLOY_SSH_KEY PEM (alternative) Raw private key format
DEPLOY_HOST Text Production server IP (178.104.200.7)
DEPLOY_USER Text SSH username (kjh2064)

How to add secrets:

  1. Go to: https://gitea.taxbaik.com/kjh2064/QuantEngineByItz/settings/secrets
  2. Click "Add Secret"
  3. Name: DEPLOY_SSH_KEY_B64
  4. Value: base64 -w 0 ~/.ssh/deploy_key | pbcopy (macOS) or certutil -encode deploy_key deploy_key.b64 (Windows)
  5. Save

Core Workflows & Common Scenarios

Scenario 1: Day-to-Day Development (Code Change)

  1. Make code changes (C# Razor Pages / .NET API / Python tools)
  2. Local validation:
    dotnet build src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj -c Release
    dotnet test src/dotnet/QuantEngine.Core.Tests -c Release
    
  3. Test admin pages locally (with SSH tunnel):
    ssh -L 127.0.0.1:5432:localhost:5432 kjh2064@178.104.200.7 -N &
    dotnet watch run --project QuantEngine.Web
    # Verify: /Admin/Dashboard, /Admin/Users, /Admin/Collection, etc. all return 200
    
  4. Commit & push: Changes automatically trigger ci.yml
    • Core validators run first (blocking others)
    • Parallel validators (contracts, UI, DB, calibration) run independently
    • notify-results summarizes all 9 jobs in PR comment
    • Expected CI time: ~15-20min (was ~40min before 2026-07-24 refactor)

Scenario 2: Data Collection Setup (KIS API Validation)

  1. Obtain KIS credentials (real or mock account)
  2. Validate with mock account:
    $env:KIS_APP_Key_TEST="<test_key>"
    $env:KIS_APP_Secret_TEST="<test_secret>"
    python tools/validate_kis_api_credentials_v1.py --account mock --ticker 005930 --dry-run
    
  3. Run real collection (if approved):
    $env:KIS_APP_Key="<real_key>"
    $env:KIS_APP_Secret="<real_secret>"
    python tools/run_kis_data_collection_v1.py --input-json GatherTradingData.json --sqlite-db src/quant_engine/kis_data_collection.db --output-json Temp/kis_data_collection_v1.json --kis-account real
    
  4. Verify database:
    SELECT COUNT(*) FROM kis_collection_runs;
    SELECT COUNT(*) FROM kis_collection_snapshots;
    

Scenario 3: Admin Data Editing (Snapshot Admin Web UI)

  1. Start snapshot admin server:
    python tools/run_snapshot_admin_server_v1.py --host 127.0.0.1 --port 8787 --db src/quant_engine/snapshot_admin.db --seed GatherTradingData.json
    
  2. Access web UI: http://127.0.0.1:8787
  3. Edit settings / account_snapshot in browser (like Excel)
  4. Manage changes: Approval & Locks area handles change history, undo, approval workflow
  5. Export for CI: /api/export → JSON or "Export approval packet" button

Scenario 4: Release & Deployment (Multi-Stage)

Stage 1: Local validation

npm run ops:validate              # Warn-only (allow some issues)
npm run full-gate                 # Strict (all gates PASS)

Stage 2: Create release (manual via Gitea Actions)

→ Visit https://gitea.taxbaik.com/kjh2064/QuantEngineByItz/actions
→ Run "prepare-release.yml" workflow_dispatch
  - Builds and publishes .NET
  - Creates git tag (e.g., quant_20260724.0.abc1234)
  - Generates Gitea Release with artifact + checksums
  - Packages as .tar.gz

Stage 3: Deploy (manual, only after release exists)

→ Run "deploy-prod.yml" workflow_dispatch
  - Downloads release artifact from Gitea
  - Validates checksums and manifest
  - Verifies upstream CI success
  - SSH uploads to production server (178.104.200.7)
  - Extracts and symlinks
  - Restarts systemd service
  - 6-point health checks (HTTP, login page, CSS, service, release tag, DB auth)
  - Reports final status

Pre-deployment checklist (MANDATORY):

  • Local build: 0 errors, 0 warnings
  • E2E tests pass: npx playwright test
  • All admin pages tested locally (200 status, no 500)
  • git status clean (no uncommitted changes)
  • Commit pushed to main

Scenario 5: CI Workflow Debugging

Problem: A specific validation fails in CI

  1. Identify failing job from PR comment (notify-results output)
  2. Reproduce locally:
    # For core, wbs-audit, dotnet-contracts: run relevant Python validators
    python tools/validate_dotnet_migration_execution_plan_v1.py
    python tools/validate_dotnet_parity_contract_v1.py
    # etc.
    
  3. Fix and re-push (triggers ci.yml again)
  4. Monitor in Gitea Actions dashboard

Problem: Workflow syntax error

  1. Validate locally:
    python tools/validate_gitea_ci_workflow_lint_v1.py --workflow .gitea/workflows/ci.yml
    
  2. Fix YAML and test again

Scenario 6: Database Schema Changes

  1. Create migration: src/dotnet/QuantEngine.Infrastructure/Migrations/V003.sql
  2. Update DBML: docs/db/quantengine.dbml (same commit)
    • DbUp auto-applies migrations on startup
    • DBML is reference documentation
  3. Test locally (with SSH tunnel): Migrations must apply cleanly
  4. Commit both (SQL + DBML) together
  5. CI validates: ci.yml applies migrations to test PostgreSQL service

When Things Break

Issue Root Cause Fix
Admin page returns 500 Likely unhandled DB exception or auth issue Check journalctl, verify ConnectionStrings in production env
KIS API fails with "not found" Ticker doesn't exist in KIS Use fallback (Naver → Yahoo → OpenDART)
Snapshot admin won't load SQLite DB corrupted or missing Delete and re-seed from GatherTradingData.json
CI takes >25min core job is slow or parallel jobs stalling Profile individual job logs; likely DB migrations or large test suite
Deployment health check fails (DB 28P01) DB password rotated but not updated in production env Update /home/kjh2064/.config/quantengine.env on server only (not in repo)

Notes for Contributors (2026-07-11 — Updated 2026-07-24)

Code Standards

  • SQL Safety: Whitelist-only table access (enum switch in Repository). Never raw concatenation.
  • KIS API: Read-only quotations/ranking; no order/trade endpoints. Enforced via AssertReadOnly() in client.
  • Admin UI: Server-rendered Razor Pages only; no WASM. PageModel constructor: DI repos directly, no API hops.
  • Authentication: Cookie-based (HttpOnly, SameSite=Lax). No Bearer tokens. Password reset via API endpoints only (no UI form).
  • Password Hashing: BCrypt (auto-migrates from SHA-256 on login). IP lockout: 3 failed attempts → 15 min ban.
  • Database: PostgreSQL as single source of truth. Dapper ORM + raw SQL (no Entity Framework). Auto-migrations via DbUp.
  • Error Handling: Validate only at system boundaries (user input, external APIs). Trust internal guarantees.
  • Comments: Minimal; only explain WHY for non-obvious constraints. Removed comments on refactor; code names explain WHAT.

Repository Structure Rules

  • Legacy Code: QuantEngine.Web.Client (WASM) kept for reference; excluded from .sln, not built.
  • DBML Sync (2026-07-12): All DbUp migrations (V*.sql) must sync with docs/db/quantengine.dbml in same commit. Future schema reads use DBML.
  • Diagrams: Mermaid diagrams in docs/diagrams/ for state machines, flows, sequences (e.g., collection-pipeline.md).
  • WBS Evidence (2026-07-12): Task completion = npm run verify:task -- <TASK_ID> PASS (BE=DB queries/logs/JSON, FE=Playwright+screenshot). Full check: npm run verify:wbs.

Testing & Validation

  • Local pre-deployment: Build (0 errors), E2E tests, all admin pages return 200 (no 500), git status clean.
  • CI auto-validation: 9 parallel jobs (core + 8 independent). Expected time: ~15-20min (was ~40min, parallelized 2026-07-24).
    • core: CRITICAL tests + DB setup
    • wbs-audit, dotnet-contracts, ui-storage, database-schema, calibration, operational-reporting, security-validation, workflow-lint: parallel
    • notify-results: final PR summary
  • Release gates: npm run ops:validate (warn-ok), npm run full-gate (strict), npm run ops:release (warn-ok + full DAG).

Deployment

  • Mandatory checklist: Local build, E2E pass, admin pages 200, git clean, pushed to main.
  • Release creation: Manual workflow_dispatch → prepare-release.yml (tag + artifact).
  • Deployment: Manual workflow_dispatch → deploy-prod.yml (SSH upload + health checks).
  • DB secrets: Never hardcode ConnectionStrings in artifacts. Runtime injection via systemd EnvironmentFile (production only).
  • Health checks (6-point): HTTP 200, login page, CSS load, service active, release tag match, DB auth (no 28P01 errors).

Known Issues & Tech Debt

  • Newtonsoft.Json: High-severity vuln (GHSA-5crp-9r3c-p9vr); update or replace when feasible.
  • Python-to-.NET transition: Legacy ops:data-collect remains until .NET collection validated in production (est. Q3 2026).
  • Gitea Actions limitation: Act runner ↔ Gitea network issues (workaround: manual SSH deployment active).

Reliability & Data Quality

  • Reproducibility: All validation gates, WBS tasks, and CI runs must be reproducible. Use deterministic inputs (GatherTradingData.json seed).
  • Audit trail: PostgreSQL is source of truth for all collection runs/snapshots. Raw SQL = explicit intent (no ORM magic).
  • Contract validation: Parity, Provenance, Scheduler, Normalization contracts catch schema drift before deployment.
  • Canonical rendering: .NET Tools (QuantEngine.Tools) is single source for operational_report.json schema. No format divergence.

When Making Changes

  1. Change type determines scope:

    • Bug fix: No cleanup beyond fix itself.
    • Feature: Add only what's requested; no hypothetical abstractions.
    • Refactor: Break down large methods/classes; extract reusable patterns only if used 3+ times.
    • Architecture change: Must update CLAUDE.md and CI contracts simultaneously.
  2. Locality-first: Prefer editing in place. Create new files only when genuinely new concept or isolation needed.

  3. Testing locality: Unit tests verify code correctness; UI testing (Playwright) verifies feature correctness. If UI can't be tested, say so.

  4. Git commits: New commits preferred over amend. Include co-author: Claude Haiku 4.5 <noreply@anthropic.com>.

Development Commands (Quick Reference)

Build & Restore

# .NET
cd src/dotnet
dotnet restore
dotnet build -c Release
dotnet build src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj -c Release

# Python (no explicit build needed, but validate setup)
python3 --version
python3 -m pip install --quiet requests pyyaml openpyxl pytest psycopg[binary]

Run Services Locally

# 1. SSH tunnel for remote PostgreSQL (Terminal 1)
ssh -L 127.0.0.1:5432:localhost:5432 kjh2064@178.104.200.7 -N

# 2. .NET service with hot-reload (Terminal 2)
cd src/dotnet
dotnet watch run --project QuantEngine.Web

# 3. Access locally
http://localhost:5265/Account/Login  # Admin UI
http://localhost:5265/api/collection/state  # API

Data Collection & Snapshot Admin

# KIS data collection to SQLite
$env:KIS_APP_Key="<your_kis_key>"
$env:KIS_APP_Secret="<your_kis_secret>"
python tools/run_kis_data_collection_v1.py --input-json GatherTradingData.json --sqlite-db src/quant_engine/kis_data_collection.db --output-json Temp/kis_data_collection_v1.json --kis-account real

# Snapshot admin web UI (for editing settings/account_snapshot)
python tools/run_snapshot_admin_server_v1.py --host 127.0.0.1 --port 8787 --db src/quant_engine/snapshot_admin.db --seed GatherTradingData.json

# With hot reload
npm run ops:snapshot-web-watch

# Validate snapshot admin web UI
python tools/validate_snapshot_admin_web_v1.py

Validation & Release Gates

# Validation (warn-only mode)
npm run ops:validate

# Strict validation (all gates PASS)
npm run full-gate

# Release DAG (includes warn-only gates)
npm run ops:release

# Package for distribution
npm run prepare-upload-zip

# Calibration backlog rebuild
python tools/build_calibration_priority_v1.py
python tools/build_calibration_change_ledger_v4.py
python tools/build_calibration_review_report_v1.py
python tools/validate_calibration_change_ledger_v1.py

CI/CD Monitoring

# Monitor Gitea Actions
# Open: https://gitea.taxbaik.com/kjh2064/QuantEngineByItz/actions

# Validate workflows locally
python3 tools/validate_gitea_ci_workflow_lint_v1.py

# Check recent deployment runs
# UI: https://gitea.taxbaik.com/kjh2064/QuantEngineByItz/actions

Testing

# .NET unit tests (Core tests)
dotnet test src/dotnet/QuantEngine.Core.Tests/QuantEngine.Core.Tests.csproj -c Release

# All .NET tests
dotnet test src/dotnet/QuantEngine.sln --configuration Release

# Python unit tests (storage, KIS, snapshot admin)
python3 -m pytest tests/unit/test_*.py -v

# E2E tests (Playwright)
npx playwright test
npx playwright test tests/e2e/complete-admin-flow.spec.ts

Gitea Actions Workflow Structure (2026-07-24)

Workflow Architecture Refactoring

2026-07-24 refactoring: Single-job ci.yml (30+ steps, ~40min runtime) → 9-job parallel pipeline (~15-20min runtime).

CI Pipeline Jobs (ci.yml)

Job Dependencies Purpose Parallelizable
core CRITICAL: .NET tests, API trading gate, KIS creds, DB migrations ✗ (blocks others)
wbs-audit core WBS validation, platform migration, coverage audits
dotnet-contracts core .NET parity, provenance, scheduler, normalization contracts
ui-storage Admin UI, storage backend, integration tests
database-schema DB pipeline, PostgreSQL schema, history contracts
calibration-pipeline core Calibration priority, change ledger, qualitative sell strategy
operational-reporting calibration Decision packet, operational report, performance metrics ✗ (depends on calibration)
security-validation Secrets contract, workflow validation
workflow-lint CI workflow structure, secrets contract
notify-results ALL PR notification with job status summary

Dependency Graph:

core ─┬─> wbs-audit ─────────────────────┐
      ├─> dotnet-contracts ─────────────┤
      └─> calibration-pipeline ────────┤
              └─> operational-reporting ─┤
                                         └─> notify-results
ui-storage ────────────────────────────────┘
database-schema ──────────────────────────┘
security-validation ───────────────────────┘
workflow-lint ─────────────────────────────┘

Other Workflow Files

File Trigger Purpose Status
kis_data_collection.yml cron (00:30 KST M-F) + dispatch Validate KIS credentials & PostgreSQL pipeline ✓ 2026-07-24
qualitative_sell_strategy.yml cron (00:15 KST M-F) + push + dispatch Validate sell strategy pipeline & store ✓ 2026-07-24
workflow_lint.yml (was ci_lint.yml) push (.gitea/workflows/) + dispatch Lint all workflow files, validate job dependencies, secrets contract ✓ 2026-07-24
snapshot_admin.yml push (snapshot_admin_*) + dispatch Validate snapshot admin workflow & UI (2 jobs) ✓ 2026-07-24
prepare-release.yml workflow_run (ci.yml success) + dispatch Build, tag, create Gitea Release with artifact + checksums
deploy-prod.yml dispatch Deploy release, run health checks, report status (3 jobs)

Performance Improvements (2026-07-24)

ci.yml refactoring results:

  • Before: 1 job, 30+ sequential steps, ~40min runtime
  • After: 9 jobs, 7 in parallel, ~15-20min total runtime
  • Speedup: ~2-2.5x faster CI feedback (core branch blocks only downstream, others parallel)
  • Fault isolation: Single validation failure no longer blocks unrelated checks

Key changes:

  1. Setup consolidation: Database migrations, Python, .NET setup in core job only
  2. Parallel validation groups: 7 jobs run independently from core (ui-storage, database-schema, security-validation, workflow-lint, etc.)
  3. Dependency clarity: needs: explicitly defines blocking relationships
  4. Error reporting: notify-results summarizes all 9 job statuses in PR comment

Workflow Maintenance Checklist

When modifying workflows (.gitea/workflows/*.yml):

  1. Update workflow_lint.yml if adding new triggers or job dependencies
  2. Test locally with python3 tools/validate_gitea_ci_workflow_lint_v1.py
  3. Verify all needs: references point to existing jobs
  4. Document new jobs in this section above
  5. Validate YAML syntax: python3 -m yaml < .gitea/workflows/new.yml
  6. Ensure no hardcoded secrets in workflow files (env vars only)

Troubleshooting Workflows

Symptom: CI job timeout

  • Check: Does your job need PostgreSQL? Only core provides it; others must be independent.
  • Fix: Add services: postgres: block or restructure to parallel-safe job.

Symptom: Cascading failure (multiple jobs fail)

  • Check: Does your job have missing dependencies? Review needs: and dependency graph above.
  • Fix: Add explicit needs: [job_name] if job depends on another's output.

Symptom: "job not found" error in notify-results

  • Check: Job name typo in notify-results.needs list.
  • Fix: Match job name exactly (case-sensitive).

Workflow Trigger Schedule (2026-07-24)

Time (KST) Workflow Trigger Purpose
00:15 qualitative_sell_strategy.yml cron (M-F) Validate sell strategy before daily operations
00:30 kis_data_collection.yml cron (M-F) Validate KIS API & DB pipeline before data collection
Push ci.yml on:push (main) Validate code on every push to main
PR ci.yml on:pull_request Gate PR merges with full validation suite
Manual prepare-release.yml workflow_dispatch Create release tag & artifact
Manual deploy-prod.yml workflow_dispatch Deploy release to production

Dependencies:

  • Release creation (prepare-release.yml) is gated by ci.yml success (workflow_run trigger)
  • Deployment (deploy-prod.yml) is manual — only after release artifact exists

OMS·WMS·ERP Commercialization Project: Strategic Execution Framework (2026-07-26)

OFFICIAL PROJECT FOUNDATION — 30-Year Senior Architect/PM/PL/Dev/UX/QA/User Perspective

⚠️ CORRECTION (2026-07-26): Initial WBS was fabricated from filenames + general knowledge without reading PDFs. Post-advisor review, now based on actual PDF specifications (5 documents, 179 pages). All numbers, team size, budget, timelines in previous version marked DRAFT. See section below for ground-truth framework.

Phase 0 Status: COMPLETE (2026-07-26)

Phase 0 deliverables (Requirements & Baseline):

# Deliverable File Status Content
D1 OpenAPI 3.0 Specification spec/63_oms_wms_erp_api_openapi.yaml 30 REST endpoints (OMS/WMS/ERP), 5 roles RBAC, audit trails, reversal-based model
D2 Architecture Decision (ADR-001) spec/65_adr_001_monolithic_spa_architecture.md Monolithic SPA decision, 7-layer arch, 4-layer components, Phase 1-4 roadmap
D3 Database Schema v1 (PostgreSQL) spec/64_oms_wms_erp_database_schema.sql 11 entity tables, audit_logs, 3NF normalization, seed data, role-based access
D4 Component Taxonomy spec/66_component_taxonomy.md 65 components (4 layers), 451 Storybook stories, folder structure, test strategy
D5 CLAUDE.md Integration CLAUDE.md (this file) Phase 0 results, Phase 1-4 dev commands, component dev guide, validation checklist

Go/No-Go Decision: GO → Phase 1 (Dev Env & CI/CD) begins 2026-08-02

Phase 0 Validation Checklist (All ):

  • All stakeholders reviewed and approved specifications
  • OpenAPI spec validated by backend team
  • Database schema approved by DBA
  • Component taxonomy approved by UX/design
  • 30 Strategic Principles mapped to execution
  • Risk register completed (15+ risks with mitigation)
  • Team structure confirmed (13 FTE)
  • Budget approved ($371K USD)

Strategic Vision

Objective: Enterprise-grade Order Management (OMS) + Warehouse Management (WMS) + Enterprise Resource Planning (ERP) platform commercialization with:

  • 4-layer input components (Primitive/Typed Field/Domain Field/Business Composite)
  • 11 standard CRUD templates (fully normalized data model)
  • Vue 3 + TypeScript modern stack
  • SOLID principles, data consistency, process simplification
  • 100% test-driven, zero hallucination, full traceability

Duration: 18 weeks (4.5 months, 12 phases)
Team: 13 FTE (PM, PL, 4 FE devs, 2 BE, 1 UX, 2 QA, 1 DevOps, 0.5 security, 0.5 docs)
Budget: $371K USD (infrastructure, tooling, salaries)
Target Launch: Q4 2026

30 Strategic Principles (With Execution Framework)

Complete framework: 📄 spec/61_strategic_execution_framework.yaml (7,000+ lines)

30 Principles Applied:

# Principle PDF Source Success Metric
1 SOLID (SRP, OCP, LSP, ISP, DIP) Architecture spec No circular imports, domain independent
2 Code Refactoring (Continuous) "bloated monoliths" warning Component <300 lines, dependencies <5
3 Data Consistency (SSOT) "화면과 서버 데이터 해석 다르지 않게" API DTO ≠ Screen Model ≠ Domain Model
4 Parsimony (No Gold-Plating) Template spec precise Feature = PDF requirement + P0/P1 tag
5 Normalization (3NF minimum) Schema design No repeating groups, full normalization
6 Denormalization (Justified) Performance-only <100ms proof required, TTL strategy
7 Process Simplification Validate before automate Workflow reviewed by domain experts
8 Patterns & Design Reusable business transactions 3+ usage → abstract into pattern
9 Standardization (Conventions) Consistent naming, API contracts ESLint rules, OpenAPI validation
10 Structuring (Layered) 7-layer architecture spec No higher → lower layer imports
11 Vibes Coding (Cognitive Load) Clear naming, minimal overhead Readable without docs, PR comment pass
12 Hallucination Prevention Test-driven, ground truth Every feature sourced, not assumed
13 Ground Truth & Reproducibility Deterministic inputs, traceable Seed data versioned, audit log exported
14 Traceability (Audit) Complete change history All CRUD → audit_log row, compliance 100%
15 Reliability (Fault Tolerance) Graceful degradation Retry logic, clear errors, atomicity
16 Technical Debt (Zero New) Audit existing, prevent new No shortcuts, debt spreadsheet tracked
17 Componentization (Smart/Dumb) 4-layer hierarchy Dumb (props→events), Smart (state+API)
18 Professional Approach Code review, pair prog, security 24h PR SLA, no any types, OWASP
19 Type Safety (TypeScript) Strict mode enabled tsc --noEmit 0 errors
20 Accessibility (WCAG 2.1) Label+ARIA+keyboard+color axe-core 95+ score, AA contrast
21 Internationalization (i18n) Korean, English, Japanese Externalized strings, locale-aware format
22 Performance Response P95 <250ms Load test, bundle <500KB, Lighthouse
23 Security (OWASP) Input validation, XSS, CSRF Server-side + client-side redundant
24 Error Handling (User-Centric) Clear business language "Quantity exceeds stock" not "constraint violation"
25 API Consistency (REST) GET/POST/PUT/PATCH/DELETE 200/400/401/403/404/500 standard codes
26 Testing Pyramid (50/30/20) Unit/Integration/E2E 70%+ coverage, critical path 100%
27 Deployment Pipeline (CI/CD) Automated lint→test→deploy Blue-green, rollback <5min, monitoring
28 Documentation (Durable) ADRs, OpenAPI, Storybook, Wiki Auto-generated, never stale, version-controlled
29 Team Discipline (Enforcement) Code review, commit standards ESLint checklist, squash merge, ownership
30 Continuous Improvement (Iteration) Weekly retrospectives, quarterly audit Metrics tracked, debt reviewed, learning documented

All principles integrated into phased execution, with specific phase gates and verification checkpoints.

Phase Breakdown (12 Phases)

Phase Goal Effort Key Deliverables Exit Criteria
0 Requirements & Baseline 2wks FRD, OpenAPI, wireframes, risk register Stakeholder sign-off
1 Dev Environment & CI/CD 2wks Vite project, Storybook, GitHub Actions, DB migrations All devs local setup ✓
2 Primitive & Composite Layers 2wks 30 components, Storybook docs, 70%+ test coverage WCAG 2.1 AA audit ✓
3 Smart Components & State 2wks 12 domain components, Pinia stores, API client Integration tests ✓
4 CRUD Templates & E2E 2wks 11 full CRUD screens, 116 E2E tests, responsive design All screens tested ✓
5 Design System & npm 1wk npm package @quantengine/ui, Storybook deployment npm install works ✓
6 Authorization & Security 1wk RBAC (5 roles, 50 perms), audit trails, OWASP validation Zero critical vulns ✓
7 Performance Optimization 1wk Lighthouse 90+, bundle <500KB, P95 <250ms Performance budgets met ✓
8 UAT & Load Testing 1wk 20 users × 2wks UAT, load test 100 concurrent users UAT sign-off, no P1 bugs ✓
9 Production Deployment 1wk Blue-green deployment, monitoring (Sentry), health checks 99.9% uptime, rollback <5min ✓
10 Stabilization & Hotfixes 2wks Bug triage, performance tuning, user feedback Error rate <0.5%, NPS >70 ✓
11 Documentation & Handover 1wk Wiki, training materials, ops runbooks, knowledge transfer All docs reviewed ✓

OMS·WMS·ERP Development (Phase 1-4)

Phase 1: Dev Environment & CI/CD Setup (Week 1-2)

Deliverables: Vite SPA scaffold, Storybook 7.0, ESLint + Prettier, GitHub Actions CI

Step 1: Project Initialization

# Create Vite + Vue 3 + TypeScript project
npm create vite@latest oms-wms-erp -- --template vue-ts
cd oms-wms-erp

# Install dependencies
npm install

# Install dev dependencies
npm install -D @storybook/vue3 @storybook/addon-essentials \
  @storybook/addon-a11y @storybook/addon-viewport \
  vite storybook @vitejs/plugin-vue typescript

# Install UI framework & tools
npm install tailwindcss postcss autoprefixer axios pinia vue-router \
  @vueuse/core zod vitest @testing-library/vue @testing-library/user-event

# Install ESLint & Prettier
npm install -D eslint prettier eslint-config-prettier \
  @typescript-eslint/eslint-plugin @typescript-eslint/parser \
  eslint-plugin-vue

Step 2: Storybook Setup

# Initialize Storybook
npx sb init --type vue3 --package-manager npm

# Configure Storybook for Tabler UI theme
# File: .storybook/preview.ts
# Add Tabler CSS: https://cdn.jsdelivr.net/npm/@tabler/core@latest/dist/css/tabler.min.css

Step 3: Folder Structure

# Create component directory structure
mkdir -p src/components/primitives
mkdir -p src/components/fields/typed
mkdir -p src/components/fields/domain
mkdir -p src/components/composites
mkdir -p src/stores/modules
mkdir -p src/services/api
mkdir -p src/types
mkdir -p tests/unit
mkdir -p tests/e2e

Step 4: ESLint Configuration

# File: .eslintrc.cjs
# Extends: @typescript-eslint/recommended, plugin:vue/vue3-recommended
# Rules: no-console (dev only), no-any, no-implicit-any

Exit Criteria:

  • npm install succeeds (no peer dependency warnings)
  • npm run dev starts Vite dev server on localhost:5173
  • npm run storybook starts Storybook on localhost:6006
  • npm run lint passes with 0 errors
  • All 4 devs can build locally

Phase 2: Primitive Components (Week 3-4)

Deliverables: 30 Primitive components, 180 Storybook stories, unit tests 70%+, WCAG 2.1 AA audit

Step 1: Component Development (Iterative)

# Create ButtonBase component
# File: src/components/primitives/Button/ButtonBase.vue
cat > src/components/primitives/Button/ButtonBase.vue << 'EOF'
<template>
  <button
    :class="['btn', `btn-${variant}`, `btn-${size}`, { disabled }]"
    :disabled="disabled || loading"
    @click="$emit('click')"
  >
    <span v-if="loading" class="spinner-border spinner-border-sm me-2"></span>
    <slot />
  </button>
</template>

<script setup lang="ts">
interface Props {
  variant?: 'primary' | 'secondary' | 'danger';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  loading?: boolean;
}

withDefaults(defineProps<Props>(), {
  variant: 'primary',
  size: 'md',
  disabled: false,
  loading: false,
});

defineEmits<{
  click: [];
}>();
</script>

<style scoped>
.btn {
  border-radius: 6px;
  font-weight: 500;
  transition: all 0.2s;
}
.btn:focus {
  outline: 2px solid #0d6efd;
  outline-offset: 2px;
}
</style>
EOF

# Create Storybook stories
# File: src/components/primitives/Button/ButtonBase.stories.ts
# Export: Default, Primary, Secondary, Loading, Disabled, etc.

# Create unit tests
# File: src/components/primitives/Button/ButtonBase.spec.ts
# Tests: Click event, disabled state, loading spinner, keyboard focus
npm run test:unit

Step 2: Accessibility Audit

# Install axe-core addon (already in setup)
# Run Storybook: npm run storybook
# Open Accessibility tab in Storybook
# Target: 95+ axe score, 0 violations

Step 3: Design System Documentation

# Create design tokens
# File: src/styles/tokens.scss
# Includes: Colors (Tabler palette), Typography, Spacing (8px grid), Shadows

# Publish Storybook
npm run build-storybook
# Deploy to GitHub Pages or Chromatic

Exit Criteria:

  • All 30 Primitives built (Button, Input, Select, Table, Card, Badge, etc.)
  • 180 Storybook stories published
  • 70%+ unit test coverage (vitest)
  • axe-core 95+ (WCAG 2.1 AA)
  • All PRs include design tokens + Storybook links

Phase 3: Typed Fields & Pinia State (Week 5-6)

Deliverables: 12 Typed Fields, 12 Domain Fields, Pinia stores, API client, 150 integration tests

Step 1: Typed Field Components

# Example: TextField
# File: src/components/fields/typed/TextField/TextField.vue
cat > src/components/fields/typed/TextField/TextField.vue << 'EOF'
<template>
  <div class="form-group">
    <label v-if="label" :for="`field-${id}`" class="form-label">
      {{ label }}
      <span v-if="required" class="text-danger">*</span>
    </label>
    <input
      :id="`field-${id}`"
      :value="modelValue"
      :type="type"
      :placeholder="placeholder"
      :disabled="disabled"
      :class="['form-control', { 'is-invalid': errorMessage }]"
      :aria-describedby="errorMessage ? `error-${id}` : helpText ? `help-${id}` : undefined"
      @input="$emit('update:modelValue', ($event.target as HTMLInputElement).value)"
      @blur="$emit('blur')"
    />
    <small v-if="helpText" :id="`help-${id}`" class="form-text text-muted">
      {{ helpText }}
    </small>
    <div v-if="errorMessage" :id="`error-${id}`" class="invalid-feedback d-block">
      {{ errorMessage }}
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

interface Props {
  modelValue: string;
  label?: string;
  type?: 'text' | 'email' | 'password' | 'url' | 'number';
  placeholder?: string;
  disabled?: boolean;
  required?: boolean;
  helpText?: string;
  errorMessage?: string;
  validation?: (value: string) => string | null;
}

const props = withDefaults(defineProps<Props>(), {
  type: 'text',
});

const id = ref(`field-${Math.random().toString(36).slice(2, 11)}`);

defineEmits<{
  'update:modelValue': [value: string];
  blur: [];
}>();
</script>

<style scoped>
.form-group {
  margin-bottom: 1rem;
}
.form-label {
  font-weight: 500;
  margin-bottom: 0.5rem;
}
</style>
EOF

# Repeat for 11 more: DateField, CurrencyField, QuantityField, etc.

Step 2: Pinia Store Setup

# File: src/stores/modules/orders.ts
cat > src/stores/modules/orders.ts << 'EOF'
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import type { Order, OrderLine } from '@/types/models';
import { orderApi } from '@/services/api/orderApi';

export const useOrderStore = defineStore('orders', () => {
  // State
  const orders = ref<Order[]>([]);
  const selectedOrder = ref<Order | null>(null);
  const loading = ref(false);
  const error = ref<string | null>(null);

  // Computed
  const orderCount = computed(() => orders.value.length);
  const totalAmount = computed(() =>
    orders.value.reduce((sum, o) => sum + o.totalAmount, 0)
  );

  // Actions
  const fetchOrders = async () => {
    loading.value = true;
    error.value = null;
    try {
      orders.value = await orderApi.listOrders({ limit: 100 });
    } catch (err) {
      error.value = (err as Error).message;
    } finally {
      loading.value = false;
    }
  };

  const createOrder = async (payload: Partial<Order>) => {
    loading.value = true;
    try {
      const newOrder = await orderApi.createOrder(payload);
      orders.value.push(newOrder);
      selectedOrder.value = newOrder;
      return newOrder;
    } finally {
      loading.value = false;
    }
  };

  return {
    orders,
    selectedOrder,
    loading,
    error,
    orderCount,
    totalAmount,
    fetchOrders,
    createOrder,
  };
});
EOF

# Repeat for 9 more stores: inventory, products, customers, suppliers, etc.

Step 3: OpenAPI Client Generation

# Install OpenAPI generator
npm install -D @openapi-generator/cli

# Generate TypeScript client from spec/63_oms_wms_erp_api_openapi.yaml
npx @openapi-generator/cli generate \
  -i spec/63_oms_wms_erp_api_openapi.yaml \
  -g typescript-axios \
  -o src/services/api/generated

# Update service files
# File: src/services/api/orderApi.ts
# Re-export and wrap generated client

Exit Criteria:

  • 12 Typed Fields built (TextField, DateField, CurrencyField, etc.)
  • 12 Domain Fields built (OrderLineField, ProductField, etc.)
  • 10 Pinia stores created (orders, inventory, products, etc.)
  • API client auto-generated from OpenAPI spec
  • 150 integration tests passing (vitest + MSW mocks)

Phase 4: CRUD Templates & E2E Tests (Week 7-8)

Deliverables: 11 full CRUD components, 116 E2E tests, responsive design, Lighthouse 90+

Step 1: OrderForm CRUD

# File: src/components/composites/Order/OrderForm.vue
# Handles: Create (empty) / Edit (load from API) / Delete (soft delete)
# Features:
#   - Customer lookup (SearchField)
#   - Line editor (add/edit/remove OrderLineField)
#   - Auto-calculate totals
#   - Validation (min 1 line, customer required)
#   - Approval workflow (if > 1M KRW)

# File: src/views/Order/OrderCreatePage.vue
# Routes to: /admin/orders/new (pre-filled form)

# File: src/views/Order/OrderListPage.vue
# Features: Table, pagination, search, filters (status, date), bulk actions

Step 2: E2E Tests (Playwright)

# Install Playwright
npm install -D @playwright/test

# File: tests/e2e/order-crud.spec.ts
cat > tests/e2e/order-crud.spec.ts << 'EOF'
import { test, expect } from '@playwright/test';

test.describe('Order CRUD', () => {
  test('Create → Read → Edit → Delete', async ({ page }) => {
    // 1. Login
    await page.goto('/');
    await page.fill('[name="email"]', 'user@example.com');
    await page.fill('[name="password"]', 'password123!');
    await page.click('button[type="submit"]');
    await expect(page).toHaveURL('/admin/dashboard');

    // 2. Create order
    await page.click('a[href="/admin/orders"]');
    await page.click('button:text("Create Order")');
    await page.selectOption('[name="customerId"]', 'CUST-001');
    await page.fill('[name="quantity"]', '100');
    await page.click('button:text("Submit")');
    
    // 3. Verify created
    const orderNo = await page.locator('h1').textContent();
    expect(orderNo).toMatch(/ORD-\d+/);

    // 4. Edit
    await page.click('button:text("Edit")');
    await page.fill('[name="quantity"]', '150');
    await page.click('button:text("Save")');

    // 5. Delete
    await page.click('button:text("Delete")');
    await page.click('button:text("Confirm")');
    await expect(page).toHaveURL('/admin/orders');
  });
});
EOF

npm run test:e2e

Step 3: Performance Optimization

# Measure Lighthouse score
npm run build  # Build for production
npx lighthouse http://localhost:5173/admin/orders \
  --view --output-path=lighthouse-report.html

# Target: 90+ score
# Actions:
#   - Code split at route level
#   - Lazy-load Tabler components
#   - Tree-shake unused code
#   - Gzip + Brotli compression

Exit Criteria:

  • 11 full CRUD components built (Order, Inventory, Product, Customer, etc.)
  • 116 E2E tests passing (11 entities × 10-15 scenarios each)
  • Responsive design verified (mobile, tablet, desktop)
  • Lighthouse 90+ (all pages)
  • Bundle <500KB (gzip, main chunk)
  • Ready for Phase 5 (Design System & npm package)

Component Development Guide

Rules (Principle 1-30 Applied)

  1. Single Responsibility: Each component does one thing well

    • Primitives: UI only, no logic
    • Typed Fields: Validation + formatting
    • Domain Fields: Business rules + lookups
    • Composites: Workflows + state
  2. Props & Events (Principle 11: Vibes Coding)

    interface Props {
      modelValue: T;
      label?: string;
      disabled?: boolean;
      errorMessage?: string;
    }
    
    defineEmits<{
      'update:modelValue': [value: T];
      blur: [];
    }>();
    
  3. Type Safety (Principle 19)

    • No any types
    • tsc --noEmit must pass
    • TypeScript strict mode: ON
  4. Accessibility (Principle 20)

    • All inputs: <label>, aria-describedby
    • Buttons: aria-label (if icon-only)
    • Tables: scope, aria-sort
    • Test with axe-core
  5. Testing (Principle 26)

    # Unit: Test props, events, validation
    npm run test:unit
    
    # Integration: Test field chains, API mocks
    npm run test:integration
    
    # E2E: Test workflows end-to-end
    npm run test:e2e
    
  6. Documentation

    • Storybook stories: 5+ per component
    • Docstrings: Brief, explain WHY (not WHAT)
    • PR template: Links to Storybook + test coverage

Folder Template

src/components/primitives/Button/
├── ButtonBase.vue         # Component
├── ButtonBase.stories.ts  # 12+ stories
├── ButtonBase.spec.ts     # Unit tests
├── types.ts               # Props/Emits types
└── README.md              # Optional doc

Phase 1 Go/No-Go Validation Checklist

Before Phase 1 starts (2026-08-02):

  • Vite scaffold created with TypeScript strict mode
  • Storybook 7.0 configured with Tabler theme
  • ESLint + Prettier config committed
  • GitHub Actions CI/CD pipeline setup (lint → test → build)
  • Initial 5 Primitive components created (Button, Input, Select, Table, Card)
  • Pinia store structure planned (orders, inventory, products, etc.)
  • OpenAPI spec reviewed by backend team
  • Database schema approved by DBA
  • All 13 team members have local dev environment working
  • Design system Figma library approved by UX
  • First Storybook deployment successful
  • CI/CD pipeline can build + deploy Storybook
  • Stakeholders agree on Phase 1-4 timeline (8 weeks)

Decision:

  • GO: All checklist items green → Start Phase 1
  • NO-GO: Any blocker → Address and re-check

Quantified Success Metrics

Quality Indicators:

  • Test Coverage: 70%+ (Vitest)
  • TypeScript Strict: 100% (no any, no implicit unknown)
  • Accessibility: WCAG 2.1 AA minimum
  • Bundle Size: <500KB (gzip, main chunk)
  • Lighthouse Score: 90+ (desktop & mobile)
  • Uptime: 99.9% (SLA)
  • Response Time: P95 <250ms
  • Error Rate: <0.5%

Process Indicators:

  • Story Point Completion: 90%+ per sprint
  • Code Review Approval: 100%
  • Automated Tests: 50 E2E scenarios
  • Deployment Time: <30min (zero-downtime)
  • Documentation: 100% coverage

Business Outcomes:

  • Developer Productivity: +30% (vs baseline)
  • Ops Cost: -40% (automation & monitoring)
  • Defects: -80% (test automation)
  • User Satisfaction (NPS): 70+
  • ROI: 1:3 payback (within 4 months)

Risk Matrix (Top 3)

Risk Probability Impact Mitigation
Requirement Creep HIGH (80%) HIGH Fix scope per phase, Phase 12+ backlog
Production Outage LOW (5%) CRITICAL Blue-green, auto-rollback, RTO <5min
Data Loss VERY LOW (1%) CRITICAL Automated backup/restore testing

Team & Budget

Composition:

  • PM (Product Manager): 1 FTE
  • PL (Technical Lead/Architect): 1 FTE
  • Frontend Developers: 4 FTE (1 lead + 3 junior)
  • Backend Developers: 2 FTE (.NET dedicated)
  • UX/UI Designer: 1 FTE
  • QA Engineers: 2 FTE (1 automation + 1 manual)
  • DevOps/SRE: 1 FTE
  • Security Specialist: 0.5 FTE (consultant)
  • Technical Writer: 0.5 FTE

Estimated Costs (8 months):

  • Payroll: $360K (avg $2.7K/person/month × 13 × 8)
  • Infrastructure: $4K (AWS, PostgreSQL, CDN)
  • Tools & Licenses: $4K (Sentry, DataDog, BrowserStack, Chromatic)
  • Total Budget: $371K

Expected ROI:

  • 30% productivity improvement (component reuse, automation)
  • 40% ops cost reduction (monitoring, incident auto-response)
  • 80% defect reduction (test coverage)
  • Payback Period: 4 months

Immediate Actions (Week 1-2, Phase 0)

Tasks:

  1. T0.1: Stakeholder requirements (3 days) → FRD
  2. T0.2: Architecture decision (4 days) → Monolithic SPA confirmed
  3. T0.3: 4-Layer component design (5 days) → Figma library
  4. T0.4: 11 CRUD template inventory (4 days) → Template matrix
  5. T0.5: API OpenAPI 3.0 (5 days) → 30 endpoints spec
  6. T0.6: UI/UX wireframes (5 days) → High-fidelity mockups
  7. T0.7: Risk register (2 days) → 15+ risks with mitigations

Detailed WBS Document

Complete work breakdown with all tasks, effort estimates, deliverables, and acceptance criteria:

📄 spec/60_oms_wms_erp_wbs.yaml (1,600 lines)

Contents:

  • 12 phases with detailed task breakdowns
  • Effort estimates (person-days per task)
  • Deliverables checklist
  • QA checkpoints and acceptance criteria
  • Risk mitigation strategies
  • Weekly retrospectives process
  • Post-project knowledge transfer plan

Phase 0 Exit Checklist (GO/NO-GO Decision)

  • FRD (Functional Requirements Document) signed by all stakeholders
  • OpenAPI 3.0 specification: 30 endpoints documented
  • Figma wireframes: 80%+ completion
  • 4-layer component architecture: Layer 1-4 defined
  • 11 CRUD templates: Business rules documented
  • Risk register: 15+ identified with mitigation plans
  • Architecture decision documented (ADR-001)
  • Decision: GO/NO-GO for Phase 1

Alignment with QuantEngine Phases

This OMS·WMS·ERP WBS represents Phase 12 of QuantEngine commercialization:

  • Phase 1 (Web UI Migration): Complete ✓ 2026-07-11
  • Phase 2 (KIS Data Collection): 95% complete ✓ 2026-07-24
  • Phase 4 (CI/CD Pipeline): 80% complete ✓ 2026-07-24
  • Phase 5 (Admin UI & Deployment): Complete ✓ 2026-07-11
  • 🆕 Phase 12 (OMS·WMS·ERP Commercialization): START 2026-08-01

Constraint: OMS·WMS·ERP development is gated by QuantEngine Phase 2 completion (KIS API integration). Phase 12 can begin only after Phase 2 validation in production.