- FormPageLayout: hardcoded minmax(18rem, 26rem) → var(--ks-preview-width) - ReviewWorkbenchLayout: hardcoded minmax values → var(--ks-detail-width) + var(--ks-aside-width) - OperationsConsoleLayout: hardcoded minmax(18rem, 28rem) → var(--ks-detail-width) - Unified all breakpoints: 950px/1000px/1200px → 1100px (tablet), 768px (mobile) - PageLayout: footer sticky overflow issue fixed (flex: 0 0 auto) Fixes responsive design for all screen sizes (768px mobile → 1920px fullHD → 2560px 4K). Reference: docs/FRONTEND-RESPONSIVE-DESIGN-STANDARD.md Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
32 KiB
K-ArtSell Aegis AI Coding Constitution v16.0
🔒 GOVERNANCE LOCK
AGENTS.md IS THE ONLY AUTHORITATIVE SOURCE FOR ENGINEERING GUIDELINES.
Rules (Non-negotiable):
- All engineering procedures, harnesses, and decision frameworks go in AGENTS.md only.
- CLAUDE.md, GEMINI.md, and all other .md files follow AGENTS.md. They do NOT define rules.
- If any document conflicts with AGENTS.md, AGENTS.md wins. Other text is void.
- Never add guidelines to CLAUDE.md, GEMINI.md, or side documents.
- Supplementary files reference AGENTS.md with explicit links only.
Scope:
- AGENTS.md owns: Coding rules, development setup, procedures, harnesses, decision frameworks, anti-patterns, workflows
- Other files provide: Project status, architecture context, navigation, references (links to AGENTS.md)
Enforcement:
- Claude Code will not accept conflicting guidance from multiple sources
- When in doubt, check AGENTS.md section headers
- If you see conflicting guidance elsewhere, update that document to reference AGENTS.md instead
Default execution procedure
All work in this repository MUST follow docs/CURRENT/WBS_EXECUTION_PROCEDURES.md as the default operating procedure, together with this constitution. Before editing, select exactly one WBS item from docs/CURRENT/CATALOGS/WBS_MASTER.csv, verify dependencies, Gate, Requirement/API/DB/Job/UI/Test IDs, Acceptance_Evidence, and Artifact. Record Source / Assumption / Unknown / Decision Required, then execute, collect actual evidence, update WBS_PROGRESS_TRACKER.csv, and commit with the WBS_ID. Do not mark a WBS item COMPLETED or claim a test/build/migration result without preserved execution evidence.
- 자동주문과 KIS 제출 Capability는 OFF다. 별도 승인 Release 전 구현·활성화·우회하지 않는다.
- 채팅과 생성 코드는 Source of Truth가 아니다. 모든 변경은 Source / Assumption / Unknown / Decision Required를 표시한다.
- 한 PR은 한 Vertical Slice 또는 한 동작보존 리팩터링 목적만 가진다.
- Endpoint→Application→Pure Policy→Dapper SQL→Outbox→Tests 경계를 지킨다.
- Domain Policy는 시간·랜덤·네트워크·DB·DI Container를 직접 읽지 않는다.
- Generic Repository, God Service, Service Locator, Job 내 비즈니스 정책, 조기 Microservice 분리를 금지한다.
- 모듈은 다른 모듈 Source Table을 직접 조회하지 않는다. 승인된 Contract/Read Model만 사용한다.
DateTime.Now/UtcNow를 직접 사용하지 않고 IClock과 MarketCalendar를 사용한다.- 금융값은 decimal, 명시적 rounding, 단위 계약을 사용한다. 모델 내부 double은 경계에서 변환한다.
SellRatioOfLot,SellQuantity,TargetPortfolioWeightAfter,StrategicCoreFloorWeight를 혼용하지 않는다.- EvidenceSnapshot·DatasetId·Model/Config/Code SHA 없이 Decision/Recommendation을 저장하지 않는다.
- Command/Job는 IdempotencyKey/JobRunId/Watermark를 갖고 replay를 견딘다.
- Evidence/Decision/Audit는 update/delete하지 않고 append/correction event로 보존한다.
- Write Model은 정규화·append·revision, 화면은 version/watermark/rebuild가 있는 Read Model이다.
- 서버 상태는 TanStack Query가 소유한다. Pinia에 API 응답을 복제하지 않는다.
- FE request/response는 Zod로 runtime validation하고 같은 retry에 같은 Idempotency-Key를 재사용한다.
/internal/*Endpoint는 Roles 또는 Policies를 선언하며 익명 접근을 허용하지 않는다.- 알고리즘 변경은 Policy ID, Golden, Frozen OOS, cost×2, false-exit/reentry/ES, ModelCard를 동반한다.
- 새 library/pattern/table/threshold는 ADR/Issue 승인 없이 도입하지 않는다.
- 실행하지 못한 build/test/migration을 통과했다고 기록하지 않는다.
- AI 생성 Migration은 fresh/upgrade/re-run/failure rehearsal 및 DBA 승인 없이는 병합하지 않는다.
- 실고객 데이터·실계좌·실주문 키·secret를 prompt/fixture/log/trace에 넣지 않는다.
- Metric·Alert·Runbook·Rollback·Owner/Secondary가 없으면 Done이 아니다.
v12.1 execution-readiness delta
- Every change must cite Requirement/Slice/Policy/Data/API/DB/Job/UI/Test IDs.
- Production commands load Evidence/Model/Config from approved server-side PIT context; never trust client-supplied evidence.
- Write models are normalized and append/correction based. Denormalization is allowed only in versioned, rebuildable read models.
- Outbox/Inbox/JobRun/Projection operations require scope, idempotency, watermark, hashes, and replay evidence.
- No generic repository, God service, reflection plugin framework, premature microservice, or unapproved threshold.
- Refactoring and policy changes must be separate PRs with characterization or Golden tests first.
- Never claim a build, migration, test, Shadow period, PBO, or DSR result that was not executed and preserved as evidence.
v12.2 strategic data-semantics delta
CurrentSecurityPortfolioWeight,CurrentLotPortfolioWeight,SellRatioOfLot, andStrategicCoreFloorWeightare distinct units. Never reintroduce the ambiguousCurrentPortfolioWeightinto active decision code.- A lot-relative sell changes security weight by
CurrentLotPortfolioWeight * SellRatioOfLot. - Persist the ordered policy trace with Applied/Blocked/NotApplicable dispositions; do not expose raw internal scores directly to customers.
- Prior migrations are immutable. v12.2 changes belong in migration
0014or later. - The six current-session attachments and their SHA-256 values are part of the release evidence.
- Use the reviewed templates under
templates/; do not bulk-generate unapproved modules or placeholder implementations.
v12.3 execution and semantic-version delta
weight_semantics_version=1contexts are legacy ambiguous data and must never enter active decisions; rebuild them as version 2 from explicit security and lot weights.- A positive opportunity edge with a zero or missing requested sell ratio is BLOCKED. Never clamp missing intent to a minimum sell.
- Policy IDs, priorities and thresholds must match
contracts/policies/sell-policy-contract.v1.json; drift blocks G2. - Decision/API/Event/DB evidence must preserve
decision_contract_versionandpolicy_trace_schema_version. - Outcome metrics must name a definition version, population, numerator, denominator, window and aggregation. Do not equate 63-session research output with an annual target without approval.
scripts/scaffold_slice.pyis dry-run by default, refuses overwrite and produces SCAFFOLD_ONLY code. Generated files are not approved implementation.- The seven cumulative attachments and their SHA-256 values are part of v12.3 release evidence.
v12.4 Model Operations Constitution
- Scheduler automation is limited to EVALUATION_ONLY, PROPOSAL_ONLY and DRILL_ONLY.
- Never generate or merge automatic model promotion, rollback, threshold mutation, code change, automatic order or KIS submission paths.
- Every evaluation request freezes Dataset/Model/Config/Code/Contract VersionSet from an approved server-side context.
- Metric changes require a versioned numerator, denominator, window, aggregation, PIT/revision rule and Golden/OOS impact.
- Improvement proposals are documents and records only; they do not edit model, policy, configuration or source files.
- Drift thresholds, false-exit definition and retention policy are DECISION_REQUIRED until approved.
v14.0 UI / Model Feedback non-negotiables
- Feature code MUST NOT import PrimeVue or AG Grid directly. Use shared UI ports and screen types.
- UI provider changes require contract, accessibility, visual, state-matrix and performance evidence.
- Model operation automation stops at evaluation/proposal. Model activation is human change approval only.
- J39 and every new schedule remain disabled until their source, calendar, ownership and alert contracts are approved.
- Never claim .NET, pnpm, PostgreSQL, Playwright or Shadow evidence passed unless the actual artifact is attached.
- [CRITICAL IRON RULE] Viewport-Fit Zero-Scroll Layout: Except for analytical dashboards, ALL workstation screens MUST fit 100% within the initial viewport upon loading WITHOUT page-level window scrolling. All primary grids, forms, and control panels must automatically calculate
height: calc(100vh - header/tabs)and handle internal scrolling inside containers. - [CRITICAL IRON RULE] Standardized Button Layout Strategy:
- Page Action Toolbar (Top-Right
.ks-page__actions): Dedicated exclusively to Primary Processing Actions (e.g.,▶ 배치 실행,⚡ 리밸런싱 실행,📤 데이터 수집) and Global Page Operations (e.g.,➕ 신규 등록). Secondary actions are styled as outline/ghost. - Grid Row & Item Context Actions (Table Row Actions): Dedicated to Single-Row CRUD & Processing (e.g.,
✏️ 수정,🗑️ 삭제,🔍 상세보기,▶ 재처리). Placed in a pinned right column or explicit context menu; never placed in page top toolbar. - Multi-Selection Batch Toolbar (Grid Top/Bottom Selection Bar): Activated conditionally upon multi-row selection for Bulk Actions (e.g.,
선택 일괄 승인(3),선택 일괄 삭제).
- Page Action Toolbar (Top-Right
- [CRITICAL IRON RULE] Standardized Loading Skeleton Rule: ALL screen-level and section-level data loading MUST render animated
SkeletonLoader(shimmer mode) matching the expected layout (e.g.skeletonType="table"for grids,skeletonType="card"for forms/summaries) throughQueryStateBoundary/StandardScreenBoundary. Static text ("불러오는 중...") or empty screen placeholders during loading states are STRICTLY PROHIBITED. - [CRITICAL IRON RULE] Standardized Empty Data State Rule: When zero records or empty dataset states occur, ALL grids, lists, and summary cards MUST render standard
EmptyStatePlaceholdercomponent (📭icon, clear title, descriptive helper text, and optional recovery action button). Blank white spaces or plain<p>데이터가 없습니다</p>text tags are STRICTLY PROHIBITED. - [CRITICAL IRON RULE] Standardized Form & Filter Control Width Rule: ALL form & filter controls MUST adhere to central default width tokens (
tokens.css/base.css). Controls MUST NOT stretch to 100% full width inside filter bars unless explicitly grouped in full-width grid layouts:- Select / Dropdown (
select,.p-select,.ks-select): Default width--ks-control-width-select(160px). - Search Input (
.search-input): Default width--ks-control-width-search(220px). - Date Picker (
input[type="date"]): Default width--ks-control-width-date(140px).
- Select / Dropdown (
- [CRITICAL IRON RULE] Standardized Grid Row Numbering Rule: Unless explicitly disabled (
showRowNumber: false), ALL data grids MUST automatically prepend a pinned leftNo.column rendering 1-indexed sequential row numbers (node.rowIndex + 1) centered with54pxfixed width. - [CRITICAL IRON RULE] Standardized Grid Theme, Zebra Stripes & Color Palette Rule: ALL data grids MUST inherit central Theme Color Tokens (
tokens.css) without ad-hoc inline overrides. Grids MUST enforce:- Header Background: Premium Header Gray
#f1f5f9(Dark Mode:#1e293b), font-weight:700. - Zebra Stripes (Odd Rows): Even rows
#ffffff, Odd rows (.ag-row-odd)#f8fafc(Dark Mode:#0f172a). - Hover Color: Sky Light Blue
#e0f2fe(Dark Mode:#334155). - Active Selection Color: Active Selected Row Sky Blue
#dbeafewith bold text#1e3a8a(Dark Mode:#1e3a8a).
- Header Background: Premium Header Gray
v16.0 Gitea API & CI/CD Automation
Environment Setup
Gitea API Token:
# Set GITEA_TOKEN_TAXBAIK environment variable
# This token enables:
# - Pull request automation (labels, milestones, comments)
# - Issue management (create, update, close)
# - Release management (tags, release notes)
# - CI/CD pipeline integration
# On Windows (PowerShell):
$env:GITEA_TOKEN_TAXBAIK = "your-token-here"
# On macOS/Linux (bash):
export GITEA_TOKEN_TAXBAIK="your-token-here"
# Verify:
echo $GITEA_TOKEN_TAXBAIK
Gitea API Patterns
Common endpoints (https://gitea.taxbaik.com/api/v1):
# Create a PR comment
curl -X POST \
-H "Authorization: token $GITEA_TOKEN_TAXBAIK" \
-H "Content-Type: application/json" \
-d '{"body":"Verification complete: 41/41 tests passed"}' \
https://gitea.taxbaik.com/api/v1/repos/kjh2064/KArtSell.Aegis/issues/{issue_id}/comments
# Add labels to PR
curl -X POST \
-H "Authorization: token $GITEA_TOKEN_TAXBAIK" \
-d '["architecture","verified"]' \
https://gitea.taxbaik.com/api/v1/repos/kjh2064/KArtSell.Aegis/issues/{pr_number}/labels
# Create release with notes
curl -X POST \
-H "Authorization: token $GITEA_TOKEN_TAXBAIK" \
-H "Content-Type: application/json" \
-d '{"tag_name":"v16.0.1","body":"Release notes..."}' \
https://gitea.taxbaik.com/api/v1/repos/kjh2064/KArtSell.Aegis/releases
# Query PR/Issue
curl -H "Authorization: token $GITEA_TOKEN_TAXBAIK" \
https://gitea.taxbaik.com/api/v1/repos/kjh2064/KArtSell.Aegis/pulls?state=open
CI/CD Integration (Gitea Actions)
Leverage in .gitea/workflows/ci.yml:
- name: Comment on PR with test results
if: github.event_name == 'pull_request'
run: |
curl -X POST \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
-H "Content-Type: application/json" \
-d "{\"body\":\"Build: ✅ Tests: 41/41 PASS\"}" \
https://gitea.taxbaik.com/api/v1/repos/kjh2064/KArtSell.Aegis/issues/${{ github.event.pull_request.number }}/comments
Automation Best Practices (from v16.0)
- PR Labels: Auto-label based on affected module (e.g.,
ModelOperations,SignalEngine) - Milestones: Link PRs to quarterly sprints for burndown tracking
- Comments: Post verification results (build, test, security scan) directly on PR
v16.0 Development Environment Configuration
Database & Backend Setup
DO NOT make up or ask for database credentials.
Read src/KArtSell.Host/appsettings.Development.json directly. Current values:
{
"ConnectionStrings": {
"Postgres": "Host=127.0.0.1;Port=5432;Database=kartselldb;Username=kartsell;Password=kartsell4321@!"
},
"Authentication": {
"Mode": "DevelopmentHeader"
}
}
Connection Parameters:
- Host:
127.0.0.1(localhost) - Port:
5432 - Database:
kartselldb(NOTkartsell) - Username:
kartsell - Password:
kartsell4321@!
SSH Tunnel (Required before starting backend):
ssh -L 5432:127.0.0.1:5432 kjh2064@178.104.200.7
Start Backend (use config file, no env var injection):
cd D:\JobRoomz\KArtSell.Aegis
dotnet run --project src/KArtSell.Host --configuration Debug --no-build
Frontend Development Server
Port: 5174 (fallback: 5173 if available)
Start Frontend (from project root):
cd frontend
pnpm install --frozen-lockfile
pnpm dev
Frontend Layout & Responsive Design Standards (v16.0)
CRITICAL: Responsive web design is MANDATORY for all layouts, not optional.
CSS Variable Standards (base.css)
:root {
--ks-sidebar-width: 16rem; /* Navigation sidebars */
--ks-aside-width: 22rem; /* Side panels */
--ks-preview-width: 24rem; /* Preview/summary panels */
--ks-detail-width: 28rem; /* Detail panels */
--ks-content-max: 1400px; /* Max content width (prevent excessive expansion) */
}
Layout Rules (Non-Negotiable)
- NO hardcoded pixel/rem widths in minmax. Always use CSS variables:
minmax(0, 1fr) var(--ks-aside-width)✅, NOTminmax(18rem, 26rem)❌ - Unified breakpoints (all layouts must use same):
- Desktop: Default (no constraint)
- Tablet:
@media (max-width: 1100px) { grid-template-columns: 1fr; }(2-col → 1-col) - Mobile:
@media (max-width: 768px) { /* adjust padding, font sizes */ }
- All flex children:
flex: 1; min-height: 0;required (prevents overflow squashing) - Scrollable containers:
overflow-y: auto; min-height: 0;(enables internal scroll without page scroll) - Grid layouts:
align-items: start;(NOT center/stretch) to prevent column stretching at different heights - Max-width constraint: Wrap pages in
.page-wrapper { max-width: var(--ks-content-max); margin: 0 auto; }to prevent 2560px+ distortion
Height Propagation Chain (Single-Screen Principle)
PageLayout (.ks-page__content)
├─ height: 100%; min-height: 0; display: flex;
↓
QueryStateBoundary (.ks-query-boundary)
├─ flex: 1; height: 100%; min-height: 0; display: flex;
↓
Content Container (KsSplitter, .ks-stack, FormPageLayout)
├─ flex: 1; min-height: 0; height: 100%;
├─ display: flex/grid;
↓
Internal Panes (.request-list, .detail-panel, .items)
├─ flex: 1; min-height: 0; overflow-y: auto;
Banned Patterns
- ❌
grid-template-columns: minmax(18rem, 26rem)(hardcoded min/max) - ❌
calc(100vh - Xpx)(brittle, changes with header size) - ❌
max-width: 600pxon full-page containers (prevents responsiveness) - ❌
align-items: centerin grid layouts (prevents height-based alignment) - ❌
position: fixedsidebars without mobile fallback - ❌ Multiple different breakpoints across layouts (950px, 900px, 1000px, 1200px all mixed)
Verification Checklist
For every layout change:
- Uses CSS variables, not hardcoded rem/px
- Breakpoints are 1100px (tablet) and 768px (mobile)
- All flex children have
flex: 1; min-height: 0 - All scrollable panes have
overflow-y: auto; min-height: 0 - Tested at 768px (mobile), 1100px (tablet breakpoint), 1512px (current test), 1920px (fullHD), 2560px (4K)
- No page-level scroll on first load (only internal pane scroll if needed)
- Content max-width prevents distortion on ultra-wide (>1400px)
Affected Layouts (Status)
| Layout | Issue | Status | Reason |
|---|---|---|---|
| PageLayout | None | ✅ COMPLIANT | Uses CSS variables |
| CrudWorkspaceLayout | None | ✅ COMPLIANT | Uses CSS variables |
| FormPageLayout | Hardcoded minmax(18rem, 26rem) |
🔴 FIX REQUIRED | Session 2026-08-16 |
| ReviewWorkbenchLayout | Mixed hardcoded widths | 🔴 FIX REQUIRED | Session 2026-08-16 |
| OperationsConsoleLayout | Hardcoded minmax(18rem, 28rem) |
🔴 FIX REQUIRED | Session 2026-08-16 |
Authentication for Testing
Development mode uses DevelopmentHeaderAuthenticationHandler. Test requests with:
$headers = @{
"X-KArtSell-User" = "kjh2064"
"X-KArtSell-Role" = "Admin"
"Content-Type" = "application/json"
}
Invoke-WebRequest -Uri "http://127.0.0.1:5002/api/shadow-runs" `
-Method POST `
-Headers $headers `
-Body $body
Rules for Development Configuration
- Never invent credentials. Read config files first.
- Never ask the user for settings. Read
appsettings.Development.jsondirectly. - Database name is
kartselldb. Notkartsell. - SSH tunnel is mandatory. PostgreSQL is not accessible without it.
- Authentication mode is
DevelopmentHeader. Use headers, not OIDC tokens.
- Releases: Tag with semver + architecture contract version (e.g.,
v16.0.1-contract-v3.0) - Issue Linking: Reference debt IDs, ADRs, decision logs in commits (e.g.,
TECH-001: Fix CA1822)
v16.0 Strategic Architecture & Engineering Excellence
Decision Criteria for All Work
Every task — code change, refactor, new feature, tooling, infrastructure — must be evaluated against these dimensions before implementation:
1. SOLID 원칙
- Single Responsibility: One class, one reason to change. Vertical Slice boundaries are trust boundaries.
- Open/Closed: Open for extension (new Policies, new decision gates); closed for modification (immutable Evidence, append-only migrations).
- Liskov Substitution: Handlers, Policies, Adapters are swappable; never break contract.
- Interface Segregation: IClock ≠ IDateTime; IOutboxWriter ≠ IEventBus. Ports are narrow.
- Dependency Inversion: Depend on abstractions (IClock, ILogger, IOutboxWriter); inject concretions at composition root only.
- 적용: 모듈 경계 설계, 인터페이스 분리, 스태틱 메서드 vs 인스턴스 메서드 판단.
2. 코드 리팩토링 (Code Mass & Complexity)
- Cyclomatic Complexity ≤ 10 per method (Policy는 예외: decision trees는 복잡해질 수 있음).
- Characterize → Isolate → Transform → Verify → Simplify → Observe → Close Debt (정공법).
- Dead code, unused flags, unreachable branches는 즉시 삭제. "혹시 필요할까봐"는 금지.
- Performance refactor와 기능 변경은 분리된 PR. 동시 변경은 회귀 탐지 불가.
3. 데이터 정합성 (Data Integrity & Audit)
- PIT (Point-in-Time):
WHERE published_at <= cutoff AND revision = latest필수. 시간 여행 쿼리는 audit 목적만. - Revision Tracking: update/delete 금지. 새 버전을 append로 저장. 수정은 correction event로 보존.
- Audit Trail: EvidenceSnapshot, DatasetId, Model/Config/Code SHA는 Decision과 함께 저장. Trace 불가능하면 미완성.
- 적용: 모든 쓰기는 append/correction 패턴. 읽기는 PIT 조건. 마이그레이션은 회원가입 없음.
4. 과유불급 (Necessity-Driven, No Gold-Plating)
- "혹시 나중에 필요하면"으로 코드를 추가하지 않는다. 근거 없는 추상화 금지.
- 한 곳에서만 쓰면 분리하지 않는다. 세 곳에서 반복되면 그때 abstract.
- Feature flag, backward-compat shim, deprecation layer는 근거 있을 때만. 사용하지 않는 코드는 삭제.
- 적용: 새 service/interface/config 도입 전에 "이것이 정말 필요한가?" 자문.
5. 정규화 & 역정규화 (Normalization Strategy)
- Write Models: 3NF + append + revision. 중복 없음, 관계 명확, 이상 불가.
- Read Models: Denormalized projections. 1NF 위반 허용 (성능, 접근성). 모든 Read는 versioned, rebuildable.
- 경계: Write는 Dapper로 스키마-규정. Read는 쿼리 최적화. 양쪽 스키마 감시.
- 적용: 새 column 추가 전에 "이것은 3NF 위반인가? 그렇다면 projection으로."
6. 프로세스 단순화 (Simplicity & Clarity)
- 한 번에 한 가지만 한다. 다중 책임 = 다중 이해 실패 = 버그.
- "왜 이 순서인가?" 묻지 않아도 명확한 코드. 숨겨진 전제 금지.
- Circular dependency, magic numbers, implicit state 제거.
- 적용: 코드 흐름이 위→아래로 읽혀야 함. 뒤로 돌아가며 읽어야 하면 리팩터.
7. 패턴화, 표준화, 구조화 (Patterns & Standards)
- Vertical Slice는 단일 패턴. Endpoint → Handler → Policy → Dapper → Outbox.
- Job은 단일 책임. 비즈니스 정책은 들어가지 않음. 승인된 Command만 실행.
- Event schema는 contract-first. 구독자가 없으면 이벤트도 없음.
- 표준 컴포넌트: QueryStateBoundary, CrudForm, PermissionGuard 등은 모든 화면에서 재사용. 직접 import 금지.
- 적용: 새 pattern/component 도입 전 팀 검토. 코드 사본 3개 = abstract 신호.
8. 바이브코딩 & 홀루시네이션 통제 (AI Guardrails)
- AI 생성 코드는 근거 없음. Source/Assumption/Decision 반드시 기록.
- 금지: 근거 없는 Policy ID, threshold, DB column, API endpoint.
- SQL은 schema owner, PIT 조건, index, execution plan 검토 필수.
- 알고리즘 변경은 Golden/Frozen OOS diff 없이 병합 금지.
- 적용: "이 값은 어디서 나왔나?" 묻는 습관. 답 없으면 DECISION_REQUIRED 표시.
9. 현장감, 재현성, 이력성 (Traceability & Reproducibility)
- 현장감: Build/test/migration artifact는 보존. "통과했다고 주장"하되 증거 없으면 거짓.
- 재현성: 동일 input → 동일 output. Random, network, system time 의존은 격리. Mock 금지, integration test로.
- 이력성: Commit message는 "왜"를 기록. "버그 수정"은 불충분. "X 기능에서 Y 조건에서 Z 버그 → 원인: 로직 오류" 기록.
- 적용: CI/CD 결과물 저장, 회귀 테스트 잠금, ADR에 의사결정 기록.
10. 안정성 (Reliability & Safety)
- Idempotency: 같은 요청 → 같은 결과. 두 번 실행해도 안전.
- Rollback 불가능한 변경 금지. Migration도 down script 필수.
- Failure mode: 각 Job/Endpoint은 실패했을 때 상태를 명확히. "실패했는데 부분 성공?" 금지.
- 적용: Command/Job는 IdempotencyKey, Watermark 필수. DB constraint, NOT NULL 검증.
11. 고도화 & 컴포넌트화 (Componentization & Maturity)
- 한 번 제대로. 임시방편 금지. 기술부채는 Debt register에 기록.
- 구현 전 contract/schema/test 먼저. "하면서 배운다"는 설계 부실의 신호.
- 버전 관리: 기능이 아닌 contract 버전. API/Event/DB schema 버전 분리.
- 적용: Release note에는 contract version, breaking change, migration step 명시.
12. 정공법 (Right Way, Not Shortcuts)
- 안 되는 길에 시간 낭비하지 말되, 편한 길도 피한다 (--no-verify, force push).
- 문제 근본 해결. Symptom 치료는 debt 증가.
- 리뷰어가 "이게 최선인가?" 묻는 코드는 재작성. "충분히 좋다" ≠ "최선".
- 적용: Build 실패 → --no-verify X, 원인 파악. Merge conflict → cherry-pick X, rebase 제대로.
13. 기술부채 관리 (Tech Debt Registry)
- 부채는 기록하는 순간부터 이자 발생. 미루지 말 것.
- Debt ID: TECH-001 등으로 추적. PR/commit에서 참조.
- 우선순위: Impact (얼마나 큰가) × Effort (고치는 데 드는 비용). 고영향 저비용 우선.
- Paydown: 분기마다 debt 20% 감축 목표. 신규 debt > paydown이면 질식.
- 적용: README.md의 TECH_DEBT_REGISTER 매월 검토. 3개월 미해결 = 리팩터 스프린트 필요.
Work Decision Checklist
모든 task에 대해 다음을 자문:
- SOLID: 이 변경이 단일 책임인가? Dependency inversion을 지킬 것인가?
- Complexity: 함수/메서드 복잡도는 10 이하인가? (Policy 예외)
- Audit: Evidence/Revision 추적 가능한가? PIT 쿼리 있는가?
- Necessity: 근거 있는 변경인가? "혹시 필요하면" 아닌가?
- Normalization: 쓰기는 3NF, 읽기는 projection인가?
- Simplicity: 위→아래로 읽혀야 하는가? 숨겨진 전제 없는가?
- Pattern: 표준 Slice/Job/Component 따르는가? 새 패턴 도입은 검증됐는가?
- Guardrails: 근거 있는가? "왜"를 기록했는가?
- Traceability: Artifact 보존되는가? Reproduction 가능한가? ADR/Issue 링크 있는가?
- Safety: Idempotent인가? Rollback 가능한가? 부분 실패 케이스 처리했는가?
- Maturity: 임시방편 아닌가? Contract/schema/test 먼저 했는가?
- Right Way: Shortcut (--no-verify, force) 안 썼는가? 근본 해결했는가?
- Debt: 새로운 debt 만들지 않는가? 기존 debt 감축하는가?
- Viewport Fit (UI): 대시보드를 제외한 모든 업무 화면이 페이지 스크롤 없이 초기 로딩 시 100% 한눈에 들어오는가?
- Button Standard (UI): 상단 툴바(배치/등록), 행별 작업(수정/상세), 다중선택(일괄), 폼 푸터(취소/저장) 버튼 배치가 규칙 매트릭스를 따르는가?
- Skeleton Loading (UI): 로딩 상태 시 텍스트 대신 레이아웃에 반응하는 shimmer 스켈레톤(SkeletonLoader)이 제대로 노출되는가?
- Empty State (UI): 데이터 0건 또는 조회 결과가 없을 시 표준 EmptyStatePlaceholder(아이콘+설명+조치버튼)가 노출되는가?
- Component Scale (UI): 입력폼, 그리드, 버튼, 선택상자 높이/폰트가 중앙 토큰(
tokens.css) 규격(헤더 30px, 행 28px, 컨트롤 28px, 폰트 12px)을 따르는가?
Anti-Patterns (금지)
- ❌ "일단 만들고 나중에 리팩터" → Feature 초기부터 정공법
- ❌ "페이지에 창 스크롤바가 생기게 방치" → 대시보드 제외 모든 업무 화면은 Viewport-Fit Zero-Scroll 필수
- ❌ "버튼 위치 난잡 배치" → 상단 우측(페이지/배치), 행 내부(개별 CRUD), 선택바(일괄), 폼 푸터(저장/취소) 표준 무시 금지
- ❌ "로딩 시 '불러오는 중...' 텍스트 방치" → 반드시 레이아웃 맞춤형 애니메이션 스켈레톤(SkeletonLoader) 적용 필수
- ❌ "데이터 0건 시 빈 흰색 공간 방치" → 반드시 표준 EmptyStatePlaceholder 컴포넌트 렌더링 필수
- ❌ "개별 인라인 height/font style 난립" → 반드시 중앙 tokens.css / base.css 디자인 토큰 상속 필수
- ❌ "혹시 필요할까봐 추상화" → Necessity-driven만
- ❌ SELECT * / Generic Repository → Explicit columns, explicit logic
- ❌ "이건 작은 변경이라 테스트 스킵" → 모든 경로 characterize
- ❌ Timestamp를 직접 DateTime.Now → IClock 주입
- ❌ Policy 로직이 Job/Handler에 → Domain Policy만
- ❌ "나중에 monitoring 추가" → 배포 전 Metric/Alert/Runbook 필수
- ❌ Magic number → 근거 있는 상수, Policy ID로 추적
- ❌ "다른 모듈 테이블 조회" → Contract/Read Model만
- ❌ 스킵된 테스트 기록 안 함 → Debt register에 DECISION_REQUIRED
Execution Protocol Addendum
Before Any Change
- Read the current Source of Truth first: user-provided configuration, current schema, active contracts, and existing tests.
- Record
Source / Assumption / Unknown / Decision Requiredin the Slice note before editing. - Preserve user-fixed development and production configuration values. Never replace them with compose defaults, environment fallbacks, or guessed credentials.
- Classify the change as exactly one Vertical Slice or one behavior-preserving refactoring. Do not mix policy, schema, configuration, and unrelated cleanup.
Database Test Routing
- Unit tests do not connect to a database.
- Integration and migration tests use the configured test database from the test project's Development settings.
- Production database access is read-only diagnostics only unless an explicitly approved production release step says otherwise.
- Before any destructive test-database operation, parse and verify the database name is the approved test database. Refuse all other names.
- Do not infer schema from a legacy migration file. Compare active runtime SQL, tests, and the current database schema first.
Time and Timezone
- Persist instants in UTC with timezone-aware database types where the contract permits.
- Convert to KST only at display, reporting, scheduling, or MarketCalendar boundaries.
- Keep
IClock.UtcNowas the application clock contract. A KST conversion requires an explicit contract and characterization test. - Never change a timezone or reinterpret existing timestamps without a documented data-meaning decision and rehearsal evidence.
Blockers Must Be Actionable
- Do not repeatedly report that work is blocked without a concrete resolution proposal.
- For each blocker, state: exact cause, safe options, recommended option, required command or approval, and the evidence that will be produced.
- If the user has provided the required authority or test resource, proceed within that scope instead of asking for the same approval again.
- If an external prerequisite is missing, perform all safe read-only checks first, then give one precise request to unblock the next Slice.
Evidence and Completion
- Never claim completion from an intended command. Record the actual command result and artifact path.
- For migrations, preserve fresh-install, upgrade, re-run, and failure-rehearsal evidence before calling the Slice complete.
- When a change fails validation, revert or isolate the failed draft before starting the next Slice; do not leave an unapplied journal or partial scaffold as if it were approved.