18 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
K-ArtSell Aegis v16.0 is a complex financial/investment advisory system built on a Modular Monolith with Vertical Slice architecture. It enforces strict execution completeness, evidence preservation, and controlled model operations—not production-ready until all validation gates (252+ trading days shadow, OOS testing, PBO/DSR verification) pass.
Status: IMPLEMENTATION_TEMPLATE / STATIC_VALIDATED / BUILD_DB_E2E_SHADOW_REHEARSAL_REQUIRED
Quick Start
Prerequisites
- .NET 10 SDK
- Node.js 22 / pnpm 10
- SSH access to remote PostgreSQL server (178.104.200.7)
Remote PostgreSQL Setup via SSH Port Forwarding
The project database is hosted on 178.104.200.7. Connect via SSH port forwarding:
ssh -L 5432:127.0.0.1:5432 kjh2064@178.104.200.7
This command:
- Forwards local port 5432 to remote PostgreSQL (127.0.0.1:5432)
- Keeps the tunnel open while you develop
- Run in a separate terminal/window and keep it running during development
Windows (PowerShell):
ssh -L 5432:127.0.0.1:5432 kjh2064@178.104.200.7
macOS/Linux:
ssh -L 5432:127.0.0.1:5432 kjh2064@178.104.200.7
Once the tunnel is open, your local localhost:5432 connects to the remote database.
Local Development Environment
# Backend: restore, build, migrate, test
dotnet restore KArtSell.sln
dotnet build KArtSell.sln -c Release
dotnet run --project src/KArtSell.DbMigrator -c Release
# Run backend tests
dotnet test KArtSell.sln -c Release --logger trx
# Run a single test
dotnet test --filter "FullyQualifiedName=MyNamespace.MyTest.TestMethod" -c Release
# Frontend: install, typecheck, test, build
cd frontend
pnpm install --frozen-lockfile
pnpm typecheck
pnpm test
pnpm build
# Run frontend E2E tests
pnpm exec playwright install --with-deps chromium
pnpm e2e
# Run dev server (watch mode, hot reload)
pnpm dev # Backend in another terminal
Database Connection
Host: localhost
Port: 5432
Database: kartsell
User: kartsell
Password: kartsell
Environment variable: KARTSELL_POSTGRES=Host=localhost;Port=5432;Database=kartsell;Username=kartsell;Password=kartsell
On Windows (PowerShell):
$env:KARTSELL_POSTGRES="Host=localhost;Port=5432;Database=kartsell;Username=kartsell;Password=kartsell"
On macOS/Linux (bash):
export KARTSELL_POSTGRES="Host=localhost;Port=5432;Database=kartsell;Username=kartsell;Password=kartsell"
Architecture
Backend: Modular Monolith + Vertical Slices
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
Vertical Slice Template
Each feature is a complete, self-contained slice from HTTP endpoint to database, located under Features/<SliceName>/:
Features/<SliceName>/
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
Key rule: Endpoint handles HTTP concerns (routing, negotiation); Handler handles transaction boundaries; Policy makes decisions; Sql uses Dapper for explicit, schema-qualified queries.
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 <= cutoffand revision resolver. - Evidence & Audit: Update/delete are blocked; new state appended as new revision.
- Migrations:
src/KArtSell.DbMigratoruses DbUp; file naming:NNNN_description.sql. Each module has ordered, checksummed migrations.
Frontend: Vue 3 + Vite + Modular Feature Structure
Directory Layout
frontend/src/
app/ # Core app initialization, routing, config
features/ # Feature modules (one per business capability)
<feature>/
components/ # Scoped to this feature
pages/ # Route-level pages
stores/ # Pinia stores (state management)
composables/ # Reusable logic (Vue 3 hooks)
types/ # TS interfaces for this feature
shared/
ui/
adapter/ # PrimeVue/AG Grid wrappers (mandatory boundary)
components/ # Common components (QueryStateBoundary, PermissionGuard, CrudForm, etc.)
layouts/ # Page layout templates
crud/ # Generic CRUD form logic
composables/ # Global composables (useFetch, useAuth, etc.)
types/ # Global types, contracts
stores/ # Global Pinia stores (auth, user, preferences)
design-system/ # Design tokens, typography, color scales (PrimeVue theme overrides)
State Management Rules
| State | Owner | Tool |
|---|---|---|
| API responses, cache, stale, retry | TanStack Query | @tanstack/vue-query |
| Session, role, UI preferences | Global store | Pinia |
| Form values, errors, touched | Form library | vee-validate + Zod |
| URL filters, pagination, sorting | Router | vue-router query/params |
| Large data tables, virtual scroll | Server-side row model | AG Grid server mode |
Anti-patterns:
- Do NOT duplicate API responses in Pinia.
- Do NOT write 401/409/422/429/503 error handling in every screen.
- Do NOT manage query cache manually; let TanStack Query handle it.
Component Elevation Criteria
Promote to shared/ui/components/ only when:
- Same business meaning & permissions (not just visual similarity).
- Repeated state/error handling logic across 3+ consumers.
- Accessibility & testing already fully implemented.
Always-shared components:
QueryStateBoundary(loading/error/empty states)PermissionGuard(RBAC enforcement)CrudForm(standard CRUD form)VersionConflictDialog(optimistic concurrency)DataFreshnessBadge(cache/stale indicators)DataGridShell(AG Grid wrapper with sorting, filtering, export)
Database & Migrations
DbUp
- Run at startup:
KArtSell.DbMigratoris the single source of truth. - Schema ownership: Each module owns its schema (e.g.,
model_operations.*,signal_engine.*). - Safety: Migrations are idempotent and checksummed; failed migration rolls back and waits for manual intervention.
- Test: Each migration has fresh/upgrade/re-run/failure-recovery tests in CI.
Query Patterns
// DO: Schema-qualified, explicit columns, 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
""";
// DON'T: SELECT *, generic repository, no token
const string sql = "SELECT * FROM signals WHERE status = @status";
Async Coupling: Outbox/Inbox
- Outbox: When a command succeeds, events are inserted into
outboxin the same transaction. - Inbox: A Hangfire job polls the outbox, publishes events, and marks them as processed.
- Idempotency: Each inbox handler is idempotent; replayed events are no-ops.
Hangfire (Background Jobs & Scheduling)
Job Design
- Not a business decision maker: Hangfire executes approved Application Commands, not policies.
- Idempotency key: Each job must be replayable without side effects.
- Watermark & version set: Track input/output state across retries.
- Queue isolation:
q-customer-sla(business SLA) is separate fromq-research(non-critical). - Retry classification:
transient(network glitch, retry immediately)permanent(bad input, log & alert)dq(data quality issue, quarantine for manual review)business-hold(awaiting approval or external event)
Example Job Structure
public class MyJobCommand : ICommand
{
public string IdempotencyKey { get; set; }
public Guid JobRunId { get; set; }
public Guid CorrelationId { get; set; }
}
Jobs do not call other jobs directly; instead, they emit events or check readiness gates.
SignalR (Real-Time Push)
Used for live notifications (model activation events, approval notifications). Follows Hub/Group pattern with correlation to CorrelationId for traceability.
Testing Strategy
xUnit Backend Tests
Test Organization
tests/
KArtSell.ArchitectureTests/ # Compile-time architecture rules
KArtSell.ModelOperations.UnitTests/
KArtSell.SignalEngine.UnitTests/
KArtSell.Integration.Tests/ # E2E with real DB (if exists)
Test Levels
- Unit: Pure functions (Policy, Mapper), no I/O. Fast, deterministic.
- Integration: Handler + Dapper + real PostgreSQL. Validates transaction boundaries, Outbox/Inbox.
- Data: SQL query validation, schema conformance, index effectiveness.
- E2E: Full HTTP stack; used sparingly for critical paths.
- Golden/Frozen OOS: Before merging algorithm changes, lock baseline and diff against new run.
Run Tests
dotnet test KArtSell.sln -c Release
dotnet test --filter "Category=Integration" -c Release
dotnet test --filter "FullyQualifiedName~UnitTests" -c Release --verbosity quiet
Vitest Frontend Tests
cd frontend
pnpm test # Run all tests
pnpm test -- --reporter=verbose # Verbose output
pnpm test -- <test-file-pattern> # Run subset
pnpm test -- --coverage # Coverage report
Playwright E2E
cd frontend
pnpm e2e # Run all E2E tests headless
pnpm e2e -- --debug # Debug mode (browser stays open)
pnpm exec playwright test --headed # Run with browser UI
Observability
Logging
- Tool: Serilog with structured properties.
- Correlation: All logs are tagged with
CorrelationId,JobRunId,EvidenceId. - Sensitive data: PII, tokens, API keys are NEVER logged (use redaction middleware).
- Levels: INFO (user actions), DEBUG (internal flow), WARN (recoverable issues), ERROR (unrecoverable, alert required).
Tracing & Metrics
- Tool: OpenTelemetry for distributed tracing and metrics.
- Spans: HTTP requests, database queries, job execution, event processing.
- Alerts: Send to Telegram integration (configured in
KArtSell.Hoststartup).
Operational Dashboards (Priority Order)
- Batch SLA: Job completion times, queue depths (q-customer-sla vs q-research).
- Data Quality Quarantine: Jobs marked
dqby retry classifier. - Duplicate Detection: Outbox duplicate events.
- Reconciliation Breaks: Mismatch between expected and actual state (Evidence vs current).
- Model Drift: OOS (out-of-sample) performance metrics.
Common Workflows
Adding a New Vertical Slice
-
Scaffold the structure:
python tools/scaffold_vertical_slice.py --name MyFeature --module ModelOperations -
Define the contract (before code):
- Request/Response DTOs in
Contracts/ - Event schema in
Contracts/Events/if async coupling needed - Validation rules (vee-validate schema on FE, Fluent on BE)
- Request/Response DTOs in
-
Implement backend slice:
Handler.cs: Orchestration, transaction handlingPolicy.cs: Pure business logicSql.cs: Dapper queries (schema-qualified, no SELECT *)Endpoint.cs: HTTP routing & status codesREADME.md: Traceability link to requirement/ADR
-
Write tests:
- Unit: Policy, Mapper logic
- Integration: Handler + Dapper + real DB
- Verify Outbox events are created if async
-
Implement frontend feature:
- Feature module under
features/<feature>/ - Use
features/<feature>/pages/for route-level components - Use
shared/ui/adapter/for any UI component usage - Form validation with vee-validate + Zod schema from BE contract
- Feature module under
-
Validation gates (pre-merge):
- Architecture tests pass
- DB migration is idempotent (fresh/upgrade test)
- No SELECT *, no direct cross-module queries
- Outbox/Inbox tests if async
- Frontend typecheck + test + build
- E2E smoke test (if user-facing)
Refactoring (Characterized, Isolated, Verified)
- Characterize: Lock current behavior with tests + perf baseline + Golden data.
- Isolate: Separate I/O (Dapper queries, HTTP) from logic (Policy).
- Transform: One small change at a time (rename, extract, move).
- Verify: All tests pass, no perf regression, backtest algorithm changes against Golden.
- Simplify: Delete dead abstractions, feature flags, branches.
- Observe: Post-release SLO/DQ/model drift monitoring.
- Close Debt: Update Debt ID, leave ADR for future maintainers.
Creating a Background Job
-
Define the command:
public class MyJobCommand : ICommand { public Guid IdempotencyKey { get; set; } public Guid CorrelationId { get; set; } public string InputData { get; set; } } -
Implement the handler:
- Idempotent: Re-run should be safe and produce same result.
- Classify failures: transient/permanent/dq/business-hold.
- Emit events to Outbox for async notifications.
-
Schedule via Hangfire:
await backgroundJobClient.EnqueueAsync<MyJobHandler>(h => h.Handle(command)); -
Test retry & replay scenarios:
- Job runs successfully.
- Job fails and is retried (verify idempotency).
- Job is replayed from cold state (verify determinism).
Guardrails & Anti-Patterns
Coding Standards (from VIBE_CODING_GUARDRAILS.md)
Before requesting code changes, ensure these 8 inputs are present:
- Source: Reference policy, ADR, data contract, requirement ID
- Slice Spec: User goal, non-goal, state transitions, RBAC
- Screen Spec: Component tree, state management, a11y
- Contract: Endpoint paths, event schemas, HTTP status codes, ETag/idempotency handling
- Data: Schema, columns, PIT conditions, migration, index plan
- Tests: Unit/integration/data/E2E/Golden scenarios + failure cases
- Ops: Metrics, alerts, runbooks, rollback procedure, on-call owner
- Output Rule: Changed files, commands to verify, assumptions, residual risks
Blocking Rules
- No undocumented policy IDs or thresholds. Every numeric constant must trace to a requirement.
- Pending decisions: Mark with
DECISION_REQUIREDorDESIGN_PROPOSALcomment. - One PR = one slice or one refactoring goal. No mixing feature work + unrelated cleanup.
- Feature changes ≠ refactoring. Separate PRs: feature, then refactoring, then verify.
- Never hide failing/skipped tests. If a test fails, fix it or raise an issue.
- SQL review: Generated SQL must pass schema owner review, PIT validation, index analysis.
- Algorithm changes: Never merge without Golden/Frozen OOS diff showing no regression.
- Real customer data: Never include in prompts, fixtures, or logs.
Model Operations Specifics
- Model lifecycle: Freeze → Mature → Score → Diagnose → Hypothesis → Challenger → Validate → Review → Manual Activation. No auto-learning, auto-promotion, or auto-ordering.
- Sell priority:
HARD_IMPAIRMENT → PORTFOLIO_SURVIVAL → DYNAMIC_PROFIT_FLOOR → CONCENTRATION/LIQUIDITY → OPPORTUNITY_COST → REENTRY_OPTION(immutable). - Non-value-loss sell: Requires ReentryWatch, new CycleId/Lot, step intervals, expiry, dedup.
- Activation gating: Every model activation requires ModelCard, OOS/PBO/DSR evidence, maker-checker approval, effective_at timestamp, rollback justification.
Tools & Scripts
Scaffolding
python tools/scaffold_vertical_slice.py --name MyFeature --module ModelOperations
python tools/scaffold_ui_screen.py --name MyScreen --feature MyFeature
Validation
python tools/validate_v16.py # Full v16 validation (contracts, migrations, Python tests)
python -m unittest discover # Run all Python unit tests
FastEndpoints
- Docs: FastEndpoints GitHub
- Pattern: Each endpoint maps to a Vertical Slice; routes are discovered automatically.
Documentation & Resources
Key Documents
docs/03_ARCHITECTURE_BE_FE.md— Modular Monolith, Vertical Slice, Dapper, Hangfire, FE state ownership rules.docs/06_VIBE_CODING_GUARDRAILS.md— AI input packets, blocking rules, refactoring methodology.contracts/ui/ui-adapter.v3.json— FE adapter contract (PrimeVue/AG Grid wrapper boundaries).contracts/schedules/model-operations.v3.json— Job scheduling contract.README.md— Project status, v16 delta, validation gates.
Contracts Directory
contracts/
ui/ # Frontend adapter & component contracts
schedules/ # Job scheduling contracts
data/ # Domain data models (PIT envelope, projection)
events/ # Async event schemas
metrics/ # Outcome metrics schema
Validation Gates (Not Yet Passed)
Do NOT claim production readiness until:
.NET 10 restore/build/teston CI passes consistentlypnpm frozen install/typecheck/Vitest/build/Playwrighton CI passes- PostgreSQL DbUp fresh/upgrade/re-run/failure-recovery tests pass
- Outbox/Inbox crash-recovery & audit reconciliation rehearsal passes
- 252+ trading-day shadow run with OOS at multiple market phases
- PBO (probability of backtest overfit) and DSR (daily sharpe ratio) evidence
Before all gates pass: No production deployment, no advisory-with-automation, no auto-ordering, no auto-model-promotion.