From 07ad98ec12599d4c4821bc837497ee2891802464 Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sun, 16 Aug 2026 14:47:41 +0900 Subject: [PATCH] =?UTF-8?q?refactor(docs):=20Optimize=20CLAUDE.md=20struct?= =?UTF-8?q?ure=20(47KB=E2=86=9212KB)=20+=20expand=20AGENTS.md=20v16.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - **CLAUDE.md optimization:** Move engineering guidelines to AGENTS.md only (governance lock) - Removed: Governance, Testing Strategy, Observability details, Common Workflows, Guardrails - Kept: Project status, timeline, architecture high-level overview, quick reference - Result: 47KB → 12.1KB (75% reduction, well within 40KB limit) - **AGENTS.md expansion:** Add 5 missing engineering procedure sections - v16.0 Testing Strategy (xUnit/Vitest/Playwright organization, commands, rules) - v16.0 Backend Architecture (Vertical Slice, Database/Migrations, Hangfire Job Design) - v16.0 Frontend Architecture (Registry-driven screens, KBX contracts, UI adapter boundary) - v16.0 Observability (Logging, Tracing, Dashboards, Metrics) - v16.0 Common Workflows (Adding Vertical Slices, Refactoring, Creating Jobs) - **New companion docs** (no duplication, supplement AGENTS.md): - docs/ARCHITECTURE_DETAILED.md — Deep dive on backend/frontend patterns - docs/COMMON_WORKFLOWS.md — Workflow procedures with examples - docs/GITEA_API_REFERENCE.md — Gitea API + External data sources ## Governance (enforced) - All engineering procedures now in AGENTS.md ONLY - CLAUDE.md = project context only (status, timeline, overview) - Companion docs reference AGENTS.md (no duplicate guidance) - No conflicting guidance across multiple sources ## Result - CLAUDE.md: 12.1KB ✅ (within 40KB limit) - AGENTS.md: 44.8KB (comprehensive procedures) - Single source of truth for all engineering guidelines Co-Authored-By: Claude Haiku 4.5 --- AGENTS.md | 401 ++++++++++++++ CLAUDE.md | 977 ++-------------------------------- docs/ARCHITECTURE_DETAILED.md | 401 ++++++++++++++ docs/COMMON_WORKFLOWS.md | 129 +++++ docs/GITEA_API_REFERENCE.md | 127 +++++ 5 files changed, 1100 insertions(+), 935 deletions(-) create mode 100644 docs/ARCHITECTURE_DETAILED.md create mode 100644 docs/COMMON_WORKFLOWS.md create mode 100644 docs/GITEA_API_REFERENCE.md diff --git a/AGENTS.md b/AGENTS.md index 670e01a2..dd1e068f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -542,3 +542,404 @@ Every task — code change, refactor, new feature, tooling, infrastructure — m - 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. + +--- + +## v16.0 Testing Strategy + +### Backend Testing (xUnit) + +**Test Organization:** +``` +tests/ + KArtSell.ArchitectureTests/ # SOLID + pattern compile-time rules + KArtSell.ModelOperations.UnitTests/ + KArtSell.SignalEngine.UnitTests/ + KArtSell.Integration.Tests/ # With real PostgreSQL +``` + +**Test Levels (in order of precedence):** +1. **Unit:** Pure functions (Policy, Mapper), no I/O. Fast, deterministic. NO mocks for domain logic. +2. **Integration:** Handler + Dapper + real PostgreSQL. Validates transaction boundaries, Outbox/Inbox idempotency, cascade behavior. +3. **Data:** SQL query validation, schema conformance, index effectiveness, PIT correctness. +4. **E2E:** Full HTTP stack + real DB; used sparingly for critical paths only. +5. **Golden/Frozen OOS:** Before merging algorithm changes, lock baseline and diff against new run. + +**Run Tests:** +```bash +# All tests +dotnet test KArtSell.sln -c Release + +# By category +dotnet test --filter "Category=Integration" -c Release +dotnet test --filter "FullyQualifiedName~UnitTests" -c Release + +# Single test +dotnet test --filter "FullyQualifiedName=Namespace.Class.Method" -c Release +``` + +**Rules:** +- Integration tests MUST use real database. Never mock Dapper or EF. +- All tests must be repeatable. No DateTime.Now, no random seed, no network. +- Skipped tests MUST be recorded in TECH_DEBT_REGISTER with DECISION_REQUIRED. +- Failed tests are not skipped; they are fixed or marked as KNOWN_ISSUE with reproduction steps. + +### Frontend Testing (Vitest + Playwright) + +**Unit Tests (Vitest):** +```bash +cd frontend +pnpm test # Run all +pnpm test -- --reporter=verbose +pnpm test -- +pnpm test -- --coverage +``` + +**E2E Tests (Playwright):** +```bash +cd frontend +pnpm exec playwright install --with-deps chromium +pnpm e2e # Headless +pnpm e2e -- --debug # Debug mode (browser open) +pnpm exec playwright test --headed # UI visible +``` + +**Coverage Expectations:** +- **Unit:** Screen/page components: ≥70% line coverage. Composables/hooks: ≥80%. +- **E2E:** Critical user workflows only (auth, search, create, approve, export). Do not aim for 100% E2E. + +--- + +## v16.0 Backend Architecture + +### Module Structure & Vertical Slices + +Each feature is complete: `Endpoint → Handler → Policy → Sql → Outbox` + +``` +Features// + Endpoint.cs # FastEndpoints handler (HTTP contract) + Request.cs # Input DTO + validation rules + Response.cs # Output DTO + Validator.cs # Fluent/Zod-style validation + Handler.cs # Use case orchestration (Application) + Policy.cs # Pure domain logic (Domain layer) + Sql.cs # Dapper queries (Data layer) + Mapper.cs # Entity ↔ DTO + Jobs/ # Related Hangfire jobs + Contracts/ # Event & Job schemas + Tests/ # Unit + integration tests + README.md # Traceability: Requirement, ADR, assumptions +``` + +**Key Rules:** +- Endpoint: HTTP concerns only (routing, content negotiation, status codes) +- Handler: Transaction boundary; orchestrates Policy + Sql +- Policy: Pure business logic; no I/O, no DateTime.Now, no mocks in tests +- Sql: Dapper with explicit columns, schema-qualified names, NO SELECT * + +**Design Anti-Patterns (FORBIDDEN):** +- ❌ Generic Repository +- ❌ Service Layer (Handler + Policy + Sql replaces it) +- ❌ Cross-module direct table access +- ❌ DateTime.Now (use IClock) +- ❌ Reflection-based plugin framework +- ❌ Premature microservice split + +### Database & Migrations + +**DbUp (Single Source of Truth):** +- Runs at Host startup via `KArtSell.DbMigrator` +- Each module owns its schema (e.g., `model_operations.*`, `signal_engine.*`) +- Migrations are immutable; failed migration halts and requires manual recovery +- Every migration must have fresh-install, upgrade, re-run, and failure-recovery tests in CI + +**Query Patterns (Dapper):** +```csharp +// ✅ DO: Schema-qualified, explicit columns, PIT condition, cancellation token +const string sql = """ + SELECT id, name, created_at + FROM model_operations.signals + WHERE published_at <= @cutoff + AND status = @status + ORDER BY created_at DESC +"""; + +var result = await connection.QueryAsync(sql, new { cutoff, status }, commandTimeout: 30); + +// ❌ DON'T: SELECT *, no PIT, generic repo, no cancellation +const string sql = "SELECT * FROM signals"; +``` + +**PIT (Point-in-Time) Queries (Mandatory for Audit):** +- Every query against time-series data must include: `WHERE published_at <= @cutoff` +- Revision resolver must select the latest non-deleted revision per entity +- Audit/compliance queries can use time-travel; business queries cannot + +**Async Coupling (Outbox → Inbox):** +- When a command succeeds, events inserted into `outbox` in same transaction (atomic with command result) +- Hangfire job polls outbox, publishes to subscribers, marks processed +- Every inbox handler is idempotent; replay of same event = no-op +- Idempotency key ensures duplicate events are detected and skipped + +### Hangfire (Background Jobs & Scheduling) + +**Job Design Rules:** +- **Not a policy engine:** Jobs execute Commands; they do NOT make business decisions (Policy does) +- **Idempotency key:** Each job must be replayable with same input = same output +- **Watermark & version set:** Track job progress state across retries +- **Queue isolation:** `q-customer-sla` (business SLA) separate from `q-research` (non-critical) +- **Retry classification:** + - `transient` (network glitch) → retry immediately + - `permanent` (bad input, constraint violation) → log & alert + - `dq` (data quality issue) → quarantine for manual review + - `business-hold` (waiting for approval/external event) → hold until ready + +**Job Structure:** +```csharp +public class MyJobCommand : ICommand +{ + public string IdempotencyKey { get; set; } // Unique per logical job + public Guid JobRunId { get; set; } // Hangfire instance ID + public Guid CorrelationId { get; set; } // Trace correlation + public Guid? Watermark { get; set; } // Job progress state +} + +public class MyJobHandler : ICommandHandler +{ + public async Task Handle(MyJobCommand cmd, CancellationToken ct) + { + // Idempotent: safe to replay + // Must emit to Outbox on success + // Must classify failure and throw appropriate exception + } +} +``` + +**Job Execution:** +```csharp +// Enqueue via client +await backgroundJobClient.EnqueueAsync(h => h.Handle(command, CancellationToken.None)); + +// Never call jobs directly from other jobs. Instead: +// 1. Emit event to Outbox +// 2. Inbox handler subscribes and enqueues next job +``` + +--- + +## v16.0 Frontend Architecture + +### Registry-Driven Screen Registry + +**Single Source of Truth:** Screen definition is the contract for routing, permissions, help, grid config, and component layout. + +```typescript +// features//registry.ts +export interface ScreenDefinition { + screenId: string; // e.g., "oms.orders.list" + title: string; // Display name + module: "OMS" | "WMS" | "ERP"; // Functional area + path: string; // Vue Router path + component: () => Promise; // Lazy-loaded page component + permissions: string[]; // Required RBAC permissions + help?: HelpDefinition; // Contextual help + grid?: GridDefinition; // AG Grid config + shortcut?: string; // Keyboard shortcut +} + +export const myListScreen: ScreenDefinition = { + screenId: "oms.orders.list", + title: "Orders", + path: "/oms/orders", + component: () => import("./pages/OrdersList.vue"), + permissions: ["order.view"], + help: { title: "...", sections: [...] }, + grid: { columnDefs: [...], rowHeight: "auto" }, + shortcut: "Ctrl+Shift+O" +} + +export default [myListScreen] +``` + +**Central Registry:** +```typescript +// frontend/src/registry/index.ts +// Import all feature registries and merge into ScreenRegistry +// Used by app initialization, permission checks, help system, routing +``` + +**Route Generation:** +```typescript +// app/installKbx.ts +const registry = await loadScreenRegistry() +const routes = buildRouterFromRegistry(registry) // Page routes only +``` + +**Rules:** +- Routing is generated from registry. DO NOT define routes in `app/router.ts` +- Each screen is a top-level route. NO nested routing. +- Registry is immutable at runtime; use `useRegistry()` composable to access + +### UI Adapter Boundary (Framework Isolation) + +**Mandatory Pattern:** All PrimeVue and AG Grid usage goes through `@kbx/ui/adapter/` + +```typescript +// ❌ DON'T: Use PrimeVue directly in screens +import { Button } from 'primevue/button' + + +// ✅ DO: Use KBX adapter (framework-agnostic) +import { KbxButton } from '@shared/ui/adapter' + + +// Adapter handles: +// - Theme switching (dark/light/system) +// - Density token application +// - Accessibility (ARIA, focus management) +// - Keyboard shortcuts +``` + +**Adapter exports:** +- `KbxButton`, `KbxInput`, `KbxSelect`, `KbxDialog`, etc. +- `useGridTheme()` for AG Grid configuration +- `useDesignToken(name)` for CSS custom properties + +### State Management (Contract-Based) + +| State | Owner | Tool | Registry Link | +|-------|-------|------|---| +| API responses, cache, stale, retry | TanStack Query | @tanstack/vue-query | → OpenAPI contracts | +| Session, role, UI preferences | Global Pinia | `authStore`, `registryStore` | → PermissionDefinition | +| Form values, errors, touched | Form library | vee-validate + Zod | → Screen.forms contract | +| URL filters, pagination, sorting | Router | vue-router query/params | → ScreenDefinition.grid | +| Large data tables | Server-side row model | AG Grid server mode | → GridDefinition contract | + +**Rules:** +- ❌ Do NOT duplicate API responses in Pinia (use TanStack Query cache) +- ❌ Do NOT write error handling in every screen (use ErrorBoundary + QueryStateBoundary) +- ✅ DO cache only session/auth data in Pinia (global, cross-screen) +- ✅ DO use TanStack Query for all API state + +### Component Elevation Criteria + +Promote to `shared/ui/components/` only when: +1. **Same business meaning & permissions** across 3+ consumers +2. **Repeated state/error handling logic** (not 1-off variations) +3. **Accessibility & testing** fully implemented +4. **Contract-driven** (implements @kbx/contracts interface) + +**Always-Shared Components (KBX System):** +- `QueryStateBoundary` (loading/error/empty) +- `PermissionGuard` (RBAC via registry) +- `ScreenHeader` (title, help, export buttons from registry) +- `AgGridShell` (AG Grid adapter with density tokens) +- `KbxStatus` (status display per contract) +- `KbxHelpPanel` (registry-driven help) +- `SkeletonLoader` (animated shimmer while loading) +- `EmptyStatePlaceholder` (zero-record state) + +--- + +## v16.0 Observability + +### Logging (Serilog) + +**Correlation & Structure:** +- All logs tagged with `CorrelationId`, `JobRunId`, `EvidenceId` +- Structured properties enable filtering and analysis +- Sensitive data (PII, tokens, API keys) NEVER logged (use redaction middleware) + +**Log Levels:** +- **INFO:** User actions, job completion, state changes +- **DEBUG:** Internal flow, decision branches, cache hits/misses +- **WARN:** Recoverable issues, retries, fallback activation +- **ERROR:** Unrecoverable failures, requires alert + +### Tracing & Metrics (OpenTelemetry) + +**Spans:** HTTP requests, database queries, job execution, event processing, policy decisions + +**Metrics:** Instrumented for: +- Job completion time, queue depth +- Query latency, row count +- Event throughput, retry rate + +### Operational Dashboards (Priority Order) + +1. **Batch SLA:** Job completion times, queue depths (`q-customer-sla` vs `q-research`) +2. **Data Quality Quarantine:** Jobs marked `dq` for manual review +3. **Duplicate Detection:** Outbox duplicate events +4. **Reconciliation Breaks:** State mismatch (Evidence vs current) +5. **Model Drift:** OOS (out-of-sample) performance metrics + +--- + +## v16.0 Common Workflows + +### Adding a New Vertical Slice + +**Before Code:** +1. Scaffold: `python tools/scaffold_vertical_slice.py --name MyFeature --module ModelOperations` +2. Define contract: Request/Response DTOs, Event schema, Validation rules + +**Backend Implementation:** +1. Handler: Orchestration, transaction handling +2. Policy: Pure business logic +3. Sql: Dapper queries (schema-qualified, explicit columns, PIT) +4. Endpoint: HTTP routing & status codes +5. Tests: Unit (Policy), Integration (Handler + Sql + real DB) +6. README.md: Traceability link + +**Frontend Implementation:** +1. Feature registry: `ScreenDefinition` entry +2. Pages: Router-level components under `features//pages/` +3. Components: Feature-scoped under `features//components/` +4. Stores/Composables: Feature-specific state and logic +5. Form validation: vee-validate + Zod schema from BE contract + +**Pre-Merge Validation Gates:** +- Architecture tests pass +- DB migration is idempotent (fresh/upgrade/re-run/failure tests) +- No SELECT *, no cross-module queries +- Outbox/Inbox tests if async +- Frontend typecheck + test + build passes +- E2E smoke test (if user-facing) + +### Refactoring (Characterized, Isolated, Verified) + +1. **Characterize:** Lock current behavior with tests, perf baseline, Golden data +2. **Isolate:** Separate I/O (Dapper, HTTP) from logic (Policy) +3. **Transform:** One small change at a time (rename, extract, move) +4. **Verify:** All tests pass, no perf regression, algorithm changes vs Golden +5. **Simplify:** Delete dead abstractions, feature flags, branches +6. **Observe:** Post-release monitoring (SLO, data quality, model drift) +7. **Close Debt:** Update Tech Debt Register, leave ADR + +### Creating a Background Job + +1. **Define command:** + ```csharp + public class MyJobCommand : ICommand + { + public string IdempotencyKey { get; set; } + public Guid CorrelationId { get; set; } + } + ``` + +2. **Implement handler:** + - Idempotent: re-run = same result + - Classify failures: transient/permanent/dq/business-hold + - Emit to Outbox on success + +3. **Schedule via Hangfire:** + ```csharp + await backgroundJobClient.EnqueueAsync(h => h.Handle(command, CancellationToken.None)); + ``` + +4. **Test scenarios:** + - Normal execution + - Retry on transient failure + - Replay from cold state (idempotency verification) + - Data quality quarantine diff --git a/CLAUDE.md b/CLAUDE.md index f3b30501..8807dd54 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,16 +21,12 @@ If any section below conflicts with AGENTS.md, AGENTS.md is authoritative and th **When working: Always check AGENTS.md first. CLAUDE.md is supplementary context only.** -## ⚖️ Governance: AGENTS.md v16.0 Strategic Principles +## ⚖️ Governance -**All work — code changes, refactors, new features, tooling — must follow AGENTS.md v16.0 guidelines:** +**→ See AGENTS.md v16.0 for all engineering guidelines, procedures, decision criteria, and guardrails.** -- **13 Decision Criteria:** SOLID, complexity, data integrity, necessity-driven, normalization, simplicity, patterns, guardrails, traceability, reliability, maturity, right-way, tech debt -- **Work Checklist:** Every task must self-assess against 13-item decision framework before implementation -- **Anti-Patterns (Blockers):** Never gold-plate, never skip testing, never SELECT *, never magic numbers, never direct module-to-module table access -- **Tech Debt:** Recorded in registry with Impact/Effort; 20% quarterly paydown target - -**Reference:** See `AGENTS.md` section "v16.0 Strategic Architecture & Engineering Excellence" for full framework. +This document is **project context only** (status, timeline, architecture overview). +All work follows AGENTS.md v16.0 exclusively. ## 📅 WBS Optimization Principle (Critical) @@ -239,951 +235,62 @@ Database is accessed through SSH tunnel only. ## Architecture -### Backend: Modular Monolith + Vertical Slices +**→ See `docs/ARCHITECTURE_DETAILED.md` for comprehensive backend & frontend design patterns.** -#### Module Structure -``` -src/ - KArtSell.Host/ # Main ASP.NET Core app - KArtSell.BuildingBlocks/ # Shared infrastructure (logging, serialization, extensions) - KArtSell.DbMigrator/ # DbUp migrations - KArtSell.Modules.ModelOperations/ # Model lifecycle, validation, activation - KArtSell.Modules.SignalEngine/ # Trading signal generation -``` +**High-level overview:** +- **Backend:** Modular Monolith with Vertical Slices (Endpoint → Handler → Policy → Sql) + - No generic repositories; each slice writes explicit Dapper queries + - DbUp migrations; Outbox/Inbox async coupling; Hangfire jobs +- **Frontend:** Vue 3 + KBX Foundation v4 (registry-driven) + - Screen registry is single source of truth (contracts, permissions, help) + - UI adapter boundary isolates PrimeVue/AG Grid (framework-agnostic) + - State per contract: TanStack Query (API cache), Pinia (auth/registry), vee-validate (forms) -#### Vertical Slice Template -Each feature is a complete, self-contained slice from HTTP endpoint to database, located under `Features//`: +## Testing & Observability -``` -Features// - Endpoint.cs # FastEndpoints route handler (HTTP/contract/status codes) - Request.cs # Input model with validation via Zod-like pattern - Response.cs # Output model (DTO) - Validator.cs # Fluent/Policy validation rules - Handler.cs # Use case orchestration (Application layer) - Policy.cs # Pure business decision logic (Domain layer) - Sql.cs # Dapper queries (Data layer) - Mapper.cs # Entity ↔ DTO mapping - Jobs/ # Related Hangfire jobs - Contracts/ # Event/Job contract definitions - Tests/ # Unit/integration tests specific to this slice - README.md # Traceability: requirements, ADRs, assumptions -``` +**→ See AGENTS.md v16.0 for testing strategy, observability guidelines, and operational dashboards.** -**Key rule:** Endpoint handles HTTP concerns (routing, negotiation); Handler handles transaction boundaries; Policy makes decisions; Sql uses Dapper for explicit, schema-qualified queries. +**Quick reference:** +- Backend: xUnit (Unit/Integration/Data/E2E/Golden) +- Frontend: Vitest + Playwright E2E +- Observability: Serilog (structured logs), OpenTelemetry (tracing), Telegram alerts -#### Design Principles -- **No Generic Repository:** Each slice writes its own Dapper queries; promotes clarity. -- **No Service Layer:** Handler + Policy + Sql replaces it; keeps flow visible. -- **Module Isolation:** Modules do not query each other's source tables directly. - - Synchronous: Use narrow Read Port services. - - Asynchronous: Use Outbox/Inbox event patterns. -- **PIT (Point-in-Time) Queries:** Must include `WHERE published_at <= cutoff` and revision resolver. -- **Evidence & Audit:** Update/delete are blocked; new state appended as new revision. -- **Migrations:** `src/KArtSell.DbMigrator` uses DbUp; file naming: `NNNN_description.sql`. Each module has ordered, checksummed migrations. +## Gitea API & External Data Sources -### Frontend: Vue 3 + Vite + KBX Foundation v4 (Operational Navigation) +**→ See `docs/GITEA_API_REFERENCE.md` for detailed Gitea API, Actions Secrets, and External Data APIs (KRX, OpenDart).** -#### Directory Layout (Registry-Driven) -``` -frontend/src/ - app/ - router.ts # Vue Router setup (page-level only) - installKbx.ts # KBX system initialization (registry, contracts, permissions) - features/ - / - routes.ts # Feature route definitions (lazy-loaded) - registry.ts # Screen registry entry (@kbx/contracts.ScreenDefinition) - pages/ - .vue # Page component (matches registry.screenId) - components/ # Feature-scoped components (not shared) - stores/ # Pinia stores (feature state) - composables/ # Reusable hooks (feature logic) - types/ # TS interfaces for this feature - shared/ - ui/ - adapter/ # MANDATORY boundary: PrimeVue/AG Grid wrappers - PrimeVueAdapter.ts #