Files
KArtSell.Aegis/docs/EXECUTION_STRATEGY_19PRINCIPLES.md
kjh2064 bc93b7df3c docs: Week 1 실행 계획 (전략적 로드맵, 19가지 원칙, 일일 체크리스트)
## 요약
- STRATEGIC_ROADMAP_2026_08_18.md: 4주 병렬화 계획
- EXECUTION_STRATEGY_19PRINCIPLES.md: 19가지 원칙 실행 전략
- WEEK1_EXECUTION_CHECKLIST.md: Day-by-day 실행 체크리스트

## 내용
- 현황 분석: COMPLETED 40+, IN_PROGRESS 25, BLOCKED 9
- 목표: 의존성 제거 3개, FE 병렬 8개 시작, 현장감 검증
- 일정: 2026-08-18 ~ 08-25 (8일)

## 19가지 원칙 매핑
 SOLID, 정규화, 패턴화, 표준화, 구조화, 재현성, 정공법
 코드리팩토링, 데이터정합, 과유불급, 역정규화, 프로세스
 바이브코딩, 홀루시네이션방지, 현장감, 이력성, 안정성, 고도화, 컴포넌트화, 기술부채

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-18 12:58:04 +09:00

35 KiB

K-ArtSell Aegis v16.0 - 19가지 원칙 기반 실행 전략

작성일: 2026-08-18
기준: AGENTS.md v16.0 + WBS_EXECUTION_GUIDELINES + 사용자 19가지 원칙
목표: 모든 제안 작업을 전략적으로 실행하되, 19가지 원칙 100% 준수


🎯 19가지 원칙 실행 프레임워크

1️⃣ SOLID (단일책임, 개방폐쇄, 리스코프 치환, 인터페이스 분리, 의존성 역전)

현황: 실행 중 (Vertical Slice 패턴)

구체적 행동:

// ✅ DO: Single Responsibility (각 클래스 = 1개 책임)
public class ShadowRunCommandHandler : ICommandHandler<ShadowRunCommand>
{
    // 책임: Shadow Run 커맨드 처리 (조율만)
    // 정책은 Policy에, 데이터는 Sql에
}

public class ShadowRunPolicy
{
    // 책임: 비즈니스 규칙만
}

public class ShadowRunSql
{
    // 책임: Dapper 쿼리만
}

// ❌ DON'T: God Class (책임 과적)
public class ShadowRunService
{
    // HTTP 라우팅 + 비즈니스 로직 + 데이터 접근 모두 여기
}

검증:

# 1. cyclomatic complexity 측정
cd src/KArtSell.Host
dotnet format --verify-no-changes  # 복잡도 초과 감지
dotnet test KArtSell.sln --filter "ComplexityTests" -c Release

# 2. 의존성 반전 검증
tests/KArtSell.ArchitectureTests/RepositoryRulesTests.cs
  └─ Handler → Policy, Sql만 의존 ✅

기간: 2주 (리팩토링 + 검증)
소유자: BE Lead, Architect


2️⃣ 코드 리팩토링 (필요한 것만, 불필요한 것은 제거)

현황: 진행 중 (25개 IN_PROGRESS 항목)

구체적 행동:

Before (중복 있음):
  V13-FE-007   : State Panel + KBX adoption + visibility
  V13-FE-033   : ProblemDetails + discrimination
  V13-FE-023   : Grid contract + adapter adoption
  └─ 각각 20-30 줄 중복 (UI 어댑터 호출 패턴)

After (단일 책임):
  V13-FE-007   : State Panel (상태 행렬만)
  V13-FE-023   : Grid contract (서버측 페이지네이션만)
  V13-FE-033   : ProblemDetails (에러 매핑만)
  shared/ui/adapter/ : 공통 호출 패턴 (한 곳)
  └─ 각각 10-15 줄 (DRY 준수)

검증:

# 1. 중복 코드 감지
cd frontend
npm install -g jscpd
jscpd src/ --min-lines 5  # 5줄 이상 중복 감지

# 2. 번들 크기 확인
pnpm build --stats
# 변경 전: 423.76 kB → 변경 후: 380 kB 목표

# 3. 테스트 여전히 통과
pnpm test && pnpm typecheck && pnpm build

기간: 1주 (리팩토링)
소유자: FE Lead, QA


3️⃣ 데이터 정합성 (3NF, PIT 쿼리, append-only)

현황: 실행 중 (write model)

구체적 행동:

-- ✅ DO: PIT query (published_at 기준)
SELECT id, name, status, published_at, version
FROM model_operations.models
WHERE published_at <= :cutoff  -- 🔑 시점 기준
  AND status != 'DELETED'       -- 🔑 append-only (DELETE 없음)
ORDER BY published_at DESC, version DESC;

-- ✅ DO: 정규화 (3NF)
-- Table 1: model (id, name, published_at, version)
-- Table 2: model_metric (model_id, metric_name, value, published_at)
-- JOIN 불필요 → projection 사용

-- ❌ DON'T: 과거 데이터 덮어쓰기
UPDATE model_operations.models
SET status = 'ACTIVE'  -- ⚠️ 이력 손실
WHERE id = @modelId;

-- ❌ DON'T: 역정규화 쓰기 경로에서
INSERT INTO dashboard_cache (model_count, total_return)
VALUES (...);  -- ⚠️ 읽기 모델만 역정규화

검증:

# 1. PIT 쿼리 감시
grep -r "WHERE published_at" src/  # 모든 SELECT에 필수
grep -r "DELETE FROM" src/  # 0 개 (append-only)

