## 요약 - 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>
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"
└─ 월별 증가 (0 → 3 → 6 → 9 → 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)