// CVNTrade — Structurizr DSL workspace
//
// Phase 2 of #593. Single-source-of-truth model for system architecture.
// Render with: structurizr-cli or the VS Code "Structurizr DSL" extension.
// See architecture/README.md for tooling.
//
// Scope (initial): System Context + Containers. Components are added ad-hoc
// per-ADR as deeper diagrams become necessary.

workspace "CVNTrade" "Crypto trading platform with ML-driven signals." {

    model {
        // ───────────────────────── Actors
        operator = person "Operator" "Solo founder running the platform end-to-end: product, engineering, on-call."

        // ───────────────────────── The system under description
        cvntrade = softwareSystem "CVNTrade Platform" "ML-driven crypto trading: discovery → PTE tuning → backtest → paper/live trading." {

            frontend = container "Trading Frontend" "React SPA. Operator UI for run monitoring, PDF reports, trading dashboards." "React"
            configConsole = container "Configuration Console" "Next.js app — parameter editor, catalog admin, runs, audit trail, real-time worker dashboard (CVN-N008-EA/EB)." "Next.js, shadcn/ui, TypeScript, Zod"
            api = container "Trading API" "FastAPI. Serves Trading Frontend + exposes internal operations." "Python, FastAPI"
            configApi = container "Configuration API" "Validated writes to ftf_config / variable_catalog / parameter_sets; RBAC + approval workflow; publishes change notifications (CVN-N008)." "Next.js API Routes or FastAPI"
            airflow = container "Airflow" "Orchestrates DAGs: discovery, PTE tuning (FTF), single/portfolio backtest, model train, paper trading." "Python, Airflow 2.10" {
                // ───── Training harness components (ADR-89, PR #891 + #898)
                orchestrator = component "AutonomousOrchestrator" "Cache-aware coordinator. _create_autonomous_trainer dispatches on MODEL_REGISTRY / ENSEMBLE_REGISTRY (no per-model branching)." "Python"
                autonomousModelTrainer = component "AutonomousModelTrainer" "Generic cache-aware wrapper. Calls harness.train_one(model_type, …) for ANY registered model. No per-model file." "Python"
                autonomousEnsembleTrainer = component "AutonomousEnsembleTrainer" "Generic cache-aware wrapper. Calls harness.train_ensemble(name, …) for ANY registered ensemble." "Python"
                modelRegistry = component "MODEL_REGISTRY" "Plugin registry of single-model Hamilton DAGs (XGB / LGB / CB / future). Populated by convention scan over dags/models/*.py." "Python dict"
                ensembleRegistry = component "ENSEMBLE_REGISTRY" "Plugin registry of ensemble Hamilton DAGs (blend_avg / stack_logreg / stack_xgb_meta / future). Populated by convention scan over dags/ensembles/*.py." "Python dict"
                trainOne = component "train_one(model_name, datasets, hpo)" "Canonical entry point — materialises a Hamilton driver over the per-model DAG, returns a TrainedArtifact." "Hamilton driver"
                trainEnsemble = component "train_ensemble(name, datasets, hpo)" "Canonical entry point — materialises a Hamilton driver over the per-ensemble DAG (which composes N base train_one calls)." "Hamilton driver"
                modelDags = component "dags/models/*_dag.py" "One file per model. Declares Hamilton nodes (native, adapter, metrics, artifact) + the per-model HPO search space. Adding a new model = drop a file." "Hamilton DAG"
                ensembleDags = component "dags/ensembles/*_dag.py" "One file per ensemble. Composes N base TrainedArtifacts via Hamilton dependency resolution." "Hamilton DAG"
                harnessAdapters = component "adapters/{xgb,lgb,cb,ensemble}.py" "predict_proba(X) -> (n, 2) Protocol implementations wrapping the native handles. Backtest engine consumes these directly via _HarnessAdapterShim." "Python Protocol"
                harnessNodes = component "nodes/{class_balance,eval_metrics,theta_sweep,log_emit,hpo_optuna}.py" "Reused Hamilton-pure functions — the 85% shared code. Single canonical θ-sweep, single metrics calculator, single logging schema." "Python"
            }
            runtime = container "Runtime" "Standalone trading kernel. Same logic for paper + live per ADR-39/40. Subscribes to configuration changes for hot-reload at safe boundaries (CVN-N008-ED)." "Python"
            mlflow = container "MLflow" "Model registry + experiment tracking. Source of truth for model versions + origin-story tags (ADR-23)." "Python, MLflow, PostgreSQL, S3"
            postgres = container "PostgreSQL" "Config (ftf_config per ADR-59), run results, MLflow backend." "Scaleway managed PG" "database"
            redis = container "Redis" "Cache L1 (hot features, signal state)." "Redis 7" "database"
            grafana = container "Grafana" "Observability single entry point per ADR-26 — logs via Loki, metrics via Prometheus, traces via Tempo." "Grafana"
            openproject = container "OpenProject CE" "Product source of truth — Need / Epic / Story / Release tracking (#593 Phase 1)." "Ruby on Rails, PostgreSQL"
            docs = container "Documentation site" "MkDocs Material — blueprint, ADRs, runbooks, templates." "MkDocs, Material"
        }

        // ───────────────────────── External systems
        binance = softwareSystem "Binance" "OHLCV + order execution." "external"
        scaleway = softwareSystem "Scaleway" "Kapsule K8s, managed PG, managed Redis, Object Storage, Registry." "external"
        github = softwareSystem "GitHub" "Source control, CI, Issues, PR review (CodeRabbit)." "external"
        letsencrypt = softwareSystem "Let's Encrypt" "TLS certs via cert-manager." "external"

        // ───────────────────────── Relationships — operator
        operator -> frontend "Views runs, reports, dashboards"
        operator -> configConsole "Edits parameters, manages catalog, approves changes (CVN-N008)"
        operator -> airflow "Triggers launchers"
        operator -> grafana "Watches observability"
        operator -> openproject "Manages Needs / Epics / Stories"
        operator -> docs "Reads blueprint + ADRs"
        operator -> github "Opens PRs, reviews changes"

        // ───────────────────────── Relationships — inside the system
        frontend -> api "REST/JSON"
        api -> postgres "SQL"
        api -> mlflow "Registry + run metadata"
        configConsole -> configApi "REST/JSON, Zod-validated"
        configApi -> postgres "CRUD on ftf_config / variable_catalog / parameter_sets (CVN-N008)"
        configApi -> postgres "NOTIFY config_changed on write (CVN-N008-ED)"
        // ───────────────────────── Relationships — training harness internals (ADR-89)
        orchestrator -> modelRegistry "Looks up registered single-model DAGs"
        orchestrator -> ensembleRegistry "Looks up registered ensemble DAGs"
        orchestrator -> autonomousModelTrainer "Instantiates with model_type when in MODEL_REGISTRY"
        orchestrator -> autonomousEnsembleTrainer "Instantiates with ensemble_name when in ENSEMBLE_REGISTRY"
        autonomousModelTrainer -> trainOne "Delegates training to the canonical entry point"
        autonomousEnsembleTrainer -> trainEnsemble "Delegates training to the canonical entry point"
        trainOne -> modelDags "Hamilton driver materialises the per-model DAG"
        trainEnsemble -> ensembleDags "Hamilton driver materialises the per-ensemble DAG"
        ensembleDags -> trainOne "Composes N base model trainings (Hamilton dep resolution)"
        modelDags -> harnessAdapters "Wraps native handles with predict_proba shim"
        modelDags -> harnessNodes "Reuses class_balance, theta_sweep, eval_metrics, log_emit, hpo_optuna"
        ensembleDags -> harnessAdapters "Builds EnsembleAdapter wrapping N base adapters"
        ensembleDags -> harnessNodes "Reuses theta_sweep, eval_metrics, log_emit"

        airflow -> postgres "Reads ftf_config, writes run results"
        airflow -> postgres "INSERT parameter_sets (immutable) on DAG trigger (CVN-N008-EC)"
        airflow -> mlflow "Logs runs, registers models"
        airflow -> redis "Feature cache"
        runtime -> binance "OHLCV stream + order exec"
        runtime -> mlflow "Loads promoted model"
        runtime -> postgres "Persists positions + PnL"
        runtime -> postgres "LISTEN config_changed; reads parameter_sets snapshot (CVN-N008-ED)"
        runtime -> grafana "Emits logs + metrics + traces (ADR-26, 62). Metrics tagged with active config_version_id (CVN-N008-ED)"
        configApi -> grafana "Emits audit-log events + distribution latency metrics"
        airflow -> grafana "Emits logs + metrics + traces"

        // ───────────────────────── Relationships — external
        cvntrade -> scaleway "Runs on Kapsule + managed DBs + object storage"
        cvntrade -> github "Source, CI/CD" "HTTPS"
        cvntrade -> letsencrypt "TLS issuance via cert-manager" "ACME"
    }

    views {
        systemContext cvntrade "SystemContext" {
            include *
            autolayout lr
            description "Who uses CVNTrade and what external systems it depends on."
        }

        container cvntrade "Containers" {
            include *
            autolayout lr
            description "Services inside the CVNTrade platform + their primary data flows."
        }

        container cvntrade "ConfigurationPlatform" {
            include configConsole configApi postgres airflow runtime grafana operator
            autolayout lr
            description "CVN-N008 Unified Configuration Platform — write path (Console → API → PG), runtime distribution (PG → LISTEN/NOTIFY → Runtime), observability (all → Grafana)."
        }

        component airflow "TrainingHarness" {
            include orchestrator modelRegistry ensembleRegistry autonomousModelTrainer autonomousEnsembleTrainer trainOne trainEnsemble modelDags ensembleDags harnessAdapters harnessNodes
            autolayout lr
            description "ADR-89 — Training harness as plugin registry. Single canonical training path for every model + ensemble. Adding a new model = drop a DAG file under dags/models/. PR #891 + #898."
        }

        styles {
            element "Person" {
                background #08427b
                color #ffffff
                shape person
            }
            element "Software System" {
                background #1168bd
                color #ffffff
            }
            element "Container" {
                background #438dd5
                color #ffffff
            }
            element "external" {
                background #999999
                color #ffffff
            }
            element "database" {
                shape cylinder
            }
        }
    }
}