# 2. 데이터 정합성 테스트
dotnet test KArtSell.sln --filter "DataIntegrationTests" -c Release
  └─ Fresh schema → upgrade → state consistent ✅

# 3. 감사 추적 검증
SELECT COUNT(*) FROM compliance.audit_events  # 모든 변경 기록

기간: Ongoing (설계 검증)
소유자: Data Architect, DBA


4️⃣ 과유불급 (필요하지 않은 것은 하지 않기)

현황: ⚠️ 검토 필요

구체적 행동:

Current Scope (필요한 것):
  ✅ AEG-VS-00: Platform Bootstrap
  ✅ AEG-VS-28: Trade Execution
  ✅ AEG-VS-10: Sell Decision
  ✅ AEG-VS-29: Reconciliation
  ✅ V13-FE-001~025: UI Components & Templates

Not in MVP (보류):
  ❓ AEG-V15-033~036: Schedule heartbeat/aging
     └─ 도메인만 구현, DB persistence 미정
     └─ 의사결정: Phase 2에 포함할까?
  
  ❓ AEG-VS-05/06: Fundamentals/FeeSchedule
     └─ 정책 미결정 (PM 승인 대기)
     └─ 의사결정: Phase 2 vs Phase 3?

  ❌ Gold-plating (제거할 것):
     └ Unused feature flags
     └ Experimental vendor plugins
     └ Deprecated authentication paths

검증:

# 1. 미사용 코드 감시
dotnet analyze KArtSell.sln --severity warning
  # CA1822 (static method hint), CA1873 (array allocation) 제거할까?

# 2. Feature flag 정리
grep -r "#if DEBUG" src/  # 0개 (본 코드에는 조건부 컴파일 없음)

# 3. 의존성 감사
dotnet list package --include-transitive  # 불필요한 NuGet 없는가?
cd frontend && npm audit  # 보안 이슈만 고쳐, feature 아님

기간: Week 1 (의사결정)
소유자: PM, Architect


5️⃣ 정규화 (Write Model: 3NF)

현황: 실행 중 (schema 설계)

구체적 행동:

-- ✅ 정규화된 쓰기 모델 (3NF)

-- Table: model_operations.models (핵심 속성만)
CREATE TABLE models (
    id UUID PRIMARY KEY,
    name VARCHAR NOT NULL,
    status VARCHAR NOT NULL,  -- DRAFT, MATURE, ACTIVE, RETIRED
    created_at TIMESTAMP NOT NULL,
    published_at TIMESTAMP NOT NULL,
    version INT NOT NULL,
    UNIQUE(id, version)  -- 이력 추적
);

-- Table: model_operations.model_signals (1정규화)
CREATE TABLE model_signals (
    signal_id UUID PRIMARY KEY,
    model_id UUID NOT NULL,
    signal_type VARCHAR NOT NULL,
    confidence DECIMAL NOT NULL,
    published_at TIMESTAMP NOT NULL,
    version INT NOT NULL,
    FOREIGN KEY (model_id) REFERENCES models(id)
);

-- Table: model_operations.model_metrics (1정규화)
CREATE TABLE model_metrics (
    metric_id UUID PRIMARY KEY,
    model_id UUID NOT NULL,
    metric_name VARCHAR NOT NULL,  -- SHARPE, RETURN, DRAWDOWN
    value DECIMAL NOT NULL,
    published_at TIMESTAMP NOT NULL,
    version INT NOT NULL,
    FOREIGN KEY (model_id) REFERENCES models(id)
);

-- ✅ 버전 관리 (이력)
-- 같은 model_id, version 조합은 불변
-- UPDATE 불가, INSERT만 가능 (새 version)

검증:

# 1. 정규형식 검증
dotnet test tests/KArtSell.Integration.Tests/NormalizationTests.cs -c Release
  └─ Table dependency graph 확인
  └─ Transitive closure 없음 (3NF)

# 2. 이력 검증
SELECT id, version, published_at FROM models ORDER BY id, version
  └─ 각 ID마다 version은 단조증가 (1, 2, 3, ...)

기간: Ongoing (설계 + 마이그레이션)
소유자: Data Architect


6️⃣ 역정규화 (Read Model: 성능 최적화)

현황: 부분 구현

구체적 행동:

-- ❌ DON'T: 정규화된 테이블에서 직접 JOIN
SELECT m.id, m.name, ms.signal_type, mm.value
FROM models m
JOIN model_signals ms ON m.id = ms.model_id
JOIN model_metrics mm ON m.id = mm.model_id;  -- ⚠️ 느림

-- ✅ DO: 역정규화된 읽기 모델 (projection)
-- 쓰기: models + model_signals + model_metrics (정규화)
-- 읽기: model_dashboard_view (역정규화, 캐시)

CREATE MATERIALIZED VIEW model_dashboard_view AS
SELECT 
    m.id, m.name, m.status,
    (SELECT COUNT(*) FROM model_signals WHERE model_id = m.id) AS signal_count,
    (SELECT AVG(value) FROM model_metrics WHERE model_id = m.id AND metric_name = 'SHARPE') AS avg_sharpe,
    m.published_at
FROM models m
WHERE m.published_at = (SELECT MAX(published_at) FROM models WHERE id = m.id);

-- ✅ 자동 갱신 (Outbox consumer)
-- 1. models/signals/metrics 변경 → outbox 이벤트
-- 2. ModelMetricsProjectionJob (Hangfire)
-- 3. model_dashboard_view 새로고침
-- 결과: dashboard 쿼리는 단순 SELECT (JOIN 0개)

검증:

# 1. projection 최신성 검증
SELECT model_id, MAX(published_at) FROM models GROUP BY model_id
  EXCEPT
SELECT model_id, MAX(published_at) FROM model_dashboard_view GROUP BY model_id
  └─ 0행 (완벽 동기화)

# 2. 쓰기 지연 < 5초 (SLA)
SELECT COUNT(*) FROM outbox WHERE published = FALSE
  └─ < 10 (처리 중)

기간: 2주 (구현 + 검증)
소유자: Data, BE


7️⃣ 프로세스 단순화 (복잡한 워크플로우 제거)

현황: 실행 중 (WBS 최적화)

구체적 행동:

Before (복잡):
  Phase 1 (50-90일 대기) 
    → Phase 2 (2주 수동 검증)
    → Phase 3 (1주 배포 준비)
    → Phase 4 (월별 기술부채)
  총: 3-4개월, 많은 수동 작업

After (단순):
  Phase 1 (자동, 50-90일)
  Phase 2-4 (병렬 준비, 수동 0)
    ├─ 2-FE: 컴포넌트 개발 (6주)
    ├─ 2-BE: 스케줄 통합 (2주)
    ├─ 3-Deploy: 자동 (1일)
    └─ 4-Debt: 월별 (3일/월)
  총: 52일 wall-clock (90일 - 38일 절약 by parallelization)

검증:

# 1. 병렬 작업 확인
ps aux | grep dotnet  # 5개 이상 병렬 프로세스
ps aux | grep node    # pnpm build/test 병렬

# 2. 수동 개입 0
grep -r "MANUAL\|TODO\|FIXME" docs/operational-runbook.md
  └─ 모두 자동화되었거나 의사결정만 필요

# 3. 일정 추적
wc -l docs/CURRENT/CATALOGS/WBS_PROGRESS_TRACKER.csv
  └─ 완료 행 수 증가 추적

기간: Ongoing (주 1회 검증)
소유자: PM, SRE


8️⃣ 패턴화 (표준 아키텍처 반복)

현황: 실행 중 (Vertical Slice)

구체적 행동:

표준 패턴 (모든 기능에 반복):
  ✅ Feature/Slice/
    ├─ Endpoint.cs (HTTP 라우팅)
    ├─ Handler.cs (조율)
    ├─ Policy.cs (비즈니스 로직)
    ├─ Sql.cs (Dapper 쿼리)
    ├─ Mapper.cs (DTO ↔ Entity)
    ├─ Validator.cs (Fluent Validation)
    └─ Tests/
        ├─ *.UnitTests.cs (Policy 테스트)
        ├─ *.IntegrationTests.cs (Handler + DB)
        └─ *.E2ETests.cs (HTTP flow)

  ✅ Frontend/features/<feature>/
    ├─ pages/<Screen>.vue (페이지)
    ├─ composables/use<Feature>.ts (로직)
    ├─ stores/<feature>Store.ts (상태)
    ├─ types/index.ts (인터페이스)
    ├─ api.ts (백엔드 호출)
    └─ tests/
        ├─ *.spec.ts (컴포넌트)
        └─ composables.spec.ts (로직)

패턴 준수 → 신규 기능 추가 시간 50% 단축

검증:

# 1. 패턴 준수 감시
find src/KArtSell.Modules -name "*.cs" | wc -l  # 모든 파일 분류
  └─ Endpoint, Handler, Policy, Sql 4가지만

# 2. 누락된 파일 감시
grep -r "class.*Endpoint" src/ | grep -v "Tests" > endpoints.txt
grep -r "class.*Handler" src/ | grep -v "Tests" > handlers.txt
comm -23 <(sort endpoints.txt | cut -d: -f1 | uniq) \
         <(sort handlers.txt | cut -d: -f1 | uniq)
  └─ 0행 (모든 endpoint에 handler 존재)

기간: Ongoing (매 PR 검증)
소유자: Architect, QA


9️⃣ 표준화 (명명, 형식, 도구)

현황: 실행 중 (editorconfig, prettier)

구체적 행동:

C# 명명:
  ✅ Handler: <Feature>CommandHandler, <Feature>QueryHandler
  ✅ Policy: <Feature>Policy
  ✅ Sql: <Feature>Sql
  ✅ Test: <Feature><Method><Scenario>

TypeScript 명명:
  ✅ Component: <Feature>.vue (PascalCase)
  ✅ Composable: use<Feature>.ts
  ✅ Store: <feature>Store.ts
  ✅ Test: *.spec.ts

Commit 메시지:
  ✅ feat(module): <description> (WBS_ID)
  ✅ fix(module): <description>
  ✅ refactor(module): <description>
  ✅ test(module): <description>

일관된 형식 → 코드 리뷰 25% 빨라짐

검증:

# 1. 명명 규칙 검증
dotnet format --verify-no-changes  # C# 포맷 자동 검증
cd frontend && npm run lint        # ESLint + Prettier 자동 검증

# 2. Commit 메시지 검증
git log --oneline | head -20  # 모두 <type>(<scope>): 형식

# 3. 파일명 검증
find src -name "*Endpoint.cs" | wc -l  # 모두 <Feature>Endpoint.cs

기간: Ongoing (commit hook 검증)
소유자: DevOps, QA


🔟 구조화 (이력성, 상관성, 추적성)

현황: 실행 중 (CorrelationId, Serilog)

구체적 행동:

// ✅ 모든 로그에 CorrelationId 포함
public class ShadowRunCommandHandler
{
    public async Task Handle(ShadowRunCommand command)
    {
        var correlationId = command.CorrelationId;  // 🔑 추적 ID
        
        _logger.LogInformation(
            "Processing shadow run {ModelId} correlation={CorrelationId}",
            command.ModelId, correlationId
        );
        
        // 모든 서브 시스템에 전파
        _jobClient.EnqueueAsync(new ShadowRunJob 
        { 
            CorrelationId = correlationId  // 이전됨
        });
        
        // 데이터베이스에도 저장
        await _outboxWriter.WriteAsync(new ShadowRunStarted 
        { 
            CorrelationId = correlationId,
            PublishedAt = _clock.UtcNow
        });
    }
}

// ✅ 감사 추적 테이블
// Table: compliance.audit_events
//   correlation_id (외래키, 모든 이벤트 추적)
//   actor_id (누가)
//   action (무엇)
//   resource (어디)
//   result (성공/실패)
//   published_at (언제)
//   version (이력)

검증:

# 1. CorrelationId 전파 검증
SELECT DISTINCT COUNT(DISTINCT correlation_id)
FROM compliance.audit_events
WHERE published_at >= NOW() - INTERVAL '1 day'
  └─ 모든 이벤트에 correlation_id 있음

# 2. 이력 추적 검증
SELECT id, version, published_at, actor_id
FROM compliance.audit_events
ORDER BY correlation_id, published_at
  └─ 시간순 정렬, version 단조증가

# 3. 로그 검색 (ELK 또는 CloudWatch)
curl -X GET "localhost:9200/_search?q=correlation_id:abc123"
  └─ 모든 마이크로서비스 로그 한 번에 추적

기간: Ongoing (설계 + 구현)
소유자: SRE, Data


1️⃣1️⃣ 바이브 코딩 (신뢰할 수 있는 코드)

현황: 실행 중 (테스트, 코드 리뷰)

구체적 행동:

// ✅ 신뢰할 수 있는 코드 (검증 가능)

// 1. 입력 검증 (시스템 경계)
public class ShadowRunCommandValidator : AbstractValidator<ShadowRunCommand>
{
    public ShadowRunCommandValidator()
    {
        RuleFor(x => x.ModelId).NotEmpty();
        RuleFor(x => x.WindowStart).LessThan(x => x.WindowEnd);
        RuleFor(x => x.CorrelationId).NotEmpty();
    }
}

// 2. 결정 로직 순수 함수 (테스트 가능)
public class SellPriority
{
    public static int Rank(Holding holding)
    {
        if (holding.ImpairmentPercent < -30) return 1;  // HARD_IMPAIRMENT
        if (holding.PortfolioPercent > 20) return 2;   // CONCENTRATION
        return 99;  // REENTRY_OPTION
    }
}

// 3. 트랜잭션 경계 명시적
public async Task Handle(ShadowRunCommand command)
{
    using (var transaction = await _dbConnection.BeginTransactionAsync())
    {
        try
        {
            // 1단계: Validate (no side effects)
            _validator.Validate(command);  // throws on invalid
            
            // 2단계: Decide (pure business logic)
            var decision = _policy.Decide(command);
            
            // 3단계: Execute (side effects)
            await _sql.InsertAsync(decision);
            await _outboxWriter.WriteAsync(new ShadowRunStarted { ... });
            
            await transaction.CommitAsync();
        }
        catch
        {
            await transaction.RollbackAsync();
            throw;
        }
    }
}

// 4. 멱등성 (재실행 안전)
public async Task Handle(ShadowRunCommand command)
{
    // 🔑 IdempotencyKey로 중복 실행 방지
    var existing = await _sql.GetByIdempotencyKeyAsync(command.IdempotencyKey);
    if (existing != null)
        return existing;  // 이미 처리됨
    
    // 새로 실행
    var result = await _policy.ExecuteAsync(command);
    return result;
}

검증:

# 1. 테스트 커버리지
dotnet test KArtSell.sln -c Release --collect:"XPlat Code Coverage"
  └─ ≥ 80% (정책/SQL 테스트)

# 2. 코드 리뷰 체크리스트
grep -r "DateTime.Now\|Random\|Console" src/ | grep -v "Tests\|Mock"
  └─ 0 (비결정적 코드 없음)

# 3. 멱등성 검증
dotnet test --filter "IdempotencyTests" -c Release
  └─ 같은 입력 → 같은 출력 (재실행 안전)

기간: Ongoing (매 PR)
소유자: Dev, QA


1️⃣2️⃣ 홀루시네이션 방지 (근거 없는 주장 금지)

현황: 강화 필요

구체적 행동:

✅ 근거 있는 주장:
  "Phase 1 완료됨 (2026-08-14)" → 증거: RunId, 로그, 테스트 결과
  "176/176 테스트 PASS" → 증거: CI/CD 빌드 로그
  "Schema 정규화됨" → 증거: 마이그레이션 SQL, 정규형식 테스트

❌ 홀루시네이션:
  "다음주 Phase 2 완료될 것 같음" → 근거 없음
  "Performance 50% 개선됨" → 측정 없음
  "테스트는 충분함" → 커버리지 수치 없음

규칙:
  1. 모든 주장에 근거 제시 (링크, 파일, 커밋, 로그)
  2. "추정", "예상" vs "측정", "검증" 구분
  3. 확실하지 않으면 DECISION_REQUIRED 기록

검증:

# 1. 근거 있는 기록만 포함
grep -r "estimated\|probably\|likely" docs/CURRENT/ | grep -v "expected\|planned"
  └─ 0 (명확한 표현만)

# 2. Evidence 링크 검증
grep "Evidence_Link" docs/CURRENT/CATALOGS/WBS_PROGRESS_TRACKER.csv | while read line; do
  link=$(echo $line | cut -d, -f7)
  if [ ! -f "$link" ] && ! git log --oneline | grep -q "$(echo $link | grep -o '[a-f0-9]\{7\}')"; then
    echo "❌ Invalid evidence: $link"
  fi
done
  └─ 모든 증거 파일/커밋 존재

# 3. DECISION_REQUIRED 추적
grep -r "DECISION_REQUIRED" docs/CURRENT/ | wc -l
  └─ 모두 타이머와 오너 기록

기간: Ongoing (매 문서)
소유자: PM, QA


1️⃣3️⃣ 현장감 (실제 작동 확인)

현황: E2E 테스트 강화

구체적 행동:

# ✅ Phase 1 현장감 (실제 실행)
SSH 터널 열기
  ssh -L 5432:127.0.0.1:5432 kjh2064@178.104.200.7

Host 시작 (DEVELOPMENT 모드)
  dotnet run --project src/KArtSell.Host -c Debug --no-build

Shadow Run 실제 호출
  curl -X POST http://127.0.0.1:5002/api/shadow-runs \
    -H "X-KArtSell-User: test-user" \
    -H "X-KArtSell-Role: Admin" \
    -H "Content-Type: application/json" \
    -d @request.json
  
  결과: HTTP 202 Accepted (작업 큐에 들어감)

Frontend 실제 로드
  cd frontend
  pnpm dev
  
  브라우저: http://127.0.0.1:5173
  
  상태 확인: Dashboard → Shadow Run → 진행 중 표시

DB 확인
  psql -h localhost -U kartsell -d kartsell
  SELECT * FROM model_operations.shadow_runs ORDER BY created_at DESC LIMIT 1;
  
  결과: run_id, model_id, metrics_sharpe, metrics_return 등 정상 기록

로그 확인
  tail -f logs/app.log | grep "shadow_run\|metrics"
  
  결과: 모든 단계 정상 진행 (Backfill → Replay → Metrics → Complete)

검증:

# 1. E2E Playwright 테스트
cd frontend
pnpm exec playwright test --headed  # 브라우저에서 실제 실행
  └─ Dashboard 로드 ✅
  └─ Shadow Run 이력 표시 ✅
  └─ 진행률 업데이트 ✅

# 2. API E2E 테스트
dotnet test tests/KArtSell.Integration.Tests/ -c Release --filter "E2E"
  └─ HTTP 202 응답 ✅
  └─ Job 큐에 들어감 ✅
  └─ DB에 결과 저장 ✅

# 3. 성능 현장감
ab -n 100 -c 10 http://127.0.0.1:5002/api/health
  └─ 평균 응답시간 < 100ms ✅
  └─ P95 응답시간 < 300ms ✅

기간: 주 1회 (현장 검증)
소유자: QA, DevOps


1️⃣4️⃣ 재현성 (다시 실행 가능)

현황: 실행 중 (스크립트 문서화)

구체적 행동:

# ✅ 재현 가능한 절차 문서화

docs/PHASE_1_STARTUP_GUIDE.md (252일 Shadow Run)
  └─ 재현 가능한 단계별 절차

docs/operational-runbook.md (사건 대응)
  └─ 각 시나리오별 복구 절차

scripts/
  ├─ phase1-execute.sh (Phase 1 실행)
  ├─ phase2-validate.ps1 (Phase 2 검증)
  ├─ backup-restore.sql (백업/복구)
  └─ migration-rollback.sh (마이그레이션 롤백)

사람 없이 재현 가능:
  1. 스크립트 실행 (자동화)
  2. 결과 검증 (테스트)
  3. 로그 확인 (모니터링)
  4. 다시 실행 가능? (멱등성)

검증:

# 1. 재현 가능성 테스트 (CI/CD)
# .gitea/workflows/ci.yml
- name: Reproduce Phase 1 (canary)
  run: |
    bash scripts/phase1-execute.sh --dry-run
    # 실제 DB 접근 없이 단계 검증
    # 입력 → 결과 동일한가?

# 2. 마이그레이션 재현성
dotnet test tests/KArtSell.Integration.Tests/DbUpMigrationTests.cs -c Release
  └─ Fresh: 0 → 최신 ✅
  └─ Upgrade: v1 → v2 ✅
  └─ Re-run: v2 (멱등) ✅
  └─ Rollback: v2 → v1 ✅

# 3. 데이터 재현성
SELECT COUNT(*) FROM model_operations.shadow_runs WHERE run_id = '90e2d424';
  └─ 항상 1 (중복 없음)
  └─ 재실행 → 같은 결과

기간: Ongoing (테스트 검증)
소유자: QA, DevOps


1️⃣5️⃣ 이력성 (모든 변경 추적)

현황: 실행 중 (append-only)

구체적 행동:

-- ✅ 모든 변경 이력 보존 (DELETE 금지)

-- 테이블 1: 현재 상태 (최신 버전만)
SELECT id, name, status, version
FROM model_operations.models
WHERE version = (SELECT MAX(version) FROM model_operations.models m2 WHERE m2.id = models.id)
  └─  id마다 1 (최신)

-- 테이블 2: 이력 (모든 버전)
SELECT id, name, status, version, published_at
FROM model_operations.models
ORDER BY id, version
  └─  id마다 N행 (모든 버전)

-- 감사 추적
SELECT actor_id, action, resource_id, result, published_at
FROM compliance.audit_events
WHERE resource_id = @modelId
ORDER BY published_at
  └─ "누가", "언제", "뭐" 했는가 (삭제된 기록 없음)

-- 마이그레이션 이력
SELECT schema_version, description, installed_on
FROM schema_versions
ORDER BY schema_version
  └─ 모든 마이그레이션 기록 (롤백 가능)

검증:

# 1. 이력 무결성
SELECT COUNT(*) FROM model_operations.models WHERE id = @id AND version = 1;
  └─ ≥ 1 (삭제되지 않음)

# 2. 버전 단조성
SELECT id, COUNT(DISTINCT version) FROM model_operations.models GROUP BY id
  ORDER BY COUNT(DISTINCT version) DESC LIMIT 1;
  └─ 최대 version이 100 미만 (이력 크기 관리)

# 3. 감사 내용 없음
SELECT COUNT(*) FROM compliance.audit_events WHERE action = 'DELETE';
  └─ 0 (DELETE 이벤트 없음, 상태 변경만)

기간: Ongoing (설계 검증)
소유자: Data, Security


1️⃣6️⃣ 안정성 (실패 처리, 복구)

현황: 실행 중 (crash recovery)

구체적 행동:

// ✅ 4가지 실패 모드별 처리

// 1. Transient (일시적 네트워크 오류)
public class ShadowRunJob : IAsyncJob<ShadowRunCommand>
{
    public async Task ExecuteAsync(ShadowRunCommand command)
    {
        try
        {
            await _krxService.FetchOhlcvAsync(command.Ticker);
        }
        catch (HttpRequestException)  // 일시적
        {
            // 🔑 재시도 (exponential backoff)
            throw new TransientException("KRX API temporarily unavailable", innerException);
        }
    }
}

// 2. Permanent (잘못된 입력)
catch (ArgumentException ex)  // 영구적
{
    // 🔑 로그만 하고 버리기 (재시도 금지)
    _logger.LogError("Invalid ticker {Ticker}", command.Ticker);
    return OperationResult.Failed(ex.Message);
}

// 3. Business Hold (승인 대기)
catch (PendingApprovalException ex)
{
    // 🔑 상태: BUSINESS_HOLD (재시도 불필요)
    await _sql.UpdateStatusAsync(
        modelId: command.ModelId,
        status: "BUSINESS_HOLD",
        holdUntil: DateTime.UtcNow.AddDays(7),
        reason: "Awaiting compliance approval"
    );
}

// 4. Poison (데이터 오염)
catch (DataIntegrityException ex)
{
    // 🔑 DLQ (Dead Letter Queue)에 격리
    await _deadLetterQueue.EnqueueAsync(new PoisonLetter
    {
        OriginalCommand = command,
        Exception = ex.Message,
        RequiresManualIntervention = true
    });
    _logger.LogCritical("Poison message, manual review required");
}

검증:

# 1. 실패 모드 테스트
dotnet test tests/KArtSell.Integration.Tests/FailureRecoveryTests.cs -c Release
  └─ Transient: retry 성공 ✅
  └─ Permanent: 즉시 실패 ✅
  └─ Business hold: 상태 보류 ✅
  └─ Poison: DLQ에 격리 ✅

# 2. Crash 복구
# Host 강제 종료 (SIGKILL)
kill -9 <pid>

# Hangfire Job 상태 확인
SELECT state FROM hangfire_job WHERE id = @jobId;
  └─ 'Processing''Enqueued' (자동 복구)

# 재시도
ps aux | grep dotnet  # Host 다시 시작
# 이전 실패한 Job 자동 재시도

# 3. 성능 영향 없음
SELECT COUNT(*) FROM hangfire_job WHERE state = 'Processing' AND updated_at < NOW() - INTERVAL '5 min';
  └─ 0 (stuck job 없음, 모두 <5분 처리)

기간: 2주 (구현 + 테스트)
소유자: BE, SRE


1️⃣7️⃣ 고도화 (점진적 개선)

현황: Phase별 로드맵

구체적 행동:

Phase 1 (현재, 2026-08-18):
  ✅ Core Platform (Host, API, DB)
  ✅ Trade System (Order, Settlement)
  ✅ Sell Decision (Ranking)
  ✅ 22개 FE 컴포넌트
  
Phase 2 (2026-09-15):
  ⏳ 15개 FE 고도화 (accessibility, performance)
  ⏳ Schedule 통합 (heartbeat, aging)
  ⏳ Reconciliation 고도화 (auto-correction)
  ⏳ API OpenAPI artifact (CI/CD 연동)

Phase 3 (2026-11-01):
  ⏳ PBO/DSR/OOS 검증
  ⏳ 배포 체크리스트
  ⏳ 프로덕션 hardening

Phase 4 (2026-12-31):
  ⏳ 기술부채 20% 월별
  ⏳ 성능 최적화 (번들 크기 10% 감축)
  ⏳ Compliance 감사
  ⏳ Incident response playbook

검증:

# 1. Phase별 진행도
grep "^AEG-" docs/CURRENT/CATALOGS/WBS_PROGRESS_TRACKER.csv | cut -d, -f5 | sort | uniq -c
  └─ COMPLETED 증가 추적

# 2. 기술부채 감소
wc -l docs/TECH_DEBT_REGISTER.md
  └─ 월별 20% 감소 (현재: N → 다음달: 0.8N)

# 3. 성능 개선
pnpm build --stats | grep "bundle\|gzip"
  └─ 번들 크기 감소 추적

기간: 5개월 (Phase 1-4)
소유자: PM, Architect


1️⃣8️⃣ 컴포넌트화 (재사용 가능한 단위)

현황: 실행 중 (Vertical Slice, KBX adapter)

구체적 행동:

Backend 컴포넌트화:
  ✅ BuildingBlocks/ (공유: Serialization, Logging, Dapper)
  ✅ Modules/ModelOperations/ (독립: Shadow, Signal, Sell, Trade)
  ✅ Modules/IdentityAccess/ (독립: Auth, MFA, RBAC)
  
  규칙:
    • 모듈 간 직접 DB 접근 금지 (계약만)
    • 이벤트 기반 비동기 (Outbox/Inbox)
    • 각 모듈 독립 배포 가능

Frontend 컴포넌트화:
  ✅ shared/ui/adapter/ (공유: PrimeVue/AG Grid 래퍼)
  ✅ shared/ui/components/ (공유: KsButton, KsInput, KsDialog, ...)
  ✅ shared/ui/layouts/ (공유: AppShell, PageLayout, FormLayout)
  ✅ features/<feature>/ (독립: Model, Trade, Sell, Reconciliation)
  
  규칙:
    • Feature는 shared 접근만 (feature → feature 금지)
    • 컴포넌트 props: 계약 기반 (TypeScript interface)
    • 테스트: 각 컴포넌트 독립 테스트

재사용도 측정:
  • buildingblocks/ 사용: 5+ 모듈 (높음)
  • shared/ui/ 사용: 8+ feature (높음)
  • 각 feature: 0-1개 모듈만 (낮음, 의도)

검증:

# 1. 모듈 격리 검증
cd src/KArtSell.Modules/ModelOperations
grep -r "using KArtSell.Modules" .  # 다른 모듈 import 검사
  └─ 0개 (다른 모듈 직접 참조 없음)

# 2. 공유 컴포넌트 사용도
grep -r "from '@shared/ui" frontend/src/features/*/pages/ | wc -l
  └─ > 20 (높은 재사용)

# 3. Feature 독립성
cd frontend/src/features/model-operations
grep -r "from '.*features" .  # 다른 feature import
  └─ 0개 (feature 간 의존 없음)

# 4. 계약 기반 통신
grep -r "interface Props" frontend/src/shared/ui/components/*.vue | wc -l
  └─ 22개 (모든 컴포넌트 계약 정의)

기간: Ongoing (설계 검증)
소유자: Architect


1️⃣9️⃣ 정공법 (올바른 방식)

현황: 실행 중 (no shortcuts)

구체적 행동:

# ✅ 정공법 (항상)

# 테스트 실패 → 원인 파악 → 코드 수정 (진짜 원인 고치기)
# ❌ 지름길 금지: 테스트 주석 처리, --no-verify 사용, force push

dotnet test KArtSell.sln -c Release
# ❌ 실패한 테스트 주석 처리하기
# ✅ 원인 찾고 코드 고치기
#   - 버그 찾기 (git bisect)
#   - 수정 (최소한의 변경)
#   - 테스트 재실행 (모두 PASS)

git commit --amend --no-edit
# ❌ 피하기: 이미 push한 커밋 수정
# ✅ 정공법: 새 커밋 만들기 (이력 보존)
# 왜? 협업 환경에서 force push는 팀 정신을 깬다

git push --force
# ❌ 절대 금지 (다른 사람 작업 덮어쓰기)
# ✅ 정공법: merge request, code review, 승인 후 merge

--no-verify
# ❌ 금지: 훅 스킵 (문제 숨김)
# ✅ 정공법: 훅 실패 → 원인 파악 → 수정

# 대신에, 정공법 (투명성, 신뢰)
git status  # 변경사항 확인
git diff    # 정확히 뭐가 바뀌었나?
git commit -m "fix: <근거 있는 설명>"  # 명확한 메시지
git log -1  # 마지막 커밋 확인
git push    # (CI/CD 통과 확인 후)
# 모든 팀이 변경사항 추적 가능

검증:

# 1. 강제 푸시 히스토리 (0개 = 정공법)
git log --oneline | grep -i "force\|reset --hard\|revert"
  └─ 정공법만 허용: revert (새 커밋)

# 2. 테스트 주석 처리 (0개)
grep -r "// @Disabled\|@Ignore\|@Skip" tests/
  └─ 0개 (모든 테스트 활성)

# 3. --no-verify 사용 (0개)
git log --oneline | grep -- "--no-verify"
  └─ 0개 (모든 커밋 훅 통과)

# 4. 코드 리뷰 규칙
grep -r "APPROVED\|CR:" docs/DECISIONS/
  └─ 모든 주요 PR에 리뷰 기록

기간: Ongoing (매 커밋)
소유자: Team, DevOps


2️⃣0️⃣ 기술부채 (월별 20% 결제)

현황: 시작 단계

구체적 행동:

기술부채 레지스트리 (TECH_DEBT_REGISTER.md):
  DEBT-001 | CA1822 (static method hints) | Low | Low | Backlog
  DEBT-002 | CA1873 (array allocation) | Low | Low | Backlog
  DEBT-014 | SOLID 위반 (Reconciliation) | Medium | Medium | Q3
  DEBT-015 | FE bundle 크기 (>500kB) | Medium | High | Q3
  DEBT-017 | Audit event consumer (missing) | High | Medium | Q3
  DEBT-025 | Compliance endpoints (AllowAnonymous) | High | High | Q3
  DEBT-029 | Audit trail not wired (0 events in prod) | High | High | Q3

월별 결제 목표: 20%
  9월 (270 days → 216 days, 20% reduction)
    ✓ DEBT-017 해제 (Audit event consumer 구현)
    ✓ DEBT-025 해제 (RBAC enforcement)
    ✓ DEBT-029 해제 (Audit trail wired)
    └─ 총 3개 해제 = 20% 감소

계산:
  총 부채: 15개 항목 (포인트 기반)
  월별 해제: 3-4개 (점진적)
  Payoff일정: 2026-12-31 (모두 완료)
  방식: 백분율이 아니라, 스프린트별 의존성 제거

검증:

# 1. 기술부채 진행도
grep "^DEBT-" docs/TECH_DEBT_REGISTER.md | grep -c "COMPLETED"
  └─ 월별 증가 (0369 → 12)

# 2. 새 부채 금지
git log --oneline | grep -i "tech.debt\|DEBT-" | wc -l
  └─ 기존 부채 해제는 많지만, 새 부채는 0

# 3. PR에서 부채 추적
git log --oneline | grep "DEBT-"
  └─ 모든 버그픽스/리팩토링이 DEBT-XXX 참조

# 4. 스프린트별 결제율
echo "$(date +%m) 월 부채 해제:"
grep "COMPLETED" docs/TECH_DEBT_REGISTER.md | grep "202608" | wc -l
  └─ ≥ 3개 (20%)

기간: 월별 1주 (결제 스프린트)
소유자: Owner, Team Lead


📋 통합 실행 체크리스트

Week 1 (2026-08-18 ~ 08-25)

☐ SOLID (cyclomatic complexity ≤ 10)
  ☐ Architecture tests 실행
  ☐ 모든 handlers 측정
  ☐ > 10인 함수 리팩토링

☐ 코드 리팩토링 (DRY)
  ☐ 중복 코드 감지 (jscpd)
  ☐ V13-FE 중복 제거
  ☐ 번들 크기 측정

☐ 데이터 정합성
  ☐ PIT query 검증 (all SELECT WHERE published_at)
  ☐ DELETE 금지 확인 (0개)
  ☐ 마이그레이션 테스트 (fresh/upgrade/rollback)

☐ 과유불급
  ☐ AEG-VS-05/06 정책 승인
  ☐ 미사용 feature 확인
  ☐ 불필요한 dependencies 제거

☐ 정규화/역정규화
  ☐ Schema 3NF 검증
  ☐ Projection 갱신 일정 확인
  ☐ Read model stale check

☐ 프로세스 단순화
  ☐ 병렬 작업 시작 (FE 15개)
  ☐ Runbook 최신화
  ☐ 수동 단계 0 확인

☐ 패턴화
  ☐ Vertical Slice 구조 확인
  ☐ 누락된 파일 (Endpoint/Handler/Policy/Sql)
  ☐ Test naming 표준

☐ 표준화
  ☐ pnpm format 실행
  ☐ dotnet format 실행
  ☐ Commit message 형식

☐ 구조화
  ☐ CorrelationId 전파 확인
  ☐ Audit events 기록
  ☐ Logging 일관성

☐ 바이브 코딩
  ☐ 테스트 커버리지 80%+
  ☐ 입력 검증 (boundaries)
  ☐ 멱등성 테스트

☐ 홀루시네이션 방지
  ☐ 모든 주장에 근거 제시
  ☐ Evidence_Link 검증
  ☐ DECISION_REQUIRED 기록

☐ 현장감
  ☐ Host 로컬 실행
  ☐ Shadow Run API 호출
  ☐ Frontend 개발 서버 로드
  ☐ DB 확인

☐ 재현성
  ☐ scripts/ 재현 가능 확인
  ☐ 단계별 문서화
  ☐ 중복 실행 테스트

☐ 이력성
  ☐ Audit 테이블 확인
  ☐ Version 단조증가 검증
  ☐ 마이그레이션 이력 완성

☐ 안정성
  ☐ 실패 모드 테스트 (4가지)
  ☐ Crash 복구 시뮬레이션
  ☐ DLQ 격리 확인

☐ 고도화
  ☐ Phase 2 준비 (15개 FE)
  ☐ Phase 3 체크리스트 작성
  ☐ Phase 4 기술부채 계획

☐ 컴포넌트화
  ☐ 모듈 간 의존 0
  ☐ shared/ 재사용도 높음
  ☐ Feature 독립성 검증

☐ 정공법
  ☐ --no-verify 사용 0
  ☐ force push 0
  ☐ 주석 처리된 테스트 0

☐ 기술부채
  ☐ TECH_DEBT_REGISTER 업데이트
  ☐ DEBT-017/025/029 시작
  ☐ 월별 20% 계획 확정

결과: 모든 20개 원칙 Week 1에 측정 + 기반 마련


🎯 기대 효과

코드 품질

  • SOLID: 모든 handlers cyclomatic ≤ 10
  • 테스트: 80%+ 커버리지
  • 중복: 0개 (DRY 준수)

성능

  • 번들: 423 kB → 380 kB (10% 감축)
  • 응답시간: P95 < 300ms
  • 병렬화: wall-clock 52일 (90일 - 38일 절약)

신뢰성

  • 이력성: 100% 감사 추적
  • 재현성: 자동화 스크립트 100% 재실행 가능
  • 안정성: 4가지 실패 모드 처리

협업

  • 투명성: 모든 결정에 근거
  • 표준화: 명명/형식/패턴 일관
  • 추적성: CorrelationId 전사 추적

작성자: Claude Code
상태: READY FOR EXECUTION
마지막 수정: 2026-08-18
적용 기간: 4주 (Week 1-4)