diff --git a/.github/workflows/diagram-nightly.yml b/.github/workflows/diagram-nightly.yml index b5395dd545..dd0f7cc514 100644 --- a/.github/workflows/diagram-nightly.yml +++ b/.github/workflows/diagram-nightly.yml @@ -45,30 +45,30 @@ jobs: - name: Validate rendered artifacts (DIAG-T010..T012) run: | - python3 scripts/check_diagram_artifacts.py \ + python3 scripts/diagrams/check_diagram_artifacts.py \ --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt - name: Validate SVG text visibility (DIAG-T014..T015) run: | - python3 scripts/check_svg_text_visibility.py \ + python3 scripts/diagrams/check_svg_text_visibility.py \ --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt - name: Visual smoke baseline drift (DIAG-T026) run: | - python3 scripts/check_diagram_visual_smoke.py \ + python3 scripts/diagrams/check_diagram_visual_smoke.py \ --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt - name: Run PR quality-gates baseline (DIAG-T018..T023) run: | mkdir -p reports/diagrams - python3 scripts/check_diagram_quality_gates.py \ + python3 scripts/diagrams/check_diagram_quality_gates.py \ --manifest docs/02-architecture/mmd-diagrams/quality-gate-manifest.txt \ --json-out reports/diagrams/diagram-quality-report-nightly.json \ --markdown-out reports/diagrams/diagram-quality-report-nightly.md - name: Run Phase 2 nightly suite (DIAG-T024..T029) run: | - python3 scripts/run_diagram_nightly_suite.py \ + python3 scripts/diagrams/run_diagram_nightly_suite.py \ --source-manifest docs/02-architecture/mmd-diagrams/quality-gate-manifest.txt \ --render-manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt \ --puppeteer /tmp/puppeteer-config.json \ @@ -138,7 +138,7 @@ jobs: - name: Validate Mermaid syntax run: | - bash scripts/validate_mermaid_syntax.sh \ + bash scripts/diagrams/validate_mermaid_syntax.sh \ --puppeteer /tmp/puppeteer-config.json - name: Canary render of reference source pool (DIAG-T030) @@ -162,7 +162,7 @@ jobs: run: | manifest_tmp="/tmp/diagram-canary-manifest.txt" find /tmp/diagram-canary/svg -type f -name '*.svg' | sort > "$manifest_tmp" - python3 scripts/check_svg_text_visibility.py --manifest "$manifest_tmp" + python3 scripts/diagrams/check_svg_text_visibility.py --manifest "$manifest_tmp" - name: Upload canary report artifacts if: always() diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 937bc1e2fc..65b1386a64 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -65,13 +65,13 @@ jobs: - name: Validate Mermaid diagrams (.mermaid + .mmd) run: | - bash scripts/validate_mermaid_syntax.sh \ + bash scripts/diagrams/validate_mermaid_syntax.sh \ --puppeteer /tmp/puppeteer-config.json - name: Diagram policy lint report (non-blocking) run: | - python3 scripts/lint_diagrams.py docs/02-architecture/mmd-diagrams --json > /tmp/diagram-lint.json || true - python3 scripts/summarize_diagram_lint.py /tmp/diagram-lint.json + python3 scripts/diagrams/lint_diagrams.py docs/02-architecture/mmd-diagrams --json > /tmp/diagram-lint.json || true + python3 scripts/diagrams/summarize_diagram_lint.py /tmp/diagram-lint.json - name: Upload diagram lint report uses: actions/upload-artifact@v4 @@ -114,17 +114,17 @@ jobs: - name: Validate rendered artifact existence (SVG/PNG) run: | - python3 scripts/check_diagram_artifacts.py \ + python3 scripts/diagrams/check_diagram_artifacts.py \ --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt - name: Validate SVG text visibility (edge labels and node text) run: | - python3 scripts/check_svg_text_visibility.py \ + python3 scripts/diagrams/check_svg_text_visibility.py \ --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt - name: Visual smoke regression (selected SVG baselines) run: | - python3 scripts/check_diagram_visual_smoke.py \ + python3 scripts/diagrams/check_diagram_visual_smoke.py \ --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt - name: Validate link harmonization post-processor @@ -134,7 +134,7 @@ jobs: - name: Diagram regression quality gates (DIAG-T018..T023) run: | mkdir -p reports/diagrams - python3 scripts/check_diagram_quality_gates.py \ + python3 scripts/diagrams/check_diagram_quality_gates.py \ --manifest docs/02-architecture/mmd-diagrams/quality-gate-manifest.txt \ --json-out reports/diagrams/diagram-quality-report.json \ --markdown-out reports/diagrams/diagram-quality-report.md diff --git a/.rollback/diagram-text-layer-20260301-151026/docs/02-architecture/mmd-diagrams/README.md b/.rollback/diagram-text-layer-20260301-151026/docs/02-architecture/mmd-diagrams/README.md new file mode 100644 index 0000000000..2aa9c2111b --- /dev/null +++ b/.rollback/diagram-text-layer-20260301-151026/docs/02-architecture/mmd-diagrams/README.md @@ -0,0 +1,345 @@ +# BioETL Architecture & Class Diagrams + +*Canonical diagram location — all `.mmd` sources live here.* + +> **Governance:** [ADR-040 — Diagram Governance and Layout Policy](../decisions/ADR-040-diagram-governance.md) +> Colour scheme, linkStyle differentiation, view decomposition rules, CI validation — all defined in ADR-040. + +All diagrams are in [Mermaid](https://mermaid.js.org/) format. +Canonical sources use `.mmd`; decomposed views use `.mermaid` in `views/`. +Render them with any Mermaid-compatible viewer, IDE plugin, or the [Mermaid Live Editor](https://mermaid.live/). + +--- + +## Architecture Diagrams (18 core) + +| # | Diagram | File | Description | +|---|---------|------|-------------| +| 1 | High-Level Hexagonal Architecture | `architecture/01-high-level-hexagonal.mmd` | Full system overview: layers, external systems, dependency directions | +| 2 | Layer Dependency Matrix | `architecture/02-layer-dependency-matrix.mmd` | ARCH-001 import boundary enforcement | +| 3 | Medallion Data Flow | `architecture/03-medallion-data-flow.mmd` | Bronze → Silver → Gold pipeline with DQ and quarantine | +| 4 | Pipeline Execution Flow | `architecture/04-pipeline-execution-flow.mmd` | Sequence diagram: preflight → lock → execute → postrun → cleanup | +| 5 | Provider Adapter Hierarchy | `architecture/05-provider-adapter-hierarchy.mmd` | All 7 provider adapters, base classes, mixins, decorators | +| 6 | Storage Layer | `architecture/06-storage-layer.mmd` | Bronze/Silver/Gold writers, Delta Lake, metadata, validation | +| 7 | Data Quality System | `architecture/07-dq-system.mmd` | DQ monitoring, analysis, anomaly detection, reporting | +| 8 | Composite Pipeline | `architecture/08-composite-pipeline.mmd` | Seed → dependencies → enrichers (parallel) → merge with FSM | +| 9 | Observability Stack | `architecture/09-observability-stack.mmd` | Logging, metrics, tracing: ports and implementations | +| 10 | Resilience Patterns | `architecture/10-resilience-patterns.mmd` | Circuit breaker, rate limiter, retry, health checks | +| 11 | Configuration System | `architecture/11-configuration-system.mmd` | YAML configs → loaders → Pydantic schemas → domain config | +| 12 | Bootstrap / DI Container | `architecture/12-bootstrap-di-container.mmd` | Composition root: factories, assembly, wiring | +| 13 | Port/Protocol Contracts | `architecture/13-port-protocol-contracts.mmd` | All 29 domain ports mapped to their implementations | +| 14 | CLI / Interface Layer | `architecture/14-cli-interface-layer.mmd` | CLI commands, routing to application services | +| 15 | BatchExecutor Internals | `architecture/15-batch-executor-internals.mmd` | Executor composition: transformer, writer, memory, metrics | +| 16 | Transformer Hierarchy | `architecture/16-transformer-hierarchy.mmd` | Template Method pattern, all provider transformers, extractors | +| 17 | Security, PII & Audit | `architecture/17-security-pii-audit.mmd` | PII hashing, salt rotation, audit trail | +| 18 | Lock, Checkpoint & Shutdown | `architecture/18-lock-checkpoint-shutdown.mmd` | Fencing tokens, safety guard, graceful shutdown | + +## Decomposed Architecture Diagrams + +Parent diagrams remain canonical references. Sub-files provide focused, low-density views for review and onboarding. + +| Parent (canonical) | Decomposed sub-files | +|---|---| +| `architecture/01-high-level-hexagonal.mmd` | `architecture/01a-hexagonal-overview.mmd`, `architecture/01b-hexagonal-domain-app.mmd`, `architecture/01c-hexagonal-infra-comp.mmd` | +| `architecture/03-medallion-data-flow.mmd` | `architecture/03a-medallion-layers-overview.mmd` | +| `architecture/05-provider-adapter-hierarchy.mmd` | `architecture/05a-adapter-hierarchy-base.mmd`, `architecture/05b-adapter-hierarchy-providers.mmd` | +| `architecture/12-bootstrap-di-container.mmd` | `architecture/12a-bootstrap-factories.mmd`, `architecture/12b-bootstrap-wiring.mmd` | +| `architecture/13-port-protocol-contracts.mmd` | `architecture/13a-port-contracts-data-sources.mmd`, `architecture/13b-port-contracts-storage.mmd`, `architecture/13c-port-contracts-observability.mmd`, `architecture/13d-port-contracts-services.mmd` | +| `architecture/13-port-protocol-contracts.mmd` (alternate slices) | `architecture/13a-data-storage-ports.mmd`, `architecture/13b-operational-ports.mmd`, `architecture/13c-validation-dq-ports.mmd` | + +## Class Diagrams (16 families) + +| # | Family | File | Description | +|---|--------|------|-------------| +| 1 | Domain Ports | `class-diagrams/01-domain-ports.mmd` | All 29 Protocol interfaces with method signatures | +| 2 | Entities & Aggregates | `class-diagrams/02-entities-aggregates.mmd` | BaseEntity, Batch, PipelineRun, BatchRecord | +| 3 | Value Objects | `class-diagrams/03-value-objects.mmd` | BronzeWriteResult, SilverWriteResult, FencingToken, etc. | +| 4 | Types & Enums | `class-diagrams/04-types-enums.mmd` | RunType, PublicationType, HealthStatus, NewTypes | +| 5 | Exceptions | `class-diagrams/05-exceptions.mmd` | BioETLError hierarchy: Critical, Recoverable, DataQuality | +| 6 | Configuration | `class-diagrams/06-config-classes.mmd` | PipelineConfig, RuntimeConfig, CompositeConfig | +| 7 | Application Core | `class-diagrams/07-application-core-services.mmd` | PipelineRunner, BatchExecutor, LockManager | +| 8 | Application Services | `class-diagrams/08-application-services.mmd` | DQ, Health, Export, Vacuum, Quarantine services | +| 9 | Transformers | `class-diagrams/09-transformers.mmd` | BaseTransformer → ChEMBL/Publication/UniProt/PubChem | +| 10 | Adapters | `class-diagrams/10-adapters.mmd` | BaseHttpAdapter, all provider adapters, resilience | +| 11 | Storage | `class-diagrams/11-storage.mmd` | BronzeWriter, SilverWriter, GoldWriter, DeltaReader | +| 12 | Composite Pipeline | `class-diagrams/12-composite-pipeline.mmd` | Runner, coordinators, merger, FSM | +| 13 | Domain Services | `class-diagrams/13-domain-services.mmd` | IdentityService, Normalization, UnitConverter | +| 14 | Observability | `class-diagrams/14-observability.mmd` | Logger, Metrics, Tracing implementations | +| 15 | Extractors | `class-diagrams/15-extractors.mmd` | BaseFieldExtractor, PubMed & UniProt extractors | +| 16 | Factories & Bootstrap | `class-diagrams/16-factories-bootstrap.mmd` | DataSourceRegistry, TransformerFactory, RunnerBuilder | + +## Foundation Diagrams (54) + +Historical/foundational diagrams consolidated from `docs/02-architecture/diagrams/`. + +### Foundation 01–25 + +| # | File | Description | +|---|------|-------------| +| 01a | `foundation/01-full-system-component.mmd` | Full system component diagram (C4-style) | +| 01b | `foundation/01-high-level.mmd` | High-level system overview | +| 02a | `foundation/02-full-medallion-data-flow.mmd` | Medallion architecture data flow (detailed) | +| 03a | `foundation/03-pipeline-execution-happy-path.mmd` | Pipeline execution sequence (happy path) | +| 04a | `foundation/04-domain-layer-class-diagram.mmd` | Domain layer ports, entities, config | +| 04b | `foundation/04-error-flow.mmd` | Error handling flow | +| 05a | `foundation/05-layers-interaction.mmd` | Layer interaction diagram | +| 05c | `foundation/05-pipeline-lifecycle-states.mmd` | Pipeline state machine | +| 06a | `foundation/06-application-layer-class-diagram.mmd` | Application layer classes | +| 06b | `foundation/06-pipeline-execution.mmd` | Pipeline execution flow | +| 07a | `foundation/07-circuit-breaker-states.mmd` | Circuit breaker state machine | +| 07b | `foundation/07-medallion-flow.mmd` | Medallion data flow | +| 08a | `foundation/08-complete-etl-workflow.mmd` | Complete ETL workflow | +| 08b | `foundation/08-domain-ddd.mmd` | Domain-driven design diagram | +| 09 | `foundation/09-full-er-diagram.mmd` | Entity-relationship diagram | +| 10 | `foundation/10-infrastructure-layer-class-diagram.mmd` | Infrastructure layer classes | +| 11 | `foundation/11-lock-acquisition-sequence.mmd` | Lock acquisition sequence | +| 12 | `foundation/12-local-deployment-architecture.mmd` | Local deployment architecture (ADR-010) | +| 13 | `foundation/13-domain-models-relationship.mmd` | Domain model relationships | +| 14 | `foundation/14-provider-health-states.mmd` | Provider health states | +| 15 | `foundation/15-dq-check-workflow.mmd` | Data quality check workflow | +| 16 | `foundation/16-memory-lock-class.mmd` | MemoryLock class diagram | +| 17 | `foundation/17-pipeline-hierarchy.mmd` | Pipeline/Transformer hierarchy | +| 18 | `foundation/18-bronze-write-sequence.mmd` | Bronze write sequence | +| 19 | `foundation/19-delta-lake-write-sequence.mmd` | Delta Lake write sequence | +| 20 | `foundation/20-quarantine-record-states.mmd` | Quarantine record states | +| 21 | `foundation/21-activity-entity-data-flow.mmd` | Activity entity data flow | +| 22 | `foundation/22-client-api-request-sequence.mmd` | Client API request sequence | +| 23 | `foundation/23-silver-writer-class.mmd` | SilverWriter class diagram | +| 24 | `foundation/24-hash-service-class.mmd` | Hash service class diagram | +| 25 | `foundation/25-circuit-breaker-observer-class.mmd` | CircuitBreaker class diagram | + +### Foundation 26–50 (TOP-25 Architecture) + +| # | File | Type | Description | +|---|------|------|-------------| +| 26 | `foundation/26-hexagonal-ports-adapters.mmd` | flowchart | Hexagonal Architecture — all 24 ports mapped to adapters | +| 27 | `foundation/27-import-matrix-enforcement.mmd` | flowchart | ARCH-001 Import Matrix — 5-layer dependency rules | +| 28 | `foundation/28-composition-root-di-graph.mmd` | flowchart | Composition Root DI Graph — full DI assembly | +| 29 | `foundation/29-composite-pipeline-workflow.mmd` | sequence | Composite Pipeline (ADR-026) — Seed→Deps→FanOut→Merge→Gold | +| 30 | `foundation/30-port-adapter-mapping.mmd` | flowchart | Port → Adapter Reference — all 24 ports | +| 31 | `foundation/31-pipeline-run-lifecycle.mmd` | state | PipelineRun Aggregate FSM | +| 32 | `foundation/32-single-record-journey.mmd` | flowchart | Single Record Journey — API→Bronze→Transform→Silver→Gold | +| 33 | `foundation/33-cli-run-interaction.mmd` | sequence | CLI → PipelineRunnerService interaction | +| 34 | `foundation/34-batch-processing-flow.mmd` | sequence | Batch Processing — BatchExecutor cycle | +| 36 | `foundation/36-architecture-principles-mindmap.mmd` | mindmap | Architecture Principles Mindmap | +| 37 | `foundation/37-cli-entry-full-chain.mmd` | sequence | CLI Entry → Exit Code full chain | +| 38 | `foundation/38-runtime-assembly-sequence.mmd` | sequence | Runtime Assembly — phases 1–8 | +| 39 | `foundation/39-medallion-invariants.mmd` | flowchart | Medallion Invariants — ARCH-007 RunType clear policy | +| 40 | `foundation/40-application-core-collaboration.mmd` | flowchart | Application Core — PipelineRunner orchestrating services | +| 41 | `foundation/41-error-classification-tree.mmd` | flowchart | Error Classification — HTTP→Domain→Actions | +| 42 | `foundation/42-pipeline-runner-class.mmd` | class | PipelineRunner Class — all 14 DI dependencies | +| 43 | `foundation/43-fan-out-fan-in-pattern.mmd` | sequence | Fan-Out/Fan-In — asyncio.gather parallel enrichment | +| 44 | `foundation/44-cross-provider-enrichment.mmd` | flowchart | Cross-Provider Enrichment — 5-provider publication flow | +| 46 | `foundation/46-yaml-config-resolution.mmd` | flowchart | YAML Config Resolution — hierarchical merge | +| 47 | `foundation/47-publication-merge-sources.mmd` | sequence | Publication Composite — multi-source merge | +| 48 | `foundation/48-composite-phase-lifecycle.mmd` | state | Composite Pipeline FSM — 10-state lifecycle | +| 49 | `foundation/49-composite-runner-class.mmd` | class | CompositePipelineRunner — component diagram | +| 50 | `foundation/50-exception-hierarchy.mmd` | flowchart | Exception Hierarchy — BioETLError full tree | + +--- + +## Colour Scheme + +| Layer | Colour | Fill | Border | +|----------------|--------|-----------|-----------| +| Domain | Purple | `#f5f3ff` | `#7c3aed` | +| Application | Green | `#f0fdf4` | `#16a34a` | +| Infrastructure | Red | `#fff1f2` | `#dc2626` | +| Interfaces | Blue | `#eff6ff` | `#2563eb` | +| Composition | Orange | `#fff7ed` | `#f59e0b` | +| External | Gray | `#f1f5f9` | `#64748b` | + +### Medallion Layers + +| Layer | Fill | Border | +|------------|-----------|-----------| +| Bronze | `#fff7ed` | `#f59e0b` | +| Silver | `#f8fafc` | `#475569` | +| Gold | `#fefce8` | `#ca8a04` | +| Quarantine | `#ffe4e6` | `#e11d48` | + +--- + +## Rendering + +### Prerequisites + +```bash +# Mermaid CLI (required) +npm install -g @mermaid-js/mermaid-cli + +# Browser runtime for mmdc (required by Puppeteer in local validation) +npx puppeteer browsers install chrome-headless-shell + +# svgo — SVG optimization (recommended) +npm install -g svgo + +# librsvg — high-quality SVG → PNG (recommended) +# macOS: +brew install librsvg +# Ubuntu/Debian: +sudo apt-get install librsvg2-bin +``` + +### Quick start + +```bash +# Render ALL diagrams (SVG + PNG) with custom theme +make render-diagrams + +# SVG only (faster) +make render-diagrams-svg + +# Smoke-check visibility for edge labels and node text in SVG baselines +make check-diagrams-visibility + +# Or run the script directly +bash docs/02-architecture/mmd-diagrams/render.sh + +# Single diagram with theme +mmdc -i docs/02-architecture/mmd-diagrams/architecture/01-high-level-hexagonal.mmd \ + -o output.svg \ + -c docs/02-architecture/mmd-diagrams/theme/mermaid-config.json \ + --cssFile docs/02-architecture/mmd-diagrams/theme/custom.css +``` + +### Render options + +```bash +# Filter by name glob +bash docs/02-architecture/mmd-diagrams/render.sh --filter "01-*" + +# Single directory only +bash docs/02-architecture/mmd-diagrams/render.sh --dir docs/02-architecture/mmd-diagrams/architecture + +# Adjust PNG resolution globally +bash docs/02-architecture/mmd-diagrams/render.sh --scale 4 --width 3200 --height 2400 + +# Auto-boost resolution for large diagrams by @nodes metadata +bash docs/02-architecture/mmd-diagrams/render.sh \ + --large-threshold 30 \ + --large-scale 4 \ + --large-png-dpi 450 + +# Per-diagram PNG override via source metadata: +# %% @png-scale 6 +# %% @png-dpi 600 +# (works for both .mmd and .mermaid files) + +# CI mode (Puppeteer sandbox disabled) +bash docs/02-architecture/mmd-diagrams/render.sh --puppeteer /tmp/puppeteer-config.json + +# Syntax validation (shows explicit hint if Chrome runtime is missing) +bash scripts/validate_mermaid_syntax.sh --puppeteer /tmp/puppeteer-config.json +``` + +### Output layout + +``` +docs/02-architecture/mmd-diagrams/ + architecture/ + *.mmd # source diagrams (32) + svg/*.svg # rendered vector (scalable) + png/*.png # rendered raster (300 DPI) + class-diagrams/ + *.mmd # source diagrams (16) + svg/*.svg + png/*.png + foundation/ + *.mmd # source diagrams (54) + svg/*.svg + png/*.png # default 300 DPI, auto high-res for large @nodes diagrams, + # plus optional per-file @png-scale/@png-dpi overrides + theme/ + mermaid-config.json # colours, fonts, spacing + custom.css # fine-tuned SVG styling + render.sh # unified render script + README.md # this file +``` + +### CI/CD + +Diagrams are validated and rendered automatically in GitHub Actions +(`.github/workflows/docs.yml`). Rendered SVG/PNG are uploaded as build artifacts. +A drift check warns when `.mmd/.mermaid` sources change without re-rendering. +The workflow also validates SVG text visibility for the smoke baseline set. + +--- + +## Size Normalization + +Use `scripts/uniform_diagram_sizes.py` to normalize class/flowchart object sizes: + +```bash +# Check normalization drift +python3 scripts/uniform_diagram_sizes.py --check + +# Fix specific files +python3 scripts/uniform_diagram_sizes.py --fix -f docs/02-architecture/mmd-diagrams/class-diagrams/07-application-core-services.mmd +``` + +Grouped diagrams support width strategy override: + +- `%% @uniform-width global` (default): one shared width across groups. +- `%% @uniform-width group`: group-local widths to reduce excessive ` ` padding. + +--- + +## Validation Rules + +`scripts/lint_diagrams.py` enforces: + +| Rule | Description | Severity | +|------|-------------|----------| +| META-001 | Missing structured metadata (`@...` in `.mmd`, `%% View:` in `.mermaid`) | WARN | +| META-002 | Invalid date format in `%% Updated:`/`%% @date` | ERROR | +| COLOUR-001 | Deprecated pre-ADR palette in `style`/`classDef` | ERROR | +| COLOUR-002 | Emoji in subgraph labels | ERROR | +| SIZE-001 | `@nodes > 35` | ERROR | +| SIZE-002 | `@nodes > 20` | WARN | +| SIZE-003 | `@nodes > 35`, but decomposed sibling `.mmd` slices exist (`01a/01b/...`) | WARN | +| LAYOUT-001 | `flowchart/graph` with `@nodes > 20` without ELK init | WARN | +| LAYOUT-002 | `flowchart/graph` with `@nodes > 40` without ELK init | ERROR | +| LINK-001 | Dense flowchart uses only one arrow semantic style | WARN | +| LINK-002 | Fragile singleton-index `linkStyle` pattern (many one-by-one index lines) | WARN | +| GRAPH-001 | Orphan nodes (defined but not in any edge) | WARN | +| NBSP-001 | ` ` padding detected in source | ERROR | + +Node-size exceptions in current lint implementation: +- `*-full.mermaid` reference views are exempt from `SIZE-001`/`SIZE-002`. +- `00-legend*` files are exempt from `SIZE-001`/`SIZE-002`. + +### Orphan Node Detection (GRAPH-001) + +`scripts/prune_orphan_nodes.py` detects nodes defined in a diagram but not +participating in any edge or message. + +**Applies to:** `flowchart` / `graph` and `sequenceDiagram` only. +**Skipped:** `classDiagram`, `stateDiagram`, `erDiagram`, `mindmap`, legend files. + +```bash +# Report orphans (CI mode) +python scripts/prune_orphan_nodes.py --check + +# Machine-readable output +python scripts/prune_orphan_nodes.py --check --json + +# Remove confirmed garbage orphans (in-place) +python scripts/prune_orphan_nodes.py --fix + +# Exempt all current orphans (one-time grandfathering) +python scripts/prune_orphan_nodes.py --grandfather +``` + +**To keep an intentional "documentation" node that has no edges:** + +``` +%% keep-orphan: NodeId +%% keep-orphan: NodeA, NodeB, NodeC +``` + +Insert anywhere in the file (commonly after the diagram-type declaration). + +**Lenient subgraph rule:** nodes inside a subgraph whose *name* appears in an +edge (e.g. `Bronze --> Silver`) are **not** flagged — they are considered +descriptive children of a connected subgraph container. diff --git a/.rollback/diagram-text-layer-20260301-151026/docs/02-architecture/mmd-diagrams/render.sh b/.rollback/diagram-text-layer-20260301-151026/docs/02-architecture/mmd-diagrams/render.sh new file mode 100644 index 0000000000..e6e3beb648 --- /dev/null +++ b/.rollback/diagram-text-layer-20260301-151026/docs/02-architecture/mmd-diagrams/render.sh @@ -0,0 +1,562 @@ +#!/usr/bin/env bash +# ───────────────────────────────────────────────────────────── +# BioETL — Unified Diagram Renderer +# Renders Mermaid (.mermaid / .mmd) diagrams to SVG + PNG. +# +# Usage: +# ./render.sh # render all docs diagrams (except docs/99-archive/**) +# ./render.sh --svg-only # SVG only (fast) +# ./render.sh --png-only # PNG only +# ./render.sh --filter "01-*" # glob filter on filename +# ./render.sh --dir docs/02-architecture/mmd-diagrams/architecture # single dir +# ./render.sh --help +# ───────────────────────────────────────────────────────────── +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +THEME_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/theme" && pwd)" +CONFIG="$THEME_DIR/mermaid-config.json" +CSS="$THEME_DIR/custom.css" + +# ── Defaults ──────────────────────────────────────────────── +SCALE=3 # 3x ≈ 300 DPI +LARGE_SCALE=4 # higher PNG scale for large diagrams +LARGE_THRESHOLD=30 +PNG_DPI=300 +LARGE_PNG_DPI=450 +WIDTH=0 # 0 = adaptive (fit to content) +HEIGHT=0 # 0 = adaptive (fit to content) +BG="white" +FORMAT_SVG=1 +FORMAT_PNG=1 +FILTER="*" +EXTRA_DIRS=() +PUPPETEER_CFG="$THEME_DIR/puppeteer-config.json" +[[ -f "$PUPPETEER_CFG" ]] || PUPPETEER_CFG="" +JOBS=4 # parallel jobs +FIT=1 # adaptive sizing by default +TEXT_LAYER="fallback-only" # dual | fo-only | fallback-only +EXCLUDE_PATHS=("docs/99-archive") + +# ── Diagram source directories ────────────────────────────── +DEFAULT_DIRS=( + "$REPO_ROOT/docs" +) + +# ── Colours ───────────────────────────────────────────────── +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' + +# ── Helpers ───────────────────────────────────────────────── +usage() { + cat </svg/.svg + /png/.png + +Options: + --svg-only Render SVG only (skip PNG conversion) + --png-only Render PNG only + --scale N PNG scale factor (default: $SCALE) + --large-scale N PNG scale for large diagrams (default: $LARGE_SCALE) + --large-threshold N @nodes threshold for large-diagram boost (default: $LARGE_THRESHOLD) + --png-dpi N PNG DPI for normal diagrams when using SVG converters (default: $PNG_DPI) + --large-png-dpi N PNG DPI for large diagrams when using SVG converters (default: $LARGE_PNG_DPI) + --width N Viewport width (0=auto) (default: $WIDTH) + --height N Viewport height (0=auto)(default: $HEIGHT) + --no-fit Use fixed width/height instead of adaptive + --bg COLOR Background colour (default: $BG) + --filter GLOB Only render matching (default: "$FILTER") + --dir DIR Add extra source dir (repeatable) + --exclude PATH Exclude path (repeatable, relative to repo root + or absolute path; default: docs/99-archive) + --jobs N Parallel render jobs (default: $JOBS) + --puppeteer FILE Puppeteer config JSON (CI sandboxing; defaults to theme/puppeteer-config.json if present) + -h, --help Show this help +EOF +} + +log_info() { echo -e "${GREEN}[INFO]${NC} $*"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +log_err() { echo -e "${RED}[ERR]${NC} $*"; } +log_step() { echo -e "${CYAN}[STEP]${NC} $*"; } + +require_option_value() { + local option_name="$1" + local arg_count="$2" + if [[ "$arg_count" -lt 2 ]]; then + log_err "Option $option_name requires a value" + usage + exit 1 + fi +} + +# ── Parse args ────────────────────────────────────────────── +while [[ $# -gt 0 ]]; do + case "$1" in + --svg-only) FORMAT_SVG=1; FORMAT_PNG=0; shift ;; + --png-only) FORMAT_SVG=0; FORMAT_PNG=1; shift ;; + --scale) require_option_value "$1" "$#"; SCALE="$2"; shift 2 ;; + --large-scale) require_option_value "$1" "$#"; LARGE_SCALE="$2"; shift 2 ;; + --large-threshold) require_option_value "$1" "$#"; LARGE_THRESHOLD="$2"; shift 2 ;; + --png-dpi) require_option_value "$1" "$#"; PNG_DPI="$2"; shift 2 ;; + --large-png-dpi) require_option_value "$1" "$#"; LARGE_PNG_DPI="$2"; shift 2 ;; + --width) require_option_value "$1" "$#"; WIDTH="$2"; shift 2 ;; + --height) require_option_value "$1" "$#"; HEIGHT="$2"; shift 2 ;; + --bg) require_option_value "$1" "$#"; BG="$2"; shift 2 ;; + --filter) require_option_value "$1" "$#"; FILTER="$2"; shift 2 ;; + --dir) require_option_value "$1" "$#"; EXTRA_DIRS+=("$2"); shift 2 ;; + --exclude) require_option_value "$1" "$#"; EXCLUDE_PATHS+=("$2"); shift 2 ;; + --jobs) require_option_value "$1" "$#"; JOBS="$2"; shift 2 ;; + --no-fit) FIT=0; shift ;; + --puppeteer) require_option_value "$1" "$#"; PUPPETEER_CFG="$2"; shift 2 ;; + -h|--help) usage; exit 0 ;; + *) log_err "Unknown option: $1"; usage; exit 1 ;; + esac +done + +if ! [[ "$SCALE" =~ ^[0-9]+([.][0-9]+)?$ ]]; then + log_err "--scale must be a positive number (got: $SCALE)" + exit 1 +fi +if ! [[ "$LARGE_SCALE" =~ ^[0-9]+([.][0-9]+)?$ ]]; then + log_err "--large-scale must be a positive number (got: $LARGE_SCALE)" + exit 1 +fi +if ! [[ "$LARGE_THRESHOLD" =~ ^[0-9]+$ ]]; then + log_err "--large-threshold must be a non-negative integer (got: $LARGE_THRESHOLD)" + exit 1 +fi +if ! [[ "$PNG_DPI" =~ ^[0-9]+$ ]]; then + log_err "--png-dpi must be a non-negative integer (got: $PNG_DPI)" + exit 1 +fi +if ! [[ "$LARGE_PNG_DPI" =~ ^[0-9]+$ ]]; then + log_err "--large-png-dpi must be a non-negative integer (got: $LARGE_PNG_DPI)" + exit 1 +fi +if ! [[ "$WIDTH" =~ ^[0-9]+$ ]]; then + log_err "--width must be a non-negative integer (got: $WIDTH)" + exit 1 +fi +if ! [[ "$HEIGHT" =~ ^[0-9]+$ ]]; then + log_err "--height must be a non-negative integer (got: $HEIGHT)" + exit 1 +fi +if ! [[ "$JOBS" =~ ^[0-9]+$ ]] || [[ "$JOBS" -lt 1 ]]; then + log_err "--jobs must be an integer >= 1 (got: $JOBS)" + exit 1 +fi + +if [[ $FIT -eq 0 ]]; then + # In fixed mode, treat zero values as "use defaults". + [[ "$WIDTH" -eq 0 ]] && WIDTH=2400 + [[ "$HEIGHT" -eq 0 ]] && HEIGHT=1800 +fi + +# ── Determine directories ────────────────────────────────── +if [[ ${#EXTRA_DIRS[@]} -gt 0 ]]; then + DIRS=("${EXTRA_DIRS[@]}") +else + DIRS=("${DEFAULT_DIRS[@]}") +fi + +# ── Check prerequisites ──────────────────────────────────── +echo "" +echo -e "${BOLD}════════════════════════════════════════════${NC}" +echo -e "${BOLD} BioETL Diagram Renderer${NC}" +echo -e "${BOLD}════════════════════════════════════════════${NC}" +echo "" + +if ! command -v mmdc &>/dev/null; then + log_err "mermaid-cli (mmdc) not installed" + echo "" + echo " Install: npm install -g @mermaid-js/mermaid-cli" + echo " Or: npx @mermaid-js/mermaid-cli --help" + echo "" + exit 1 +fi +log_info "mmdc $(mmdc --version 2>/dev/null || echo '(version unknown)') found" + +PYTHON_BIN="" +if command -v python3 &>/dev/null; then + PYTHON_BIN="python3" +elif command -v python &>/dev/null; then + PYTHON_BIN="python" +fi + +HAS_RSVG=0 +if command -v rsvg-convert &>/dev/null; then + HAS_RSVG=1 + log_info "rsvg-convert found (high-quality PNG conversion)" +elif command -v inkscape &>/dev/null; then + HAS_RSVG=2 + log_info "inkscape found (will use for PNG conversion)" +else + log_warn "Neither rsvg-convert nor inkscape found; mmdc will render PNG directly" +fi + +if [[ ! -f "$CONFIG" ]]; then + log_warn "Theme config not found: $CONFIG — using mmdc defaults" + CONFIG="" +fi + +if [[ ! -f "$CSS" ]]; then + log_warn "Custom CSS not found: $CSS — using mmdc defaults" + CSS="" +fi + +HAS_SVGO=0 +if command -v svgo &>/dev/null; then + HAS_SVGO=1 + log_info "svgo found (SVG optimization enabled)" +else + log_warn "svgo not found; SVG optimization skipped. Install: npm install -g svgo" +fi + +echo "" + +# ── Collect diagram files ────────────────────────────────── +files=() +exclude_abs=() + +for ex in "${EXCLUDE_PATHS[@]}"; do + if [[ "$ex" = /* ]]; then + exclude_abs+=("$ex") + else + exclude_abs+=("$REPO_ROOT/$ex") + fi +done + +for dir in "${DIRS[@]}"; do + if [[ "$dir" != /* ]]; then + dir="$REPO_ROOT/$dir" + fi + if [[ ! -d "$dir" ]]; then + log_warn "Directory not found, skipping: $dir" + continue + fi + while IFS= read -r -d '' f; do + base_name="$(basename "$f")" + stem="${base_name%.*}" + [[ "$base_name" = _* ]] && continue + [[ "$stem" == $FILTER ]] || continue + + is_excluded=0 + for ex in "${exclude_abs[@]}"; do + if [[ "$f" == "$ex"/* ]]; then + is_excluded=1 + break + fi + done + [[ $is_excluded -eq 1 ]] && continue + + files+=("$f") + done < <(find "$dir" -type f \( -name "*.mermaid" -o -name "*.mmd" \) -print0) +done + +if [[ ${#files[@]} -gt 0 ]]; then + mapfile -t files < <(printf '%s\n' "${files[@]}" | sort -u) +fi + +TOTAL=${#files[@]} +if [[ $TOTAL -eq 0 ]]; then + log_warn "No diagrams found matching filter '$FILTER'" + exit 0 +fi + +log_info "Found ${BOLD}$TOTAL${NC} diagrams across ${#DIRS[@]} root directory(ies)" +echo "" + +# ── Build mmdc base args ─────────────────────────────────── +MMDC_ARGS=() +[[ -n "$CONFIG" ]] && MMDC_ARGS+=(-c "$CONFIG") +[[ -n "$CSS" ]] && MMDC_ARGS+=("--cssFile" "$CSS") +[[ -n "$PUPPETEER_CFG" ]] && MMDC_ARGS+=(-p "$PUPPETEER_CFG") + +# ── Render function ───────────────────────────────────────── +render_one() { + local src="$1" + local idx="$2" + local dir + dir="$(dirname "$src")" + local base + base="$(basename "${src%.*}")" + + local svg_dir="$dir/svg" + local png_dir="$dir/png" + + # High-res boost for dense diagrams using @nodes metadata. + local node_count="0" + local edge_count="0" + local custom_png_scale="" + local custom_png_dpi="" + local is_large=0 + local large_reason="" + local scale_for_file="$SCALE" + local dpi_for_file="$PNG_DPI" + node_count="$(sed -nE "s/^%%[[:space:]]*@nodes[[:space:]]+([0-9]+).*/\1/p" "$src" | head -n 1)" + if [[ -z "$node_count" ]]; then + node_count="0" + fi + if [[ "$node_count" =~ ^[0-9]+$ ]] && [[ "$node_count" -ge "$LARGE_THRESHOLD" ]]; then + is_large=1 + large_reason="@nodes=${node_count}" + fi + # Fallback heuristic for legacy files without @nodes: dense edge count. + if [[ "$is_large" -eq 0 ]]; then + edge_count="$(grep -Ev '^[[:space:]]*%%' "$src" | grep -Ec '(-\.->|==>|-->)' || true)" + if [[ "$edge_count" =~ ^[0-9]+$ ]] && [[ "$edge_count" -ge "$LARGE_THRESHOLD" ]]; then + is_large=1 + large_reason="edge-density=${edge_count}" + fi + fi + if [[ "$is_large" -eq 1 ]]; then + scale_for_file="$LARGE_SCALE" + dpi_for_file="$LARGE_PNG_DPI" + fi + # Per-diagram overrides (optional metadata comments): + # %% @png-scale N + # %% @png-dpi N + custom_png_scale="$(sed -nE "s/^%%[[:space:]]*@png-scale[[:space:]]+([0-9]+).*/\1/p" "$src" | head -n 1)" + custom_png_dpi="$(sed -nE "s/^%%[[:space:]]*@png-dpi[[:space:]]+([0-9]+).*/\1/p" "$src" | head -n 1)" + if [[ "$custom_png_scale" =~ ^[0-9]+$ ]] && [[ "$custom_png_scale" -ge 1 ]]; then + scale_for_file="$custom_png_scale" + fi + if [[ "$custom_png_dpi" =~ ^[0-9]+$ ]] && [[ "$custom_png_dpi" -ge 72 ]]; then + dpi_for_file="$custom_png_dpi" + fi + + # Build per-format mmdc size args + local size_args=() + if [[ $FIT -eq 0 ]]; then + # Fixed size mode (--no-fit) + size_args+=(-w "$WIDTH" -H "$HEIGHT") + fi + # In adaptive mode (FIT=1), omit -w/-H so mmdc sizes SVG to content + + # Render SVG + if [[ $FORMAT_SVG -eq 1 ]]; then + mkdir -p "$svg_dir" + local svg_out="$svg_dir/${base}.svg" + if mmdc -i "$src" -o "$svg_out" "${MMDC_ARGS[@]}" "${size_args[@]}" -b "$BG" 2>/dev/null; then + # Add plain SVG text fallback under foreignObject labels for renderers + # that do not support foreignObject. + if [[ -n "$PYTHON_BIN" ]]; then + "$PYTHON_BIN" "$REPO_ROOT/scripts/add_svg_text_fallback.py" --fix -f "$svg_out" >/dev/null 2>&1 || true + fi + # Optimize SVG with svgo if available + if [[ $HAS_SVGO -eq 1 ]]; then + svgo --quiet --config "$THEME_DIR/../svgo.config.js" "$svg_out" -o "$svg_out" 2>/dev/null || true + fi + # Inject CSS overrides for edge label readability + if [[ -n "$PYTHON_BIN" ]]; then + "$PYTHON_BIN" "$REPO_ROOT/scripts/inject_svg_styles.py" --fix -f "$svg_out" >/dev/null 2>&1 || true + fi + echo -e " ${GREEN}✓${NC} SVG [$idx/$TOTAL] $base" + else + echo -e " ${RED}✗${NC} SVG [$idx/$TOTAL] $base" + return 1 + fi + fi + + # Render PNG + if [[ $FORMAT_PNG -eq 1 ]]; then + mkdir -p "$png_dir" + local png_out="$png_dir/${base}.png" + + if [[ $FORMAT_SVG -eq 1 && $HAS_RSVG -eq 1 ]]; then + # SVG → PNG via rsvg-convert (adaptive: use SVG intrinsic size) + if [[ $FIT -eq 0 ]]; then + rsvg-convert -b "$BG" -w "$WIDTH" -h "$HEIGHT" "$svg_dir/${base}.svg" -o "$png_out" 2>/dev/null + else + rsvg-convert -b "$BG" -d "$dpi_for_file" -p "$dpi_for_file" "$svg_dir/${base}.svg" -o "$png_out" 2>/dev/null + fi + elif [[ $FORMAT_SVG -eq 1 && $HAS_RSVG -eq 2 ]]; then + # SVG → PNG via inkscape + if [[ $FIT -eq 0 ]]; then + inkscape "$svg_dir/${base}.svg" --export-type=png --export-width="$WIDTH" \ + --export-height="$HEIGHT" --export-background="$BG" --export-background-opacity=1 \ + --export-filename="$png_out" 2>/dev/null + else + inkscape "$svg_dir/${base}.svg" --export-type=png --export-dpi="$dpi_for_file" \ + --export-background="$BG" --export-background-opacity=1 --export-filename="$png_out" 2>/dev/null + fi + else + # Direct mmdc → PNG (adaptive: use -s scale only) + mmdc -i "$src" -o "$png_out" "${MMDC_ARGS[@]}" \ + "${size_args[@]}" -s "$scale_for_file" -b "$BG" 2>/dev/null + fi + + if [[ -f "$png_out" ]]; then + local size + size=$(du -h "$png_out" | cut -f1) + if [[ "$is_large" -eq 1 ]]; then + echo -e " ${GREEN}✓${NC} PNG [$idx/$TOTAL] $base (${size}, hi-res ${large_reason})" + else + echo -e " ${GREEN}✓${NC} PNG [$idx/$TOTAL] $base (${size})" + fi + else + echo -e " ${RED}✗${NC} PNG [$idx/$TOTAL] $base" + return 1 + fi + fi + + return 0 +} + +# ── Main loop ─────────────────────────────────────────────── +success=0 +failed=0 +current_dir="" + +if [[ "$JOBS" -eq 1 ]]; then + for i in "${!files[@]}"; do + src="${files[$i]}" + idx=$((i + 1)) + dir="$(dirname "$src")" + + # Print directory header on change + if [[ "$dir" != "$current_dir" ]]; then + current_dir="$dir" + echo "" + log_step "Directory: ${dir#"$REPO_ROOT/"}" + echo "" + fi + + if render_one "$src" "$idx"; then + success=$((success + 1)) + else + failed=$((failed + 1)) + fi + done +else + log_step "Rendering in parallel with $JOBS jobs..." + echo "" + result_dir="$(mktemp -d)" + active_jobs=0 + + for i in "${!files[@]}"; do + src="${files[$i]}" + idx=$((i + 1)) + ( + if render_one "$src" "$idx"; then + printf "ok\n" > "$result_dir/$idx.status" + else + printf "fail\n" > "$result_dir/$idx.status" + fi + ) & + active_jobs=$((active_jobs + 1)) + + if [[ "$active_jobs" -ge "$JOBS" ]]; then + wait -n || true + active_jobs=$((active_jobs - 1)) + fi + done + + while [[ "$active_jobs" -gt 0 ]]; do + wait -n || true + active_jobs=$((active_jobs - 1)) + done + + for i in "${!files[@]}"; do + idx=$((i + 1)) + if [[ -f "$result_dir/$idx.status" ]] && [[ "$(cat "$result_dir/$idx.status")" == "ok" ]]; then + success=$((success + 1)) + else + failed=$((failed + 1)) + fi + done + rm -rf "$result_dir" +fi + +# ── Generate index files per output directory ─────────────── +log_step "Generating index files..." +echo "" + +declare -A source_dirs_map=() +for src in "${files[@]}"; do + src_dir="$(dirname "$src")" + source_dirs_map["$src_dir"]=1 +done +mapfile -t source_dirs < <(printf '%s\n' "${!source_dirs_map[@]}" | sort) + +for dir in "${source_dirs[@]}"; do + for sub in svg png; do + out_dir="$dir/$sub" + [[ ! -d "$out_dir" ]] && continue + + index_file="$out_dir/INDEX.md" + { + echo "# BioETL Diagrams — ${sub^^} Index" + echo "" + echo "_Generated: $(date -Iseconds)_" + echo "" + shopt -s nullglob + for f in "$out_dir"/*."$sub"; do + name="$(basename "$f" ".$sub")" + title="${name//-/ }" + # Capitalize first letter of each word + title="$(echo "$title" | sed 's/\b[0-9]*\b //;s/\b\(.\)/\u\1/g')" + echo "## $title" + echo "" + if [[ "$sub" == "svg" ]]; then + echo "![${name}](./${name}.svg)" + else + echo "![${name}](./${name}.png)" + fi + echo "" + echo "---" + echo "" + done + shopt -u nullglob + } > "$index_file" + echo -e " ${GREEN}✓${NC} Index: ${index_file#"$REPO_ROOT/"}" + done +done + +# ── Summary ───────────────────────────────────────────────── +echo "" +echo -e "${BOLD}════════════════════════════════════════════${NC}" +echo -e "${BOLD} Summary${NC}" +echo -e "${BOLD}════════════════════════════════════════════${NC}" +echo "" +echo -e " Total diagrams: ${BOLD}$TOTAL${NC}" +echo -e " ${GREEN}Rendered OK:${NC} $success" +[[ $failed -gt 0 ]] && echo -e " ${RED}Failed:${NC} $failed" +echo "" +echo -e " Theme: ${CONFIG:-'(default)'}" +echo -e " CSS: ${CSS:-'(none)'}" +echo "" + +formats="" +[[ $FORMAT_SVG -eq 1 ]] && formats+="SVG " +[[ $FORMAT_PNG -eq 1 ]] && formats+="PNG " +echo -e " Formats: ${BOLD}${formats}${NC}" +if [[ $FIT -eq 1 ]]; then + echo -e " Layout: ${BOLD}adaptive${NC} (fit to content, ELK engine)" +else + echo -e " Layout: ${BOLD}fixed${NC} (${WIDTH}x${HEIGHT})" +fi +echo -e " PNG: base scale=${SCALE}, large scale=${LARGE_SCALE} (@nodes>=${LARGE_THRESHOLD})" +echo -e " base dpi=${PNG_DPI}, large dpi=${LARGE_PNG_DPI}" +echo "" + +if [[ $failed -eq 0 ]]; then + log_info "All diagrams rendered successfully" + exit 0 +else + log_warn "$failed diagram(s) failed — check errors above" + exit 1 +fi diff --git a/.rollback/diagram-text-layer-20260301-151026/restore.sh b/.rollback/diagram-text-layer-20260301-151026/restore.sh new file mode 100644 index 0000000000..30ba7b5f61 --- /dev/null +++ b/.rollback/diagram-text-layer-20260301-151026/restore.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cp -f "$REPO_ROOT/.rollback/diagram-text-layer-20260301-151026/docs/02-architecture/mmd-diagrams/render.sh" "$REPO_ROOT/docs/02-architecture/mmd-diagrams/render.sh" +cp -f "$REPO_ROOT/.rollback/diagram-text-layer-20260301-151026/docs/02-architecture/mmd-diagrams/README.md" "$REPO_ROOT/docs/02-architecture/mmd-diagrams/README.md" +cp -f "$REPO_ROOT/.rollback/diagram-text-layer-20260301-151026/scripts/run_diagram_checks.sh" "$REPO_ROOT/scripts/run_diagram_checks.sh" +cp -f "$REPO_ROOT/.rollback/diagram-text-layer-20260301-151026/tests/architecture/test_run_diagram_checks_script.py" "$REPO_ROOT/tests/architecture/test_run_diagram_checks_script.py" +rm -f "$REPO_ROOT/scripts/strip_svg_foreign_object.py" +rm -f "$REPO_ROOT/tests/architecture/test_strip_svg_foreign_object.py" +echo "Rollback restored from .rollback/diagram-text-layer-20260301-151026" diff --git a/.rollback/diagram-text-layer-20260301-151026/scripts/run_diagram_checks.sh b/.rollback/diagram-text-layer-20260301-151026/scripts/run_diagram_checks.sh new file mode 100644 index 0000000000..f3e93ad3fe --- /dev/null +++ b/.rollback/diagram-text-layer-20260301-151026/scripts/run_diagram_checks.sh @@ -0,0 +1,282 @@ +#!/usr/bin/env bash +# Unified runner for diagram validation suites. +# Profiles: +# pr - hard-gate PR checks (syntax/lint/render/artifacts/smoke/quality) +# nightly - pr profile + nightly DIAG-T024..T029 suite +# quick - lightweight local checks without render +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +PROFILE="pr" +PUPPETEER_CFG="${PUPPETEER_CFG:-/tmp/puppeteer-config.json}" +STRICT_NIGHTLY=0 +SKIP_RENDER=0 +DIAGRAM_PATH="" +SOURCE_MANIFEST="$REPO_ROOT/docs/02-architecture/mmd-diagrams/quality-gate-manifest.txt" +RENDER_MANIFEST="$REPO_ROOT/docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt" +TEMP_SOURCE_MANIFEST="" +TEMP_RENDER_MANIFEST="" +THEME_CONFIG="$REPO_ROOT/docs/02-architecture/mmd-diagrams/theme/mermaid-config.json" + +usage() { + cat <<'EOF' +Usage: scripts/run_diagram_checks.sh [options] + +Options: + --profile Check profile (default: pr) + --diagram Run checks only for one .mmd/.mermaid diagram + --puppeteer Puppeteer config path (default: /tmp/puppeteer-config.json) + --strict-nightly Fail nightly profile on warnings + --skip-render Skip render step (useful for local dry loops) + -h, --help Show this help + +Examples: + scripts/run_diagram_checks.sh --profile pr + scripts/run_diagram_checks.sh --profile pr --diagram docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd + scripts/run_diagram_checks.sh --profile nightly --strict-nightly + scripts/run_diagram_checks.sh --profile quick +EOF +} + +log() { printf '[INFO] %s\n' "$*"; } + +cleanup_temp_manifests() { + [[ -n "$TEMP_SOURCE_MANIFEST" ]] && rm -f "$TEMP_SOURCE_MANIFEST" || true + [[ -n "$TEMP_RENDER_MANIFEST" ]] && rm -f "$TEMP_RENDER_MANIFEST" || true +} + +trap cleanup_temp_manifests EXIT + +ensure_puppeteer_config() { + cat > "$PUPPETEER_CFG" <<'EOF' +{ + "args": ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage", "--disable-gpu"] +} +EOF +} + +run_syntax_check() { + if [[ -z "$DIAGRAM_PATH" ]]; then + bash "$REPO_ROOT/scripts/validate_mermaid_syntax.sh" --puppeteer "$PUPPETEER_CFG" + return + fi + + if ! command -v mmdc >/dev/null 2>&1; then + echo "Error: mmdc not found. Install with: npm install -g @mermaid-js/mermaid-cli" >&2 + exit 2 + fi + + local source_abs="$REPO_ROOT/$DIAGRAM_PATH" + local tmp_svg + local tmp_err + tmp_svg="$(mktemp "${TMPDIR:-/tmp}/diagram-syntax.XXXXXX.svg")" + tmp_err="$(mktemp "${TMPDIR:-/tmp}/diagram-syntax.XXXXXX.err")" + local mmdc_args=() + [[ -f "$THEME_CONFIG" ]] && mmdc_args+=(-c "$THEME_CONFIG") + [[ -n "$PUPPETEER_CFG" ]] && mmdc_args+=(-p "$PUPPETEER_CFG") + + if ! mmdc -i "$source_abs" -o "$tmp_svg" "${mmdc_args[@]}" >/dev/null 2>"$tmp_err"; then + if ! mmdc -i "$source_abs" -o "$tmp_svg" "${mmdc_args[@]}" >/dev/null 2>"$tmp_err"; then + echo "ERROR: Mermaid validation failed for $DIAGRAM_PATH" >&2 + if grep -q "Could not find Chrome" "$tmp_err"; then + echo "HINT: mmdc could not find Chrome/Chromium for Puppeteer." >&2 + fi + sed -n '1,8p' "$tmp_err" >&2 || true + rm -f "$tmp_svg" "$tmp_err" + exit 1 + fi + fi + + rm -f "$tmp_svg" "$tmp_err" + log "Syntax validation passed for $DIAGRAM_PATH" +} + +prepare_diagram_scope() { + local input_path="$1" + local abs_path="$input_path" + + if [[ "$abs_path" != /* ]]; then + abs_path="$REPO_ROOT/$abs_path" + fi + if [[ ! -f "$abs_path" ]]; then + echo "--diagram file not found: $input_path" >&2 + exit 2 + fi + + case "$abs_path" in + *.mmd|*.mermaid) ;; + *) + echo "--diagram must point to .mmd or .mermaid file: $input_path" >&2 + exit 2 + ;; + esac + + local rel_path="${abs_path#$REPO_ROOT/}" + if [[ "$rel_path" == "$abs_path" ]]; then + echo "--diagram must be inside repository: $input_path" >&2 + exit 2 + fi + + DIAGRAM_PATH="$rel_path" + TEMP_SOURCE_MANIFEST="$(mktemp "${TMPDIR:-/tmp}/diagram-source-manifest.XXXXXX.txt")" + TEMP_RENDER_MANIFEST="$(mktemp "${TMPDIR:-/tmp}/diagram-render-manifest.XXXXXX.txt")" + printf '%s\n' "$DIAGRAM_PATH" > "$TEMP_SOURCE_MANIFEST" + + local diagram_dir + local diagram_stem + diagram_dir="$(dirname "$DIAGRAM_PATH")" + diagram_stem="$(basename "${DIAGRAM_PATH%.*}")" + printf '%s\n' "${diagram_dir}/svg/${diagram_stem}.svg" > "$TEMP_RENDER_MANIFEST" + + SOURCE_MANIFEST="$TEMP_SOURCE_MANIFEST" + RENDER_MANIFEST="$TEMP_RENDER_MANIFEST" + log "Single-diagram scope enabled: $DIAGRAM_PATH" +} + +run_lint_check() { + if [[ -n "$DIAGRAM_PATH" ]]; then + python3 "$REPO_ROOT/scripts/lint_diagrams.py" "$REPO_ROOT/$DIAGRAM_PATH" + else + python3 "$REPO_ROOT/scripts/lint_diagrams.py" "$REPO_ROOT/docs/02-architecture/mmd-diagrams" + fi +} + +run_render_step() { + if [[ -n "$DIAGRAM_PATH" ]]; then + local diagram_dir + local diagram_stem + diagram_dir="$(dirname "$DIAGRAM_PATH")" + diagram_stem="$(basename "${DIAGRAM_PATH%.*}")" + bash "$REPO_ROOT/docs/02-architecture/mmd-diagrams/render.sh" \ + --dir "$REPO_ROOT/$diagram_dir" \ + --filter "$diagram_stem" \ + --puppeteer "$PUPPETEER_CFG" + else + bash "$REPO_ROOT/docs/02-architecture/mmd-diagrams/render.sh" --puppeteer "$PUPPETEER_CFG" + fi +} + +run_pr_profile() { + log "DIAG-T001: Mermaid syntax" + run_syntax_check + + log "DIAG-T002..T008: Diagram lint" + run_lint_check + + if [[ "$SKIP_RENDER" -eq 0 ]]; then + log "DIAG-T009: Render diagrams" + run_render_step + else + log "Render skipped (--skip-render)" + fi + + log "DIAG-T010..T012: Artifact existence/non-empty" + python3 "$REPO_ROOT/scripts/check_diagram_artifacts.py" \ + --manifest "$RENDER_MANIFEST" + + log "DIAG-T014..T015: SVG text visibility" + python3 "$REPO_ROOT/scripts/check_svg_text_visibility.py" \ + --manifest "$RENDER_MANIFEST" + + log "DIAG-T013/DIAG-T026: Visual smoke drift" + python3 "$REPO_ROOT/scripts/check_diagram_visual_smoke.py" \ + --manifest "$RENDER_MANIFEST" + + log "DIAG-T018..T023: Quality gates" + python3 "$REPO_ROOT/scripts/check_diagram_quality_gates.py" \ + --manifest "$SOURCE_MANIFEST" +} + +run_nightly_profile() { + run_pr_profile + + log "DIAG-T024..T029: Nightly suite" + nightly_cmd=( + python3 "$REPO_ROOT/scripts/run_diagram_nightly_suite.py" + --source-manifest "$SOURCE_MANIFEST" + --render-manifest "$RENDER_MANIFEST" + --puppeteer "$PUPPETEER_CFG" + ) + + if [[ "$STRICT_NIGHTLY" -eq 1 ]]; then + nightly_cmd+=(--strict) + fi + + "${nightly_cmd[@]}" +} + +run_quick_profile() { + log "Quick profile: syntax + lint + quality + nightly (light)" + + log "DIAG-T001: Mermaid syntax" + run_syntax_check + + log "DIAG-T002..T008: Diagram lint" + run_lint_check + + log "DIAG-T018..T023: Quality gates" + python3 "$REPO_ROOT/scripts/check_diagram_quality_gates.py" \ + --manifest "$SOURCE_MANIFEST" + + log "DIAG-T024..T029: Nightly suite (light mode)" + python3 "$REPO_ROOT/scripts/run_diagram_nightly_suite.py" \ + --source-manifest "$SOURCE_MANIFEST" \ + --render-manifest "$RENDER_MANIFEST" \ + --skip-chaos --skip-growth --skip-theme +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --profile) + [[ $# -lt 2 ]] && { echo "--profile requires value" >&2; exit 2; } + PROFILE="$2" + shift 2 + ;; + --diagram) + [[ $# -lt 2 ]] && { echo "--diagram requires value" >&2; exit 2; } + DIAGRAM_PATH="$2" + shift 2 + ;; + --puppeteer) + [[ $# -lt 2 ]] && { echo "--puppeteer requires value" >&2; exit 2; } + PUPPETEER_CFG="$2" + shift 2 + ;; + --strict-nightly) + STRICT_NIGHTLY=1 + shift + ;; + --skip-render) + SKIP_RENDER=1 + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + usage + exit 2 + ;; + esac +done + +if [[ -n "$DIAGRAM_PATH" ]]; then + prepare_diagram_scope "$DIAGRAM_PATH" +fi + +ensure_puppeteer_config + +case "$PROFILE" in + pr) run_pr_profile ;; + nightly) run_nightly_profile ;; + quick) run_quick_profile ;; + *) + echo "Unsupported profile: $PROFILE" >&2 + usage + exit 2 + ;; +esac + +log "Diagram checks completed (profile=$PROFILE)" diff --git a/.rollback/diagram-text-layer-20260301-151026/tests/architecture/test_run_diagram_checks_script.py b/.rollback/diagram-text-layer-20260301-151026/tests/architecture/test_run_diagram_checks_script.py new file mode 100644 index 0000000000..c3c7947cd3 --- /dev/null +++ b/.rollback/diagram-text-layer-20260301-151026/tests/architecture/test_run_diagram_checks_script.py @@ -0,0 +1,48 @@ +"""Architecture tests for unified diagram checks runner script.""" + +from __future__ import annotations + +from pathlib import Path + + +def _script_text() -> str: + script_path = Path("scripts/run_diagram_checks.sh") + assert script_path.exists(), "scripts/run_diagram_checks.sh must exist" + return script_path.read_text(encoding="utf-8") + + +def test_runner_supports_single_diagram_flag() -> None: + script = _script_text() + + assert "--diagram " in script + assert "prepare_diagram_scope" in script + assert "--diagram requires value" in script + assert "--diagram must point to .mmd or .mermaid file" in script + + +def test_runner_uses_temp_manifests_for_single_diagram_scope() -> None: + script = _script_text() + + assert 'TEMP_SOURCE_MANIFEST="$(mktemp' in script + assert 'TEMP_RENDER_MANIFEST="$(mktemp' in script + assert 'SOURCE_MANIFEST="$TEMP_SOURCE_MANIFEST"' in script + assert 'RENDER_MANIFEST="$TEMP_RENDER_MANIFEST"' in script + assert "trap cleanup_temp_manifests EXIT" in script + + +def test_runner_routes_checks_through_scope_manifests() -> None: + script = _script_text() + + assert '--manifest "$SOURCE_MANIFEST"' in script + assert '--manifest "$RENDER_MANIFEST"' in script + assert '--source-manifest "$SOURCE_MANIFEST"' in script + assert '--render-manifest "$RENDER_MANIFEST"' in script + + +def test_runner_renders_single_diagram_with_dir_and_filter() -> None: + script = _script_text() + + assert 'run_render_step()' in script + assert '--dir "$REPO_ROOT/$diagram_dir"' in script + assert '--filter "$diagram_stem"' in script + assert '--puppeteer "$PUPPETEER_CFG"' in script diff --git a/.rollback/render.sh.20260301-150622.bak b/.rollback/render.sh.20260301-150622.bak new file mode 100644 index 0000000000..e6e3beb648 --- /dev/null +++ b/.rollback/render.sh.20260301-150622.bak @@ -0,0 +1,562 @@ +#!/usr/bin/env bash +# ───────────────────────────────────────────────────────────── +# BioETL — Unified Diagram Renderer +# Renders Mermaid (.mermaid / .mmd) diagrams to SVG + PNG. +# +# Usage: +# ./render.sh # render all docs diagrams (except docs/99-archive/**) +# ./render.sh --svg-only # SVG only (fast) +# ./render.sh --png-only # PNG only +# ./render.sh --filter "01-*" # glob filter on filename +# ./render.sh --dir docs/02-architecture/mmd-diagrams/architecture # single dir +# ./render.sh --help +# ───────────────────────────────────────────────────────────── +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +THEME_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/theme" && pwd)" +CONFIG="$THEME_DIR/mermaid-config.json" +CSS="$THEME_DIR/custom.css" + +# ── Defaults ──────────────────────────────────────────────── +SCALE=3 # 3x ≈ 300 DPI +LARGE_SCALE=4 # higher PNG scale for large diagrams +LARGE_THRESHOLD=30 +PNG_DPI=300 +LARGE_PNG_DPI=450 +WIDTH=0 # 0 = adaptive (fit to content) +HEIGHT=0 # 0 = adaptive (fit to content) +BG="white" +FORMAT_SVG=1 +FORMAT_PNG=1 +FILTER="*" +EXTRA_DIRS=() +PUPPETEER_CFG="$THEME_DIR/puppeteer-config.json" +[[ -f "$PUPPETEER_CFG" ]] || PUPPETEER_CFG="" +JOBS=4 # parallel jobs +FIT=1 # adaptive sizing by default +TEXT_LAYER="fallback-only" # dual | fo-only | fallback-only +EXCLUDE_PATHS=("docs/99-archive") + +# ── Diagram source directories ────────────────────────────── +DEFAULT_DIRS=( + "$REPO_ROOT/docs" +) + +# ── Colours ───────────────────────────────────────────────── +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' + +# ── Helpers ───────────────────────────────────────────────── +usage() { + cat </svg/.svg + /png/.png + +Options: + --svg-only Render SVG only (skip PNG conversion) + --png-only Render PNG only + --scale N PNG scale factor (default: $SCALE) + --large-scale N PNG scale for large diagrams (default: $LARGE_SCALE) + --large-threshold N @nodes threshold for large-diagram boost (default: $LARGE_THRESHOLD) + --png-dpi N PNG DPI for normal diagrams when using SVG converters (default: $PNG_DPI) + --large-png-dpi N PNG DPI for large diagrams when using SVG converters (default: $LARGE_PNG_DPI) + --width N Viewport width (0=auto) (default: $WIDTH) + --height N Viewport height (0=auto)(default: $HEIGHT) + --no-fit Use fixed width/height instead of adaptive + --bg COLOR Background colour (default: $BG) + --filter GLOB Only render matching (default: "$FILTER") + --dir DIR Add extra source dir (repeatable) + --exclude PATH Exclude path (repeatable, relative to repo root + or absolute path; default: docs/99-archive) + --jobs N Parallel render jobs (default: $JOBS) + --puppeteer FILE Puppeteer config JSON (CI sandboxing; defaults to theme/puppeteer-config.json if present) + -h, --help Show this help +EOF +} + +log_info() { echo -e "${GREEN}[INFO]${NC} $*"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +log_err() { echo -e "${RED}[ERR]${NC} $*"; } +log_step() { echo -e "${CYAN}[STEP]${NC} $*"; } + +require_option_value() { + local option_name="$1" + local arg_count="$2" + if [[ "$arg_count" -lt 2 ]]; then + log_err "Option $option_name requires a value" + usage + exit 1 + fi +} + +# ── Parse args ────────────────────────────────────────────── +while [[ $# -gt 0 ]]; do + case "$1" in + --svg-only) FORMAT_SVG=1; FORMAT_PNG=0; shift ;; + --png-only) FORMAT_SVG=0; FORMAT_PNG=1; shift ;; + --scale) require_option_value "$1" "$#"; SCALE="$2"; shift 2 ;; + --large-scale) require_option_value "$1" "$#"; LARGE_SCALE="$2"; shift 2 ;; + --large-threshold) require_option_value "$1" "$#"; LARGE_THRESHOLD="$2"; shift 2 ;; + --png-dpi) require_option_value "$1" "$#"; PNG_DPI="$2"; shift 2 ;; + --large-png-dpi) require_option_value "$1" "$#"; LARGE_PNG_DPI="$2"; shift 2 ;; + --width) require_option_value "$1" "$#"; WIDTH="$2"; shift 2 ;; + --height) require_option_value "$1" "$#"; HEIGHT="$2"; shift 2 ;; + --bg) require_option_value "$1" "$#"; BG="$2"; shift 2 ;; + --filter) require_option_value "$1" "$#"; FILTER="$2"; shift 2 ;; + --dir) require_option_value "$1" "$#"; EXTRA_DIRS+=("$2"); shift 2 ;; + --exclude) require_option_value "$1" "$#"; EXCLUDE_PATHS+=("$2"); shift 2 ;; + --jobs) require_option_value "$1" "$#"; JOBS="$2"; shift 2 ;; + --no-fit) FIT=0; shift ;; + --puppeteer) require_option_value "$1" "$#"; PUPPETEER_CFG="$2"; shift 2 ;; + -h|--help) usage; exit 0 ;; + *) log_err "Unknown option: $1"; usage; exit 1 ;; + esac +done + +if ! [[ "$SCALE" =~ ^[0-9]+([.][0-9]+)?$ ]]; then + log_err "--scale must be a positive number (got: $SCALE)" + exit 1 +fi +if ! [[ "$LARGE_SCALE" =~ ^[0-9]+([.][0-9]+)?$ ]]; then + log_err "--large-scale must be a positive number (got: $LARGE_SCALE)" + exit 1 +fi +if ! [[ "$LARGE_THRESHOLD" =~ ^[0-9]+$ ]]; then + log_err "--large-threshold must be a non-negative integer (got: $LARGE_THRESHOLD)" + exit 1 +fi +if ! [[ "$PNG_DPI" =~ ^[0-9]+$ ]]; then + log_err "--png-dpi must be a non-negative integer (got: $PNG_DPI)" + exit 1 +fi +if ! [[ "$LARGE_PNG_DPI" =~ ^[0-9]+$ ]]; then + log_err "--large-png-dpi must be a non-negative integer (got: $LARGE_PNG_DPI)" + exit 1 +fi +if ! [[ "$WIDTH" =~ ^[0-9]+$ ]]; then + log_err "--width must be a non-negative integer (got: $WIDTH)" + exit 1 +fi +if ! [[ "$HEIGHT" =~ ^[0-9]+$ ]]; then + log_err "--height must be a non-negative integer (got: $HEIGHT)" + exit 1 +fi +if ! [[ "$JOBS" =~ ^[0-9]+$ ]] || [[ "$JOBS" -lt 1 ]]; then + log_err "--jobs must be an integer >= 1 (got: $JOBS)" + exit 1 +fi + +if [[ $FIT -eq 0 ]]; then + # In fixed mode, treat zero values as "use defaults". + [[ "$WIDTH" -eq 0 ]] && WIDTH=2400 + [[ "$HEIGHT" -eq 0 ]] && HEIGHT=1800 +fi + +# ── Determine directories ────────────────────────────────── +if [[ ${#EXTRA_DIRS[@]} -gt 0 ]]; then + DIRS=("${EXTRA_DIRS[@]}") +else + DIRS=("${DEFAULT_DIRS[@]}") +fi + +# ── Check prerequisites ──────────────────────────────────── +echo "" +echo -e "${BOLD}════════════════════════════════════════════${NC}" +echo -e "${BOLD} BioETL Diagram Renderer${NC}" +echo -e "${BOLD}════════════════════════════════════════════${NC}" +echo "" + +if ! command -v mmdc &>/dev/null; then + log_err "mermaid-cli (mmdc) not installed" + echo "" + echo " Install: npm install -g @mermaid-js/mermaid-cli" + echo " Or: npx @mermaid-js/mermaid-cli --help" + echo "" + exit 1 +fi +log_info "mmdc $(mmdc --version 2>/dev/null || echo '(version unknown)') found" + +PYTHON_BIN="" +if command -v python3 &>/dev/null; then + PYTHON_BIN="python3" +elif command -v python &>/dev/null; then + PYTHON_BIN="python" +fi + +HAS_RSVG=0 +if command -v rsvg-convert &>/dev/null; then + HAS_RSVG=1 + log_info "rsvg-convert found (high-quality PNG conversion)" +elif command -v inkscape &>/dev/null; then + HAS_RSVG=2 + log_info "inkscape found (will use for PNG conversion)" +else + log_warn "Neither rsvg-convert nor inkscape found; mmdc will render PNG directly" +fi + +if [[ ! -f "$CONFIG" ]]; then + log_warn "Theme config not found: $CONFIG — using mmdc defaults" + CONFIG="" +fi + +if [[ ! -f "$CSS" ]]; then + log_warn "Custom CSS not found: $CSS — using mmdc defaults" + CSS="" +fi + +HAS_SVGO=0 +if command -v svgo &>/dev/null; then + HAS_SVGO=1 + log_info "svgo found (SVG optimization enabled)" +else + log_warn "svgo not found; SVG optimization skipped. Install: npm install -g svgo" +fi + +echo "" + +# ── Collect diagram files ────────────────────────────────── +files=() +exclude_abs=() + +for ex in "${EXCLUDE_PATHS[@]}"; do + if [[ "$ex" = /* ]]; then + exclude_abs+=("$ex") + else + exclude_abs+=("$REPO_ROOT/$ex") + fi +done + +for dir in "${DIRS[@]}"; do + if [[ "$dir" != /* ]]; then + dir="$REPO_ROOT/$dir" + fi + if [[ ! -d "$dir" ]]; then + log_warn "Directory not found, skipping: $dir" + continue + fi + while IFS= read -r -d '' f; do + base_name="$(basename "$f")" + stem="${base_name%.*}" + [[ "$base_name" = _* ]] && continue + [[ "$stem" == $FILTER ]] || continue + + is_excluded=0 + for ex in "${exclude_abs[@]}"; do + if [[ "$f" == "$ex"/* ]]; then + is_excluded=1 + break + fi + done + [[ $is_excluded -eq 1 ]] && continue + + files+=("$f") + done < <(find "$dir" -type f \( -name "*.mermaid" -o -name "*.mmd" \) -print0) +done + +if [[ ${#files[@]} -gt 0 ]]; then + mapfile -t files < <(printf '%s\n' "${files[@]}" | sort -u) +fi + +TOTAL=${#files[@]} +if [[ $TOTAL -eq 0 ]]; then + log_warn "No diagrams found matching filter '$FILTER'" + exit 0 +fi + +log_info "Found ${BOLD}$TOTAL${NC} diagrams across ${#DIRS[@]} root directory(ies)" +echo "" + +# ── Build mmdc base args ─────────────────────────────────── +MMDC_ARGS=() +[[ -n "$CONFIG" ]] && MMDC_ARGS+=(-c "$CONFIG") +[[ -n "$CSS" ]] && MMDC_ARGS+=("--cssFile" "$CSS") +[[ -n "$PUPPETEER_CFG" ]] && MMDC_ARGS+=(-p "$PUPPETEER_CFG") + +# ── Render function ───────────────────────────────────────── +render_one() { + local src="$1" + local idx="$2" + local dir + dir="$(dirname "$src")" + local base + base="$(basename "${src%.*}")" + + local svg_dir="$dir/svg" + local png_dir="$dir/png" + + # High-res boost for dense diagrams using @nodes metadata. + local node_count="0" + local edge_count="0" + local custom_png_scale="" + local custom_png_dpi="" + local is_large=0 + local large_reason="" + local scale_for_file="$SCALE" + local dpi_for_file="$PNG_DPI" + node_count="$(sed -nE "s/^%%[[:space:]]*@nodes[[:space:]]+([0-9]+).*/\1/p" "$src" | head -n 1)" + if [[ -z "$node_count" ]]; then + node_count="0" + fi + if [[ "$node_count" =~ ^[0-9]+$ ]] && [[ "$node_count" -ge "$LARGE_THRESHOLD" ]]; then + is_large=1 + large_reason="@nodes=${node_count}" + fi + # Fallback heuristic for legacy files without @nodes: dense edge count. + if [[ "$is_large" -eq 0 ]]; then + edge_count="$(grep -Ev '^[[:space:]]*%%' "$src" | grep -Ec '(-\.->|==>|-->)' || true)" + if [[ "$edge_count" =~ ^[0-9]+$ ]] && [[ "$edge_count" -ge "$LARGE_THRESHOLD" ]]; then + is_large=1 + large_reason="edge-density=${edge_count}" + fi + fi + if [[ "$is_large" -eq 1 ]]; then + scale_for_file="$LARGE_SCALE" + dpi_for_file="$LARGE_PNG_DPI" + fi + # Per-diagram overrides (optional metadata comments): + # %% @png-scale N + # %% @png-dpi N + custom_png_scale="$(sed -nE "s/^%%[[:space:]]*@png-scale[[:space:]]+([0-9]+).*/\1/p" "$src" | head -n 1)" + custom_png_dpi="$(sed -nE "s/^%%[[:space:]]*@png-dpi[[:space:]]+([0-9]+).*/\1/p" "$src" | head -n 1)" + if [[ "$custom_png_scale" =~ ^[0-9]+$ ]] && [[ "$custom_png_scale" -ge 1 ]]; then + scale_for_file="$custom_png_scale" + fi + if [[ "$custom_png_dpi" =~ ^[0-9]+$ ]] && [[ "$custom_png_dpi" -ge 72 ]]; then + dpi_for_file="$custom_png_dpi" + fi + + # Build per-format mmdc size args + local size_args=() + if [[ $FIT -eq 0 ]]; then + # Fixed size mode (--no-fit) + size_args+=(-w "$WIDTH" -H "$HEIGHT") + fi + # In adaptive mode (FIT=1), omit -w/-H so mmdc sizes SVG to content + + # Render SVG + if [[ $FORMAT_SVG -eq 1 ]]; then + mkdir -p "$svg_dir" + local svg_out="$svg_dir/${base}.svg" + if mmdc -i "$src" -o "$svg_out" "${MMDC_ARGS[@]}" "${size_args[@]}" -b "$BG" 2>/dev/null; then + # Add plain SVG text fallback under foreignObject labels for renderers + # that do not support foreignObject. + if [[ -n "$PYTHON_BIN" ]]; then + "$PYTHON_BIN" "$REPO_ROOT/scripts/add_svg_text_fallback.py" --fix -f "$svg_out" >/dev/null 2>&1 || true + fi + # Optimize SVG with svgo if available + if [[ $HAS_SVGO -eq 1 ]]; then + svgo --quiet --config "$THEME_DIR/../svgo.config.js" "$svg_out" -o "$svg_out" 2>/dev/null || true + fi + # Inject CSS overrides for edge label readability + if [[ -n "$PYTHON_BIN" ]]; then + "$PYTHON_BIN" "$REPO_ROOT/scripts/inject_svg_styles.py" --fix -f "$svg_out" >/dev/null 2>&1 || true + fi + echo -e " ${GREEN}✓${NC} SVG [$idx/$TOTAL] $base" + else + echo -e " ${RED}✗${NC} SVG [$idx/$TOTAL] $base" + return 1 + fi + fi + + # Render PNG + if [[ $FORMAT_PNG -eq 1 ]]; then + mkdir -p "$png_dir" + local png_out="$png_dir/${base}.png" + + if [[ $FORMAT_SVG -eq 1 && $HAS_RSVG -eq 1 ]]; then + # SVG → PNG via rsvg-convert (adaptive: use SVG intrinsic size) + if [[ $FIT -eq 0 ]]; then + rsvg-convert -b "$BG" -w "$WIDTH" -h "$HEIGHT" "$svg_dir/${base}.svg" -o "$png_out" 2>/dev/null + else + rsvg-convert -b "$BG" -d "$dpi_for_file" -p "$dpi_for_file" "$svg_dir/${base}.svg" -o "$png_out" 2>/dev/null + fi + elif [[ $FORMAT_SVG -eq 1 && $HAS_RSVG -eq 2 ]]; then + # SVG → PNG via inkscape + if [[ $FIT -eq 0 ]]; then + inkscape "$svg_dir/${base}.svg" --export-type=png --export-width="$WIDTH" \ + --export-height="$HEIGHT" --export-background="$BG" --export-background-opacity=1 \ + --export-filename="$png_out" 2>/dev/null + else + inkscape "$svg_dir/${base}.svg" --export-type=png --export-dpi="$dpi_for_file" \ + --export-background="$BG" --export-background-opacity=1 --export-filename="$png_out" 2>/dev/null + fi + else + # Direct mmdc → PNG (adaptive: use -s scale only) + mmdc -i "$src" -o "$png_out" "${MMDC_ARGS[@]}" \ + "${size_args[@]}" -s "$scale_for_file" -b "$BG" 2>/dev/null + fi + + if [[ -f "$png_out" ]]; then + local size + size=$(du -h "$png_out" | cut -f1) + if [[ "$is_large" -eq 1 ]]; then + echo -e " ${GREEN}✓${NC} PNG [$idx/$TOTAL] $base (${size}, hi-res ${large_reason})" + else + echo -e " ${GREEN}✓${NC} PNG [$idx/$TOTAL] $base (${size})" + fi + else + echo -e " ${RED}✗${NC} PNG [$idx/$TOTAL] $base" + return 1 + fi + fi + + return 0 +} + +# ── Main loop ─────────────────────────────────────────────── +success=0 +failed=0 +current_dir="" + +if [[ "$JOBS" -eq 1 ]]; then + for i in "${!files[@]}"; do + src="${files[$i]}" + idx=$((i + 1)) + dir="$(dirname "$src")" + + # Print directory header on change + if [[ "$dir" != "$current_dir" ]]; then + current_dir="$dir" + echo "" + log_step "Directory: ${dir#"$REPO_ROOT/"}" + echo "" + fi + + if render_one "$src" "$idx"; then + success=$((success + 1)) + else + failed=$((failed + 1)) + fi + done +else + log_step "Rendering in parallel with $JOBS jobs..." + echo "" + result_dir="$(mktemp -d)" + active_jobs=0 + + for i in "${!files[@]}"; do + src="${files[$i]}" + idx=$((i + 1)) + ( + if render_one "$src" "$idx"; then + printf "ok\n" > "$result_dir/$idx.status" + else + printf "fail\n" > "$result_dir/$idx.status" + fi + ) & + active_jobs=$((active_jobs + 1)) + + if [[ "$active_jobs" -ge "$JOBS" ]]; then + wait -n || true + active_jobs=$((active_jobs - 1)) + fi + done + + while [[ "$active_jobs" -gt 0 ]]; do + wait -n || true + active_jobs=$((active_jobs - 1)) + done + + for i in "${!files[@]}"; do + idx=$((i + 1)) + if [[ -f "$result_dir/$idx.status" ]] && [[ "$(cat "$result_dir/$idx.status")" == "ok" ]]; then + success=$((success + 1)) + else + failed=$((failed + 1)) + fi + done + rm -rf "$result_dir" +fi + +# ── Generate index files per output directory ─────────────── +log_step "Generating index files..." +echo "" + +declare -A source_dirs_map=() +for src in "${files[@]}"; do + src_dir="$(dirname "$src")" + source_dirs_map["$src_dir"]=1 +done +mapfile -t source_dirs < <(printf '%s\n' "${!source_dirs_map[@]}" | sort) + +for dir in "${source_dirs[@]}"; do + for sub in svg png; do + out_dir="$dir/$sub" + [[ ! -d "$out_dir" ]] && continue + + index_file="$out_dir/INDEX.md" + { + echo "# BioETL Diagrams — ${sub^^} Index" + echo "" + echo "_Generated: $(date -Iseconds)_" + echo "" + shopt -s nullglob + for f in "$out_dir"/*."$sub"; do + name="$(basename "$f" ".$sub")" + title="${name//-/ }" + # Capitalize first letter of each word + title="$(echo "$title" | sed 's/\b[0-9]*\b //;s/\b\(.\)/\u\1/g')" + echo "## $title" + echo "" + if [[ "$sub" == "svg" ]]; then + echo "![${name}](./${name}.svg)" + else + echo "![${name}](./${name}.png)" + fi + echo "" + echo "---" + echo "" + done + shopt -u nullglob + } > "$index_file" + echo -e " ${GREEN}✓${NC} Index: ${index_file#"$REPO_ROOT/"}" + done +done + +# ── Summary ───────────────────────────────────────────────── +echo "" +echo -e "${BOLD}════════════════════════════════════════════${NC}" +echo -e "${BOLD} Summary${NC}" +echo -e "${BOLD}════════════════════════════════════════════${NC}" +echo "" +echo -e " Total diagrams: ${BOLD}$TOTAL${NC}" +echo -e " ${GREEN}Rendered OK:${NC} $success" +[[ $failed -gt 0 ]] && echo -e " ${RED}Failed:${NC} $failed" +echo "" +echo -e " Theme: ${CONFIG:-'(default)'}" +echo -e " CSS: ${CSS:-'(none)'}" +echo "" + +formats="" +[[ $FORMAT_SVG -eq 1 ]] && formats+="SVG " +[[ $FORMAT_PNG -eq 1 ]] && formats+="PNG " +echo -e " Formats: ${BOLD}${formats}${NC}" +if [[ $FIT -eq 1 ]]; then + echo -e " Layout: ${BOLD}adaptive${NC} (fit to content, ELK engine)" +else + echo -e " Layout: ${BOLD}fixed${NC} (${WIDTH}x${HEIGHT})" +fi +echo -e " PNG: base scale=${SCALE}, large scale=${LARGE_SCALE} (@nodes>=${LARGE_THRESHOLD})" +echo -e " base dpi=${PNG_DPI}, large dpi=${LARGE_PNG_DPI}" +echo "" + +if [[ $failed -eq 0 ]]; then + log_info "All diagrams rendered successfully" + exit 0 +else + log_warn "$failed diagram(s) failed — check errors above" + exit 1 +fi diff --git a/.rollback/uniform-detect-fix-20260301-162337/uniform_diagram_sizes.py.bak b/.rollback/uniform-detect-fix-20260301-162337/uniform_diagram_sizes.py.bak new file mode 100644 index 0000000000..d4a69cf985 --- /dev/null +++ b/.rollback/uniform-detect-fix-20260301-162337/uniform_diagram_sizes.py.bak @@ -0,0 +1,984 @@ +#!/usr/bin/env python3 +""" +uniform_diagram_sizes.py — Normalize object sizes in Mermaid diagrams. + +For each diagram file, determines the maximum width (by longest visible text +line) and maximum height (by most content lines) across all objects, then +pads every object to those dimensions using   characters. + +Supports groupwise sizing: when @uniform-group tags are present, objects +within each group are normalized to their group's max height rather than +the global max. Width strategy can be controlled via: + %% @uniform-width global (default, globally uniform width) + %% @uniform-width group (group-local width) +Objects not assigned to any group go into an implicit "default" group. + +Supports two diagram types: + - classDiagram: class Name { ... } blocks + - flowchart/graph: ID["Label
line2
..."] nodes + +Usage: + # Check all diagrams (exit 1 on drift) + python scripts/uniform_diagram_sizes.py --check + + # Fix all diagrams in-place + python scripts/uniform_diagram_sizes.py --fix + + # Dry-run: show diff without writing + python scripts/uniform_diagram_sizes.py --dry-run + + # Process specific files + python scripts/uniform_diagram_sizes.py --fix -f docs/.../01-domain-ports.mmd + + # Process specific directory + python scripts/uniform_diagram_sizes.py --fix --dir docs/.../class-diagrams + +Groupwise sizing (add to .mmd file header): + %% @uniform-group base nodes=BaseHttpAdapter,BaseSyncAdapter + %% @uniform-group adapter nodes=ChemblAdapter,PubMedAdapter,... +""" +from __future__ import annotations + +import argparse +import difflib +import re +import sys +from dataclasses import dataclass, field +from pathlib import Path + +# ── Defaults ──────────────────────────────────────────────────────────────── + +DIAGRAM_DIRS = [ + Path("docs/02-architecture/mmd-diagrams/architecture"), + Path("docs/02-architecture/mmd-diagrams/class-diagrams"), + Path("docs/02-architecture/mmd-diagrams/foundation"), +] +SUPPORTED_SUFFIXES = {".mmd", ".mermaid"} + +# ── ANSI colours ──────────────────────────────────────────────────────────── + +RED = "\033[0;31m" +GREEN = "\033[0;32m" +YELLOW = "\033[1;33m" +CYAN = "\033[0;36m" +BOLD = "\033[1m" +NC = "\033[0m" + +# ── Regex patterns ────────────────────────────────────────────────────────── + +_CLASS_DIAGRAM_RE = re.compile(r"^\s*classDiagram\b", re.IGNORECASE) +_FLOWCHART_RE = re.compile(r"^\s*(graph|flowchart)\b", re.IGNORECASE) +_CLASS_BLOCK_START_RE = re.compile(r"^\s+class\s+(\w+)\s*\{") +_CLASS_BLOCK_END_RE = re.compile(r"^\s+\}") +_UNIFORM_TAG_RE = re.compile(r"^%% @uniform(?:\s|$).*$") +_UNIFORM_STATS_RE = re.compile(r"^%% @uniform-stats\b.*$") +_UNIFORM_GROUP_RE = re.compile( + r"^%%\s*@uniform-group\s+(\S+)\s+nodes=(.+)$" +) +_UNIFORM_WIDTH_RE = re.compile( + r"^%%\s*@uniform-width\s+(global|group|grouped)\s*$", + re.IGNORECASE, +) +_NBSP = " " + +# Flowchart node patterns: +# ID["Label text"] — rectangle +# ID(["Label text"]) — rounded +# ID[("Label text")] — cylinder +# ID(("Label text")) — circle +# ID{{"Label text"}} — hexagon +# We capture: ID, opening bracket sequence, label content, closing bracket sequence +_FLOWCHART_NODE_RE = re.compile( + r'^(\s+)' # leading indent + r'(\w+)' # node ID + r'(\["|\(\["|\[\("|\(\("|\{\{")' # opening brackets + r'(.+?)' # label content (non-greedy) + r'("\]|"\)\]|"\)\]|"\)\)|"\}\})' # closing brackets + r'\s*$' # trailing whitespace +) + + +# ── Data structures ───────────────────────────────────────────────────────── + +@dataclass +class ClassBlock: + """A parsed class block from a classDiagram.""" + + name: str + start_line: int # index in file lines (0-based), the `class Name {` line + end_line: int # index of the closing `}` + stereotype_line: str | None # e.g. "<>" with existing padding + content_lines: list[str] # real content lines (stripped of padding  ) + padding_lines: int # count of trailing  -only lines + raw_lines: list[str] # original lines between { and } (exclusive) + indent: str # whitespace prefix for body lines + + +@dataclass +class FlowchartNode: + """A parsed flowchart node.""" + + node_id: str + line_index: int + indent: str + open_bracket: str + close_bracket: str + label_parts: list[str] # split by
+ content_parts: list[str] # label_parts stripped of   padding + raw_label: str + + +@dataclass +class UniformStats: + """Computed uniform dimensions for a diagram.""" + + max_visible_width: int # in characters (longest line across all objects) + max_total_body: int # total body lines (stereotype + content) max + max_title_len: int # longest class/node name + + +@dataclass +class UniformGroup: + """A named group of objects that share uniform height.""" + + name: str + node_names: set[str] + + +# ── Group parsing ────────────────────────────────────────────────────────── + + +def _parse_uniform_groups(lines: list[str]) -> list[UniformGroup]: + """Parse all @uniform-group tags from file header comments.""" + groups: list[UniformGroup] = [] + for line in lines: + m = _UNIFORM_GROUP_RE.match(line.strip()) + if m: + group_name = m.group(1) + node_names = {n.strip() for n in m.group(2).split(",") if n.strip()} + groups.append(UniformGroup(name=group_name, node_names=node_names)) + return groups + + +def _parse_uniform_width_strategy(lines: list[str]) -> str: + """Parse optional @uniform-width strategy; default is 'global'.""" + for line in lines: + match = _UNIFORM_WIDTH_RE.match(line.strip()) + if not match: + continue + raw = match.group(1).lower() + return "group" if raw in {"group", "grouped"} else "global" + return "global" + + +def _assign_groups( + object_names: list[str], + groups: list[UniformGroup], +) -> dict[str, str]: + """Return mapping of object_name -> group_name. + + Unassigned objects go into the 'default' group. + Raises ValueError if a name appears in multiple groups. + """ + assignment: dict[str, str] = {} + for g in groups: + for name in g.node_names: + if name in assignment: + raise ValueError( + f"Node '{name}' assigned to multiple groups: " + f"'{assignment[name]}' and '{g.name}'" + ) + assignment[name] = g.name + for name in object_names: + if name not in assignment: + assignment[name] = "default" + return assignment + + +def _partition_by_group( + items: list[ClassBlock] | list[FlowchartNode], + assignment: dict[str, str], +) -> dict[str, list]: + """Partition items into groups based on assignment map.""" + groups: dict[str, list] = {} + for item in items: + name = item.name if isinstance(item, ClassBlock) else item.node_id + g = assignment.get(name, "default") + groups.setdefault(g, []).append(item) + return groups + + +# ── Helpers ───────────────────────────────────────────────────────────────── + +def _strip_nbsp(text: str) -> str: + """Remove trailing   sequences from text.""" + while text.endswith(_NBSP): + text = text[: -len(_NBSP)] + return text.rstrip() + + +def _count_visual_chars(text: str) -> int: + """Count visual character width, treating   as 1 char.""" + clean = text.replace(_NBSP, " ") + return len(clean) + + +def _is_nbsp_only(text: str) -> bool: + """Check if line consists only of   and whitespace.""" + return text.strip().replace(_NBSP, "").strip() == "" + + +def _pad_width(text: str, target_width: int) -> str: + """Pad text with   to reach target visual width.""" + current = _count_visual_chars(text) + if current >= target_width: + return text + needed = target_width - current + return text + _NBSP * needed + + +# ── Class diagram parser ─────────────────────────────────────────────────── + +def _detect_diagram_type(lines: list[str]) -> str | None: + """Detect whether file is classDiagram or flowchart.""" + for line in lines: + stripped = line.strip() + if not stripped or stripped.startswith("%%"): + if stripped.startswith("%%{"): + continue + continue + if _CLASS_DIAGRAM_RE.match(stripped): + return "class" + if _FLOWCHART_RE.match(stripped): + return "flowchart" + return None + return None + + +def _parse_class_blocks(lines: list[str]) -> list[ClassBlock]: + """Parse all class blocks from classDiagram lines.""" + blocks: list[ClassBlock] = [] + i = 0 + while i < len(lines): + m = _CLASS_BLOCK_START_RE.match(lines[i]) + if m: + name = m.group(1) + start = i + # Detect indent from body lines + indent = " " # default 8 spaces + # Find closing brace + j = i + 1 + body_lines: list[str] = [] + while j < len(lines): + if _CLASS_BLOCK_END_RE.match(lines[j]): + break + body_lines.append(lines[j]) + j += 1 + end = j + + # Detect actual indent + for bl in body_lines: + if bl.strip(): + indent = bl[: len(bl) - len(bl.lstrip())] + break + + # Separate stereotype, content, and padding + stereotype_line: str | None = None + content_lines: list[str] = [] + padding_count = 0 + + for bl in body_lines: + stripped = bl.strip() + if stereotype_line is None and stripped.startswith("<<"): + stereotype_line = stripped + elif _is_nbsp_only(stripped): + padding_count += 1 + else: + # If we had padding lines before content, they were + # actually content separators — treat them as content + if padding_count > 0 and content_lines: + content_lines.extend([""] * padding_count) + padding_count = 0 + if stripped: + content_lines.append(stripped) + + blocks.append( + ClassBlock( + name=name, + start_line=start, + end_line=end, + stereotype_line=stereotype_line, + content_lines=content_lines, + padding_lines=padding_count, + raw_lines=body_lines, + indent=indent, + ) + ) + i = end + 1 + else: + i += 1 + + return blocks + + +def _compute_class_uniform(blocks: list[ClassBlock]) -> UniformStats: + """Compute uniform dimensions across all class blocks. + + Height is computed as total body lines (stereotype + content), so + classes with and without stereotypes get the same rendered height. + """ + max_title = 0 + max_total_body = 0 + max_width = 0 + + for b in blocks: + # Title length (class name) + max_title = max(max_title, len(b.name)) + + # Total body = stereotype (0 or 1) + content lines + stripped_content = [_strip_nbsp(c) for c in b.content_lines] + total_body = (1 if b.stereotype_line else 0) + len(stripped_content) + max_total_body = max(max_total_body, total_body) + + # Max visible width across all visible lines in block + all_visible: list[str] = [] + if b.stereotype_line: + all_visible.append(_strip_nbsp(b.stereotype_line)) + all_visible.extend(stripped_content) + + for line in all_visible: + max_width = max(max_width, _count_visual_chars(line)) + + return UniformStats( + max_visible_width=max_width, + max_total_body=max_total_body, + max_title_len=max_title, + ) + + +def _rebuild_class_block( + block: ClassBlock, + stats: UniformStats, +) -> list[str]: + """Rebuild a class block with uniform padding. + + Total body lines = stereotype (0 or 1) + content + padding = max_total_body. + """ + result: list[str] = [] + + # Stereotype line (pad width) + if block.stereotype_line: + stripped_stereo = _strip_nbsp(block.stereotype_line) + padded = _pad_width(stripped_stereo, stats.max_visible_width) + result.append(f"{block.indent}{padded}") + + # Content lines (pad width) + stripped_content = [_strip_nbsp(c) for c in block.content_lines] + for line in stripped_content: + if line: + padded = _pad_width(line, stats.max_visible_width) + result.append(f"{block.indent}{padded}") + else: + result.append(f"{block.indent}{_NBSP}") + + # Height padding: total body (stereo + content + padding) = max_total_body + current_body = (1 if block.stereotype_line else 0) + len(stripped_content) + pad_needed = stats.max_total_body - current_body + for _ in range(pad_needed): + result.append(f"{block.indent}{_NBSP}") + + return result + + +def _normalize_class_diagram(lines: list[str]) -> list[str]: + """Normalize all class blocks in a classDiagram to uniform sizes. + + When @uniform-group tags are present, height is normalized per-group + while width stays globally uniform. Without groups, all blocks share + a single global uniform (backward compatible). + """ + blocks = _parse_class_blocks(lines) + if not blocks: + return lines + + groups = _parse_uniform_groups(lines) + width_strategy = _parse_uniform_width_strategy(lines) + + if not groups: + # Backward compatible: single global uniform + stats = _compute_class_uniform(blocks) + stats_map: dict[str, UniformStats] = {b.name: stats for b in blocks} + group_stats: dict[str, UniformStats] | None = None + else: + # Group-aware normalization + assignment = _assign_groups([b.name for b in blocks], groups) + grouped_blocks = _partition_by_group(blocks, assignment) + + # Per-group stats (height always per-group, width by strategy) + group_stats_raw: dict[str, UniformStats] = {} + for gname, gblocks in grouped_blocks.items(): + gs = _compute_class_uniform(gblocks) + group_stats_raw[gname] = gs + + group_stats = {} + if width_strategy == "global": + global_max_width = 0 + global_max_title = 0 + for gs in group_stats_raw.values(): + global_max_width = max(global_max_width, gs.max_visible_width) + global_max_title = max(global_max_title, gs.max_title_len) + + # Override width to global max for visual consistency + for gname, gs in group_stats_raw.items(): + group_stats[gname] = UniformStats( + max_visible_width=global_max_width, + max_total_body=gs.max_total_body, + max_title_len=global_max_title, + ) + else: + for gname, gs in group_stats_raw.items(): + group_stats[gname] = UniformStats( + max_visible_width=gs.max_visible_width, + max_total_body=gs.max_total_body, + max_title_len=gs.max_title_len, + ) + + stats_map = { + b.name: group_stats[assignment[b.name]] for b in blocks + } + + # Rebuild file, replacing block bodies + result: list[str] = [] + block_map: dict[int, ClassBlock] = {b.start_line: b for b in blocks} + skip_until: int | None = None + + for i, line in enumerate(lines): + if skip_until is not None: + if i <= skip_until: + continue + skip_until = None + + if i in block_map: + b = block_map[i] + result.append(line) + result.extend(_rebuild_class_block(b, stats_map[b.name])) + result.append(lines[b.end_line]) + skip_until = b.end_line + else: + result.append(line) + + # Update @uniform tag(s) + if group_stats is not None: + result = _update_uniform_tag_grouped( + result, + group_stats, + groups, + "class", + width_strategy=width_strategy, + ) + else: + result = _update_uniform_tag(result, stats, "class") + + return result + + +# ── Flowchart parser ──────────────────────────────────────────────────────── + +def _parse_flowchart_nodes(lines: list[str]) -> list[FlowchartNode]: + """Parse flowchart nodes that use multi-line labels (with
).""" + nodes: list[FlowchartNode] = [] + + for i, line in enumerate(lines): + m = _FLOWCHART_NODE_RE.match(line) + if m: + indent = m.group(1) + node_id = m.group(2) + open_br = m.group(3) + raw_label = m.group(4) + close_br = m.group(5) + + # Split by
(case insensitive) + parts = re.split(r"
", raw_label, flags=re.IGNORECASE) + content_parts = [_strip_nbsp(p) for p in parts] + + nodes.append( + FlowchartNode( + node_id=node_id, + line_index=i, + indent=indent, + open_bracket=open_br, + close_bracket=close_br, + label_parts=parts, + content_parts=content_parts, + raw_label=raw_label, + ) + ) + + return nodes + + +def _compute_flowchart_uniform(nodes: list[FlowchartNode]) -> UniformStats: + """Compute uniform dimensions for flowchart nodes.""" + max_title = 0 + max_lines = 0 + max_width = 0 + + for n in nodes: + # First part is typically the title + if n.content_parts: + max_title = max(max_title, _count_visual_chars(n.content_parts[0])) + + # Number of
parts + max_lines = max(max_lines, len(n.content_parts)) + + # Width of each part + for part in n.content_parts: + max_width = max(max_width, _count_visual_chars(part)) + + return UniformStats( + max_visible_width=max_width, + max_total_body=max_lines, + max_title_len=max_title, + ) + + +def _rebuild_flowchart_node( + node: FlowchartNode, + stats: UniformStats, +) -> str: + """Rebuild a flowchart node with uniform padding.""" + # Pad each content part to max width + padded_parts: list[str] = [] + for part in node.content_parts: + if part: + padded_parts.append(_pad_width(part, stats.max_visible_width)) + else: + padded_parts.append(_NBSP) + + # Height padding: add
  lines + while len(padded_parts) < stats.max_total_body: + padded_parts.append(_NBSP) + + label = "
".join(padded_parts) + return ( + f"{node.indent}{node.node_id}" + f"{node.open_bracket}{label}{node.close_bracket}" + ) + + +def _normalize_flowchart(lines: list[str]) -> list[str]: + """Normalize all flowchart nodes to uniform sizes. + + When @uniform-group tags are present, height is normalized per-group + while width stays globally uniform. + """ + nodes = _parse_flowchart_nodes(lines) + if not nodes: + return lines + + groups = _parse_uniform_groups(lines) + width_strategy = _parse_uniform_width_strategy(lines) + + if not groups: + stats = _compute_flowchart_uniform(nodes) + stats_map: dict[str, UniformStats] = {n.node_id: stats for n in nodes} + group_stats: dict[str, UniformStats] | None = None + else: + assignment = _assign_groups([n.node_id for n in nodes], groups) + grouped_nodes = _partition_by_group(nodes, assignment) + + group_stats_raw: dict[str, UniformStats] = {} + for gname, gnodes in grouped_nodes.items(): + gs = _compute_flowchart_uniform(gnodes) + group_stats_raw[gname] = gs + + group_stats = {} + if width_strategy == "global": + global_max_width = 0 + global_max_title = 0 + for gs in group_stats_raw.values(): + global_max_width = max(global_max_width, gs.max_visible_width) + global_max_title = max(global_max_title, gs.max_title_len) + for gname, gs in group_stats_raw.items(): + group_stats[gname] = UniformStats( + max_visible_width=global_max_width, + max_total_body=gs.max_total_body, + max_title_len=global_max_title, + ) + else: + for gname, gs in group_stats_raw.items(): + group_stats[gname] = UniformStats( + max_visible_width=gs.max_visible_width, + max_total_body=gs.max_total_body, + max_title_len=gs.max_title_len, + ) + + stats_map = { + n.node_id: group_stats[assignment[n.node_id]] for n in nodes + } + + # Build index of lines to replace + replacements: dict[int, str] = {} + for n in nodes: + replacements[n.line_index] = _rebuild_flowchart_node(n, stats_map[n.node_id]) + + result: list[str] = [] + for i, line in enumerate(lines): + if i in replacements: + result.append(replacements[i]) + else: + result.append(line) + + if group_stats is not None: + result = _update_uniform_tag_grouped( + result, + group_stats, + groups, + "flowchart", + width_strategy=width_strategy, + ) + else: + result = _update_uniform_tag(result, stats, "flowchart") + + return result + + +# ── @uniform tag management ───────────────────────────────────────────────── + + +def _estimate_pixel_dims( + stats: UniformStats, +) -> tuple[int, int]: + """Estimate pixel width and height for a UniformStats. + + Returns (est_width, est_height) rounded to nearest 8px. + """ + title_char_px = 10 # 15px bold font + body_char_px = 7 # 12-13px regular font + line_px = 18 + header_px = 36 # class name header height + + title_px = stats.max_title_len * title_char_px + body_px = stats.max_visible_width * body_char_px + est_width = max(title_px, body_px) + est_height = stats.max_total_body * line_px + header_px + + est_width = ((est_width + 7) // 8) * 8 + est_height = ((est_height + 7) // 8) * 8 + return est_width, est_height + + +def _update_uniform_tag_grouped( + lines: list[str], + group_stats: dict[str, UniformStats], + groups: list[UniformGroup], + diagram_type: str, + width_strategy: str = "global", +) -> list[str]: + """Update @uniform + @uniform-stats tags for grouped normalization. + + Generates: + %% @uniform class width=304 groups=3 + %% @uniform-stats base height=180 max_desc_lines=8 nodes=3 + %% @uniform-stats adapter height=126 max_desc_lines=5 nodes=7 + """ + # Compute global width from all groups + global_width = 0 + for gs in group_stats.values(): + w, _ = _estimate_pixel_dims(gs) + global_width = max(global_width, w) + + num_groups = len(group_stats) + type_prefix = f"{diagram_type} " if diagram_type == "class" else "" + main_tag = ( + f"%% @uniform {type_prefix}width={global_width} " + f"groups={num_groups} width_strategy={width_strategy}" + ) + + # Build stats lines in group definition order, then default last + stats_lines: list[str] = [] + # Ordered group names: explicit groups first, then 'default' if present + ordered_names: list[str] = [g.name for g in groups] + if "default" in group_stats and "default" not in ordered_names: + ordered_names.append("default") + + for gname in ordered_names: + if gname not in group_stats: + continue + gs = group_stats[gname] + est_w, est_h = _estimate_pixel_dims(gs) + stats_lines.append( + f"%% @uniform-stats {gname:<12s} " + f"width={est_w} " + f"height={est_h} " + f"max_desc_lines={gs.max_total_body}" + ) + + # Remove existing @uniform and @uniform-stats lines + cleaned: list[str] = [] + for line in lines: + stripped = line.strip() + if _UNIFORM_TAG_RE.match(stripped) or _UNIFORM_STATS_RE.match(stripped): + continue + cleaned.append(line) + + # Find insertion point: before diagram declaration or %%{init + insert_at: int | None = None + for i, line in enumerate(cleaned): + stripped = line.strip() + if ( + _CLASS_DIAGRAM_RE.match(stripped) + or _FLOWCHART_RE.match(stripped) + or stripped.startswith("%%{init") + ): + insert_at = i + break + + if insert_at is not None: + for j, tag_line in enumerate([main_tag, *stats_lines]): + cleaned.insert(insert_at + j, tag_line) + else: + cleaned.append(main_tag) + cleaned.extend(stats_lines) + + return cleaned + + +def _update_uniform_tag( + lines: list[str], + stats: UniformStats, + diagram_type: str, +) -> list[str]: + """Update or insert the @uniform metadata tag (non-grouped mode).""" + est_width, est_height = _estimate_pixel_dims(stats) + + if diagram_type == "class": + tag = ( + f"%% @uniform class " + f"width={est_width} height={est_height} " + f"max_title_len={stats.max_title_len} " + f"max_desc_lines={stats.max_total_body}" + ) + else: + tag = ( + f"%% @uniform " + f"width={est_width} height={est_height} " + f"max_title_len={stats.max_title_len} " + f"max_desc_lines={stats.max_total_body}" + ) + + # Remove any stale @uniform-stats lines (leftover from grouped mode) + lines = [ + line for line in lines + if not _UNIFORM_STATS_RE.match(line.strip()) + ] + + # Find and replace existing @uniform, or insert before diagram declaration + for i, line in enumerate(lines): + if _UNIFORM_TAG_RE.match(line.strip()): + lines[i] = tag + return lines + + # Insert before first diagram declaration line + for i, line in enumerate(lines): + stripped = line.strip() + if ( + _CLASS_DIAGRAM_RE.match(stripped) + or _FLOWCHART_RE.match(stripped) + or stripped.startswith("%%{init") + ): + lines.insert(i, tag) + return lines + + return lines + + +# ── Main processing ───────────────────────────────────────────────────────── + +def normalize_file(path: Path) -> tuple[str, str, bool]: + """Normalize a single diagram file. + + Returns (original_content, normalized_content, changed). + """ + content = path.read_text(encoding="utf-8") + lines = content.splitlines() + + dtype = _detect_diagram_type(lines) + if dtype == "class": + normalized = _normalize_class_diagram(lines) + elif dtype == "flowchart": + normalized = _normalize_flowchart(lines) + else: + return content, content, False + + new_content = "\n".join(normalized) + # Preserve trailing newline + if content.endswith("\n"): + new_content += "\n" + + return content, new_content, content != new_content + + +def find_diagram_files(targets: list[Path]) -> list[Path]: + """Find all supported diagram files from target paths.""" + files: list[Path] = [] + seen: set[Path] = set() + + for target in targets: + if target.is_file(): + if target.suffix in SUPPORTED_SUFFIXES and target not in seen: + seen.add(target) + files.append(target) + continue + + for suffix in SUPPORTED_SUFFIXES: + for f in sorted(target.rglob(f"*{suffix}")): + if not f.name.startswith("_") and f not in seen: + seen.add(f) + files.append(f) + + return sorted(files) + + +def show_diff(path: Path, original: str, normalized: str) -> None: + """Print a unified diff for a file.""" + import io + + # Force UTF-8 output to avoid Windows cp1251 encoding errors + out = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace") + diff = difflib.unified_diff( + original.splitlines(keepends=True), + normalized.splitlines(keepends=True), + fromfile=f"a/{path.name}", + tofile=f"b/{path.name}", + n=2, + ) + for line in diff: + if line.startswith("+") and not line.startswith("+++"): + out.write(f"{GREEN}{line}{NC}") + elif line.startswith("-") and not line.startswith("---"): + out.write(f"{RED}{line}{NC}") + elif line.startswith("@@"): + out.write(f"{CYAN}{line}{NC}") + else: + out.write(line) + out.flush() + out.detach() # prevent closing sys.stdout + + +# ── CLI ───────────────────────────────────────────────────────────────────── + +def main() -> int: + parser = argparse.ArgumentParser( + description=( + "Normalize object sizes in Mermaid diagrams. " + "Pads all objects to uniform width (by max name length) " + "and height (by max description lines)." + ), + ) + mode = parser.add_mutually_exclusive_group(required=True) + mode.add_argument( + "--check", + action="store_true", + help="Check for drift (exit 1 if any file needs normalization)", + ) + mode.add_argument( + "--fix", + action="store_true", + help="Fix files in-place", + ) + mode.add_argument( + "--dry-run", + action="store_true", + help="Show diffs without writing", + ) + parser.add_argument( + "-f", + "--files", + nargs="+", + type=Path, + help="Specific files to process", + ) + parser.add_argument( + "--dir", + nargs="+", + type=Path, + dest="dirs", + help="Specific directories to process", + ) + + args = parser.parse_args() + + # Determine targets + if args.files: + targets = args.files + elif args.dirs: + targets = args.dirs + else: + targets = [d for d in DIAGRAM_DIRS if d.exists()] + + files = find_diagram_files(targets) + if not files: + print(f"{YELLOW}No diagram files found.{NC}") + return 0 + + print(f"{BOLD}Uniform Diagram Sizer{NC}") + print(f" Files: {len(files)}") + print() + + changed_count = 0 + checked_count = 0 + error_count = 0 + + for path in files: + try: + original, normalized, changed = normalize_file(path) + except Exception as e: + print(f" {RED}ERROR{NC} {path.name}: {e}") + error_count += 1 + continue + + checked_count += 1 + + if not changed: + if not args.check: + print(f" {GREEN}OK{NC} {path}") + continue + + changed_count += 1 + + if args.check: + print(f" {RED}DRIFT{NC} {path}") + elif args.dry_run: + print(f" {YELLOW}DIFF{NC} {path}") + show_diff(path, original, normalized) + print() + else: + path.write_text(normalized, encoding="utf-8") + print(f" {GREEN}FIXED{NC} {path}") + + # Summary + print() + print(f" Checked: {checked_count}") + if args.fix: + print(f" {GREEN}Fixed: {changed_count}{NC}") + elif args.check: + print(f" Drifted: {changed_count}") + else: + print(f" Would fix: {changed_count}") + if error_count: + print(f" {RED}Errors: {error_count}{NC}") + + if args.check and changed_count > 0: + print() + print( + f" {RED}FAIL{NC}: {changed_count} file(s) need normalization. " + f"Run with --fix to correct." + ) + return 1 + + return 1 if error_count > 0 else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/Makefile b/Makefile index b165290f80..825838cc60 100644 --- a/Makefile +++ b/Makefile @@ -189,16 +189,16 @@ diagram-preflight: ## Check Mermaid render dependencies (mmdc required, svgo/rsv lint-diagrams: ## Lint all Mermaid source files in docs/ (excluding docs/99-archive/**) @echo "$(BLUE)Linting diagram policies...$(NC)" - $(PY_RUN) scripts/lint_diagrams.py docs + $(PY_RUN) scripts/diagrams/lint_diagrams.py docs report-diagrams-policy: ## Generate non-blocking diagram lint summary report @echo "$(BLUE)Generating diagram lint summary report...$(NC)" - $(PY_RUN) scripts/lint_diagrams.py docs/02-architecture/mmd-diagrams --json > /tmp/diagram-lint.json || true - $(PY_RUN) scripts/summarize_diagram_lint.py /tmp/diagram-lint.json + $(PY_RUN) scripts/diagrams/lint_diagrams.py docs/02-architecture/mmd-diagrams --json > /tmp/diagram-lint.json || true + $(PY_RUN) scripts/diagrams/summarize_diagram_lint.py /tmp/diagram-lint.json validate-diagrams-syntax: diagram-preflight ## Validate Mermaid syntax for docs/**/*.mmd|*.mermaid @echo "$(BLUE)Validating Mermaid syntax...$(NC)" - bash scripts/validate_mermaid_syntax.sh + bash scripts/diagrams/validate_mermaid_syntax.sh render-diagrams-all: diagram-preflight ## Render all docs diagrams to SVG+PNG (excluding docs/99-archive/**) @echo "$(BLUE)Rendering all diagrams (SVG+PNG)...$(NC)" @@ -216,14 +216,14 @@ render-diagrams-png: diagram-preflight ## Render all docs diagrams to PNG only check-diagrams-visibility: ## Check text visibility in baseline SVG smoke set @echo "$(BLUE)Checking SVG text visibility (smoke manifest)...$(NC)" - $(PY_RUN) scripts/check_svg_text_visibility.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt + $(PY_RUN) scripts/diagrams/check_svg_text_visibility.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt diagrams-all: lint-diagrams validate-diagrams-syntax render-diagrams-all check-diagrams-visibility ## Full diagram pipeline (lint + validate + render + visibility check) @echo "$(GREEN)Diagram pipeline complete.$(NC)" report-diagram-padding: ## Report top files by   usage in Mermaid sources @echo "$(BLUE)Reporting Mermaid   usage...$(NC)" - $(PY_RUN) scripts/report_diagram_padding.py --top 30 + $(PY_RUN) scripts/diagrams/report_diagram_padding.py --top 30 security: ## Run security audit (osv-scanner + pip-audit) @echo "$(BLUE)Running security audit...$(NC)" diff --git a/docs/02-architecture/06-diagram-policy.md b/docs/02-architecture/06-diagram-policy.md index d91baf8ce2..b8ea5c57b9 100644 --- a/docs/02-architecture/06-diagram-policy.md +++ b/docs/02-architecture/06-diagram-policy.md @@ -103,15 +103,15 @@ 2. Есть соответствующий рендер (`svg/png`) в ожидаемом каталоге. 3. Есть запись в индексной странице/разделе документации. 4. Ссылка на диаграмму не битая. -5. `scripts/lint_diagrams.py` не даёт ошибок. +5. `scripts/diagrams/lint_diagrams.py` не даёт ошибок. ## 8. Обязательные проверки ```bash -python3 scripts/lint_diagrams.py docs +python3 scripts/diagrams/lint_diagrams.py docs python3 scripts/check_doc_links.py --links -python3 scripts/check_diagram_visual_smoke.py -bash scripts/validate_mermaid_syntax.sh +python3 scripts/diagrams/check_diagram_visual_smoke.py +bash scripts/diagrams/validate_mermaid_syntax.sh ``` Если runtime для `validate_mermaid_syntax.sh` не готов, это фиксируется как открытый риск до устранения. diff --git a/docs/02-architecture/decisions/ADR-040-diagram-governance.md b/docs/02-architecture/decisions/ADR-040-diagram-governance.md index c01ee7a9ba..d435aaa32e 100644 --- a/docs/02-architecture/decisions/ADR-040-diagram-governance.md +++ b/docs/02-architecture/decisions/ADR-040-diagram-governance.md @@ -41,7 +41,7 @@ BioETL содержит два каталога диаграмм с разным - Тема: `theme/mermaid-config.json` + `theme/custom.css` (строки 140–151) - Рендер: `render.sh` (SVG + PNG, 300 DPI) -- Lint: `scripts/lint_diagrams.py` +- Lint: `scripts/diagrams/lint_diagrams.py` - Шаблон: `mmd-diagrams/_template.mmd` - Политика LLM: `docs/02-architecture/06-diagram-policy.md` (POL-LLM-DIAGRAMS-001) @@ -152,7 +152,7 @@ View-файлы с ≥3 типами связей и >5 соединениями ### D6: CI Validation -`scripts/lint_diagrams.py` проверяет оба каталога: +`scripts/diagrams/lint_diagrams.py` проверяет оба каталога: | Rule | Description | |------|-------------| @@ -178,7 +178,7 @@ Pre-commit hooks: `lint-diagrams`, `prune-orphan-diagram-nodes`. #### GRAPH-001 — Orphan Node Rule -Реализован в `scripts/prune_orphan_nodes.py`. Нода считается orphan, если: +Реализован в `scripts/diagrams/prune_orphan_nodes.py`. Нода считается orphan, если: - Определена (`NodeId["label"]` или bare `NodeId`) в diagram - Не участвует ни в одном edge / message в том же файле @@ -190,9 +190,9 @@ Pre-commit hooks: `lint-diagrams`, `prune-orphan-diagram-nodes`. **Инструмент:** ```bash -python scripts/prune_orphan_nodes.py --check # аудит -python scripts/prune_orphan_nodes.py --fix # удалить garbage orphans -python scripts/prune_orphan_nodes.py --grandfather # exemption для всех текущих +python scripts/diagrams/prune_orphan_nodes.py --check # аудит +python scripts/diagrams/prune_orphan_nodes.py --fix # удалить garbage orphans +python scripts/diagrams/prune_orphan_nodes.py --grandfather # exemption для всех текущих ``` ### D7: Tool Selection Criteria diff --git a/docs/02-architecture/diagrams/mermaid/01-full-system-component-full.mermaid b/docs/02-architecture/diagrams/mermaid/01-full-system-component-full.mermaid index 0fbde14841..f061310e1d 100644 --- a/docs/02-architecture/diagrams/mermaid/01-full-system-component-full.mermaid +++ b/docs/02-architecture/diagrams/mermaid/01-full-system-component-full.mermaid @@ -11,7 +11,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=216 height=56 max_title_len=22 max_desc_lines=1 flowchart TB %% keep-orphan: Activity, Assay, AssayTransformer, CheckpointManager, CheckpointPort, Checkpoints, DQConfig, LifecycleOrchestrator, LoggerPort, MetricsPort, Molecule, PipelineConfig, Publication, Quarantine, QuarantinePort, RuntimeConfig, Target, TargetTransformer, TracingPort diff --git a/docs/02-architecture/diagrams/mermaid/21-activity-entity-data-flow-full.mermaid b/docs/02-architecture/diagrams/mermaid/21-activity-entity-data-flow-full.mermaid index 89d54fb60d..0fe5056749 100644 --- a/docs/02-architecture/diagrams/mermaid/21-activity-entity-data-flow-full.mermaid +++ b/docs/02-architecture/diagrams/mermaid/21-activity-entity-data-flow-full.mermaid @@ -12,7 +12,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=264 height=72 max_title_len=28 max_desc_lines=2 flowchart LR %% keep-orphan: LocalFS, S1, S10, S11, S12, S2, S4, S5, S6, S7, S8, S9 diff --git a/docs/02-architecture/diagrams/mermaid/26-hexagonal-ports-adapters-full.mermaid b/docs/02-architecture/diagrams/mermaid/26-hexagonal-ports-adapters-full.mermaid index 782407c113..4e5080b13a 100644 --- a/docs/02-architecture/diagrams/mermaid/26-hexagonal-ports-adapters-full.mermaid +++ b/docs/02-architecture/diagrams/mermaid/26-hexagonal-ports-adapters-full.mermaid @@ -11,7 +11,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=232 height=90 max_title_len=24 max_desc_lines=3 flowchart TB %% keep-orphan: CBP, FDSP, HCP, INP, MCP2, RLMP, SHP, SRLP diff --git a/docs/02-architecture/diagrams/mermaid/28-composition-root-di-graph-full.mermaid b/docs/02-architecture/diagrams/mermaid/28-composition-root-di-graph-full.mermaid index 7d7c3d4013..82325aeffe 100644 --- a/docs/02-architecture/diagrams/mermaid/28-composition-root-di-graph-full.mermaid +++ b/docs/02-architecture/diagrams/mermaid/28-composition-root-di-graph-full.mermaid @@ -12,7 +12,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=272 height=126 max_title_len=29 max_desc_lines=5 flowchart TB %% keep-orphan: OB diff --git a/docs/02-architecture/diagrams/mermaid/29-composite-pipeline-workflow-full.mermaid b/docs/02-architecture/diagrams/mermaid/29-composite-pipeline-workflow-full.mermaid index 9ae57f8c5c..d2eb22a28d 100644 --- a/docs/02-architecture/diagrams/mermaid/29-composite-pipeline-workflow-full.mermaid +++ b/docs/02-architecture/diagrams/mermaid/29-composite-pipeline-workflow-full.mermaid @@ -11,7 +11,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=288 height=90 max_title_len=31 max_desc_lines=3 flowchart TB subgraph Init["Phase 1: Initialization"] diff --git a/docs/02-architecture/diagrams/mermaid/30-port-adapter-mapping-full.mermaid b/docs/02-architecture/diagrams/mermaid/30-port-adapter-mapping-full.mermaid index 90032cef89..9562746364 100644 --- a/docs/02-architecture/diagrams/mermaid/30-port-adapter-mapping-full.mermaid +++ b/docs/02-architecture/diagrams/mermaid/30-port-adapter-mapping-full.mermaid @@ -19,7 +19,17 @@ %% @uniform-stats ports width=240 height=168 max_desc_lines=7 %% @uniform-stats adapters width=400 height=168 max_desc_lines=7 %% @uniform-stats noop width=184 height=168 max_desc_lines=7 -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart LR subgraph Ports["Domain Ports (domain/ports/)"] direction TB diff --git a/docs/02-architecture/diagrams/mermaid/32-single-record-journey-full.mermaid b/docs/02-architecture/diagrams/mermaid/32-single-record-journey-full.mermaid index 64267e3d79..c6afef8521 100644 --- a/docs/02-architecture/diagrams/mermaid/32-single-record-journey-full.mermaid +++ b/docs/02-architecture/diagrams/mermaid/32-single-record-journey-full.mermaid @@ -12,7 +12,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=304 height=108 max_title_len=33 max_desc_lines=4 flowchart TB subgraph Source["1. External API"] diff --git a/docs/02-architecture/diagrams/mermaid/35-bootstrap-sequence-full.mermaid b/docs/02-architecture/diagrams/mermaid/35-bootstrap-sequence-full.mermaid index 610acc08bc..d72526aebc 100644 --- a/docs/02-architecture/diagrams/mermaid/35-bootstrap-sequence-full.mermaid +++ b/docs/02-architecture/diagrams/mermaid/35-bootstrap-sequence-full.mermaid @@ -11,7 +11,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=328 height=56 max_title_len=36 max_desc_lines=1 flowchart TB subgraph Step1["Step 1: Logger"] diff --git a/docs/02-architecture/diagrams/mermaid/39-medallion-invariants-full.mermaid b/docs/02-architecture/diagrams/mermaid/39-medallion-invariants-full.mermaid index dba704b453..92f072ce0f 100644 --- a/docs/02-architecture/diagrams/mermaid/39-medallion-invariants-full.mermaid +++ b/docs/02-architecture/diagrams/mermaid/39-medallion-invariants-full.mermaid @@ -12,7 +12,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=256 height=90 max_title_len=27 max_desc_lines=3 flowchart TB %% keep-orphan: E3, E4 diff --git a/docs/02-architecture/diagrams/mermaid/44-cross-provider-enrichment-full.mermaid b/docs/02-architecture/diagrams/mermaid/44-cross-provider-enrichment-full.mermaid index a8b6cc744e..45fb2559ee 100644 --- a/docs/02-architecture/diagrams/mermaid/44-cross-provider-enrichment-full.mermaid +++ b/docs/02-architecture/diagrams/mermaid/44-cross-provider-enrichment-full.mermaid @@ -12,7 +12,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=336 height=162 max_title_len=37 max_desc_lines=7 flowchart LR subgraph ChEMBL["ChEMBL (Seed)"] diff --git a/docs/02-architecture/diagrams/mermaid/46-yaml-config-resolution-full.mermaid b/docs/02-architecture/diagrams/mermaid/46-yaml-config-resolution-full.mermaid index 1bdcce37b5..b54a30fae5 100644 --- a/docs/02-architecture/diagrams/mermaid/46-yaml-config-resolution-full.mermaid +++ b/docs/02-architecture/diagrams/mermaid/46-yaml-config-resolution-full.mermaid @@ -12,7 +12,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=420 height=108 max_title_len=49 max_desc_lines=4 flowchart TD %% keep-orphan: SOURCE_YAML_CFG diff --git a/docs/02-architecture/diagrams/mermaid/png/INDEX.md b/docs/02-architecture/diagrams/mermaid/png/INDEX.md new file mode 100644 index 0000000000..12d605aca1 --- /dev/null +++ b/docs/02-architecture/diagrams/mermaid/png/INDEX.md @@ -0,0 +1,76 @@ +# BioETL Diagrams — PNG Index + +_Generated: 2026-03-01T17:13:37+03:00_ + +## Full System Component Full + +![01-full-system-component-full](./01-full-system-component-full.png) + +--- + +## Domain Layer Class Diagram Full + +![04-domain-layer-class-diagram-full](./04-domain-layer-class-diagram-full.png) + +--- + +## Activity Entity Data Flow Full + +![21-activity-entity-data-flow-full](./21-activity-entity-data-flow-full.png) + +--- + +## Hexagonal Ports Adapters Full + +![26-hexagonal-ports-adapters-full](./26-hexagonal-ports-adapters-full.png) + +--- + +## Composition Root Di Graph Full + +![28-composition-root-di-graph-full](./28-composition-root-di-graph-full.png) + +--- + +## Composite Pipeline Workflow Full + +![29-composite-pipeline-workflow-full](./29-composite-pipeline-workflow-full.png) + +--- + +## Port Adapter Mapping Full + +![30-port-adapter-mapping-full](./30-port-adapter-mapping-full.png) + +--- + +## Single Record Journey Full + +![32-single-record-journey-full](./32-single-record-journey-full.png) + +--- + +## Bootstrap Sequence Full + +![35-bootstrap-sequence-full](./35-bootstrap-sequence-full.png) + +--- + +## Medallion Invariants Full + +![39-medallion-invariants-full](./39-medallion-invariants-full.png) + +--- + +## Cross Provider Enrichment Full + +![44-cross-provider-enrichment-full](./44-cross-provider-enrichment-full.png) + +--- + +## Yaml Config Resolution Full + +![46-yaml-config-resolution-full](./46-yaml-config-resolution-full.png) + +--- + diff --git a/docs/02-architecture/diagrams/mermaid/svg/INDEX.md b/docs/02-architecture/diagrams/mermaid/svg/INDEX.md new file mode 100644 index 0000000000..70f31bdedf --- /dev/null +++ b/docs/02-architecture/diagrams/mermaid/svg/INDEX.md @@ -0,0 +1,76 @@ +# BioETL Diagrams — SVG Index + +_Generated: 2026-03-01T17:13:37+03:00_ + +## Full System Component Full + +![01-full-system-component-full](./01-full-system-component-full.svg) + +--- + +## Domain Layer Class Diagram Full + +![04-domain-layer-class-diagram-full](./04-domain-layer-class-diagram-full.svg) + +--- + +## Activity Entity Data Flow Full + +![21-activity-entity-data-flow-full](./21-activity-entity-data-flow-full.svg) + +--- + +## Hexagonal Ports Adapters Full + +![26-hexagonal-ports-adapters-full](./26-hexagonal-ports-adapters-full.svg) + +--- + +## Composition Root Di Graph Full + +![28-composition-root-di-graph-full](./28-composition-root-di-graph-full.svg) + +--- + +## Composite Pipeline Workflow Full + +![29-composite-pipeline-workflow-full](./29-composite-pipeline-workflow-full.svg) + +--- + +## Port Adapter Mapping Full + +![30-port-adapter-mapping-full](./30-port-adapter-mapping-full.svg) + +--- + +## Single Record Journey Full + +![32-single-record-journey-full](./32-single-record-journey-full.svg) + +--- + +## Bootstrap Sequence Full + +![35-bootstrap-sequence-full](./35-bootstrap-sequence-full.svg) + +--- + +## Medallion Invariants Full + +![39-medallion-invariants-full](./39-medallion-invariants-full.svg) + +--- + +## Cross Provider Enrichment Full + +![44-cross-provider-enrichment-full](./44-cross-provider-enrichment-full.svg) + +--- + +## Yaml Config Resolution Full + +![46-yaml-config-resolution-full](./46-yaml-config-resolution-full.svg) + +--- + diff --git a/docs/02-architecture/mmd-diagrams/README.md b/docs/02-architecture/mmd-diagrams/README.md index 2aa9c2111b..7cfaf70b74 100644 --- a/docs/02-architecture/mmd-diagrams/README.md +++ b/docs/02-architecture/mmd-diagrams/README.md @@ -229,8 +229,14 @@ bash docs/02-architecture/mmd-diagrams/render.sh \ # CI mode (Puppeteer sandbox disabled) bash docs/02-architecture/mmd-diagrams/render.sh --puppeteer /tmp/puppeteer-config.json +# Text-layer mode (recommended for Chrome/SVG export parity) +# dual : keep foreignObject + add fallback text +# fo-only : keep only foreignObject labels +# fallback-only : add fallback text and strip foreignObject labels +bash docs/02-architecture/mmd-diagrams/render.sh --text-layer fallback-only + # Syntax validation (shows explicit hint if Chrome runtime is missing) -bash scripts/validate_mermaid_syntax.sh --puppeteer /tmp/puppeteer-config.json +bash scripts/diagrams/validate_mermaid_syntax.sh --puppeteer /tmp/puppeteer-config.json ``` ### Output layout @@ -287,7 +293,7 @@ Grouped diagrams support width strategy override: ## Validation Rules -`scripts/lint_diagrams.py` enforces: +`scripts/diagrams/lint_diagrams.py` enforces: | Rule | Description | Severity | |------|-------------|----------| @@ -311,7 +317,7 @@ Node-size exceptions in current lint implementation: ### Orphan Node Detection (GRAPH-001) -`scripts/prune_orphan_nodes.py` detects nodes defined in a diagram but not +`scripts/diagrams/prune_orphan_nodes.py` detects nodes defined in a diagram but not participating in any edge or message. **Applies to:** `flowchart` / `graph` and `sequenceDiagram` only. @@ -319,16 +325,16 @@ participating in any edge or message. ```bash # Report orphans (CI mode) -python scripts/prune_orphan_nodes.py --check +python scripts/diagrams/prune_orphan_nodes.py --check # Machine-readable output -python scripts/prune_orphan_nodes.py --check --json +python scripts/diagrams/prune_orphan_nodes.py --check --json # Remove confirmed garbage orphans (in-place) -python scripts/prune_orphan_nodes.py --fix +python scripts/diagrams/prune_orphan_nodes.py --fix # Exempt all current orphans (one-time grandfathering) -python scripts/prune_orphan_nodes.py --grandfather +python scripts/diagrams/prune_orphan_nodes.py --grandfather ``` **To keep an intentional "documentation" node that has no edges:** diff --git a/docs/02-architecture/mmd-diagrams/all-diagrams-catalog.html b/docs/02-architecture/mmd-diagrams/all-diagrams-catalog.html new file mode 100644 index 0000000000..8740d927f6 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/all-diagrams-catalog.html @@ -0,0 +1,275 @@ + +BioETL MMD Diagrams Catalog + + +

BioETL Diagram Catalog

Source: docs/02-architecture/mmd-diagrams/**/png/*.png

Total images: 260

Generated: 2026-03-01T17:22:20+03:00

+

001. architecture/png/01-high-level-hexagonal.png

architecture/png/01-high-level-hexagonal.png
+

002. architecture/png/01a-hexagonal-overview.png

architecture/png/01a-hexagonal-overview.png
+

003. architecture/png/01b-hexagonal-domain-app.png

architecture/png/01b-hexagonal-domain-app.png
+

004. architecture/png/01c-hexagonal-infra-comp.png

architecture/png/01c-hexagonal-infra-comp.png
+

005. architecture/png/01d-hexagonal-overview-rounded.png

architecture/png/01d-hexagonal-overview-rounded.png
+

006. architecture/png/02-layer-dependency-matrix.png

architecture/png/02-layer-dependency-matrix.png
+

007. architecture/png/03-medallion-data-flow.png

architecture/png/03-medallion-data-flow.png
+

008. architecture/png/03a-medallion-layers-overview.png

architecture/png/03a-medallion-layers-overview.png
+

009. architecture/png/04-pipeline-execution-flow.png

architecture/png/04-pipeline-execution-flow.png
+

010. architecture/png/05-provider-adapter-hierarchy.png

architecture/png/05-provider-adapter-hierarchy.png
+

011. architecture/png/05a-adapter-hierarchy-base.png

architecture/png/05a-adapter-hierarchy-base.png
+

012. architecture/png/05b-adapter-hierarchy-providers.png

architecture/png/05b-adapter-hierarchy-providers.png
+

013. architecture/png/06-storage-layer.png

architecture/png/06-storage-layer.png
+

014. architecture/png/07-dq-system.png

architecture/png/07-dq-system.png
+

015. architecture/png/08-composite-pipeline.png

architecture/png/08-composite-pipeline.png
+

016. architecture/png/09-observability-stack.png

architecture/png/09-observability-stack.png
+

017. architecture/png/10-resilience-patterns.png

architecture/png/10-resilience-patterns.png
+

018. architecture/png/11-configuration-system.png

architecture/png/11-configuration-system.png
+

019. architecture/png/12-bootstrap-di-container.png

architecture/png/12-bootstrap-di-container.png
+

020. architecture/png/12a-bootstrap-factories.png

architecture/png/12a-bootstrap-factories.png
+

021. architecture/png/12b-bootstrap-wiring.png

architecture/png/12b-bootstrap-wiring.png
+

022. architecture/png/13-port-protocol-contracts.png

architecture/png/13-port-protocol-contracts.png
+

023. architecture/png/13a-data-storage-ports.png

architecture/png/13a-data-storage-ports.png
+

024. architecture/png/13a-port-contracts-data-sources.png

architecture/png/13a-port-contracts-data-sources.png
+

025. architecture/png/13b-operational-ports.png

architecture/png/13b-operational-ports.png
+

026. architecture/png/13b-port-contracts-storage.png

architecture/png/13b-port-contracts-storage.png
+

027. architecture/png/13c-port-contracts-observability.png

architecture/png/13c-port-contracts-observability.png
+

028. architecture/png/13c-validation-dq-ports.png

architecture/png/13c-validation-dq-ports.png
+

029. architecture/png/13d-port-contracts-services.png

architecture/png/13d-port-contracts-services.png
+

030. architecture/png/14-cli-interface-layer.png

architecture/png/14-cli-interface-layer.png
+

031. architecture/png/15-batch-executor-internals.png

architecture/png/15-batch-executor-internals.png
+

032. architecture/png/16-transformer-hierarchy.png

architecture/png/16-transformer-hierarchy.png
+

033. architecture/png/17-security-pii-audit.png

architecture/png/17-security-pii-audit.png
+

034. architecture/png/18-lock-checkpoint-shutdown.png

architecture/png/18-lock-checkpoint-shutdown.png
+

035. class-diagrams/png/01-domain-ports.png

class-diagrams/png/01-domain-ports.png
+

036. class-diagrams/png/02-entities-aggregates.png

class-diagrams/png/02-entities-aggregates.png
+

037. class-diagrams/png/03-value-objects.png

class-diagrams/png/03-value-objects.png
+

038. class-diagrams/png/04-types-enums.png

class-diagrams/png/04-types-enums.png
+

039. class-diagrams/png/05-exceptions.png

class-diagrams/png/05-exceptions.png
+

040. class-diagrams/png/06-config-classes.png

class-diagrams/png/06-config-classes.png
+

041. class-diagrams/png/07-application-core-services.png

class-diagrams/png/07-application-core-services.png
+

042. class-diagrams/png/08-application-services.png

class-diagrams/png/08-application-services.png
+

043. class-diagrams/png/09-transformers.png

class-diagrams/png/09-transformers.png
+

044. class-diagrams/png/10-adapters.png

class-diagrams/png/10-adapters.png
+

045. class-diagrams/png/11-storage.png

class-diagrams/png/11-storage.png
+

046. class-diagrams/png/12-composite-pipeline.png

class-diagrams/png/12-composite-pipeline.png
+

047. class-diagrams/png/13-domain-services.png

class-diagrams/png/13-domain-services.png
+

048. class-diagrams/png/14-observability.png

class-diagrams/png/14-observability.png
+

049. class-diagrams/png/15-extractors.png

class-diagrams/png/15-extractors.png
+

050. class-diagrams/png/16-factories-bootstrap.png

class-diagrams/png/16-factories-bootstrap.png
+

051. foundation/png/01-full-system-component.png

foundation/png/01-full-system-component.png
+

052. foundation/png/01-high-level.png

foundation/png/01-high-level.png
+

053. foundation/png/02-full-medallion-data-flow.png

foundation/png/02-full-medallion-data-flow.png
+

054. foundation/png/03-pipeline-execution-happy-path.png

foundation/png/03-pipeline-execution-happy-path.png
+

055. foundation/png/04-domain-layer-class-diagram.png

foundation/png/04-domain-layer-class-diagram.png
+

056. foundation/png/04-error-flow.png

foundation/png/04-error-flow.png
+

057. foundation/png/05-layers-interaction.png

foundation/png/05-layers-interaction.png
+

058. foundation/png/05-pipeline-lifecycle-states.png

foundation/png/05-pipeline-lifecycle-states.png
+

059. foundation/png/06-application-layer-class-diagram.png

foundation/png/06-application-layer-class-diagram.png
+

060. foundation/png/06-pipeline-execution.png

foundation/png/06-pipeline-execution.png
+

061. foundation/png/07-circuit-breaker-states.png

foundation/png/07-circuit-breaker-states.png
+

062. foundation/png/07-medallion-flow.png

foundation/png/07-medallion-flow.png
+

063. foundation/png/08-complete-etl-workflow.png

foundation/png/08-complete-etl-workflow.png
+

064. foundation/png/08-domain-ddd.png

foundation/png/08-domain-ddd.png
+

065. foundation/png/09-full-er-diagram.png

foundation/png/09-full-er-diagram.png
+

066. foundation/png/10-infrastructure-layer-class-diagram.png

foundation/png/10-infrastructure-layer-class-diagram.png
+

067. foundation/png/11-lock-acquisition-sequence.png

foundation/png/11-lock-acquisition-sequence.png
+

068. foundation/png/12-local-deployment-architecture.png

foundation/png/12-local-deployment-architecture.png
+

069. foundation/png/13-domain-models-relationship.png

foundation/png/13-domain-models-relationship.png
+

070. foundation/png/14-provider-health-states.png

foundation/png/14-provider-health-states.png
+

071. foundation/png/15-dq-check-workflow.png

foundation/png/15-dq-check-workflow.png
+

072. foundation/png/16-memory-lock-class.png

foundation/png/16-memory-lock-class.png
+

073. foundation/png/17-pipeline-hierarchy.png

foundation/png/17-pipeline-hierarchy.png
+

074. foundation/png/18-bronze-write-sequence.png

foundation/png/18-bronze-write-sequence.png
+

075. foundation/png/19-delta-lake-write-sequence.png

foundation/png/19-delta-lake-write-sequence.png
+

076. foundation/png/20-quarantine-record-states.png

foundation/png/20-quarantine-record-states.png
+

077. foundation/png/21-activity-entity-data-flow.png

foundation/png/21-activity-entity-data-flow.png
+

078. foundation/png/22-client-api-request-sequence.png

foundation/png/22-client-api-request-sequence.png
+

079. foundation/png/23-silver-writer-class.png

foundation/png/23-silver-writer-class.png
+

080. foundation/png/24-hash-service-class.png

foundation/png/24-hash-service-class.png
+

081. foundation/png/25-circuit-breaker-observer-class.png

foundation/png/25-circuit-breaker-observer-class.png
+

082. foundation/png/26-hexagonal-ports-adapters.png

foundation/png/26-hexagonal-ports-adapters.png
+

083. foundation/png/27-import-matrix-enforcement.png

foundation/png/27-import-matrix-enforcement.png
+

084. foundation/png/28-composition-root-di-graph.png

foundation/png/28-composition-root-di-graph.png
+

085. foundation/png/29-composite-pipeline-workflow.png

foundation/png/29-composite-pipeline-workflow.png
+

086. foundation/png/30-port-adapter-mapping.png

foundation/png/30-port-adapter-mapping.png
+

087. foundation/png/31-pipeline-run-lifecycle.png

foundation/png/31-pipeline-run-lifecycle.png
+

088. foundation/png/32-single-record-journey.png

foundation/png/32-single-record-journey.png
+

089. foundation/png/33-cli-run-interaction.png

foundation/png/33-cli-run-interaction.png
+

090. foundation/png/34-batch-processing-flow.png

foundation/png/34-batch-processing-flow.png
+

091. foundation/png/36-architecture-principles-mindmap.png

foundation/png/36-architecture-principles-mindmap.png
+

092. foundation/png/37-cli-entry-full-chain.png

foundation/png/37-cli-entry-full-chain.png
+

093. foundation/png/38-runtime-assembly-sequence.png

foundation/png/38-runtime-assembly-sequence.png
+

094. foundation/png/39-medallion-invariants.png

foundation/png/39-medallion-invariants.png
+

095. foundation/png/40-application-core-collaboration.png

foundation/png/40-application-core-collaboration.png
+

096. foundation/png/41-error-classification-tree.png

foundation/png/41-error-classification-tree.png
+

097. foundation/png/42-pipeline-runner-class.png

foundation/png/42-pipeline-runner-class.png
+

098. foundation/png/43-fan-out-fan-in-pattern.png

foundation/png/43-fan-out-fan-in-pattern.png
+

099. foundation/png/44-cross-provider-enrichment.png

foundation/png/44-cross-provider-enrichment.png
+

100. foundation/png/46-yaml-config-resolution.png

foundation/png/46-yaml-config-resolution.png
+

101. foundation/png/47-publication-merge-sources.png

foundation/png/47-publication-merge-sources.png
+

102. foundation/png/48-composite-phase-lifecycle.png

foundation/png/48-composite-phase-lifecycle.png
+

103. foundation/png/49-composite-runner-class.png

foundation/png/49-composite-runner-class.png
+

104. foundation/png/50-exception-hierarchy.png

foundation/png/50-exception-hierarchy.png
+

105. views/png/00-legend.png

views/png/00-legend.png
+

106. views/png/01-full-system-component-dataflow.png

views/png/01-full-system-component-dataflow.png
+

107. views/png/01-full-system-component-domain.png

views/png/01-full-system-component-domain.png
+

108. views/png/01-full-system-component-full.png

views/png/01-full-system-component-full.png
+

109. views/png/01-full-system-component-infra.png

views/png/01-full-system-component-infra.png
+

110. views/png/01-full-system-component-overview.png

views/png/01-full-system-component-overview.png
+

111. views/png/01-high-level-dataflow.png

views/png/01-high-level-dataflow.png
+

112. views/png/01-high-level-domain.png

views/png/01-high-level-domain.png
+

113. views/png/01-high-level-full.png

views/png/01-high-level-full.png
+

114. views/png/01-high-level-infra.png

views/png/01-high-level-infra.png
+

115. views/png/01-high-level-overview.png

views/png/01-high-level-overview.png
+

116. views/png/02-medallion-dataflow.png

views/png/02-medallion-dataflow.png
+

117. views/png/02-medallion-domain.png

views/png/02-medallion-domain.png
+

118. views/png/02-medallion-full.png

views/png/02-medallion-full.png
+

119. views/png/02-medallion-infra.png

views/png/02-medallion-infra.png
+

120. views/png/02-medallion-overview.png

views/png/02-medallion-overview.png
+

121. views/png/04-domain-layer-class-diagram-dataflow.png

views/png/04-domain-layer-class-diagram-dataflow.png
+

122. views/png/04-domain-layer-class-diagram-domain.png

views/png/04-domain-layer-class-diagram-domain.png
+

123. views/png/04-domain-layer-class-diagram-full.png

views/png/04-domain-layer-class-diagram-full.png
+

124. views/png/04-domain-layer-class-diagram-infra.png

views/png/04-domain-layer-class-diagram-infra.png
+

125. views/png/04-domain-layer-class-diagram-overview.png

views/png/04-domain-layer-class-diagram-overview.png
+

126. views/png/05-layers-interaction-dataflow.png

views/png/05-layers-interaction-dataflow.png
+

127. views/png/05-layers-interaction-domain.png

views/png/05-layers-interaction-domain.png
+

128. views/png/05-layers-interaction-full.png

views/png/05-layers-interaction-full.png
+

129. views/png/05-layers-interaction-infra.png

views/png/05-layers-interaction-infra.png
+

130. views/png/05-layers-interaction-overview.png

views/png/05-layers-interaction-overview.png
+

131. views/png/05-pipeline-lifecycle-states-dataflow.png

views/png/05-pipeline-lifecycle-states-dataflow.png
+

132. views/png/05-pipeline-lifecycle-states-domain.png

views/png/05-pipeline-lifecycle-states-domain.png
+

133. views/png/05-pipeline-lifecycle-states-full.png

views/png/05-pipeline-lifecycle-states-full.png
+

134. views/png/05-pipeline-lifecycle-states-infra.png

views/png/05-pipeline-lifecycle-states-infra.png
+

135. views/png/05-pipeline-lifecycle-states-overview.png

views/png/05-pipeline-lifecycle-states-overview.png
+

136. views/png/06-application-layer-class-diagram-dataflow.png

views/png/06-application-layer-class-diagram-dataflow.png
+

137. views/png/06-application-layer-class-diagram-domain.png

views/png/06-application-layer-class-diagram-domain.png
+

138. views/png/06-application-layer-class-diagram-full.png

views/png/06-application-layer-class-diagram-full.png
+

139. views/png/06-application-layer-class-diagram-infra.png

views/png/06-application-layer-class-diagram-infra.png
+

140. views/png/06-application-layer-class-diagram-overview.png

views/png/06-application-layer-class-diagram-overview.png
+

141. views/png/07-circuit-breaker-states-dataflow.png

views/png/07-circuit-breaker-states-dataflow.png
+

142. views/png/07-circuit-breaker-states-domain.png

views/png/07-circuit-breaker-states-domain.png
+

143. views/png/07-circuit-breaker-states-full.png

views/png/07-circuit-breaker-states-full.png
+

144. views/png/07-circuit-breaker-states-infra.png

views/png/07-circuit-breaker-states-infra.png
+

145. views/png/07-circuit-breaker-states-overview.png

views/png/07-circuit-breaker-states-overview.png
+

146. views/png/08-complete-etl-workflow-dataflow.png

views/png/08-complete-etl-workflow-dataflow.png
+

147. views/png/08-complete-etl-workflow-domain.png

views/png/08-complete-etl-workflow-domain.png
+

148. views/png/08-complete-etl-workflow-full.png

views/png/08-complete-etl-workflow-full.png
+

149. views/png/08-complete-etl-workflow-infra.png

views/png/08-complete-etl-workflow-infra.png
+

150. views/png/08-complete-etl-workflow-overview.png

views/png/08-complete-etl-workflow-overview.png
+

151. views/png/08-domain-ddd-dataflow.png

views/png/08-domain-ddd-dataflow.png
+

152. views/png/08-domain-ddd-domain.png

views/png/08-domain-ddd-domain.png
+

153. views/png/08-domain-ddd-full.png

views/png/08-domain-ddd-full.png
+

154. views/png/08-domain-ddd-infra.png

views/png/08-domain-ddd-infra.png
+

155. views/png/08-domain-ddd-overview.png

views/png/08-domain-ddd-overview.png
+

156. views/png/10-infrastructure-layer-class-diagram-dataflow.png

views/png/10-infrastructure-layer-class-diagram-dataflow.png
+

157. views/png/10-infrastructure-layer-class-diagram-domain.png

views/png/10-infrastructure-layer-class-diagram-domain.png
+

158. views/png/10-infrastructure-layer-class-diagram-full.png

views/png/10-infrastructure-layer-class-diagram-full.png
+

159. views/png/10-infrastructure-layer-class-diagram-infra.png

views/png/10-infrastructure-layer-class-diagram-infra.png
+

160. views/png/10-infrastructure-layer-class-diagram-overview.png

views/png/10-infrastructure-layer-class-diagram-overview.png
+

161. views/png/12-local-deployment-architecture-dataflow.png

views/png/12-local-deployment-architecture-dataflow.png
+

162. views/png/12-local-deployment-architecture-domain.png

views/png/12-local-deployment-architecture-domain.png
+

163. views/png/12-local-deployment-architecture-full.png

views/png/12-local-deployment-architecture-full.png
+

164. views/png/12-local-deployment-architecture-infra.png

views/png/12-local-deployment-architecture-infra.png
+

165. views/png/12-local-deployment-architecture-overview.png

views/png/12-local-deployment-architecture-overview.png
+

166. views/png/14-provider-health-states-dataflow.png

views/png/14-provider-health-states-dataflow.png
+

167. views/png/14-provider-health-states-domain.png

views/png/14-provider-health-states-domain.png
+

168. views/png/14-provider-health-states-full.png

views/png/14-provider-health-states-full.png
+

169. views/png/14-provider-health-states-infra.png

views/png/14-provider-health-states-infra.png
+

170. views/png/14-provider-health-states-overview.png

views/png/14-provider-health-states-overview.png
+

171. views/png/15-dq-check-workflow-dataflow.png

views/png/15-dq-check-workflow-dataflow.png
+

172. views/png/15-dq-check-workflow-domain.png

views/png/15-dq-check-workflow-domain.png
+

173. views/png/15-dq-check-workflow-full.png

views/png/15-dq-check-workflow-full.png
+

174. views/png/15-dq-check-workflow-infra.png

views/png/15-dq-check-workflow-infra.png
+

175. views/png/15-dq-check-workflow-overview.png

views/png/15-dq-check-workflow-overview.png
+

176. views/png/21-activity-entity-data-flow-dataflow.png

views/png/21-activity-entity-data-flow-dataflow.png
+

177. views/png/21-activity-entity-data-flow-domain.png

views/png/21-activity-entity-data-flow-domain.png
+

178. views/png/21-activity-entity-data-flow-full.png

views/png/21-activity-entity-data-flow-full.png
+

179. views/png/21-activity-entity-data-flow-infra.png

views/png/21-activity-entity-data-flow-infra.png
+

180. views/png/21-activity-entity-data-flow-overview.png

views/png/21-activity-entity-data-flow-overview.png
+

181. views/png/26-hexagonal-ports-adapters-dataflow.png

views/png/26-hexagonal-ports-adapters-dataflow.png
+

182. views/png/26-hexagonal-ports-adapters-domain.png

views/png/26-hexagonal-ports-adapters-domain.png
+

183. views/png/26-hexagonal-ports-adapters-full.png

views/png/26-hexagonal-ports-adapters-full.png
+

184. views/png/26-hexagonal-ports-adapters-infra.png

views/png/26-hexagonal-ports-adapters-infra.png
+

185. views/png/26-hexagonal-ports-adapters-overview.png

views/png/26-hexagonal-ports-adapters-overview.png
+

186. views/png/28-composition-root-di-graph-dataflow.png

views/png/28-composition-root-di-graph-dataflow.png
+

187. views/png/28-composition-root-di-graph-domain.png

views/png/28-composition-root-di-graph-domain.png
+

188. views/png/28-composition-root-di-graph-full.png

views/png/28-composition-root-di-graph-full.png
+

189. views/png/28-composition-root-di-graph-infra.png

views/png/28-composition-root-di-graph-infra.png
+

190. views/png/28-composition-root-di-graph-overview.png

views/png/28-composition-root-di-graph-overview.png
+

191. views/png/29-composite-pipeline-workflow-dataflow.png

views/png/29-composite-pipeline-workflow-dataflow.png
+

192. views/png/29-composite-pipeline-workflow-domain.png

views/png/29-composite-pipeline-workflow-domain.png
+

193. views/png/29-composite-pipeline-workflow-full.png

views/png/29-composite-pipeline-workflow-full.png
+

194. views/png/29-composite-pipeline-workflow-infra.png

views/png/29-composite-pipeline-workflow-infra.png
+

195. views/png/29-composite-pipeline-workflow-overview.png

views/png/29-composite-pipeline-workflow-overview.png
+

196. views/png/30-port-adapter-mapping-dataflow.png

views/png/30-port-adapter-mapping-dataflow.png
+

197. views/png/30-port-adapter-mapping-domain.png

views/png/30-port-adapter-mapping-domain.png
+

198. views/png/30-port-adapter-mapping-full.png

views/png/30-port-adapter-mapping-full.png
+

199. views/png/30-port-adapter-mapping-infra.png

views/png/30-port-adapter-mapping-infra.png
+

200. views/png/30-port-adapter-mapping-overview.png

views/png/30-port-adapter-mapping-overview.png
+

201. views/png/31-pipeline-run-lifecycle-dataflow.png

views/png/31-pipeline-run-lifecycle-dataflow.png
+

202. views/png/31-pipeline-run-lifecycle-domain.png

views/png/31-pipeline-run-lifecycle-domain.png
+

203. views/png/31-pipeline-run-lifecycle-full.png

views/png/31-pipeline-run-lifecycle-full.png
+

204. views/png/31-pipeline-run-lifecycle-infra.png

views/png/31-pipeline-run-lifecycle-infra.png
+

205. views/png/31-pipeline-run-lifecycle-overview.png

views/png/31-pipeline-run-lifecycle-overview.png
+

206. views/png/32-single-record-journey-dataflow.png

views/png/32-single-record-journey-dataflow.png
+

207. views/png/32-single-record-journey-domain.png

views/png/32-single-record-journey-domain.png
+

208. views/png/32-single-record-journey-full.png

views/png/32-single-record-journey-full.png
+

209. views/png/32-single-record-journey-infra.png

views/png/32-single-record-journey-infra.png
+

210. views/png/32-single-record-journey-overview.png

views/png/32-single-record-journey-overview.png
+

211. views/png/33-cli-run-interaction-dataflow.png

views/png/33-cli-run-interaction-dataflow.png
+

212. views/png/33-cli-run-interaction-domain.png

views/png/33-cli-run-interaction-domain.png
+

213. views/png/33-cli-run-interaction-full.png

views/png/33-cli-run-interaction-full.png
+

214. views/png/33-cli-run-interaction-infra.png

views/png/33-cli-run-interaction-infra.png
+

215. views/png/33-cli-run-interaction-overview.png

views/png/33-cli-run-interaction-overview.png
+

216. views/png/34-batch-processing-flow-dataflow.png

views/png/34-batch-processing-flow-dataflow.png
+

217. views/png/34-batch-processing-flow-domain.png

views/png/34-batch-processing-flow-domain.png
+

218. views/png/34-batch-processing-flow-full.png

views/png/34-batch-processing-flow-full.png
+

219. views/png/34-batch-processing-flow-infra.png

views/png/34-batch-processing-flow-infra.png
+

220. views/png/34-batch-processing-flow-overview.png

views/png/34-batch-processing-flow-overview.png
+

221. views/png/35-bootstrap-sequence-dataflow.png

views/png/35-bootstrap-sequence-dataflow.png
+

222. views/png/35-bootstrap-sequence-domain.png

views/png/35-bootstrap-sequence-domain.png
+

223. views/png/35-bootstrap-sequence-full.png

views/png/35-bootstrap-sequence-full.png
+

224. views/png/35-bootstrap-sequence-infra.png

views/png/35-bootstrap-sequence-infra.png
+

225. views/png/35-bootstrap-sequence-overview.png

views/png/35-bootstrap-sequence-overview.png
+

226. views/png/36-architecture-principles-mindmap-dataflow.png

views/png/36-architecture-principles-mindmap-dataflow.png
+

227. views/png/36-architecture-principles-mindmap-domain.png

views/png/36-architecture-principles-mindmap-domain.png
+

228. views/png/36-architecture-principles-mindmap-full.png

views/png/36-architecture-principles-mindmap-full.png
+

229. views/png/36-architecture-principles-mindmap-infra.png

views/png/36-architecture-principles-mindmap-infra.png
+

230. views/png/36-architecture-principles-mindmap-overview.png

views/png/36-architecture-principles-mindmap-overview.png
+

231. views/png/39-medallion-invariants-dataflow.png

views/png/39-medallion-invariants-dataflow.png
+

232. views/png/39-medallion-invariants-domain.png

views/png/39-medallion-invariants-domain.png
+

233. views/png/39-medallion-invariants-full.png

views/png/39-medallion-invariants-full.png
+

234. views/png/39-medallion-invariants-infra.png

views/png/39-medallion-invariants-infra.png
+

235. views/png/39-medallion-invariants-overview.png

views/png/39-medallion-invariants-overview.png
+

236. views/png/41-error-classification-tree-dataflow.png

views/png/41-error-classification-tree-dataflow.png
+

237. views/png/41-error-classification-tree-domain.png

views/png/41-error-classification-tree-domain.png
+

238. views/png/41-error-classification-tree-full.png

views/png/41-error-classification-tree-full.png
+

239. views/png/41-error-classification-tree-infra.png

views/png/41-error-classification-tree-infra.png
+

240. views/png/41-error-classification-tree-overview.png

views/png/41-error-classification-tree-overview.png
+

241. views/png/44-cross-provider-enrichment-dataflow.png

views/png/44-cross-provider-enrichment-dataflow.png
+

242. views/png/44-cross-provider-enrichment-domain.png

views/png/44-cross-provider-enrichment-domain.png
+

243. views/png/44-cross-provider-enrichment-full.png

views/png/44-cross-provider-enrichment-full.png
+

244. views/png/44-cross-provider-enrichment-infra.png

views/png/44-cross-provider-enrichment-infra.png
+

245. views/png/44-cross-provider-enrichment-overview.png

views/png/44-cross-provider-enrichment-overview.png
+

246. views/png/46-yaml-config-resolution-dataflow.png

views/png/46-yaml-config-resolution-dataflow.png
+

247. views/png/46-yaml-config-resolution-domain.png

views/png/46-yaml-config-resolution-domain.png
+

248. views/png/46-yaml-config-resolution-full.png

views/png/46-yaml-config-resolution-full.png
+

249. views/png/46-yaml-config-resolution-infra.png

views/png/46-yaml-config-resolution-infra.png
+

250. views/png/46-yaml-config-resolution-overview.png

views/png/46-yaml-config-resolution-overview.png
+

251. views/png/48-composite-phase-lifecycle-dataflow.png

views/png/48-composite-phase-lifecycle-dataflow.png
+

252. views/png/48-composite-phase-lifecycle-domain.png

views/png/48-composite-phase-lifecycle-domain.png
+

253. views/png/48-composite-phase-lifecycle-full.png

views/png/48-composite-phase-lifecycle-full.png
+

254. views/png/48-composite-phase-lifecycle-infra.png

views/png/48-composite-phase-lifecycle-infra.png
+

255. views/png/48-composite-phase-lifecycle-overview.png

views/png/48-composite-phase-lifecycle-overview.png
+

256. views/png/50-exception-hierarchy-dataflow.png

views/png/50-exception-hierarchy-dataflow.png
+

257. views/png/50-exception-hierarchy-domain.png

views/png/50-exception-hierarchy-domain.png
+

258. views/png/50-exception-hierarchy-full.png

views/png/50-exception-hierarchy-full.png
+

259. views/png/50-exception-hierarchy-infra.png

views/png/50-exception-hierarchy-infra.png
+

260. views/png/50-exception-hierarchy-overview.png

views/png/50-exception-hierarchy-overview.png
+ diff --git a/docs/02-architecture/mmd-diagrams/all-diagrams-catalog.pdf b/docs/02-architecture/mmd-diagrams/all-diagrams-catalog.pdf new file mode 100644 index 0000000000..eb2f5b4c55 Binary files /dev/null and b/docs/02-architecture/mmd-diagrams/all-diagrams-catalog.pdf differ diff --git a/docs/02-architecture/mmd-diagrams/architecture-diagrams-catalog.html b/docs/02-architecture/mmd-diagrams/architecture-diagrams-catalog.html new file mode 100644 index 0000000000..5677f309e7 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/architecture-diagrams-catalog.html @@ -0,0 +1,49 @@ + +BioETL Diagram Catalog + + +

BioETL architecture Diagrams

Source: docs/02-architecture/mmd-diagrams/architecture/png/*.png

Total images: 34

Generated: 2026-03-01T17:35:03+03:00

+

001. architecture/png/01-high-level-hexagonal.png

architecture/png/01-high-level-hexagonal.png
+

002. architecture/png/01a-hexagonal-overview.png

architecture/png/01a-hexagonal-overview.png
+

003. architecture/png/01b-hexagonal-domain-app.png

architecture/png/01b-hexagonal-domain-app.png
+

004. architecture/png/01c-hexagonal-infra-comp.png

architecture/png/01c-hexagonal-infra-comp.png
+

005. architecture/png/01d-hexagonal-overview-rounded.png

architecture/png/01d-hexagonal-overview-rounded.png
+

006. architecture/png/02-layer-dependency-matrix.png

architecture/png/02-layer-dependency-matrix.png
+

007. architecture/png/03-medallion-data-flow.png

architecture/png/03-medallion-data-flow.png
+

008. architecture/png/03a-medallion-layers-overview.png

architecture/png/03a-medallion-layers-overview.png
+

009. architecture/png/04-pipeline-execution-flow.png

architecture/png/04-pipeline-execution-flow.png
+

010. architecture/png/05-provider-adapter-hierarchy.png

architecture/png/05-provider-adapter-hierarchy.png
+

011. architecture/png/05a-adapter-hierarchy-base.png

architecture/png/05a-adapter-hierarchy-base.png
+

012. architecture/png/05b-adapter-hierarchy-providers.png

architecture/png/05b-adapter-hierarchy-providers.png
+

013. architecture/png/06-storage-layer.png

architecture/png/06-storage-layer.png
+

014. architecture/png/07-dq-system.png

architecture/png/07-dq-system.png
+

015. architecture/png/08-composite-pipeline.png

architecture/png/08-composite-pipeline.png
+

016. architecture/png/09-observability-stack.png

architecture/png/09-observability-stack.png
+

017. architecture/png/10-resilience-patterns.png

architecture/png/10-resilience-patterns.png
+

018. architecture/png/11-configuration-system.png

architecture/png/11-configuration-system.png
+

019. architecture/png/12-bootstrap-di-container.png

architecture/png/12-bootstrap-di-container.png
+

020. architecture/png/12a-bootstrap-factories.png

architecture/png/12a-bootstrap-factories.png
+

021. architecture/png/12b-bootstrap-wiring.png

architecture/png/12b-bootstrap-wiring.png
+

022. architecture/png/13-port-protocol-contracts.png

architecture/png/13-port-protocol-contracts.png
+

023. architecture/png/13a-data-storage-ports.png

architecture/png/13a-data-storage-ports.png
+

024. architecture/png/13a-port-contracts-data-sources.png

architecture/png/13a-port-contracts-data-sources.png
+

025. architecture/png/13b-operational-ports.png

architecture/png/13b-operational-ports.png
+

026. architecture/png/13b-port-contracts-storage.png

architecture/png/13b-port-contracts-storage.png
+

027. architecture/png/13c-port-contracts-observability.png

architecture/png/13c-port-contracts-observability.png
+

028. architecture/png/13c-validation-dq-ports.png

architecture/png/13c-validation-dq-ports.png
+

029. architecture/png/13d-port-contracts-services.png

architecture/png/13d-port-contracts-services.png
+

030. architecture/png/14-cli-interface-layer.png

architecture/png/14-cli-interface-layer.png
+

031. architecture/png/15-batch-executor-internals.png

architecture/png/15-batch-executor-internals.png
+

032. architecture/png/16-transformer-hierarchy.png

architecture/png/16-transformer-hierarchy.png
+

033. architecture/png/17-security-pii-audit.png

architecture/png/17-security-pii-audit.png
+

034. architecture/png/18-lock-checkpoint-shutdown.png

architecture/png/18-lock-checkpoint-shutdown.png
+ diff --git a/docs/02-architecture/mmd-diagrams/architecture-diagrams-catalog.pdf b/docs/02-architecture/mmd-diagrams/architecture-diagrams-catalog.pdf new file mode 100644 index 0000000000..c98df2ae0f Binary files /dev/null and b/docs/02-architecture/mmd-diagrams/architecture-diagrams-catalog.pdf differ diff --git a/docs/02-architecture/mmd-diagrams/architecture/01-high-level-hexagonal.mmd b/docs/02-architecture/mmd-diagrams/architecture/01-high-level-hexagonal.mmd index c1cfc71b64..f0de9ef37c 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/01-high-level-hexagonal.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/01-high-level-hexagonal.mmd @@ -8,7 +8,17 @@ %% @nodes 46 %% @reference Decomposed into 01a, 01b, 01c sub-diagrams -%%{init: {'theme': 'base', 'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=208 height=72 max_title_len=21 max_desc_lines=2 graph TB %% keep-orphan: CFG, EXCEPTIONS, OBSERVER, PROVIDERS, SCHEMAS, TYPES, VALIDATION diff --git a/docs/02-architecture/mmd-diagrams/architecture/01a-hexagonal-overview.mmd b/docs/02-architecture/mmd-diagrams/architecture/01a-hexagonal-overview.mmd index 43706dfe82..fa7a3abea7 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/01a-hexagonal-overview.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/01a-hexagonal-overview.mmd @@ -10,7 +10,17 @@ %% @nodes 11 %% @uniform width=240 height=56 max_title_len=24 max_desc_lines=1 -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'BRANDES_KOEPF', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph TB subgraph Interfaces["Interfaces Layer"] CLI["CLI Commands (Click)"]:::size-sm diff --git a/docs/02-architecture/mmd-diagrams/architecture/01b-hexagonal-domain-app.mmd b/docs/02-architecture/mmd-diagrams/architecture/01b-hexagonal-domain-app.mmd index 46a4279a18..038441cb33 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/01b-hexagonal-domain-app.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/01b-hexagonal-domain-app.mmd @@ -10,7 +10,17 @@ %% @nodes 13 %% @uniform width=504 height=56 max_title_len=50 max_desc_lines=1 -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'BRANDES_KOEPF', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph TB %% keep-orphan: CFG, EXCEPTIONS, OBSERVER, SCHEMAS, TYPES subgraph Application["Application Layer"] diff --git a/docs/02-architecture/mmd-diagrams/architecture/01c-hexagonal-infra-comp.mmd b/docs/02-architecture/mmd-diagrams/architecture/01c-hexagonal-infra-comp.mmd index 454d47e71e..4b483f35fd 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/01c-hexagonal-infra-comp.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/01c-hexagonal-infra-comp.mmd @@ -10,7 +10,17 @@ %% @nodes 14 %% @uniform width=200 height=56 max_title_len=20 max_desc_lines=1 -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'BRANDES_KOEPF', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph TB %% keep-orphan: FACTORIES, PROVIDERS, RT_BUILDERS, VALIDATION subgraph Composition["Composition Layer"] diff --git a/docs/02-architecture/mmd-diagrams/architecture/01d-hexagonal-overview-rounded.mmd b/docs/02-architecture/mmd-diagrams/architecture/01d-hexagonal-overview-rounded.mmd new file mode 100644 index 0000000000..f9b0b3c4a7 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/architecture/01d-hexagonal-overview-rounded.mmd @@ -0,0 +1,79 @@ +%% BioETL — Hexagonal Overview (Rounded Nodes) +%% Covers 5 architectural layers, external systems, and main dependency directions. + +%% @version 1.2.0 +%% @date 2026-03-01 +%% @type flowchart +%% @level System / Component +%% @view overview-rounded +%% @parent 01a-hexagonal-overview.mmd +%% @nodes 11 +%% @uniform width=240 height=56 max_title_len=34 max_desc_lines=1 + +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% +graph TB + subgraph Interfaces["Interfaces Layer"] + CLI["CLI Commands (Click)"]:::size-sm + ORCH["Orchestration"]:::size-sm + end + + subgraph Composition["Composition Layer"] + BOOTSTRAP["Bootstrap / Assembly"]:::size-sm + end + + subgraph Application["Application Layer"] + CORE["Application Core"]:::size-sm + end + + subgraph Domain["Domain Layer"] + PORTS["Port Protocols"]:::size-sm + end + + subgraph Infrastructure["Infrastructure Layer"] + ADAPTERS["Provider Adapters"]:::size-sm + STORAGE["Storage Writers / Reader"]:::size-sm + OBS_INFRA["Observability Infra"]:::size-sm + end + + ExternalAPIs["External APIs"]:::size-sm + FS["File System"]:::size-sm + PROM["Prometheus"]:::size-sm + OTEL["OpenTelemetry"]:::size-sm + ExternalAPIs -.-> ADAPTERS + FS -.-> STORAGE + PROM -.-> OBS_INFRA + OTEL -.-> OBS_INFRA + CLI --> BOOTSTRAP + ORCH --> BOOTSTRAP + BOOTSTRAP --> CORE + BOOTSTRAP --> ADAPTERS + BOOTSTRAP --> STORAGE + BOOTSTRAP --> OBS_INFRA + CORE --> PORTS + ADAPTERS -->|implements| PORTS + STORAGE -->|implements| PORTS + OBS_INFRA -->|implements| PORTS + + classDef domain fill:#f5f3ff,stroke:#7c3aed + classDef app fill:#f0fdf4,stroke:#16a34a + classDef infra fill:#fff1f2,stroke:#dc2626 + classDef comp fill:#fff7ed,stroke:#f59e0b + classDef iface fill:#eff6ff,stroke:#2563eb + classDef ext fill:#f1f5f9,stroke:#64748b + + class CLI,ORCH iface + class BOOTSTRAP comp + class CORE app + class PORTS domain + class ADAPTERS,STORAGE,OBS_INFRA infra + class ExternalAPIs,FS,PROM,OTEL ext diff --git a/docs/02-architecture/mmd-diagrams/architecture/02-layer-dependency-matrix.mmd b/docs/02-architecture/mmd-diagrams/architecture/02-layer-dependency-matrix.mmd index 513dfba290..431ebe3411 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/02-layer-dependency-matrix.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/02-layer-dependency-matrix.mmd @@ -8,6 +8,17 @@ %% @nodes 5 %% @uniform width=184 height=96 max_title_len=14 max_desc_lines=3 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph LR %% keep-orphan: FORBIDDEN, OK subgraph Legend diff --git a/docs/02-architecture/mmd-diagrams/architecture/03-medallion-data-flow.mmd b/docs/02-architecture/mmd-diagrams/architecture/03-medallion-data-flow.mmd index c4a44b02da..34ec8589dd 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/03-medallion-data-flow.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/03-medallion-data-flow.mmd @@ -8,7 +8,17 @@ %% @nodes 36 %% @reference Canonical medallion flow — at threshold boundary -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=200 height=56 max_title_len=20 max_desc_lines=1 graph LR subgraph Sources["External Data Sources"] diff --git a/docs/02-architecture/mmd-diagrams/architecture/03a-medallion-layers-overview.mmd b/docs/02-architecture/mmd-diagrams/architecture/03a-medallion-layers-overview.mmd index 14568ba255..62f1e80551 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/03a-medallion-layers-overview.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/03a-medallion-layers-overview.mmd @@ -8,6 +8,17 @@ %% @nodes 12 %% @adr ADR-002, ADR-040 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart LR subgraph Ingest["Ingestion"] Sources["Provider APIs"] diff --git a/docs/02-architecture/mmd-diagrams/architecture/04-pipeline-execution-flow.mmd b/docs/02-architecture/mmd-diagrams/architecture/04-pipeline-execution-flow.mmd index 359bd8b88e..107655c59f 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/04-pipeline-execution-flow.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/04-pipeline-execution-flow.mmd @@ -8,6 +8,15 @@ %% @nodes 12 %% @uniform sequence width=168 max_title_len=16 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'elk': { + 'mergeEdges': true + } +}}%% + sequenceDiagram participant CLI as CLI / Interfaces participant Boot as Bootstrap diff --git a/docs/02-architecture/mmd-diagrams/architecture/05-provider-adapter-hierarchy.mmd b/docs/02-architecture/mmd-diagrams/architecture/05-provider-adapter-hierarchy.mmd index 49a665ed74..57efc3ec0e 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/05-provider-adapter-hierarchy.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/05-provider-adapter-hierarchy.mmd @@ -8,7 +8,17 @@ %% @nodes 27 %% @reference Decomposed into 05a, 05b sub-diagrams -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=304 height=180 max_title_len=33 max_desc_lines=8 graph TB %% keep-orphan: DFM, HCP, UIDM diff --git a/docs/02-architecture/mmd-diagrams/architecture/05a-adapter-hierarchy-base.mmd b/docs/02-architecture/mmd-diagrams/architecture/05a-adapter-hierarchy-base.mmd index 37804ba06c..4cf1f765c5 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/05a-adapter-hierarchy-base.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/05a-adapter-hierarchy-base.mmd @@ -10,7 +10,17 @@ %% @nodes 12 %% @uniform width=280 height=56 max_title_len=28 max_desc_lines=1 -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'BRANDES_KOEPF', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph TB %% keep-orphan: FSM, HCP, NSMF, PFM subgraph Domain["Domain Layer"] diff --git a/docs/02-architecture/mmd-diagrams/architecture/05b-adapter-hierarchy-providers.mmd b/docs/02-architecture/mmd-diagrams/architecture/05b-adapter-hierarchy-providers.mmd index c76536cd89..8187ba99bf 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/05b-adapter-hierarchy-providers.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/05b-adapter-hierarchy-providers.mmd @@ -10,7 +10,17 @@ %% @nodes 15 %% @uniform width=224 height=56 max_title_len=22 max_desc_lines=1 -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'BRANDES_KOEPF', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph TB %% keep-orphan: UIDM subgraph Infrastructure["Infrastructure Layer"] diff --git a/docs/02-architecture/mmd-diagrams/architecture/06-storage-layer.mmd b/docs/02-architecture/mmd-diagrams/architecture/06-storage-layer.mmd index a1b04727ad..b19486e76e 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/06-storage-layer.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/06-storage-layer.mmd @@ -8,7 +8,17 @@ %% @nodes 21 %% @reference Decomposed into 06a-storage-writers, 06b-storage-support -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=216 height=198 max_title_len=22 max_desc_lines=9 graph LR %% keep-orphan: DQW, NOV diff --git a/docs/02-architecture/mmd-diagrams/architecture/07-dq-system.mmd b/docs/02-architecture/mmd-diagrams/architecture/07-dq-system.mmd index b1a9e03ece..832725d6fa 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/07-dq-system.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/07-dq-system.mmd @@ -10,22 +10,32 @@ %% @allow-polyline-routing %% @uniform width=208 height=128 max_title_len=20 max_desc_lines=5 -%%{init: {'theme': 'base', 'themeVariables': {'fontSize': '16px', 'edgeLabelBackground': '#ffffffee'}, 'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'POLYLINE', 'spacing.nodeNode': 40, 'spacing.edgeNode': 25, 'spacing.rankRank': 60}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph TB %% keep-orphan: DQConfig %% ── Domain Ports (contracts) ────────────────────────── subgraph Ports["Domain Ports"] - DQM["DQMonitorPort



"] - BDQAP["BronzeDQAnalyzerPort



"] - SDQAP["SilverDQAnalyzerPort



"] - GDQAP["GoldDQAnalyzerPort



"] - DQRWP["DQReportWriterPort



"] + DQM["DQMonitorPort"] + BDQAP["BronzeDQAnalyzerPort"] + SDQAP["SilverDQAnalyzerPort"] + GDQAP["GoldDQAnalyzerPort"] + DQRWP["DQReportWriterPort"] end %% ── Application Services ────────────────────────────── subgraph AppServices["Application Services"] - DQS["DataQualityService
━━━━━━━━━━━━━━━━━
+ evaluate(context, executor)

"] - DQRS["DQReportService
━━━━━━━━━━━━━━━━━
+ generate_reports(context)

"] + DQS["DataQualityService
--------
+ evaluate(context, executor)"] + DQRS["DQReportService
--------
+ generate_reports(context)"] end %% ── Application DQ Analyzers + Anomaly ──────────────── @@ -33,16 +43,16 @@ graph TB BDA["BronzeDQAnalyzer
━━━━━━━━━━━━━━━━━
+ analyze(records)
+ check_completeness()
+ check_format()"] SDA["SilverDQAnalyzer
━━━━━━━━━━━━━━━━━
+ analyze(delta_table)
+ check_nullability()
+ check_schema()"] GDA["GoldDQAnalyzer
━━━━━━━━━━━━━━━━━
+ analyze(delta_table)
+ check_pk_uniqueness()
+ validate_schema()"] - AD["AnomalyDetector



"] - ZSD["ZScoreDetector
(DetectorStrategy)


"] + AD["AnomalyDetector"] + ZSD["ZScoreDetector
(DetectorStrategy)"] AN["Anomaly
━━━━━━━━━━━━━━━━━
type: AnomalyType
severity: AnomalySeverity
metric_name: str"] end %% ── Pipeline Integration (application layer) ────────── subgraph Pipeline["Pipeline Integration"] - BT["BatchTransformer
━━━━━━━━━━━━━━━━━
_check_dq_thresholds()

"] - QM["QuarantineManager
━━━━━━━━━━━━━━━━━
Quarantines failed records

"] - EC["ErrorClassifier
━━━━━━━━━━━━━━━━━
recoverable vs fatal

"] + BT["BatchTransformer
--------
_check_dq_thresholds()"] + QM["QuarantineManager
--------
Quarantines failed records"] + EC["ErrorClassifier
--------
recoverable vs fatal"] end %% ── Domain Value Objects ────────────────────────────── @@ -55,8 +65,8 @@ graph TB %% ── Infrastructure Implementations ──────────────────── subgraph InfraImpl["Infrastructure Implementations"] - DQCL["DQConfigLoader
(YAML → DQConfig)


"] - DQRW["DQReportWriter
(JSON reports)


"] + DQCL["DQConfigLoader
(YAML -> DQConfig)"] + DQRW["DQReportWriter
(JSON reports)"] end %% ── Port implementations (DI / implements) ──────────── diff --git a/docs/02-architecture/mmd-diagrams/architecture/08-composite-pipeline.mmd b/docs/02-architecture/mmd-diagrams/architecture/08-composite-pipeline.mmd index 6b378d92f6..c98025cb31 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/08-composite-pipeline.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/08-composite-pipeline.mmd @@ -8,7 +8,17 @@ %% @nodes 33 %% @reference Decomposed into 08a-composite-config, 08b-composite-execution -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=256 height=126 max_title_len=27 max_desc_lines=5 graph TB subgraph Config["Composite Configuration"] diff --git a/docs/02-architecture/mmd-diagrams/architecture/09-observability-stack.mmd b/docs/02-architecture/mmd-diagrams/architecture/09-observability-stack.mmd index ef3ad909a7..775a969ebf 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/09-observability-stack.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/09-observability-stack.mmd @@ -8,7 +8,17 @@ %% @nodes 24 %% @reference Decomposed into 09a-observability-app, 09b-observability-infra -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=224 height=198 max_title_len=23 max_desc_lines=9 graph TB %% keep-orphan: DQMP diff --git a/docs/02-architecture/mmd-diagrams/architecture/10-resilience-patterns.mmd b/docs/02-architecture/mmd-diagrams/architecture/10-resilience-patterns.mmd index 07a0d759a1..093070f3a2 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/10-resilience-patterns.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/10-resilience-patterns.mmd @@ -9,57 +9,67 @@ %% @allow-polyline-routing %% @uniform width=336 height=240 max_title_len=33 max_desc_lines=11 -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'BRANDES_KOEPF', 'edgeRouting': 'POLYLINE'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph TB %% keep-orphan: CBDSD, RDSD, R_CR, R_OA, R_PC, R_PM, R_SS, R_UP subgraph Ports["Domain Ports"] - CBP["CircuitBreakerPort
(Protocol)
━━━━━━━━━━━━━━━━━
+ get_state() → CircuitBreakerState
+ get_failure_count() → int
+ call(fn) → T
+ reset()



"]:::size-lg - RLP["RateLimiterPort
(Protocol)
━━━━━━━━━━━━━━━━━
+ acquire(tokens)
+ try_acquire() → bool
+ available_tokens() → int




"]:::size-lg - HCP["HealthCheckPort
(Protocol)
━━━━━━━━━━━━━━━━━
+ check_health() → HealthCheckResult






"]:::size-lg + CBP["CircuitBreakerPort
(Protocol)
--------
+ get_state()
+ call(fn)"]:::size-md + RLP["RateLimiterPort
(Protocol)
--------
+ acquire(tokens)
+ try_acquire()"]:::size-md + HCP["HealthCheckPort
(Protocol)
--------
+ check_health()"]:::size-md end subgraph CircuitBreaker["Circuit Breaker Pattern"] - CB["CircuitBreaker
━━━━━━━━━━━━━━━━━
provider: str
failure_threshold: int
recovery_timeout: int
metrics: MetricsPort




"]:::size-lg + CB["CircuitBreaker
--------
provider
failure_threshold
recovery_timeout"]:::size-md subgraph CBStates["State Machine"] - CLOSED["CLOSED
(normal operation)








"]:::size-lg - OPEN["OPEN
(fail fast,
no requests)







"]:::size-lg - HALF["HALF_OPEN
(probe with
single request)







"]:::size-lg - CLOSED -->|"failures ≥ N"| OPEN - OPEN -->|"timeout elapsed"| HALF + CLOSED["CLOSED
(normal operation)"]:::size-md + OPEN["OPEN
(fail fast)"]:::size-md + HALF["HALF_OPEN
(probe request)"]:::size-md + CLOSED -->|"failures ≥ threshold"| OPEN + OPEN -->|"recovery_timeout elapsed"| HALF HALF -->|"success"| CLOSED HALF -->|"failure"| OPEN end end subgraph RateLimiter["Rate Limiter (Token Bucket)"] - TB["TokenBucket
━━━━━━━━━━━━━━━━━
rate: float
capacity: int
provider: str
metrics: MetricsPort
━━━━━━━━━━━━━━━━━
+ acquire(tokens=1)
waits until tokens available
+ _refill()
replenish based on elapsed time"]:::size-lg + TB["TokenBucket
--------
rate, capacity, provider
+ acquire(tokens=1)
+ _refill()"]:::size-md subgraph Rates["Provider Rate Limits"] - R_PC["PubChem: 5 req/s









"]:::size-lg - R_UP["UniProt: 100 req/s









"]:::size-lg - R_OA["OpenAlex: 10 req/s









"]:::size-lg - R_CR["CrossRef: 50 req/s









"]:::size-lg - R_SS["Semantic Scholar: 0.33 req/s









"]:::size-lg - R_PM["PubMed: 3-10 req/s









"]:::size-lg + R_PC["PubChem: 5 req/s"]:::size-sm + R_UP["UniProt: 100 req/s"]:::size-sm + R_OA["OpenAlex: 10 req/s"]:::size-sm + R_CR["CrossRef: 50 req/s"]:::size-sm + R_SS["Semantic Scholar: 0.33 req/s"]:::size-sm + R_PM["PubMed: 3-10 req/s"]:::size-sm end end subgraph Retry["Retry Logic"] - RP["Retry (in UnifiedHTTPClient)
━━━━━━━━━━━━━━━━━
max_retries: int
backoff_factor: float
retry_on: set[int]
━━━━━━━━━━━━━━━━━
Exponential backoff
with jitter


"]:::size-lg + RP["Retry in UnifiedHTTPClient
--------
max_retries
backoff_factor
exponential backoff + jitter"]:::size-md end subgraph HealthCheck["Health Check Template"] - HCPM["HealthCheckProviderMixin
━━━━━━━━━━━━━━━━━
Template Method Pattern:
1. _probe_health() — override
2. Log success/failure
3. Record metrics
4. Return HealthCheckResult
5. Fallback to CB state


"]:::size-lg - HCR["HealthCheckResult
━━━━━━━━━━━━━━━━━
status: HealthStatus
latency_ms: float
provider: str
endpoint: str
last_error: str | None
consecutive_failures: int


"]:::size-lg - HS["HealthStatus
━━━━━━━━━━━━━━━━━
HEALTHY
DEGRADED
UNHEALTHY





"]:::size-lg + HCPM["HealthCheckProviderMixin
--------
probe -> log -> metrics
return HealthCheckResult"]:::size-md + HCR["HealthCheckResult
--------
status, latency, provider
endpoint, last_error"]:::size-md + HS["HealthStatus
--------
HEALTHY / DEGRADED / UNHEALTHY"]:::size-sm end subgraph Client["UnifiedHTTPClient"] - UHC["UnifiedHTTPClient
━━━━━━━━━━━━━━━━━
Composes all patterns:
1. acquire rate limiter
2. check circuit breaker
3. attempt request
4. retry on failure
5. record metrics


"]:::size-lg + UHC["UnifiedHTTPClient
--------
rate limit -> circuit breaker
request -> retry -> metrics"]:::size-md end subgraph Decorators["Data Source Decorators"] - CBDSD["CircuitBreakerDataSourceDecorator
━━━━━━━━━━━━━━━━━
Wraps DataSourcePort
with circuit breaker






"]:::size-lg - RDSD["RetryingDataSourceDecorator
━━━━━━━━━━━━━━━━━
Wraps DataSourcePort
with retry logic






"]:::size-lg + CBDSD["CircuitBreakerDataSourceDecorator
--------
wraps DataSourcePort"]:::size-md + RDSD["RetryingDataSourceDecorator
--------
wraps DataSourcePort"]:::size-md end %% Port implementations diff --git a/docs/02-architecture/mmd-diagrams/architecture/11-configuration-system.mmd b/docs/02-architecture/mmd-diagrams/architecture/11-configuration-system.mmd index c1cd2dfe98..6183d7a392 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/11-configuration-system.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/11-configuration-system.mmd @@ -10,7 +10,17 @@ %% @nodes 29 %% @reference Decomposed into 11a-config-loading, 11b-config-domain -%%{init: {'layout': 'elk', 'theme': 'base', 'flowchart': {'nodeSpacing': 56, 'rankSpacing': 84, 'padding': 24, 'curve': 'linear'}, 'elk': {'mergeEdges': true, 'nodePlacementStrategy': 'BRANDES_KOEPF', 'cycleBreakingStrategy': 'GREEDY', 'direction': 'RIGHT', 'spacing.nodeNode': 44, 'spacing.edgeNode': 32, 'spacing.edgeEdge': 24, 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=216 height=198 max_title_len=22 max_desc_lines=9 flowchart LR %% keep-orphan: APC, CBC, CCFG, OBS_SET, PCP, PIPE_SET, SETTINGS, SRC diff --git a/docs/02-architecture/mmd-diagrams/architecture/12-bootstrap-di-container.mmd b/docs/02-architecture/mmd-diagrams/architecture/12-bootstrap-di-container.mmd index 8d8199e9c1..f9066a5efd 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/12-bootstrap-di-container.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/12-bootstrap-di-container.mmd @@ -8,7 +8,17 @@ %% @nodes 29 %% @reference Decomposed into 12a, 12b sub-diagrams -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=192 height=108 max_title_len=19 max_desc_lines=4 graph TB subgraph Entry["Entry Points"] diff --git a/docs/02-architecture/mmd-diagrams/architecture/12a-bootstrap-factories.mmd b/docs/02-architecture/mmd-diagrams/architecture/12a-bootstrap-factories.mmd index a2e57b0e7d..1c426644dd 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/12a-bootstrap-factories.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/12a-bootstrap-factories.mmd @@ -10,6 +10,17 @@ %% @nodes 10 %% @uniform width=296 height=56 max_title_len=29 max_desc_lines=1 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph TB subgraph Interfaces["Interfaces Layer"] CLI["CLI Commands (Click)"]:::size-sm diff --git a/docs/02-architecture/mmd-diagrams/architecture/12b-bootstrap-wiring.mmd b/docs/02-architecture/mmd-diagrams/architecture/12b-bootstrap-wiring.mmd index 1e85e54900..e35bdd3b2d 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/12b-bootstrap-wiring.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/12b-bootstrap-wiring.mmd @@ -10,7 +10,17 @@ %% @nodes 15 %% @uniform width=400 height=56 max_title_len=40 max_desc_lines=1 -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'BRANDES_KOEPF', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph TB subgraph Composition["Composition Layer"] RA["bootstrap_pipeline_runner"]:::size-sm diff --git a/docs/02-architecture/mmd-diagrams/architecture/13-port-protocol-contracts.mmd b/docs/02-architecture/mmd-diagrams/architecture/13-port-protocol-contracts.mmd index b2cd1c2b9e..0d91f69405 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/13-port-protocol-contracts.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/13-port-protocol-contracts.mmd @@ -8,7 +8,17 @@ %% @nodes 68 %% @reference Decomposed into 13a, 13b, 13c, 13d sub-diagrams -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=232 height=56 max_title_len=24 max_desc_lines=0 graph LR %% keep-orphan: DNP, DQMP, FDSP, HCP, MCP, SHP diff --git a/docs/02-architecture/mmd-diagrams/architecture/13a-data-storage-ports.mmd b/docs/02-architecture/mmd-diagrams/architecture/13a-data-storage-ports.mmd index b963fb0bc5..ac40332b0e 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/13a-data-storage-ports.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/13a-data-storage-ports.mmd @@ -8,41 +8,36 @@ %% @nodes 20 %%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, 'layout': 'elk', - 'theme': 'base', - 'themeVariables': { 'fontFamily': 'Inter, system-ui, sans-serif' }, 'elk': { 'mergeEdges': true, 'nodePlacementStrategy': 'BRANDES_KOEPF', - 'cycleBreakingStrategy': 'GREEDY', - 'direction': 'RIGHT', - 'spacing.nodeNode': 40, - 'spacing.edgeNode': 30, - 'spacing.edgeEdge': 20, 'edgeRouting': 'ORTHOGONAL' } }}%% - -%% @uniform width=232 height=56 max_title_len=24 max_desc_lines=0 +%% @uniform width=232 height=56 max_title_len=34 max_desc_lines=0 graph LR %% keep-orphan: FDSP subgraph Domain["Domain Ports"] - DSP["fa:fa-plug DataSourcePort"]:::size-sm - FDSP["fa:fa-filter FilterableDataSourcePort"]:::size-sm - STP["fa:fa-database StoragePort"]:::size-sm - DRP["fa:fa-book-open DeltaReaderPort"]:::size-sm - IFP["fa:fa-file-import InputFilterPort"]:::size-sm + DSP["fa:fa-plug DataSourcePort"]:::size-md + FDSP["fa:fa-filter FilterableDataSourcePort"]:::size-lg + STP["fa:fa-database StoragePort"]:::size-md + DRP["fa:fa-book-open DeltaReaderPort"]:::size-md + IFP["fa:fa-file-import InputFilterPort"]:::size-md end subgraph Infrastructure["Implementations"] - CA["ChemblAdapter"]:::size-sm - PA["PubchemAdapter"]:::size-sm - UA["UniprotAdapter"]:::size-sm - BW["BronzeWriter"]:::size-sm - SW["SilverWriter"]:::size-sm - GW["GoldWriter"]:::size-sm - DR_I["DeltaReader"]:::size-sm - CSVR["CsvFilterReader"]:::size-sm + CA["ChemblAdapter"]:::size-md + PA["PubchemAdapter"]:::size-md + UA["UniprotAdapter"]:::size-md + BW["BronzeWriter"]:::size-md + SW["SilverWriter"]:::size-md + GW["GoldWriter"]:::size-md + DR_I["DeltaReader"]:::size-md + CSVR["CsvFilterReader"]:::size-md end DSP --- CA & PA & UA diff --git a/docs/02-architecture/mmd-diagrams/architecture/13a-port-contracts-data-sources.mmd b/docs/02-architecture/mmd-diagrams/architecture/13a-port-contracts-data-sources.mmd index f84bc86152..11c32cea57 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/13a-port-contracts-data-sources.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/13a-port-contracts-data-sources.mmd @@ -8,8 +8,19 @@ %% @view data-sources %% @parent 13-port-protocol-contracts.mmd %% @nodes 9 -%% @uniform width=240 height=56 max_title_len=24 max_desc_lines=1 +%% @uniform width=240 height=56 max_title_len=34 max_desc_lines=1 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph LR %% keep-orphan: FDSP subgraph Domain["Domain Layer"] diff --git a/docs/02-architecture/mmd-diagrams/architecture/13b-operational-ports.mmd b/docs/02-architecture/mmd-diagrams/architecture/13b-operational-ports.mmd index b918b9abf0..4deb2009c8 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/13b-operational-ports.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/13b-operational-ports.mmd @@ -9,21 +9,16 @@ %% @reference Decomposed into 13e-operational-ports-domain, 13f-operational-ports-infra %%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, 'layout': 'elk', - 'theme': 'base', - 'themeVariables': { 'fontFamily': 'Inter, system-ui, sans-serif' }, 'elk': { 'mergeEdges': true, 'nodePlacementStrategy': 'BRANDES_KOEPF', - 'cycleBreakingStrategy': 'GREEDY', - 'direction': 'RIGHT', - 'spacing.nodeNode': 40, - 'spacing.edgeNode': 30, - 'spacing.edgeEdge': 20, 'edgeRouting': 'ORTHOGONAL' } }}%% - %% @uniform width=232 height=56 max_title_len=24 max_desc_lines=0 graph LR %% keep-orphan: SHP diff --git a/docs/02-architecture/mmd-diagrams/architecture/13b-port-contracts-storage.mmd b/docs/02-architecture/mmd-diagrams/architecture/13b-port-contracts-storage.mmd index 42c76fbc97..23f4f9e5d5 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/13b-port-contracts-storage.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/13b-port-contracts-storage.mmd @@ -10,6 +10,17 @@ %% @nodes 9 %% @uniform width=184 height=56 max_title_len=18 max_desc_lines=1 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph LR subgraph Domain["Domain Layer"] STP["StoragePort"]:::size-sm diff --git a/docs/02-architecture/mmd-diagrams/architecture/13c-port-contracts-observability.mmd b/docs/02-architecture/mmd-diagrams/architecture/13c-port-contracts-observability.mmd index 1dae68406a..e95dc0e567 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/13c-port-contracts-observability.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/13c-port-contracts-observability.mmd @@ -10,7 +10,17 @@ %% @nodes 15 %% @uniform width=192 height=56 max_title_len=19 max_desc_lines=1 -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'BRANDES_KOEPF', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph LR subgraph Domain["Domain Layer"] LGP["LoggerPort"]:::size-sm diff --git a/docs/02-architecture/mmd-diagrams/architecture/13c-validation-dq-ports.mmd b/docs/02-architecture/mmd-diagrams/architecture/13c-validation-dq-ports.mmd index 7da89be764..3461231770 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/13c-validation-dq-ports.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/13c-validation-dq-ports.mmd @@ -8,17 +8,13 @@ %% @nodes 20 %%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, 'layout': 'elk', - 'theme': 'base', - 'themeVariables': { 'fontFamily': 'Inter, system-ui, sans-serif' }, 'elk': { 'mergeEdges': true, 'nodePlacementStrategy': 'BRANDES_KOEPF', - 'cycleBreakingStrategy': 'GREEDY', - 'direction': 'RIGHT', - 'spacing.nodeNode': 40, - 'spacing.edgeNode': 30, - 'spacing.edgeEdge': 20, 'edgeRouting': 'ORTHOGONAL' } }}%% @@ -26,26 +22,26 @@ %% @uniform width=232 height=56 max_title_len=24 max_desc_lines=0 graph LR subgraph Domain["Domain Ports"] - SVP["fa:fa-check-double SilverValidatorPort"]:::size-sm - GVP["fa:fa-shield-check GoldValidatorPort"]:::size-sm - BDQP["fa:fa-magnifying-glass BronzeDQAnalyzerPort"]:::size-sm - SDQP["fa:fa-magnifying-glass-plus SilverDQAnalyzerPort"]:::size-sm - GDQP["fa:fa-magnifying-glass-chart GoldDQAnalyzerPort"]:::size-sm - DQRWP["fa:fa-file-contract DQReportWriterPort"]:::size-sm - QRP["fa:fa-biohazard QuarantinePort"]:::size-sm + SVP["fa:fa-check-double SilverValidatorPort"]:::size-md + GVP["fa:fa-shield-check GoldValidatorPort"]:::size-md + BDQP["fa:fa-magnifying-glass BronzeDQAnalyzerPort"]:::size-md + SDQP["fa:fa-magnifying-glass-plus SilverDQAnalyzerPort"]:::size-md + GDQP["fa:fa-magnifying-glass-chart GoldDQAnalyzerPort"]:::size-md + DQRWP["fa:fa-file-contract DQReportWriterPort"]:::size-md + QRP["fa:fa-biohazard QuarantinePort"]:::size-md end subgraph Infrastructure["Infrastructure"] - PSV["PanderaSilverValidator"]:::size-sm - PGV["PanderaGoldValidator"]:::size-sm - DQRW_I["DQReportWriter"]:::size-sm - UQ["UnifiedQuarantine"]:::size-sm + PSV["PanderaSilverValidator"]:::size-md + PGV["PanderaGoldValidator"]:::size-md + DQRW_I["DQReportWriter"]:::size-md + UQ["UnifiedQuarantine"]:::size-md end subgraph Application["Application"] - BDA["BronzeDQAnalyzer"]:::size-sm - SDA["SilverDQAnalyzer"]:::size-sm - GDA["GoldDQAnalyzer"]:::size-sm + BDA["BronzeDQAnalyzer"]:::size-md + SDA["SilverDQAnalyzer"]:::size-md + GDA["GoldDQAnalyzer"]:::size-md end SVP --- PSV diff --git a/docs/02-architecture/mmd-diagrams/architecture/13d-port-contracts-services.mmd b/docs/02-architecture/mmd-diagrams/architecture/13d-port-contracts-services.mmd index 230964a890..7dd3bbd015 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/13d-port-contracts-services.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/13d-port-contracts-services.mmd @@ -10,7 +10,17 @@ %% @nodes 20 %% @uniform width=200 height=56 max_title_len=20 max_desc_lines=1 -%%{init: {'layout': 'elk', 'theme': 'base', 'themeVariables': {'fontFamily': 'Inter, Roboto, sans-serif'}, 'elk': {'mergeEdges': true, 'nodePlacementStrategy': 'BRANDES_KOEPF', 'cycleBreakingStrategy': 'GREEDY', 'direction': 'RIGHT', 'spacing.nodeNode': 40, 'spacing.edgeNode': 30, 'spacing.edgeEdge': 20, 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph LR %% keep-orphan: DQMP %% keep-orphan: NTP diff --git a/docs/02-architecture/mmd-diagrams/architecture/14-cli-interface-layer.mmd b/docs/02-architecture/mmd-diagrams/architecture/14-cli-interface-layer.mmd index b444fd8922..f8f97a32f5 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/14-cli-interface-layer.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/14-cli-interface-layer.mmd @@ -8,7 +8,17 @@ %% @nodes 24 %% @reference Decomposed into 14a-cli-commands, 14b-cli-routing -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=248 height=72 max_title_len=26 max_desc_lines=2 graph LR subgraph User["User"] diff --git a/docs/02-architecture/mmd-diagrams/architecture/15-batch-executor-internals.mmd b/docs/02-architecture/mmd-diagrams/architecture/15-batch-executor-internals.mmd index 6c835ad303..96cb175421 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/15-batch-executor-internals.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/15-batch-executor-internals.mmd @@ -9,26 +9,36 @@ %% @allow-polyline-routing %% @uniform width=280 height=256 max_title_len=20 max_desc_lines=12 -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'BRANDES_KOEPF', 'edgeRouting': 'POLYLINE'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph TB subgraph BatchExecutor["BatchExecutor"] - BE["BatchExecutor
━━━━━━━━━━━━━━━━━
_services: PipelineServices
_context: PipelineContext
_config: RecordProcessorConfig
batch_size: int
checkpoint_interval: int
━━━━━━━━━━━━━━━━━
+ execute(limit, query, offset)
+ process(records, start_index)
+ get_dq_context()
+ get_run_statistics()"]:::size-lg + BE["BatchExecutor
--------
services, context, config
batch_size, checkpoint_interval
+ execute()
+ process()"]:::size-md end subgraph Helpers["Composed Helper Components"] - BMM["BatchMemoryManager
━━━━━━━━━━━━━━━━━
_memory_monitor: MemoryMonitorPort
_memory_config: MemoryConfig
_initial_batch_size: int
━━━━━━━━━━━━━━━━━
+ check_pressure() → new_size
+ maybe_recover() → new_size
Adaptive batch sizing:
reduces under memory pressure,
recovers when pressure drops
"]:::size-lg - BMR["BatchMetricsRecorder
━━━━━━━━━━━━━━━━━
_metrics: MetricsPort
_pipeline_label: str
_run_type_label: str
━━━━━━━━━━━━━━━━━
+ track_batch_size(stage, size)
+ track_processed_records(stage, count)
+ track_error(stage, error_type)
+ track_quarantined_records()

"]:::size-lg - BTM["BatchTracingManager
━━━━━━━━━━━━━━━━━
_tracer: TracingPort
TRACER_NAME = 'bioetl.batch_executor'
━━━━━━━━━━━━━━━━━
+ start_execution_span()
+ start_batch_span(batch_id)
+ start_layer_span(name)
+ end_span(span, error)


"]:::size-lg - BT["BatchTransformer
━━━━━━━━━━━━━━━━━
_transform: TransformCallback
_gold_filter: GoldFilterCallback
_gold_transform: GoldTransformCallback
_error_classifier: ErrorClassifier
━━━━━━━━━━━━━━━━━
+ transform_batch(records, batch_id)
+ transform_single(record)
+ _check_dq_thresholds()

"]:::size-lg - BW["BatchWriter
━━━━━━━━━━━━━━━━━
_storage: StoragePort
_gold_validator: GoldValidatorPort
_lock_validator: Callable
━━━━━━━━━━━━━━━━━
+ write_bronze(records, batch_id)
+ write_silver(records, batch_id)
+ write_gold(records)
+ _validate_lock() — Safety Guard

"]:::size-lg - QM["QuarantineManager
━━━━━━━━━━━━━━━━━
_quarantine: QuarantinePort
━━━━━━━━━━━━━━━━━
+ quarantine_record(raw, error_type,
batch_id, error_msg, ts)





"]:::size-lg - CM["CheckpointManager
━━━━━━━━━━━━━━━━━
_checkpoint: CheckpointPort
━━━━━━━━━━━━━━━━━
+ load_checkpoint()
+ save_checkpoint(offset)
+ delete_checkpoint()




"]:::size-lg + BMM["BatchMemoryManager
--------
adaptive batch sizing
+ check_pressure()
+ maybe_recover()"]:::size-md + BMR["BatchMetricsRecorder
--------
batch and error metrics
+ track_batch_size()
+ track_error()"]:::size-md + BTM["BatchTracingManager
--------
execution spans
+ start_batch_span()
+ end_span()"]:::size-md + BT["BatchTransformer
--------
transform callbacks
+ transform_batch()
+ _check_dq_thresholds()"]:::size-md + BW["BatchWriter
--------
bronze/silver/gold writes
+ write_bronze()
+ _validate_lock()"]:::size-md + QM["QuarantineManager
--------
quarantine failed records
+ quarantine_record()"]:::size-md + CM["CheckpointManager
--------
offset checkpoints
+ load/save/delete"]:::size-md end subgraph DataFlow["Data Flow Through Batch"] direction LR - RAW["Raw API Records
(dict[str, Any])









"]:::size-lg - SILVER["Silver Records
(Delta Lake)









"]:::size-lg + RAW["Raw API Records
(dict[str, Any])"]:::size-sm + SILVER["Silver Records
(Delta Lake)"]:::size-sm RAW -->|"write_bronze()"| BRONZE RAW -->|"transform()"| SILVER SILVER -->|"write_gold()"| GOLD @@ -36,11 +46,11 @@ graph TB end subgraph TransformResult["TransformResult"] - TR["TransformResult
━━━━━━━━━━━━━━━━━
silver_records: list[SilverRecord]
gold_records: list[dict]
quarantined_count: int
errors: list[TransformError]





"]:::size-lg + TR["TransformResult
--------
silver_records
gold_records
quarantined_count
errors"]:::size-md end subgraph ErrorClassification["Error Classification"] - ECL["ErrorClassifier
━━━━━━━━━━━━━━━━━
Classifies exceptions as:
• QUARANTINE (data issue)
• RETRY (transient)
• FATAL (stop pipeline)





"]:::size-lg + ECL["ErrorClassifier
--------
QUARANTINE / RETRY / FATAL"]:::size-md end %% Composition diff --git a/docs/02-architecture/mmd-diagrams/architecture/16-transformer-hierarchy.mmd b/docs/02-architecture/mmd-diagrams/architecture/16-transformer-hierarchy.mmd index 1ec2e15306..211dea5f73 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/16-transformer-hierarchy.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/16-transformer-hierarchy.mmd @@ -8,7 +8,17 @@ %% @nodes 35 %% @reference Decomposed into 16a-transformer-base, 16b-transformer-pub-other -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=336 height=240 max_title_len=37 max_desc_lines=18 graph TB subgraph TemplateMethod["Template Method Pattern"] diff --git a/docs/02-architecture/mmd-diagrams/architecture/17-security-pii-audit.mmd b/docs/02-architecture/mmd-diagrams/architecture/17-security-pii-audit.mmd index 4cd0bc62f8..289ec3995f 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/17-security-pii-audit.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/17-security-pii-audit.mmd @@ -9,41 +9,51 @@ %% @allow-polyline-routing %% @uniform width=312 height=216 max_title_len=31 max_desc_lines=10 -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'NETWORK_SIMPLEX', 'edgeRouting': 'POLYLINE'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% graph TB subgraph Ports["Domain Ports"] - PHP["PiiHasherPort
(Protocol)
━━━━━━━━━━━━━━━━━
+ hash(value: str) → str





"]:::size-lg - AP["AuditPort
(Protocol)
━━━━━━━━━━━━━━━━━
+ log_write(entry: AuditEntry)
+ get_entries(filters) → list




"]:::size-lg + PHP["PiiHasherPort
(Protocol)
--------
+ hash(value: str) -> str"]:::size-md + AP["AuditPort
(Protocol)
--------
+ log_write(entry)
+ get_entries(filters)"]:::size-md end subgraph DomainTypes["Domain Types"] - AE["AuditEntry
(frozen dataclass)
━━━━━━━━━━━━━━━━━
run_id: RunID
timestamp: datetime
layer: AuditLayer
table_name: str
operation: AuditOperation
records_count: int
metadata: dict"]:::size-lg - AL["AuditLayer (StrEnum)
━━━━━━━━━━━━━━━━━
BRONZE
SILVER
GOLD




"]:::size-lg - AO["AuditOperation (StrEnum)
━━━━━━━━━━━━━━━━━
WRITE
MERGE
APPEND
DELETE
OVERWRITE


"]:::size-lg + AE["AuditEntry
(frozen dataclass)
--------
run_id, timestamp, layer
table_name, operation
records_count, metadata"]:::size-md + AL["AuditLayer
--------
BRONZE / SILVER / GOLD"]:::size-sm + AO["AuditOperation
--------
WRITE / MERGE / APPEND
DELETE / OVERWRITE"]:::size-sm end subgraph PIIFlow["PII Hashing Flow"] - RAW_PII["Raw PII Data
(author names, emails,
affiliations)






"]:::size-lg - HASH_FN["SHA256(lowercase(value) + salt)








"]:::size-lg + RAW_PII["Raw PII Data
(names, emails, affiliations)"]:::size-md + HASH_FN["SHA256(lowercase(value) + salt)"]:::size-sm RAW_PII --> HASH_FN --> HASHED end subgraph InfraPII["Infrastructure: PII Hasher"] - SPH["Sha256PiiHasher
━━━━━━━━━━━━━━━━━
+ hash(value) → str






"]:::size-lg - SC["SaltConfig
(frozen dataclass)
━━━━━━━━━━━━━━━━━
current_salt: str
next_salt: str | None
rotation_active: bool
━━━━━━━━━━━━━━━━━
+ from_settings()
+ from_env()
"]:::size-lg + SPH["Sha256PiiHasher
--------
+ hash(value) -> str"]:::size-md + SC["SaltConfig
(frozen dataclass)
--------
current_salt
next_salt
rotation_active"]:::size-md end subgraph InfraAudit["Infrastructure: Audit"] - FAA["FileAuditAdapter
━━━━━━━━━━━━━━━━━
base_path: Path
logger: LoggerPort
━━━━━━━━━━━━━━━━━
+ log_write(entry)
+ get_entries(filters)
+ aclose()

"]:::size-lg - JSONL["audit_YYYY-MM-DD.jsonl
(one file per day,
append-only)






"]:::size-lg + FAA["FileAuditAdapter
--------
base_path, logger
+ log_write(entry)
+ get_entries(filters)"]:::size-md + JSONL["audit_YYYY-MM-DD.jsonl
(daily append-only file)"]:::size-sm end subgraph Usage["Usage in Transformers"] - BT["BaseTransformer
━━━━━━━━━━━━━━━━━
+ hash_pii_value(value) → str
+ hash_pii_list(values) → list[str]





"]:::size-lg + BT["BaseTransformer
--------
+ hash_pii_value()
+ hash_pii_list()"]:::size-md end subgraph StorageAudit["Storage Audit Integration"] - GW["GoldWriter
━━━━━━━━━━━━━━━━━
audit: AuditPort
logs writes





"]:::size-lg + GW["GoldWriter
--------
audit: AuditPort
logs writes"]:::size-md end %% Port implementations diff --git a/docs/02-architecture/mmd-diagrams/architecture/18-lock-checkpoint-shutdown.mmd b/docs/02-architecture/mmd-diagrams/architecture/18-lock-checkpoint-shutdown.mmd index ee75e2d4bf..bd879380d7 100644 --- a/docs/02-architecture/mmd-diagrams/architecture/18-lock-checkpoint-shutdown.mmd +++ b/docs/02-architecture/mmd-diagrams/architecture/18-lock-checkpoint-shutdown.mmd @@ -8,7 +8,17 @@ %% @nodes 22 %% @reference Decomposed into 18a-lock-system, 18b-checkpoint-shutdown -%%{init: {'layout': 'elk', 'elk': {'mergeEdges': false, 'nodePlacementStrategy': 'SIMPLE', 'edgeRouting': 'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=264 height=216 max_title_len=28 max_desc_lines=10 graph TB %% keep-orphan: LNHE, SHP diff --git a/docs/02-architecture/mmd-diagrams/architecture/png/INDEX.md b/docs/02-architecture/mmd-diagrams/architecture/png/INDEX.md new file mode 100644 index 0000000000..72469780f2 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/architecture/png/INDEX.md @@ -0,0 +1,208 @@ +# BioETL Diagrams — PNG Index + +_Generated: 2026-03-01T18:07:54+03:00_ + +## High Level Hexagonal + +![01-high-level-hexagonal](./01-high-level-hexagonal.png) + +--- + +## 01ahexagonal Overview + +![01a-hexagonal-overview](./01a-hexagonal-overview.png) + +--- + +## 01bhexagonal Domain App + +![01b-hexagonal-domain-app](./01b-hexagonal-domain-app.png) + +--- + +## 01chexagonal Infra Comp + +![01c-hexagonal-infra-comp](./01c-hexagonal-infra-comp.png) + +--- + +## 01dhexagonal Overview Rounded + +![01d-hexagonal-overview-rounded](./01d-hexagonal-overview-rounded.png) + +--- + +## Layer Dependency Matrix + +![02-layer-dependency-matrix](./02-layer-dependency-matrix.png) + +--- + +## Medallion Data Flow + +![03-medallion-data-flow](./03-medallion-data-flow.png) + +--- + +## 03amedallion Layers Overview + +![03a-medallion-layers-overview](./03a-medallion-layers-overview.png) + +--- + +## Pipeline Execution Flow + +![04-pipeline-execution-flow](./04-pipeline-execution-flow.png) + +--- + +## Provider Adapter Hierarchy + +![05-provider-adapter-hierarchy](./05-provider-adapter-hierarchy.png) + +--- + +## 05aadapter Hierarchy Base + +![05a-adapter-hierarchy-base](./05a-adapter-hierarchy-base.png) + +--- + +## 05badapter Hierarchy Providers + +![05b-adapter-hierarchy-providers](./05b-adapter-hierarchy-providers.png) + +--- + +## Storage Layer + +![06-storage-layer](./06-storage-layer.png) + +--- + +## Dq System + +![07-dq-system](./07-dq-system.png) + +--- + +## Composite Pipeline + +![08-composite-pipeline](./08-composite-pipeline.png) + +--- + +## Observability Stack + +![09-observability-stack](./09-observability-stack.png) + +--- + +## Resilience Patterns + +![10-resilience-patterns](./10-resilience-patterns.png) + +--- + +## Configuration System + +![11-configuration-system](./11-configuration-system.png) + +--- + +## Bootstrap Di Container + +![12-bootstrap-di-container](./12-bootstrap-di-container.png) + +--- + +## 12abootstrap Factories + +![12a-bootstrap-factories](./12a-bootstrap-factories.png) + +--- + +## 12bbootstrap Wiring + +![12b-bootstrap-wiring](./12b-bootstrap-wiring.png) + +--- + +## Port Protocol Contracts + +![13-port-protocol-contracts](./13-port-protocol-contracts.png) + +--- + +## 13adata Storage Ports + +![13a-data-storage-ports](./13a-data-storage-ports.png) + +--- + +## 13aport Contracts Data Sources + +![13a-port-contracts-data-sources](./13a-port-contracts-data-sources.png) + +--- + +## 13boperational Ports + +![13b-operational-ports](./13b-operational-ports.png) + +--- + +## 13bport Contracts Storage + +![13b-port-contracts-storage](./13b-port-contracts-storage.png) + +--- + +## 13cport Contracts Observability + +![13c-port-contracts-observability](./13c-port-contracts-observability.png) + +--- + +## 13cvalidation Dq Ports + +![13c-validation-dq-ports](./13c-validation-dq-ports.png) + +--- + +## 13dport Contracts Services + +![13d-port-contracts-services](./13d-port-contracts-services.png) + +--- + +## Cli Interface Layer + +![14-cli-interface-layer](./14-cli-interface-layer.png) + +--- + +## Batch Executor Internals + +![15-batch-executor-internals](./15-batch-executor-internals.png) + +--- + +## Transformer Hierarchy + +![16-transformer-hierarchy](./16-transformer-hierarchy.png) + +--- + +## Security Pii Audit + +![17-security-pii-audit](./17-security-pii-audit.png) + +--- + +## Lock Checkpoint Shutdown + +![18-lock-checkpoint-shutdown](./18-lock-checkpoint-shutdown.png) + +--- + diff --git a/docs/02-architecture/mmd-diagrams/architecture/svg/INDEX.md b/docs/02-architecture/mmd-diagrams/architecture/svg/INDEX.md new file mode 100644 index 0000000000..081d079925 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/architecture/svg/INDEX.md @@ -0,0 +1,214 @@ +# BioETL Diagrams — SVG Index + +_Generated: 2026-03-01T18:07:54+03:00_ + +## High Level Hexagonal + +![01-high-level-hexagonal](./01-high-level-hexagonal.svg) + +--- + +## 01ahexagonal Overview + +![01a-hexagonal-overview](./01a-hexagonal-overview.svg) + +--- + +## 01bhexagonal Domain App + +![01b-hexagonal-domain-app](./01b-hexagonal-domain-app.svg) + +--- + +## 01chexagonal Infra Comp + +![01c-hexagonal-infra-comp](./01c-hexagonal-infra-comp.svg) + +--- + +## 01dhexagonal Overview Rounded + +![01d-hexagonal-overview-rounded](./01d-hexagonal-overview-rounded.svg) + +--- + +## Layer Dependency Matrix + +![02-layer-dependency-matrix](./02-layer-dependency-matrix.svg) + +--- + +## Medallion Data Flow + +![03-medallion-data-flow](./03-medallion-data-flow.svg) + +--- + +## 03amedallion Layers Overview + +![03a-medallion-layers-overview](./03a-medallion-layers-overview.svg) + +--- + +## Pipeline Execution Flow + +![04-pipeline-execution-flow](./04-pipeline-execution-flow.svg) + +--- + +## Provider Adapter Hierarchy + +![05-provider-adapter-hierarchy](./05-provider-adapter-hierarchy.svg) + +--- + +## 05aadapter Hierarchy Base + +![05a-adapter-hierarchy-base](./05a-adapter-hierarchy-base.svg) + +--- + +## 05badapter Hierarchy Providers + +![05b-adapter-hierarchy-providers](./05b-adapter-hierarchy-providers.svg) + +--- + +## Storage Layer + +![06-storage-layer](./06-storage-layer.svg) + +--- + +## Dq System + +![07-dq-system](./07-dq-system.svg) + +--- + +## Composite Pipeline + +![08-composite-pipeline](./08-composite-pipeline.svg) + +--- + +## Observability Stack + +![09-observability-stack](./09-observability-stack.svg) + +--- + +## Resilience Patterns + +![10-resilience-patterns](./10-resilience-patterns.svg) + +--- + +## Configuration System + +![11-configuration-system](./11-configuration-system.svg) + +--- + +## Bootstrap Di Container + +![12-bootstrap-di-container](./12-bootstrap-di-container.svg) + +--- + +## 12abootstrap Factories + +![12a-bootstrap-factories](./12a-bootstrap-factories.svg) + +--- + +## 12bbootstrap Wiring + +![12b-bootstrap-wiring](./12b-bootstrap-wiring.svg) + +--- + +## Port Protocol Contracts + +![13-port-protocol-contracts](./13-port-protocol-contracts.svg) + +--- + +## 13adata Storage Ports + +![13a-data-storage-ports](./13a-data-storage-ports.svg) + +--- + +## 13aport Contracts Data Sources + +![13a-port-contracts-data-sources](./13a-port-contracts-data-sources.svg) + +--- + +## 13a.Afterfix.Copy2 No Class Suffix + +![13a.after-fix.copy2-no-class-suffix](./13a.after-fix.copy2-no-class-suffix.svg) + +--- + +## 13boperational Ports + +![13b-operational-ports](./13b-operational-ports.svg) + +--- + +## 13bport Contracts Storage + +![13b-port-contracts-storage](./13b-port-contracts-storage.svg) + +--- + +## 13cport Contracts Observability + +![13c-port-contracts-observability](./13c-port-contracts-observability.svg) + +--- + +## 13cvalidation Dq Ports + +![13c-validation-dq-ports](./13c-validation-dq-ports.svg) + +--- + +## 13dport Contracts Services + +![13d-port-contracts-services](./13d-port-contracts-services.svg) + +--- + +## Cli Interface Layer + +![14-cli-interface-layer](./14-cli-interface-layer.svg) + +--- + +## Batch Executor Internals + +![15-batch-executor-internals](./15-batch-executor-internals.svg) + +--- + +## Transformer Hierarchy + +![16-transformer-hierarchy](./16-transformer-hierarchy.svg) + +--- + +## Security Pii Audit + +![17-security-pii-audit](./17-security-pii-audit.svg) + +--- + +## Lock Checkpoint Shutdown + +![18-lock-checkpoint-shutdown](./18-lock-checkpoint-shutdown.svg) + +--- + diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams-catalog.pdf b/docs/02-architecture/mmd-diagrams/class-diagrams-catalog.pdf new file mode 100644 index 0000000000..93063ca339 Binary files /dev/null and b/docs/02-architecture/mmd-diagrams/class-diagrams-catalog.pdf differ diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams-diagrams-catalog.html b/docs/02-architecture/mmd-diagrams/class-diagrams-diagrams-catalog.html new file mode 100644 index 0000000000..562847561b --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/class-diagrams-diagrams-catalog.html @@ -0,0 +1,31 @@ + +BioETL Diagram Catalog + + +

BioETL class-diagrams Diagrams

Source: docs/02-architecture/mmd-diagrams/class-diagrams/png/*.png

Total images: 16

Generated: 2026-03-01T17:35:58+03:00

+

001. class-diagrams/png/01-domain-ports.png

class-diagrams/png/01-domain-ports.png
+

002. class-diagrams/png/02-entities-aggregates.png

class-diagrams/png/02-entities-aggregates.png
+

003. class-diagrams/png/03-value-objects.png

class-diagrams/png/03-value-objects.png
+

004. class-diagrams/png/04-types-enums.png

class-diagrams/png/04-types-enums.png
+

005. class-diagrams/png/05-exceptions.png

class-diagrams/png/05-exceptions.png
+

006. class-diagrams/png/06-config-classes.png

class-diagrams/png/06-config-classes.png
+

007. class-diagrams/png/07-application-core-services.png

class-diagrams/png/07-application-core-services.png
+

008. class-diagrams/png/08-application-services.png

class-diagrams/png/08-application-services.png
+

009. class-diagrams/png/09-transformers.png

class-diagrams/png/09-transformers.png
+

010. class-diagrams/png/10-adapters.png

class-diagrams/png/10-adapters.png
+

011. class-diagrams/png/11-storage.png

class-diagrams/png/11-storage.png
+

012. class-diagrams/png/12-composite-pipeline.png

class-diagrams/png/12-composite-pipeline.png
+

013. class-diagrams/png/13-domain-services.png

class-diagrams/png/13-domain-services.png
+

014. class-diagrams/png/14-observability.png

class-diagrams/png/14-observability.png
+

015. class-diagrams/png/15-extractors.png

class-diagrams/png/15-extractors.png
+

016. class-diagrams/png/16-factories-bootstrap.png

class-diagrams/png/16-factories-bootstrap.png
+ diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/01-domain-ports.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/01-domain-ports.mmd index 7348072325..f6030d47e6 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/01-domain-ports.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/01-domain-ports.mmd @@ -8,7 +8,7 @@ %% @uniform class width=232 height=216 max_title_len=24 max_desc_lines=10 classDiagram - direction TB + direction LR class DataSourcePort { <> +fetch(entity_type, limit, query, filter_ids, filter_field) AsyncIterator~dict~ diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/05-exceptions.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/05-exceptions.mmd index ec31f8a894..ec5092bf1f 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/05-exceptions.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/05-exceptions.mmd @@ -8,7 +8,7 @@ %% @uniform class width=240 height=90 max_title_len=25 max_desc_lines=3 classDiagram - direction TB + direction LR class BioETLError { <> +context: dict diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/06-config-classes.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/06-config-classes.mmd index 8a39a17ec5..92fb47ef72 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/06-config-classes.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/06-config-classes.mmd @@ -15,25 +15,18 @@ %% @uniform-stats composite width=296 height=144 max_desc_lines=6 %% @uniform-stats support width=216 height=128 max_desc_lines=5 classDiagram - direction TB + direction LR class RuntimeConfig { <> +run_type: RunType +resume: bool +limit: int | None - +heartbeat_interval: int - +wait_for_lock: bool - +lock_wait_timeout: int - +lock_ttl: int | None - +query: str | None +dry_run: bool - +vacuum_after_run: bool - +vacuum_retention_days: int - +optimize_storage: bool + +lock_ttl: int | None +strict_validation: bool - +strict_gold_validation: bool +skip_gold: bool +effective_lock_ttl: int + +... : Runtime flags } class PipelineConfig { @@ -42,18 +35,14 @@ classDiagram +provider: str +entity_type: str +table: TableConfig - +silver_filters: SilverFilterConfig | None - +gold_filters: GoldFilterConfig | None +batch_size: int +checkpoint_interval: int +fields: tuple~str~ - +column_groups: tuple~ColumnGroupConfig~ +dq: DQConfig - +transform_version: str | None - +transform_steps: tuple~str~ +loading_strategy: LoadingStrategy | None - +scd_config: dict | None - +gold_schema: Any | None + +silver_filters: SilverFilterConfig | None + +gold_filters: GoldFilterConfig | None + +... : Schema and transform options } class TableConfig { diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/07-application-core-services.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/07-application-core-services.mmd index 9cfee44ef1..8384220c1f 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/07-application-core-services.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/07-application-core-services.mmd @@ -19,185 +19,165 @@ %% @uniform-stats manager width=256 height=200 max_desc_lines=9 %% @uniform-stats support width=552 height=112 max_desc_lines=4 classDiagram - direction TB - class PipelineRunner { - -_config: PipelineConfig - -_runtime: RuntimeConfig - -_services: PipelineServices - -_context: PipelineContext - -_executor: BatchExecutor - -_checkpoint_manager: CheckpointManager - -_shutdown_signal: ShutdownSignal - -_logger: LoggerPort - -_lock_manager: LockManager - -_preflight_service: PreflightService - -_postrun_service: PostrunService - -_lifecycle_service: MedallionLifecycleService - -_observer: PipelineObserver - +run() None - - } - - class PipelineServices { - <> - +data_source: DataSourcePort - +storage: StoragePort - +lock: LockPort - +checkpoint: CheckpointPort - +quarantine: QuarantinePort - +metrics: MetricsPort - +tracing: TracingPort | None - +logger: LoggerPort - +dq_monitor: DQMonitorPort | None - +metadata_coordinator: MetadataCoordinatorPort | None - +metadata_writer: MetadataWriterPort | None - +dq_report_writer: DQReportWriterPort | None - +dq_report_service: DQReportService | None - - } - - class BatchExecutor { - -_services: PipelineServices - -_context: PipelineContext - -_config: RecordProcessorConfig - -_checkpoint_manager: CheckpointManager - +batch_size: int - +checkpoint_interval: int - +records_fetched: int - +records_bronze: int - +records_silver: int - +records_gold: int - +records_quarantined: int - +execute(limit, query, offset) None - +process(records, start_index) BatchResult - +get_dq_context() DQReportContext | None - +get_run_statistics() dict - } - - class BatchTransformer { - -_context: PipelineContext - -_config: RecordProcessorConfig - -_error_classifier: ErrorClassifier - -_quarantine_manager: QuarantineManager - -_batch_metrics: BatchMetricsRecorder - -_transform: TransformCallback - -_gold_filter: GoldFilterCallback - -_gold_transform: GoldTransformCallback - +transform_batch(records, batch_id, start_index) TransformResult - +transform_single(raw_record, batch_id, index) TransformedRecord - +_check_dq_thresholds(records, quarantined_count) None - - } - - class BatchWriter { - -_storage: StoragePort - -_context: PipelineContext - -_gold_validator: GoldValidatorPort - -_error_classifier: ErrorClassifier - -_lock_validator: Callable - -_silver_mode: WriteMode - -_gold_mode: WriteMode - -_column_orderer: ColumnOrderer | None - +write_bronze(records, batch_id, ingestion_ts, metadata) BronzeWriteResult - +write_silver(records, batch_id, ingestion_ts, bronze_refs) SilverWriteResult | None - +write_gold(records, silver_refs) None - +_validate_lock(operation) None - } - - class BatchMemoryManager { - -_memory_monitor: MemoryMonitorPort | None - -_memory_config: MemoryConfig | None - -_initial_batch_size: int - +enabled: bool - +batch_size_reductions: int - +check_pressure(current_size, interval, fetched) int - +maybe_recover(current_size) int - } - - class BatchMetricsRecorder { - -_metrics: MetricsPort | None - -_pipeline_label: str - -_run_type_label: str - +track_batch_size(stage, size) None - +track_processed_records(stage, count) None - +track_error(stage, error_type) None - +track_quarantined_records(error_type, count) None - } - - class BatchTracingManager { - -_tracer: TracingPort - -_context: PipelineContext - +TRACER_NAME: str - +start_execution_span() Span | None - +start_batch_span(batch_id, count, start) Span | None - +start_layer_span(name, batch_id, count) Span | None - +end_span(span, error) None - } - - class CheckpointManager { - -_checkpoint: CheckpointPort - -_logger: LoggerPort - -_pipeline_name: str - -_run_id: RunID - -_resume: bool - +load_checkpoint() dict | None - +save_checkpoint(offset) None - +delete_checkpoint() None - - } - - class LockManager { - -_lock: LockPort - -_run_id: RunID - -_config: LockConfig - -_shutdown_signal: ShutdownSignal - -_heartbeat: HeartbeatTask | None - -_fencing_token: FencingToken | None - +acquire(timeout) FencingToken - +release() None - +validate() bool - } - - class PreflightService { - +execute(config, runtime, services, context, observer) PreflightReport - - - - } - - class PostrunService { - +execute(config, runtime, context, executor, metadata, observer) PostrunResult - - - - } - - class QuarantineManager { - -_quarantine: QuarantinePort - +quarantine_record(raw, error_type, batch_id, msg, ts) None - - - } - - class ShutdownSignal { - +is_requested: bool - +reason: ShutdownReason | None - +request(reason) None - +reset() None - } - - class HeartbeatTask { - Background async task - +start() None - +stop() None - - } - - class ErrorClassifier { - +classify(error) ErrorCategory - - - + direction LR + namespace Runner_Core { + class PipelineRunner { + -_config: PipelineConfig + -_runtime: RuntimeConfig + -_services: PipelineServices + -_executor: BatchExecutor + -_checkpoint_manager: CheckpointManager + -_shutdown_signal: ShutdownSignal + -_lock_manager: LockManager + -_preflight_service: PreflightService + -_postrun_service: PostrunService + +run() None + +... : lifecycle orchestration + } + + class PipelineServices { + <> + +data_source: DataSourcePort + +storage: StoragePort + +lock: LockPort + +checkpoint: CheckpointPort + +quarantine: QuarantinePort + +metrics: MetricsPort + +tracing: TracingPort | None + +logger: LoggerPort + +dq_monitor: DQMonitorPort | None + +... : optional reporting services + } + + class BatchExecutor { + -_services: PipelineServices + -_context: PipelineContext + -_config: RecordProcessorConfig + -_checkpoint_manager: CheckpointManager + +batch_size: int + +checkpoint_interval: int + +records_fetched: int + +records_bronze: int + +records_quarantined: int + +execute(limit, query, offset) None + +process(records, start_index) BatchResult + +get_dq_context() DQReportContext | None + +... : run statistics API + } + } + + namespace Batch_Processing { + class BatchTransformer { + -_context: PipelineContext + -_config: RecordProcessorConfig + -_error_classifier: ErrorClassifier + -_quarantine_manager: QuarantineManager + -_batch_metrics: BatchMetricsRecorder + +transform_batch(records, batch_id, start_index) TransformResult + +transform_single(raw_record, batch_id, index) TransformedRecord + +... : internal transform callbacks + } + + class BatchWriter { + -_storage: StoragePort + -_context: PipelineContext + -_gold_validator: GoldValidatorPort + -_error_classifier: ErrorClassifier + -_silver_mode: WriteMode + -_gold_mode: WriteMode + -_column_orderer: ColumnOrderer | None + +write_bronze(records, batch_id, ingestion_ts, metadata) BronzeWriteResult + +write_silver(records, batch_id, ingestion_ts, bronze_refs) SilverWriteResult | None + +write_gold(records, silver_refs) None + +... : validation and lock checks + } + + class BatchMemoryManager { + -_memory_monitor: MemoryMonitorPort | None + -_memory_config: MemoryConfig | None + -_initial_batch_size: int + +enabled: bool + +batch_size_reductions: int + +check_pressure(current_size, interval, fetched) int + +maybe_recover(current_size) int + } + + class BatchMetricsRecorder { + -_metrics: MetricsPort | None + -_pipeline_label: str + -_run_type_label: str + +track_batch_size(stage, size) None + +track_processed_records(stage, count) None + +track_error(stage, error_type) None + +track_quarantined_records(error_type, count) None + } + + class BatchTracingManager { + -_tracer: TracingPort + -_context: PipelineContext + +TRACER_NAME: str + +start_execution_span() Span | None + +start_batch_span(batch_id, count, start) Span | None + +start_layer_span(name, batch_id, count) Span | None + +end_span(span, error) None + } + } + + namespace Execution_Managers { + class CheckpointManager { + -_checkpoint: CheckpointPort + -_logger: LoggerPort + -_pipeline_name: str + -_run_id: RunID + -_resume: bool + +load_checkpoint() dict | None + +save_checkpoint(offset) None + +delete_checkpoint() None + } + + class LockManager { + -_lock: LockPort + -_run_id: RunID + -_config: LockConfig + -_shutdown_signal: ShutdownSignal + -_heartbeat: HeartbeatTask | None + -_fencing_token: FencingToken | None + +acquire(timeout) FencingToken + +release() None + +validate() bool + } + } + + namespace Support_Services { + class PreflightService { + +execute(config, runtime, services, context, observer) PreflightReport + } + + class PostrunService { + +execute(config, runtime, context, executor, metadata, observer) PostrunResult + } + + class QuarantineManager { + -_quarantine: QuarantinePort + +quarantine_record(raw, error_type, batch_id, msg, ts) None + } + + class ShutdownSignal { + +is_requested: bool + +reason: ShutdownReason | None + +request(reason) None + +reset() None + } + + class HeartbeatTask { + Background async task + +start() None + +stop() None + } + + class ErrorClassifier { + +classify(error) ErrorCategory + } } PipelineRunner *-- BatchExecutor diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/08-application-services.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/08-application-services.mmd index 369bc41806..8b6db276cc 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/08-application-services.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/08-application-services.mmd @@ -16,168 +16,136 @@ %% @uniform-stats simple width=344 height=72 max_desc_lines=2 classDiagram direction TB - class DataQualityService { - -_dq_monitor: DQMonitorPort | None - -_config: DQConfig - -_logger: LoggerPort - -_metrics: MetricsPort | None - -_pipeline_name: str - -_entity_type: str - +evaluate(context, executor) DQResult - - - - - - - - - } - - class DQReportService { - +generate_reports(context) DQReportResult - - } - - class MedallionLifecycleService { - <> - +storage: StoragePort - +logger: LoggerPort - +prepare_for_run(config, runtime) PrepareResult - +finalize_run(config, runtime) VacuumResult - +clear() None - +vacuum() None - +archive() None - - - - - - - - } - - class VacuumService { - <> - +storage: StoragePort - +logger: LoggerPort - +vacuum_table(table_name) None - +vacuum_all() None - - - } - - class HealthService { - +check_provider(provider, factory) HealthResult - +check_all(factory) HealthCheckSummary - } - - class ConfigService { - +list_pipelines() list - +get_pipeline(name) PipelineConfig - } - - class ExportService { - +export(table_name, format, options) ExportResult - - } - - class CheckpointService { - +list_checkpoints() list - +delete_checkpoint(key) None - } - - class MetricsService { - +start_server() None - +stop_server() None - } - - class ShutdownService { - +shutdown(reason, grace_period) None - - } - - class QuarantineService { - +inspect(pipeline, limit) list - +get_stats(pipeline) dict - +replay(pipeline) int - +purge(pipeline) int - - - - } - - class BronzeCleanupService { - +cleanup(config, dry_run) BronzeCleanupResult - - } - - class LockService { - +get_lock_info(key) dict | None - - } - - class PipelineRunnerService { - +run_pipeline(config, runtime) None - - } - - class BronzeDQAnalyzer { - +analyze(records) DQMetrics - +check_completeness() float - +check_format() float - - - - - } - - class SilverDQAnalyzer { - +analyze(delta_table) DQMetrics - +check_nullability() float - +check_schema() float - - - - - } - - class GoldDQAnalyzer { - +analyze(delta_table) DQMetrics - +check_pk_uniqueness() float - +validate_schema() float - - - - - } - - class PipelineObserver { - -_pipeline_name: str - -_run_id: RunID - -_run_type: RunType - -_metrics: MetricsPort - -_logger: LoggerPort - -_tracer: TracingPort | None - -_start_time: float - -_root_span: Span | None - -_phase: LifecyclePhase | None - +__enter__() Self - +__exit__(...) None - +emit_event(event) None - +on_preflight() None - +on_execution() None - +on_postrun() None - } - - class LifecyclePhase { - <> - STARTUP - PREFLIGHT - LIFECYCLE_CLEAR - EXECUTION - POSTRUN - CLEANUP + namespace Core_Application { + class DataQualityService { + -_dq_monitor: DQMonitorPort | None + -_config: DQConfig + -_logger: LoggerPort + -_metrics: MetricsPort | None + -_pipeline_name: str + -_entity_type: str + +evaluate(context, executor) DQResult + } + + class DQReportService { + +generate_reports(context) DQReportResult + } + + class MedallionLifecycleService { + <> + +storage: StoragePort + +logger: LoggerPort + +prepare_for_run(config, runtime) PrepareResult + +finalize_run(config, runtime) VacuumResult + +clear() None + +vacuum() None + +archive() None + } + + class VacuumService { + <> + +storage: StoragePort + +logger: LoggerPort + +vacuum_table(table_name) None + +vacuum_all() None + } + + class PipelineObserver { + -_pipeline_name: str + -_run_id: RunID + -_run_type: RunType + -_metrics: MetricsPort + -_logger: LoggerPort + -_tracer: TracingPort | None + -_start_time: float + -_root_span: Span | None + -_phase: LifecyclePhase | None + +__enter__() Self + +__exit__(...) None + +emit_event(event) None + +on_preflight() None + +on_execution() None + +on_postrun() None + } + + class LifecyclePhase { + <> + STARTUP + PREFLIGHT + LIFECYCLE_CLEAR + EXECUTION + POSTRUN + CLEANUP + } + } + + namespace Operational_Services { + class HealthService { + +check_provider(provider, factory) HealthResult + +check_all(factory) HealthCheckSummary + } + + class ConfigService { + +list_pipelines() list + +get_pipeline(name) PipelineConfig + } + + class ExportService { + +export(table_name, format, options) ExportResult + } + + class CheckpointService { + +list_checkpoints() list + +delete_checkpoint(key) None + } + + class MetricsService { + +start_server() None + +stop_server() None + } + + class ShutdownService { + +shutdown(reason, grace_period) None + } + + class QuarantineService { + +inspect(pipeline, limit) list + +get_stats(pipeline) dict + +replay(pipeline) int + +purge(pipeline) int + } + + class BronzeCleanupService { + +cleanup(config, dry_run) BronzeCleanupResult + } + + class LockService { + +get_lock_info(key) dict | None + } + + class PipelineRunnerService { + +run_pipeline(config, runtime) None + } + } + + namespace DQ_Analyzers { + class BronzeDQAnalyzer { + +analyze(records) DQMetrics + +check_completeness() float + +check_format() float + } + + class SilverDQAnalyzer { + +analyze(delta_table) DQMetrics + +check_nullability() float + +check_schema() float + } + + class GoldDQAnalyzer { + +analyze(delta_table) DQMetrics + +check_pk_uniqueness() float + +validate_schema() float + } } PipelineObserver --> LifecyclePhase diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/09-transformers.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/09-transformers.mmd index 9323f765b9..14d0d3d3c0 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/09-transformers.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/09-transformers.mmd @@ -15,115 +15,123 @@ %% @uniform-stats intermediate width=280 height=112 max_desc_lines=4 %% @uniform-stats concrete width=376 height=72 max_desc_lines=2 classDiagram - direction TB - class BaseTransformer { - <> - +provider: str - +entity_type: str - #_tracer: TracingPort - #_metrics: MetricsPort - #_silver_filters: SilverFilterConfig | None - #_gold_filters: GoldFilterConfig | None - #_identity: IdentityService - #_pii_hasher: PiiHasherPort - #_data_normalizer: DataNormalizationPort - #_contract_policy: PipelineContractPolicy - +GOLD_EXCLUDE_FIELDS: frozenset~str~ - +transform(ctx, record, idx) SilverRecord | None - #_transform_impl(ctx, record, idx)* SilverRecord | None - +should_write_silver(ctx, record) bool - +should_write_gold(ctx, record) bool - +transform_for_gold(ctx, silver_record) dict - +compute_content_hash(data, exclude_none) ContentHash - +compute_entity_id(source_id, record) EntityID - +entity_to_silver_record(entity) dict - +hash_pii_value(value) str - +hash_pii_list(values) list~str~ - +validate_value_object(vo_class, value)$ str | None - } + direction LR + namespace Base_Layer { + class BaseTransformer { + <> + +provider: str + +entity_type: str + #_tracer: TracingPort + #_metrics: MetricsPort + #_silver_filters: SilverFilterConfig | None + #_gold_filters: GoldFilterConfig | None + #_identity: IdentityService + #_pii_hasher: PiiHasherPort + #_data_normalizer: DataNormalizationPort + #_contract_policy: PipelineContractPolicy + +GOLD_EXCLUDE_FIELDS: frozenset~str~ + +transform(ctx, record, idx) SilverRecord | None + #_transform_impl(ctx, record, idx)* SilverRecord | None + +should_write_silver(ctx, record) bool + +should_write_gold(ctx, record) bool + +transform_for_gold(ctx, silver_record) dict + +compute_content_hash(data, exclude_none) ContentHash + +compute_entity_id(source_id, record) EntityID + +entity_to_silver_record(entity) dict + +hash_pii_value(value) str + +hash_pii_list(values) list~str~ + +validate_value_object(vo_class, value)$ str | None + } - class BaseChemblTransformer { - <> - +entity_class: type - +primary_id_field: str - #_extract_business_data(record)* dict - } + class BaseChemblTransformer { + <> + +entity_class: type + +primary_id_field: str + #_extract_business_data(record)* dict + } - class ActivityTransformer { - provider = "chembl" - entity_type = "activity" - } - class AssayTransformer { - provider = "chembl" - entity_type = "assay" - } - class MoleculeTransformer { - provider = "chembl" - entity_type = "molecule" - } - class TargetTransformer { - provider = "chembl" - entity_type = "target" - } - class TargetComponentTransformer { - provider = "chembl" - entity_type = "target_component" - } - class PublicationTransformer { - provider = "chembl" - entity_type = "publication" - } - class TissueTransformer { - provider = "chembl" - entity_type = "tissue" - } - class CellLineTransformer { - provider = "chembl" - entity_type = "cell_line" - } - class ProteinClassTransformer { - provider = "chembl" - entity_type = "protein_class" - } - class CompoundRecordTransformer { - provider = "chembl" - entity_type = "compound_record" + class BasePublicationTransformer { + <> + #_extract_fields(record)* dict + #_build_entity(fields)* PublicationBase + } } - class BasePublicationTransformer { - <> - #_extract_fields(record)* dict - #_build_entity(fields)* PublicationBase - - } - class PubMedPublicationTransformer { - provider = "pubmed" - entity_type = "publication" - } - class CrossRefPublicationTransformer { - provider = "crossref" - entity_type = "publication" - } - class OpenAlexPublicationTransformer { - provider = "openalex" - entity_type = "publication" - } - class SemanticScholarPublicationTransformer { - provider = "semanticscholar" - entity_type = "publication" + namespace ChEMBL_Transformers { + class ActivityTransformer { + provider = "chembl" + entity_type = "activity" + } + class AssayTransformer { + provider = "chembl" + entity_type = "assay" + } + class MoleculeTransformer { + provider = "chembl" + entity_type = "molecule" + } + class TargetTransformer { + provider = "chembl" + entity_type = "target" + } + class TargetComponentTransformer { + provider = "chembl" + entity_type = "target_component" + } + class PublicationTransformer { + provider = "chembl" + entity_type = "publication" + } + class TissueTransformer { + provider = "chembl" + entity_type = "tissue" + } + class CellLineTransformer { + provider = "chembl" + entity_type = "cell_line" + } + class ProteinClassTransformer { + provider = "chembl" + entity_type = "protein_class" + } + class CompoundRecordTransformer { + provider = "chembl" + entity_type = "compound_record" + } } - class UniProtProteinTransformer { - provider = "uniprot" - entity_type = "protein" + namespace Publication_Enrichers { + class PubMedPublicationTransformer { + provider = "pubmed" + entity_type = "publication" + } + class CrossRefPublicationTransformer { + provider = "crossref" + entity_type = "publication" + } + class OpenAlexPublicationTransformer { + provider = "openalex" + entity_type = "publication" + } + class SemanticScholarPublicationTransformer { + provider = "semanticscholar" + entity_type = "publication" + } } - class IDMappingTransformer { - provider = "uniprot" - entity_type = "idmapping" - } - class PubChemCompoundTransformer { - provider = "pubchem" - entity_type = "compound" + + namespace Other_Providers { + class UniProtProteinTransformer { + provider = "uniprot" + entity_type = "protein" + } + class IDMappingTransformer { + provider = "uniprot" + entity_type = "idmapping" + } + class PubChemCompoundTransformer { + provider = "pubchem" + entity_type = "compound" + } } BaseTransformer <|-- BaseChemblTransformer diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/10-adapters.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/10-adapters.mmd index 39903aac54..36a7d9bc5f 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/10-adapters.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/10-adapters.mmd @@ -19,7 +19,7 @@ %% @uniform-stats util width=232 height=200 max_desc_lines=9 %% @uniform-stats decorator width=336 height=72 max_desc_lines=2 classDiagram - direction TB + direction LR class HealthCheckMixin { <> #_start_health_check(provider, endpoint) HealthCheckContext @@ -34,8 +34,7 @@ classDiagram +health_check() HealthCheckResult +check_health() HealthCheckResult #_probe_health()* HealthCheckResult - #_fallback_health_status() HealthCheckResult - #_circuit_breaker: CircuitBreakerPort* + +... : fallback policy } class BaseHttpAdapter { @@ -43,16 +42,10 @@ classDiagram +logger: LoggerPort +metrics: MetricsPort | None +provider_name: str - #_error_handler: ErrorService +__aenter__() Self +__aexit__(...) None +aclose() None - - - - - - + } class BaseSyncAdapter { @@ -61,15 +54,7 @@ classDiagram +rate_limiter: TokenBucket +circuit_breaker: CircuitBreaker +thread_pool: ThreadPoolExecutor - - - - - - - - - + } class UnifiedHTTPClient { @@ -78,23 +63,17 @@ classDiagram +circuit_breaker: CircuitBreakerPort +retry_config: RetryConfig +timeout: float - +run_id: RunID | None +user_agent: str +provider: str - +tracer: TracingPort | None - +metrics: MetricsPort | None +get(url, params, headers) Response +post(url, data, headers) Response - +head(url) Response - +get_once(url) Response + +... : request helpers } class ChemblAdapter { +fetch() AsyncIterator~dict~ +fetch_filtered(filter_ids) AsyncIterator~dict~ - +fetch_multi_filtered(filters) AsyncIterator~dict~ - +fetch_filtered_with_fallback() AsyncIterator~dict~ - +fetch_as_models() AsyncIterator~Model~ + +... : extra filter variants } class PubMedAdapter { @@ -153,8 +132,7 @@ classDiagram +metrics: MetricsPort | None +call(fn) T +get_state() CircuitBreakerState - +get_failure_count() int - +get_trips_total() int + +... : counters } class TokenBucket { diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/11-storage.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/11-storage.mmd index 7acb40cef9..7ac0c53232 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/11-storage.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/11-storage.mmd @@ -8,7 +8,7 @@ %% @uniform class width=216 height=216 max_title_len=22 max_desc_lines=10 classDiagram - direction TB + direction LR class BaseDeltaWriter { +base_path: Path +logger: LoggerPort diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/12-composite-pipeline.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/12-composite-pipeline.mmd index ae860effbf..9fa993ea61 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/12-composite-pipeline.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/12-composite-pipeline.mmd @@ -8,7 +8,7 @@ %% @uniform class width=256 height=198 max_title_len=27 max_desc_lines=9 classDiagram - direction TB + direction LR class CompositePipelineRunner { -_config: CompositeConfig -_runtime: CompositeRuntimeConfig diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/13-domain-services.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/13-domain-services.mmd index e02175aa67..decbaebaed 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/13-domain-services.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/13-domain-services.mmd @@ -8,7 +8,7 @@ %% @uniform class width=248 height=72 max_title_len=26 max_desc_lines=2 classDiagram - direction TB + direction LR class IdentityService { +compute_entity_id(provider, entity_type, source_id, record) EntityID +compute_content_hash(provider, record) ContentHash diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/14-observability.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/14-observability.mmd index 71cd4fb8c7..fec8e7e935 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/14-observability.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/14-observability.mmd @@ -8,7 +8,7 @@ %% @uniform class width=200 height=198 max_title_len=20 max_desc_lines=9 classDiagram - direction TB + direction LR class LoggerPort { <> +bind(**kwargs) LoggerPort diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/15-extractors.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/15-extractors.mmd index 5e2570152c..be22ec7ece 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/15-extractors.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/15-extractors.mmd @@ -8,7 +8,7 @@ %% @uniform class width=224 height=72 max_title_len=23 max_desc_lines=2 classDiagram - direction TB + direction LR class BaseFieldExtractor { <> +extract(record: dict) dict* diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/16-factories-bootstrap.mmd b/docs/02-architecture/mmd-diagrams/class-diagrams/16-factories-bootstrap.mmd index 8f93ca04ec..afff1e43eb 100644 --- a/docs/02-architecture/mmd-diagrams/class-diagrams/16-factories-bootstrap.mmd +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/16-factories-bootstrap.mmd @@ -8,7 +8,7 @@ %% @uniform class width=192 height=126 max_title_len=19 max_desc_lines=5 classDiagram - direction TB + direction LR class DataSourceRegistry { -_registry: dict~str, Callable~ +register(provider, entity_type, factory) None diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/png/INDEX.md b/docs/02-architecture/mmd-diagrams/class-diagrams/png/INDEX.md new file mode 100644 index 0000000000..774a053903 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/png/INDEX.md @@ -0,0 +1,100 @@ +# BioETL Diagrams — PNG Index + +_Generated: 2026-03-01T18:13:55+03:00_ + +## Domain Ports + +![01-domain-ports](./01-domain-ports.png) + +--- + +## Entities Aggregates + +![02-entities-aggregates](./02-entities-aggregates.png) + +--- + +## Value Objects + +![03-value-objects](./03-value-objects.png) + +--- + +## Types Enums + +![04-types-enums](./04-types-enums.png) + +--- + +## Exceptions + +![05-exceptions](./05-exceptions.png) + +--- + +## Config Classes + +![06-config-classes](./06-config-classes.png) + +--- + +## Application Core Services + +![07-application-core-services](./07-application-core-services.png) + +--- + +## Application Services + +![08-application-services](./08-application-services.png) + +--- + +## Transformers + +![09-transformers](./09-transformers.png) + +--- + +## Adapters + +![10-adapters](./10-adapters.png) + +--- + +## Storage + +![11-storage](./11-storage.png) + +--- + +## Composite Pipeline + +![12-composite-pipeline](./12-composite-pipeline.png) + +--- + +## Domain Services + +![13-domain-services](./13-domain-services.png) + +--- + +## Observability + +![14-observability](./14-observability.png) + +--- + +## Extractors + +![15-extractors](./15-extractors.png) + +--- + +## Factories Bootstrap + +![16-factories-bootstrap](./16-factories-bootstrap.png) + +--- + diff --git a/docs/02-architecture/mmd-diagrams/class-diagrams/svg/INDEX.md b/docs/02-architecture/mmd-diagrams/class-diagrams/svg/INDEX.md new file mode 100644 index 0000000000..361d44b07e --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/class-diagrams/svg/INDEX.md @@ -0,0 +1,100 @@ +# BioETL Diagrams — SVG Index + +_Generated: 2026-03-01T18:13:55+03:00_ + +## Domain Ports + +![01-domain-ports](./01-domain-ports.svg) + +--- + +## Entities Aggregates + +![02-entities-aggregates](./02-entities-aggregates.svg) + +--- + +## Value Objects + +![03-value-objects](./03-value-objects.svg) + +--- + +## Types Enums + +![04-types-enums](./04-types-enums.svg) + +--- + +## Exceptions + +![05-exceptions](./05-exceptions.svg) + +--- + +## Config Classes + +![06-config-classes](./06-config-classes.svg) + +--- + +## Application Core Services + +![07-application-core-services](./07-application-core-services.svg) + +--- + +## Application Services + +![08-application-services](./08-application-services.svg) + +--- + +## Transformers + +![09-transformers](./09-transformers.svg) + +--- + +## Adapters + +![10-adapters](./10-adapters.svg) + +--- + +## Storage + +![11-storage](./11-storage.svg) + +--- + +## Composite Pipeline + +![12-composite-pipeline](./12-composite-pipeline.svg) + +--- + +## Domain Services + +![13-domain-services](./13-domain-services.svg) + +--- + +## Observability + +![14-observability](./14-observability.svg) + +--- + +## Extractors + +![15-extractors](./15-extractors.svg) + +--- + +## Factories Bootstrap + +![16-factories-bootstrap](./16-factories-bootstrap.svg) + +--- + diff --git a/docs/02-architecture/mmd-diagrams/docs/DIAGRAM-WORKFLOW-GUIDE.md b/docs/02-architecture/mmd-diagrams/docs/DIAGRAM-WORKFLOW-GUIDE.md index 110c7b9f6f..e51b689000 100644 --- a/docs/02-architecture/mmd-diagrams/docs/DIAGRAM-WORKFLOW-GUIDE.md +++ b/docs/02-architecture/mmd-diagrams/docs/DIAGRAM-WORKFLOW-GUIDE.md @@ -245,20 +245,20 @@ python src/tools/differentiate_linkstyle.py # Применить Исключения: `-full.mermaid` reference views и `00-legend*` освобождены от SIZE-001/SIZE-002. ```bash -python scripts/lint_diagrams.py # Проверить всё -python scripts/lint_diagrams.py --json # JSON-вывод для CI -python scripts/lint_diagrams.py --stale-days 120 # Свой порог +python scripts/diagrams/lint_diagrams.py # Проверить всё +python scripts/diagrams/lint_diagrams.py --json # JSON-вывод для CI +python scripts/diagrams/lint_diagrams.py --stale-days 120 # Свой порог ``` ### 6.2. Управление orphan-нодами -Скрипт `scripts/prune_orphan_nodes.py` находит ноды, определённые в диаграмме, но не участвующие ни в одном ребре. +Скрипт `scripts/diagrams/prune_orphan_nodes.py` находит ноды, определённые в диаграмме, но не участвующие ни в одном ребре. ```bash -python scripts/prune_orphan_nodes.py --check # Отчёт (exit 1 при нахождении) -python scripts/prune_orphan_nodes.py --check --json # JSON для CI -python scripts/prune_orphan_nodes.py --fix # Удалить orphan-ноды -python scripts/prune_orphan_nodes.py --grandfather # Пометить все текущие как допустимые +python scripts/diagrams/prune_orphan_nodes.py --check # Отчёт (exit 1 при нахождении) +python scripts/diagrams/prune_orphan_nodes.py --check --json # JSON для CI +python scripts/diagrams/prune_orphan_nodes.py --fix # Удалить orphan-ноды +python scripts/diagrams/prune_orphan_nodes.py --grandfather # Пометить все текущие как допустимые ``` Нода **не считается orphan**, если: @@ -272,12 +272,12 @@ python scripts/prune_orphan_nodes.py --grandfather # Пометить все | Хук | Скрипт | Назначение | |-----|--------|------------| -| `lint-diagrams` | `scripts/lint_diagrams.py` | Валидация всех правил | -| `prune-orphan-diagram-nodes` | `scripts/prune_orphan_nodes.py --check` | Детекция orphan-нод | +| `lint-diagrams` | `scripts/diagrams/lint_diagrams.py` | Валидация всех правил | +| `prune-orphan-diagram-nodes` | `scripts/diagrams/prune_orphan_nodes.py --check` | Детекция orphan-нод | ### 6.4. Проверка видимости текста в SVG -Скрипт `scripts/check_svg_text_visibility.py` валидирует smoke-набор SVG на предмет +Скрипт `scripts/diagrams/check_svg_text_visibility.py` валидирует smoke-набор SVG на предмет типичного регресса: edge-label отображается как белый прямоугольник без видимого текста. Проверки скрипта: @@ -287,8 +287,8 @@ python scripts/prune_orphan_nodes.py --grandfather # Пометить все - наличие инжектированных CSS-правил для `.edgeLabel span` и `text.fo-fallback`. ```bash -python scripts/check_svg_text_visibility.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt -python scripts/check_svg_text_visibility.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt --json +python scripts/diagrams/check_svg_text_visibility.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt +python scripts/diagrams/check_svg_text_visibility.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt --json ``` --- @@ -323,11 +323,8 @@ python scripts/check_svg_text_visibility.py --manifest docs/02-architecture/mmd- ### 8.1. Конвейер рендеринга ```bash -# Linux/WSL +# Linux/WSL/Windows (Git Bash, WSL, CI) bash docs/02-architecture/mmd-diagrams/render.sh - -# Windows (PowerShell) -pwsh docs/02-architecture/mmd-diagrams/render-windows.ps1 ``` Формат вывода: SVG + PNG (base 300 DPI). Применяется тема из `theme/mermaid-config.json` и `theme/custom.css`. SVG-файлы дополнительно оптимизируются через SVGO (`svgo.config.js`). @@ -348,15 +345,15 @@ pwsh docs/02-architecture/mmd-diagrams/render-windows.ps1 1. **Скопировать шаблон:** `cp _template.mmd architecture/NN-topic.mmd` 2. **Заполнить метаданные:** `@version`, `@date`, `@type`, `@level`, `@nodes` 3. **Нарисовать диаграмму:** использовать каноническую палитру цветов -4. **Проверить lint:** `python scripts/lint_diagrams.py` +4. **Проверить lint:** `python scripts/diagrams/lint_diagrams.py` 5. **Применить ELK** (если @nodes > 20): `python src/tools/apply_elk_layout.py` 6. **Применить linkStyle** (если flowchart с 5+ связями): `python src/tools/differentiate_linkstyle.py` -7. **Проверить orphan-ноды:** `python scripts/prune_orphan_nodes.py --check` -8. **Отрендерить:** `render.sh` или `render-windows.ps1` +7. **Проверить orphan-ноды:** `python scripts/diagrams/prune_orphan_nodes.py --check` +8. **Отрендерить:** `bash docs/02-architecture/mmd-diagrams/render.sh` Для усиленного рендера больших схем можно задать: `--large-threshold`, `--large-scale`, `--large-png-dpi`. -9. **Проверить артефакты SVG/PNG:** `python scripts/check_diagram_artifacts.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt` -10. **Проверить видимость текста в SVG:** `python scripts/check_svg_text_visibility.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt` -11. **Прогнать quality-gates:** `python scripts/check_diagram_quality_gates.py --manifest docs/02-architecture/mmd-diagrams/quality-gate-manifest.txt` +9. **Проверить артефакты SVG/PNG:** `python scripts/diagrams/check_diagram_artifacts.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt` +10. **Проверить видимость текста в SVG:** `python scripts/diagrams/check_svg_text_visibility.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt` +11. **Прогнать quality-gates:** `python scripts/diagrams/check_diagram_quality_gates.py --manifest docs/02-architecture/mmd-diagrams/quality-gate-manifest.txt` 12. **Добавить в индекс:** обновить `README.md` каталога --- @@ -365,17 +362,16 @@ pwsh docs/02-architecture/mmd-diagrams/render-windows.ps1 | Инструмент | Расположение | Назначение | |------------|-------------|------------| -| run_diagram_checks.sh | `scripts/` | Единый запуск профилей проверок (`pr`/`nightly`/`quick`) | +| run_diagram_checks.sh | `scripts/diagrams/` | Единый запуск профилей проверок (`pr`/`nightly`/`quick`) | | apply_elk_layout.py | `src/tools/` | Добавление ELK init к flowchart с >20 нод | | differentiate_linkstyle.py | `src/tools/` | Семантическая стилизация рёбер | -| lint_diagrams.py | `scripts/` | Lint-проверка по 14 правилам | -| prune_orphan_nodes.py | `scripts/` | Детекция и удаление orphan-нод | -| check_diagram_artifacts.py | `scripts/` | DIAG-T010..T012 (наличие/непустота SVG+PNG) | -| check_svg_text_visibility.py | `scripts/` | Smoke-проверка видимости текста в SVG | -| check_diagram_quality_gates.py | `scripts/` | DIAG-T018..T023 (style/classDef/decomposition/legend/labels) | -| run_diagram_nightly_suite.py | `scripts/` | DIAG-T024..T029 nightly heuristics (interactivity/chaos/growth/theme) | +| lint_diagrams.py | `scripts/diagrams/` | Lint-проверка по 14 правилам | +| prune_orphan_nodes.py | `scripts/diagrams/` | Детекция и удаление orphan-нод | +| check_diagram_artifacts.py | `scripts/diagrams/` | DIAG-T010..T012 (наличие/непустота SVG+PNG) | +| check_svg_text_visibility.py | `scripts/diagrams/` | Smoke-проверка видимости текста в SVG | +| check_diagram_quality_gates.py | `scripts/diagrams/` | DIAG-T018..T023 (style/classDef/decomposition/legend/labels) | +| run_diagram_nightly_suite.py | `scripts/diagrams/` | DIAG-T024..T029 nightly heuristics (interactivity/chaos/growth/theme) | | render.sh | `mmd-diagrams/` | Рендеринг SVG + PNG (300 DPI, auto-hires + `@png-scale/@png-dpi`) | -| render-windows.ps1 | `mmd-diagrams/` | Windows-версия рендеринга | --- @@ -384,7 +380,7 @@ pwsh docs/02-architecture/mmd-diagrams/render-windows.ps1 Для локального и CI-совместимого запуска используйте единый раннер: ```bash -scripts/run_diagram_checks.sh --profile pr +scripts/diagrams/run_diagram_checks.sh --profile pr ``` Доступные профили: @@ -403,7 +399,7 @@ scripts/run_diagram_checks.sh --profile pr Пример single-file запуска: ```bash -scripts/run_diagram_checks.sh --profile pr \ +scripts/diagrams/run_diagram_checks.sh --profile pr \ --diagram docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd ``` diff --git a/docs/02-architecture/mmd-diagrams/docs/diagram-modernization-program.md b/docs/02-architecture/mmd-diagrams/docs/diagram-modernization-program.md index 69e8e60717..9c50e38b69 100644 --- a/docs/02-architecture/mmd-diagrams/docs/diagram-modernization-program.md +++ b/docs/02-architecture/mmd-diagrams/docs/diagram-modernization-program.md @@ -107,11 +107,11 @@ _Основание: POL-LLM-DIAGRAMS-001, ADR-040, DIAGRAM-WORKFLOW-GUIDE.md_ ## 8. Реализация в текущем репозитории Используемые инструменты и точки интеграции: -1. `scripts/lint_diagrams.py` -2. `scripts/check_diagram_visual_smoke.py` -3. `scripts/validate_mermaid_syntax.sh` +1. `scripts/diagrams/lint_diagrams.py` +2. `scripts/diagrams/check_diagram_visual_smoke.py` +3. `scripts/diagrams/validate_mermaid_syntax.sh` 4. `docs/02-architecture/mmd-diagrams/render.sh` -5. `scripts/add_svg_text_fallback.py` +5. `scripts/diagrams/add_svg_text_fallback.py` 6. `.github/workflows/docs.yml` 7. `.github/workflows/validate-mermaid.yml` diff --git a/docs/02-architecture/mmd-diagrams/docs/diagram-regression-test-plan.md b/docs/02-architecture/mmd-diagrams/docs/diagram-regression-test-plan.md index 02fd9119a2..b28150b610 100644 --- a/docs/02-architecture/mmd-diagrams/docs/diagram-regression-test-plan.md +++ b/docs/02-architecture/mmd-diagrams/docs/diagram-regression-test-plan.md @@ -29,29 +29,29 @@ _Связанные документы: diagram-modernization-program.md, 06-dia | ID | Название теста | Цель | Инструмент | Тип | Частота | Gate | |---|---|---|---|---|---|---| -| DIAG-T001 | Mermaid syntax valid | Исключить синтаксические ошибки | `scripts/validate_mermaid_syntax.sh` | Auto | PR | Hard | -| DIAG-T002 | Diagram lint no ERROR | Проверка правил policy | `scripts/lint_diagrams.py` | Auto | PR | Hard | +| DIAG-T001 | Mermaid syntax valid | Исключить синтаксические ошибки | `scripts/diagrams/validate_mermaid_syntax.sh` | Auto | PR | Hard | +| DIAG-T002 | Diagram lint no ERROR | Проверка правил policy | `scripts/diagrams/lint_diagrams.py` | Auto | PR | Hard | | DIAG-T003 | Metadata required | Контроль `@version/@date/@type/@level` | `lint_diagrams.py` | Auto | PR | Hard | | DIAG-T004 | Stale metadata check | Выявление устаревших диаграмм | `lint_diagrams.py` | Auto | PR/Nightly | Soft | | DIAG-T005 | No forbidden colors | Контраст и палитра | `lint_diagrams.py` | Auto | PR | Hard | | DIAG-T006 | No emoji labels | Единый стиль | `lint_diagrams.py` | Auto | PR | Hard | | DIAG-T007 | ELK required for large flowcharts | Стабильность layout | `lint_diagrams.py` | Auto | PR | Hard | -| DIAG-T008 | Orphan nodes controlled | Чистота графа | `scripts/prune_orphan_nodes.py --check` | Auto | PR | Soft | +| DIAG-T008 | Orphan nodes controlled | Чистота графа | `scripts/diagrams/prune_orphan_nodes.py --check` | Auto | PR | Soft | | DIAG-T009 | Render completes | Рендер без падений | `render.sh` | Auto | PR | Hard | | DIAG-T010 | SVG artifacts exist | Проверка обязательных артефактов | CI shell check | Auto | PR | Hard | | DIAG-T011 | PNG artifacts exist | Проверка обязательных артефактов | CI shell check | Auto | PR | Hard | | DIAG-T012 | Artifacts non-empty | Отсев пустых файлов | CI shell check | Auto | PR | Hard | | DIAG-T013 | Visual smoke manifest pass | Базовая читаемость эталонного пула | `check_diagram_visual_smoke.py` | Auto | PR | Hard | -| DIAG-T014 | SVG text nodes present | Не потерян текст в SVG | `scripts/check_svg_text_visibility.py` | Auto | PR | Hard | -| DIAG-T015 | Edge labels present | Не потеряны подписи связей | `scripts/check_svg_text_visibility.py` | Auto | PR | Hard | +| DIAG-T014 | SVG text nodes present | Не потерян текст в SVG | `scripts/diagrams/check_svg_text_visibility.py` | Auto | PR | Hard | +| DIAG-T015 | Edge labels present | Не потеряны подписи связей | `scripts/diagrams/check_svg_text_visibility.py` | Auto | PR | Hard | | DIAG-T016 | Fallback text applied | Совместимость просмотрщиков | `add_svg_text_fallback.py` + check | Auto | PR | Hard | | DIAG-T017 | Source-render drift | Source изменен -> рендер обновлен | `docs.yml` drift check | Auto | PR | Hard | -| DIAG-T018 | Link style guide compliance | Семантика линий | `scripts/check_diagram_quality_gates.py` | Auto | PR | Hard | -| DIAG-T019 | classDef coverage | Типизация узлов | `scripts/check_diagram_quality_gates.py` | Auto | PR | Soft | -| DIAG-T020 | Large diagram decomposition | Наличие L1/L2/L3 | `scripts/check_diagram_quality_gates.py` | Auto | PR | Hard | -| DIAG-T021 | Legend present for large | Пояснение семантики | `scripts/check_diagram_quality_gates.py` | Auto | PR | Hard | -| DIAG-T022 | Label length threshold | Читаемость текста | `scripts/check_diagram_quality_gates.py` | Auto | PR | Soft | -| DIAG-T023 | `
` overuse check | Снижение рендер-рисков | `scripts/check_diagram_quality_gates.py` | Auto | PR | Soft | +| DIAG-T018 | Link style guide compliance | Семантика линий | `scripts/diagrams/check_diagram_quality_gates.py` | Auto | PR | Hard | +| DIAG-T019 | classDef coverage | Типизация узлов | `scripts/diagrams/check_diagram_quality_gates.py` | Auto | PR | Soft | +| DIAG-T020 | Large diagram decomposition | Наличие L1/L2/L3 | `scripts/diagrams/check_diagram_quality_gates.py` | Auto | PR | Hard | +| DIAG-T021 | Legend present for large | Пояснение семантики | `scripts/diagrams/check_diagram_quality_gates.py` | Auto | PR | Hard | +| DIAG-T022 | Label length threshold | Читаемость текста | `scripts/diagrams/check_diagram_quality_gates.py` | Auto | PR | Soft | +| DIAG-T023 | `
` overuse check | Снижение рендер-рисков | `scripts/diagrams/check_diagram_quality_gates.py` | Auto | PR | Soft | | DIAG-T024 | Click/tooltip fallback | Навигация и перенос длинных пояснений | render smoke + heuristic (planned) | Auto | PR/Nightly | Soft | | DIAG-T025 | PNG/SVG semantic equivalence | Смысл не теряется между форматами | visual diff + checklist (planned) | Semi-auto | Nightly | Soft | | DIAG-T026 | Reference pool baseline diff | Быстрый регресс-контроль | snapshot diff (planned) | Auto | PR | Hard | @@ -137,7 +137,7 @@ _Связанные документы: diagram-modernization-program.md, 06-dia ## 9. Реализовано в Phase 1 -1. Добавлен `scripts/check_diagram_quality_gates.py` (DIAG-T018..T023). +1. Добавлен `scripts/diagrams/check_diagram_quality_gates.py` (DIAG-T018..T023). 2. Добавлен source-manifest `quality-gate-manifest.txt` для эталонного пула. 3. Расширен `.github/workflows/docs.yml`: - запуск `check_diagram_artifacts.py` (DIAG-T010/T011/T012); @@ -164,32 +164,32 @@ _Связанные документы: diagram-modernization-program.md, 06-dia 1. Полный pre-merge профиль: ```bash -scripts/run_diagram_checks.sh --profile pr +scripts/diagrams/run_diagram_checks.sh --profile pr ``` 2. Nightly-профиль локально (включая DIAG-T024..T029): ```bash -scripts/run_diagram_checks.sh --profile nightly +scripts/diagrams/run_diagram_checks.sh --profile nightly ``` 3. Быстрый локальный цикл: ```bash -scripts/run_diagram_checks.sh --profile quick +scripts/diagrams/run_diagram_checks.sh --profile quick ``` 4. Проверка только одной диаграммы: ```bash -scripts/run_diagram_checks.sh --profile pr \ +scripts/diagrams/run_diagram_checks.sh --profile pr \ --diagram docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd ``` 5. Для single-file быстрой проверки: ```bash -scripts/run_diagram_checks.sh --profile quick \ +scripts/diagrams/run_diagram_checks.sh --profile quick \ --diagram docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd ``` diff --git a/docs/02-architecture/mmd-diagrams/docs/diagrams-index.md b/docs/02-architecture/mmd-diagrams/docs/diagrams-index.md index 0339bdabb0..6fb430d636 100644 --- a/docs/02-architecture/mmd-diagrams/docs/diagrams-index.md +++ b/docs/02-architecture/mmd-diagrams/docs/diagrams-index.md @@ -53,19 +53,19 @@ ## Render And Validation ```bash -scripts/run_diagram_checks.sh --profile pr -scripts/run_diagram_checks.sh --profile pr --diagram docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd +scripts/diagrams/run_diagram_checks.sh --profile pr +scripts/diagrams/run_diagram_checks.sh --profile pr --diagram docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd # Or run checks individually: -python3 scripts/lint_diagrams.py docs -python3 scripts/lint_diagrams.py docs/02-architecture/mmd-diagrams --json > /tmp/diagram-lint.json || true -python3 scripts/summarize_diagram_lint.py /tmp/diagram-lint.json +python3 scripts/diagrams/lint_diagrams.py docs +python3 scripts/diagrams/lint_diagrams.py docs/02-architecture/mmd-diagrams --json > /tmp/diagram-lint.json || true +python3 scripts/diagrams/summarize_diagram_lint.py /tmp/diagram-lint.json python3 scripts/check_doc_links.py --links -bash scripts/validate_mermaid_syntax.sh +bash scripts/diagrams/validate_mermaid_syntax.sh bash docs/02-architecture/mmd-diagrams/render.sh -python3 scripts/check_svg_text_visibility.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt -python3 scripts/check_diagram_visual_smoke.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt -python3 scripts/check_diagram_quality_gates.py --manifest docs/02-architecture/mmd-diagrams/quality-gate-manifest.txt +python3 scripts/diagrams/check_svg_text_visibility.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt +python3 scripts/diagrams/check_diagram_visual_smoke.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt +python3 scripts/diagrams/check_diagram_quality_gates.py --manifest docs/02-architecture/mmd-diagrams/quality-gate-manifest.txt ``` ## Notes diff --git a/docs/02-architecture/mmd-diagrams/foundation-diagrams-catalog.html b/docs/02-architecture/mmd-diagrams/foundation-diagrams-catalog.html new file mode 100644 index 0000000000..584ffa7dc1 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/foundation-diagrams-catalog.html @@ -0,0 +1,69 @@ + +BioETL Diagram Catalog + + +

BioETL foundation Diagrams

Source: docs/02-architecture/mmd-diagrams/foundation/png/*.png

Total images: 54

Generated: 2026-03-01T17:35:12+03:00

+

001. foundation/png/01-full-system-component.png

foundation/png/01-full-system-component.png
+

002. foundation/png/01-high-level.png

foundation/png/01-high-level.png
+

003. foundation/png/02-full-medallion-data-flow.png

foundation/png/02-full-medallion-data-flow.png
+

004. foundation/png/03-pipeline-execution-happy-path.png

foundation/png/03-pipeline-execution-happy-path.png
+

005. foundation/png/04-domain-layer-class-diagram.png

foundation/png/04-domain-layer-class-diagram.png
+

006. foundation/png/04-error-flow.png

foundation/png/04-error-flow.png
+

007. foundation/png/05-layers-interaction.png

foundation/png/05-layers-interaction.png
+

008. foundation/png/05-pipeline-lifecycle-states.png

foundation/png/05-pipeline-lifecycle-states.png
+

009. foundation/png/06-application-layer-class-diagram.png

foundation/png/06-application-layer-class-diagram.png
+

010. foundation/png/06-pipeline-execution.png

foundation/png/06-pipeline-execution.png
+

011. foundation/png/07-circuit-breaker-states.png

foundation/png/07-circuit-breaker-states.png
+

012. foundation/png/07-medallion-flow.png

foundation/png/07-medallion-flow.png
+

013. foundation/png/08-complete-etl-workflow.png

foundation/png/08-complete-etl-workflow.png
+

014. foundation/png/08-domain-ddd.png

foundation/png/08-domain-ddd.png
+

015. foundation/png/09-full-er-diagram.png

foundation/png/09-full-er-diagram.png
+

016. foundation/png/10-infrastructure-layer-class-diagram.png

foundation/png/10-infrastructure-layer-class-diagram.png
+

017. foundation/png/11-lock-acquisition-sequence.png

foundation/png/11-lock-acquisition-sequence.png
+

018. foundation/png/12-local-deployment-architecture.png

foundation/png/12-local-deployment-architecture.png
+

019. foundation/png/13-domain-models-relationship.png

foundation/png/13-domain-models-relationship.png
+

020. foundation/png/14-provider-health-states.png

foundation/png/14-provider-health-states.png
+

021. foundation/png/15-dq-check-workflow.png

foundation/png/15-dq-check-workflow.png
+

022. foundation/png/16-memory-lock-class.png

foundation/png/16-memory-lock-class.png
+

023. foundation/png/17-pipeline-hierarchy.png

foundation/png/17-pipeline-hierarchy.png
+

024. foundation/png/18-bronze-write-sequence.png

foundation/png/18-bronze-write-sequence.png
+

025. foundation/png/19-delta-lake-write-sequence.png

foundation/png/19-delta-lake-write-sequence.png
+

026. foundation/png/20-quarantine-record-states.png

foundation/png/20-quarantine-record-states.png
+

027. foundation/png/21-activity-entity-data-flow.png

foundation/png/21-activity-entity-data-flow.png
+

028. foundation/png/22-client-api-request-sequence.png

foundation/png/22-client-api-request-sequence.png
+

029. foundation/png/23-silver-writer-class.png

foundation/png/23-silver-writer-class.png
+

030. foundation/png/24-hash-service-class.png

foundation/png/24-hash-service-class.png
+

031. foundation/png/25-circuit-breaker-observer-class.png

foundation/png/25-circuit-breaker-observer-class.png
+

032. foundation/png/26-hexagonal-ports-adapters.png

foundation/png/26-hexagonal-ports-adapters.png
+

033. foundation/png/27-import-matrix-enforcement.png

foundation/png/27-import-matrix-enforcement.png
+

034. foundation/png/28-composition-root-di-graph.png

foundation/png/28-composition-root-di-graph.png
+

035. foundation/png/29-composite-pipeline-workflow.png

foundation/png/29-composite-pipeline-workflow.png
+

036. foundation/png/30-port-adapter-mapping.png

foundation/png/30-port-adapter-mapping.png
+

037. foundation/png/31-pipeline-run-lifecycle.png

foundation/png/31-pipeline-run-lifecycle.png
+

038. foundation/png/32-single-record-journey.png

foundation/png/32-single-record-journey.png
+

039. foundation/png/33-cli-run-interaction.png

foundation/png/33-cli-run-interaction.png
+

040. foundation/png/34-batch-processing-flow.png

foundation/png/34-batch-processing-flow.png
+

041. foundation/png/36-architecture-principles-mindmap.png

foundation/png/36-architecture-principles-mindmap.png
+

042. foundation/png/37-cli-entry-full-chain.png

foundation/png/37-cli-entry-full-chain.png
+

043. foundation/png/38-runtime-assembly-sequence.png

foundation/png/38-runtime-assembly-sequence.png
+

044. foundation/png/39-medallion-invariants.png

foundation/png/39-medallion-invariants.png
+

045. foundation/png/40-application-core-collaboration.png

foundation/png/40-application-core-collaboration.png
+

046. foundation/png/41-error-classification-tree.png

foundation/png/41-error-classification-tree.png
+

047. foundation/png/42-pipeline-runner-class.png

foundation/png/42-pipeline-runner-class.png
+

048. foundation/png/43-fan-out-fan-in-pattern.png

foundation/png/43-fan-out-fan-in-pattern.png
+

049. foundation/png/44-cross-provider-enrichment.png

foundation/png/44-cross-provider-enrichment.png
+

050. foundation/png/46-yaml-config-resolution.png

foundation/png/46-yaml-config-resolution.png
+

051. foundation/png/47-publication-merge-sources.png

foundation/png/47-publication-merge-sources.png
+

052. foundation/png/48-composite-phase-lifecycle.png

foundation/png/48-composite-phase-lifecycle.png
+

053. foundation/png/49-composite-runner-class.png

foundation/png/49-composite-runner-class.png
+

054. foundation/png/50-exception-hierarchy.png

foundation/png/50-exception-hierarchy.png
+ diff --git a/docs/02-architecture/mmd-diagrams/foundation-diagrams-catalog.pdf b/docs/02-architecture/mmd-diagrams/foundation-diagrams-catalog.pdf new file mode 100644 index 0000000000..5430a45bc0 Binary files /dev/null and b/docs/02-architecture/mmd-diagrams/foundation-diagrams-catalog.pdf differ diff --git a/docs/02-architecture/mmd-diagrams/foundation/01-full-system-component.mmd b/docs/02-architecture/mmd-diagrams/foundation/01-full-system-component.mmd index 42e1aa5b8c..d8828c9cca 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/01-full-system-component.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/01-full-system-component.mmd @@ -20,25 +20,16 @@ %% @uniform width=272 groups=6 width_strategy=group %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'flowchart': { -%% 'nodeSpacing': 64, -%% 'rankSpacing': 72, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'DOWN', -%% 'spacing.nodeNode': 48, -%% 'spacing.edgeNode': 36, -%% 'spacing.edgeEdge': 24, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB %% keep-orphan: DQConfig, PipelineConfig, Publication, RuntimeConfig diff --git a/docs/02-architecture/mmd-diagrams/foundation/01-high-level.mmd b/docs/02-architecture/mmd-diagrams/foundation/01-high-level.mmd index d6ab04c9c5..643641dcc6 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/01-high-level.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/01-high-level.mmd @@ -8,10 +8,27 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=120 height=72 max_title_len=12 max_desc_lines=2 flowchart TD subgraph Sources["External Data Sources"] + A1["ChEMBL API"] + A2["PubChem API"] + A3["UniProt API"] + A4["PubMed API"] + A5["CrossRef API"] + A6["OpenAlex API"] + A7["Semantic Scholar API"] end subgraph Interfaces["Interfaces Layer"] @@ -38,6 +55,7 @@ flowchart TD Bronze["Bronze Layer
(JSONL + zstd)"] Silver["Silver Layer
(Delta Lake)"] Gold["Gold Layer
(Delta Lake)"] + Quarantine["Quarantine
(Failed records)"] end Sources --> Adapters diff --git a/docs/02-architecture/mmd-diagrams/foundation/02-full-medallion-data-flow.mmd b/docs/02-architecture/mmd-diagrams/foundation/02-full-medallion-data-flow.mmd index 7e2e8e1771..6a0d17ae28 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/02-full-medallion-data-flow.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/02-full-medallion-data-flow.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=336 height=168 max_title_len=20 max_desc_lines=7 flowchart LR subgraph Sources["External Sources"] diff --git a/docs/02-architecture/mmd-diagrams/foundation/04-error-flow.mmd b/docs/02-architecture/mmd-diagrams/foundation/04-error-flow.mmd index 4bd087065f..5b18391af0 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/04-error-flow.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/04-error-flow.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TD subgraph Pipeline["Pipeline Execution"] B -->|Pass| C[BatchTransformer
normalize & enrich] diff --git a/docs/02-architecture/mmd-diagrams/foundation/05-layers-interaction.mmd b/docs/02-architecture/mmd-diagrams/foundation/05-layers-interaction.mmd index 9b6ea0ddfa..22b5044d89 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/05-layers-interaction.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/05-layers-interaction.mmd @@ -8,6 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) %% @uniform width=224 height=56 max_title_len=23 max_desc_lines=0 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB %% keep-orphan: Entities, Exceptions, Locking, Types diff --git a/docs/02-architecture/mmd-diagrams/foundation/07-medallion-flow.mmd b/docs/02-architecture/mmd-diagrams/foundation/07-medallion-flow.mmd index 0d45406590..93d45e7970 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/07-medallion-flow.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/07-medallion-flow.mmd @@ -8,6 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) %% @uniform width=320 height=96 max_title_len=32 max_desc_lines=3 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart LR %% keep-orphan: B, G, S diff --git a/docs/02-architecture/mmd-diagrams/foundation/08-complete-etl-workflow.mmd b/docs/02-architecture/mmd-diagrams/foundation/08-complete-etl-workflow.mmd index c710f27cf2..8cbc1fd481 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/08-complete-etl-workflow.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/08-complete-etl-workflow.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'},'layout':'elk','flowchart':{'curve':'linear'},'elk':{'nodePlacementStrategy':'BRANDES_KOEPF','mergeEdges':true,'edgeRouting':'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=392 height=72 max_title_len=39 max_desc_lines=2 flowchart TD %% keep-orphan: M1, M2, M3, M4, N1, N2, N3, N4, P1, P2 diff --git a/docs/02-architecture/mmd-diagrams/foundation/08-domain-ddd.mmd b/docs/02-architecture/mmd-diagrams/foundation/08-domain-ddd.mmd index d2871ac387..0d6c0244ae 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/08-domain-ddd.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/08-domain-ddd.mmd @@ -8,6 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) %% @uniform width=256 height=144 max_title_len=25 max_desc_lines=6 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB %% keep-orphan: CheckpointPort, CriticalError, DataQualityError, DataSourcePort, HealthStatus, InvalidStateError, LockPort, Measurement, MetricsPort, QuarantinePort, RecoverableError, RunType, StoragePort, TracingPort diff --git a/docs/02-architecture/mmd-diagrams/foundation/12-local-deployment-architecture.mmd b/docs/02-architecture/mmd-diagrams/foundation/12-local-deployment-architecture.mmd index 9fba807e4d..59b0574e1b 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/12-local-deployment-architecture.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/12-local-deployment-architecture.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=200 height=72 max_title_len=20 max_desc_lines=2 flowchart TB subgraph External["External APIs"] diff --git a/docs/02-architecture/mmd-diagrams/foundation/15-dq-check-workflow.mmd b/docs/02-architecture/mmd-diagrams/foundation/15-dq-check-workflow.mmd index 54b8a04be7..b4b6ab6d1c 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/15-dq-check-workflow.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/15-dq-check-workflow.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'},'layout':'elk','flowchart':{'curve':'linear'},'elk':{'nodePlacementStrategy':'BRANDES_KOEPF','mergeEdges':true,'edgeRouting':'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=312 height=72 max_title_len=31 max_desc_lines=2 flowchart TD %% keep-orphan: CFG1, CFG2, CFG3 diff --git a/docs/02-architecture/mmd-diagrams/foundation/21-activity-entity-data-flow.mmd b/docs/02-architecture/mmd-diagrams/foundation/21-activity-entity-data-flow.mmd index 0025c7aaa4..f0b5d8d731 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/21-activity-entity-data-flow.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/21-activity-entity-data-flow.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=280 height=96 max_title_len=28 max_desc_lines=3 flowchart LR %% keep-orphan: LocalFS, S1, S10, S11, S12, S2, S4, S5, S6, S7, S8, S9 diff --git a/docs/02-architecture/mmd-diagrams/foundation/26-hexagonal-ports-adapters.mmd b/docs/02-architecture/mmd-diagrams/foundation/26-hexagonal-ports-adapters.mmd index 10436fba09..675ea14946 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/26-hexagonal-ports-adapters.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/26-hexagonal-ports-adapters.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=240 height=112 max_title_len=24 max_desc_lines=4 flowchart TB %% keep-orphan: CBP, FDSP, HCP, INP, MCP2, RLMP, SHP, SRLP diff --git a/docs/02-architecture/mmd-diagrams/foundation/27-import-matrix-enforcement.mmd b/docs/02-architecture/mmd-diagrams/foundation/27-import-matrix-enforcement.mmd index 6e7f0cc571..8d7c45db17 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/27-import-matrix-enforcement.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/27-import-matrix-enforcement.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=272 height=128 max_title_len=27 max_desc_lines=5 flowchart TB %% keep-orphan: BLOCK, OK, SR diff --git a/docs/02-architecture/mmd-diagrams/foundation/28-composition-root-di-graph.mmd b/docs/02-architecture/mmd-diagrams/foundation/28-composition-root-di-graph.mmd index 7a1b69ba75..fb496bc265 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/28-composition-root-di-graph.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/28-composition-root-di-graph.mmd @@ -19,26 +19,16 @@ %% @uniform-stats registry width=200 height=144 max_desc_lines=6 %% @uniform-stats created width=176 height=144 max_desc_lines=6 %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'themeVariables': {'lineWidth': '2'}, -%% 'flowchart': { -%% 'nodeSpacing': 64, -%% 'rankSpacing': 80, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'DOWN', -%% 'spacing.nodeNode': 52, -%% 'spacing.edgeNode': 36, -%% 'spacing.edgeEdge': 24, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB %% keep-orphan: OB subgraph Entry["Entry Point"] diff --git a/docs/02-architecture/mmd-diagrams/foundation/29-composite-pipeline-workflow.mmd b/docs/02-architecture/mmd-diagrams/foundation/29-composite-pipeline-workflow.mmd index f7867adb4f..efb715113a 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/29-composite-pipeline-workflow.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/29-composite-pipeline-workflow.mmd @@ -27,26 +27,16 @@ %% @uniform-stats gold width=240 height=112 max_desc_lines=4 %% @uniform-stats ckp width=264 height=112 max_desc_lines=4 %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'themeVariables': {'lineWidth': '2'}, -%% 'flowchart': { -%% 'nodeSpacing': 64, -%% 'rankSpacing': 80, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'DOWN', -%% 'spacing.nodeNode': 52, -%% 'spacing.edgeNode': 36, -%% 'spacing.edgeEdge': 24, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB subgraph Init["Phase 1: Initialization"] CFG["[S] Load CompositeConfig
from YAML

"] diff --git a/docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd b/docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd index 7a1109a1c4..b6914e8739 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd @@ -17,25 +17,16 @@ %% @uniform-stats adapters width=400 height=168 max_desc_lines=7 %% Tooltip: Nodes with aggregated adapter lists (e.g. A1/A21) are summarized; see provider docs for full breakdown. %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'flowchart': { -%% 'nodeSpacing': 72, -%% 'rankSpacing': 96, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'RIGHT', -%% 'spacing.nodeNode': 56, -%% 'spacing.edgeNode': 36, -%% 'spacing.edgeEdge': 26, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart LR subgraph Ports["Domain Ports (domain/ports/)"] direction TB diff --git a/docs/02-architecture/mmd-diagrams/foundation/32-single-record-journey.mmd b/docs/02-architecture/mmd-diagrams/foundation/32-single-record-journey.mmd index a2ac6bfe74..04ff13a581 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/32-single-record-journey.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/32-single-record-journey.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=336 height=128 max_title_len=33 max_desc_lines=5 flowchart TB subgraph Source["1. External API"] diff --git a/docs/02-architecture/mmd-diagrams/foundation/37-cli-entry-full-chain.mmd b/docs/02-architecture/mmd-diagrams/foundation/37-cli-entry-full-chain.mmd index 99f6000f81..3f1beff838 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/37-cli-entry-full-chain.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/37-cli-entry-full-chain.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=712 height=184 max_title_len=71 max_desc_lines=8 flowchart TB subgraph CLI["Interfaces Layer (Click)"] diff --git a/docs/02-architecture/mmd-diagrams/foundation/39-medallion-invariants.mmd b/docs/02-architecture/mmd-diagrams/foundation/39-medallion-invariants.mmd index 89ed956ee0..b081db84b6 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/39-medallion-invariants.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/39-medallion-invariants.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=272 height=112 max_title_len=27 max_desc_lines=4 flowchart TB %% keep-orphan: E3, E4 diff --git a/docs/02-architecture/mmd-diagrams/foundation/40-application-core-collaboration.mmd b/docs/02-architecture/mmd-diagrams/foundation/40-application-core-collaboration.mmd index 0ea9d4557f..7636df3452 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/40-application-core-collaboration.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/40-application-core-collaboration.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=256 height=144 max_title_len=25 max_desc_lines=6 flowchart TB subgraph Runner["PipelineRunner (application/core/runner.py)"] @@ -17,9 +27,14 @@ flowchart TB subgraph Lifecycle["Lifecycle Services"] LM["LockManager
• acquire(key, owner, ttl=90s)
• release(key, owner)
• validate_ownership()

"] + HB["HeartbeatService
• start()
• stop()


"] + CM["CheckpointManager
• read_checkpoint()
• save_checkpoint()


"] + SD["ShutdownService
• should_shutdown()
• request_shutdown()


"] end subgraph Validation["Pre/Post Services"] + PF["PreflightService
• validate_pipeline_config()
• validate_provider_health()


"] + POST["PostrunService
• finalize_run()
• emit_summary()


"] end subgraph Execution["Batch Execution"] @@ -57,9 +72,13 @@ flowchart TB BMR -.->|"records"| BE BTM -.->|"traces"| BE - %% All use PipelineServices - PS -.->|"ports"| Runner & Lifecycle & Validation & Execution + %% PipelineServices dependencies for orchestration components + PS -.->|"provides ports"| RUN + PS -.->|"provides ports"| LM + PS -.->|"provides ports"| PF + PS -.->|"provides ports"| BE + PS -.->|"provides ports"| BWR %% Styling style Runner fill:#eff6ff,stroke:#2563eb,stroke-width:3px - style Bundle fill:#f1f5f9,stroke:#64748b + style Bundle fill:#f5f5f5,stroke:#9e9e9e diff --git a/docs/02-architecture/mmd-diagrams/foundation/41-error-classification-tree.mmd b/docs/02-architecture/mmd-diagrams/foundation/41-error-classification-tree.mmd index 4ec1fde855..ff2e1690ba 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/41-error-classification-tree.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/41-error-classification-tree.mmd @@ -20,26 +20,16 @@ %% @uniform-stats root width=144 height=112 max_desc_lines=4 %% @uniform-stats actions width=168 height=112 max_desc_lines=4 %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'themeVariables': {'lineWidth': '2'}, -%% 'flowchart': { -%% 'nodeSpacing': 60, -%% 'rankSpacing': 76, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'DOWN', -%% 'spacing.nodeNode': 48, -%% 'spacing.edgeNode': 34, -%% 'spacing.edgeEdge': 22, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB ERROR["Error Occurred


"] diff --git a/docs/02-architecture/mmd-diagrams/foundation/43-fan-out-fan-in-pattern.mmd b/docs/02-architecture/mmd-diagrams/foundation/43-fan-out-fan-in-pattern.mmd index 4ae1458d05..189640743e 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/43-fan-out-fan-in-pattern.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/43-fan-out-fan-in-pattern.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=376 height=128 max_title_len=37 max_desc_lines=5 flowchart TB subgraph Seed["Seed Pipeline Result"] diff --git a/docs/02-architecture/mmd-diagrams/foundation/44-cross-provider-enrichment.mmd b/docs/02-architecture/mmd-diagrams/foundation/44-cross-provider-enrichment.mmd index 49800d4f85..85e7db2d10 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/44-cross-provider-enrichment.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/44-cross-provider-enrichment.mmd @@ -8,7 +8,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=376 height=184 max_title_len=37 max_desc_lines=8 flowchart LR subgraph ChEMBL["ChEMBL (Seed)"] diff --git a/docs/02-architecture/mmd-diagrams/foundation/46-yaml-config-resolution.mmd b/docs/02-architecture/mmd-diagrams/foundation/46-yaml-config-resolution.mmd index 0e3075e710..589b99e7b5 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/46-yaml-config-resolution.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/46-yaml-config-resolution.mmd @@ -11,25 +11,16 @@ %% @png-dpi 600 %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'flowchart': { -%% 'nodeSpacing': 56, -%% 'rankSpacing': 84, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'DOWN', -%% 'spacing.nodeNode': 44, -%% 'spacing.edgeNode': 34, -%% 'spacing.edgeEdge': 24, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=496 height=128 max_title_len=49 max_desc_lines=5 flowchart TD %% keep-orphan: SOURCE_YAML_CFG diff --git a/docs/02-architecture/mmd-diagrams/foundation/50-exception-hierarchy.mmd b/docs/02-architecture/mmd-diagrams/foundation/50-exception-hierarchy.mmd index 59834b45b2..58559e75cc 100644 --- a/docs/02-architecture/mmd-diagrams/foundation/50-exception-hierarchy.mmd +++ b/docs/02-architecture/mmd-diagrams/foundation/50-exception-hierarchy.mmd @@ -10,7 +10,17 @@ %% @png-scale 6 %% @png-dpi 600 -%%{init: {'theme': 'base', 'themeVariables': {'lineWidth': '2'},'layout':'elk','flowchart':{'curve':'linear'},'elk':{'nodePlacementStrategy':'BRANDES_KOEPF','mergeEdges':true,'edgeRouting':'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=200 height=112 max_title_len=19 max_desc_lines=4 flowchart TD ROOT["Exception
(Python built-in)

"] diff --git a/docs/02-architecture/mmd-diagrams/foundation/png/INDEX.md b/docs/02-architecture/mmd-diagrams/foundation/png/INDEX.md new file mode 100644 index 0000000000..ae02acaa9a --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/foundation/png/INDEX.md @@ -0,0 +1,328 @@ +# BioETL Diagrams — PNG Index + +_Generated: 2026-03-01T18:07:54+03:00_ + +## Full System Component + +![01-full-system-component](./01-full-system-component.png) + +--- + +## High Level + +![01-high-level](./01-high-level.png) + +--- + +## Full Medallion Data Flow + +![02-full-medallion-data-flow](./02-full-medallion-data-flow.png) + +--- + +## Pipeline Execution Happy Path + +![03-pipeline-execution-happy-path](./03-pipeline-execution-happy-path.png) + +--- + +## Domain Layer Class Diagram + +![04-domain-layer-class-diagram](./04-domain-layer-class-diagram.png) + +--- + +## Error Flow + +![04-error-flow](./04-error-flow.png) + +--- + +## Layers Interaction + +![05-layers-interaction](./05-layers-interaction.png) + +--- + +## Pipeline Lifecycle States + +![05-pipeline-lifecycle-states](./05-pipeline-lifecycle-states.png) + +--- + +## Application Layer Class Diagram + +![06-application-layer-class-diagram](./06-application-layer-class-diagram.png) + +--- + +## Pipeline Execution + +![06-pipeline-execution](./06-pipeline-execution.png) + +--- + +## Circuit Breaker States + +![07-circuit-breaker-states](./07-circuit-breaker-states.png) + +--- + +## Medallion Flow + +![07-medallion-flow](./07-medallion-flow.png) + +--- + +## Complete Etl Workflow + +![08-complete-etl-workflow](./08-complete-etl-workflow.png) + +--- + +## Domain Ddd + +![08-domain-ddd](./08-domain-ddd.png) + +--- + +## Full Er Diagram + +![09-full-er-diagram](./09-full-er-diagram.png) + +--- + +## Infrastructure Layer Class Diagram + +![10-infrastructure-layer-class-diagram](./10-infrastructure-layer-class-diagram.png) + +--- + +## Lock Acquisition Sequence + +![11-lock-acquisition-sequence](./11-lock-acquisition-sequence.png) + +--- + +## Local Deployment Architecture + +![12-local-deployment-architecture](./12-local-deployment-architecture.png) + +--- + +## Domain Models Relationship + +![13-domain-models-relationship](./13-domain-models-relationship.png) + +--- + +## Provider Health States + +![14-provider-health-states](./14-provider-health-states.png) + +--- + +## Dq Check Workflow + +![15-dq-check-workflow](./15-dq-check-workflow.png) + +--- + +## Memory Lock Class + +![16-memory-lock-class](./16-memory-lock-class.png) + +--- + +## Pipeline Hierarchy + +![17-pipeline-hierarchy](./17-pipeline-hierarchy.png) + +--- + +## Bronze Write Sequence + +![18-bronze-write-sequence](./18-bronze-write-sequence.png) + +--- + +## Delta Lake Write Sequence + +![19-delta-lake-write-sequence](./19-delta-lake-write-sequence.png) + +--- + +## Quarantine Record States + +![20-quarantine-record-states](./20-quarantine-record-states.png) + +--- + +## Activity Entity Data Flow + +![21-activity-entity-data-flow](./21-activity-entity-data-flow.png) + +--- + +## Client Api Request Sequence + +![22-client-api-request-sequence](./22-client-api-request-sequence.png) + +--- + +## Silver Writer Class + +![23-silver-writer-class](./23-silver-writer-class.png) + +--- + +## Hash Service Class + +![24-hash-service-class](./24-hash-service-class.png) + +--- + +## Circuit Breaker Observer Class + +![25-circuit-breaker-observer-class](./25-circuit-breaker-observer-class.png) + +--- + +## Hexagonal Ports Adapters + +![26-hexagonal-ports-adapters](./26-hexagonal-ports-adapters.png) + +--- + +## Import Matrix Enforcement + +![27-import-matrix-enforcement](./27-import-matrix-enforcement.png) + +--- + +## Composition Root Di Graph + +![28-composition-root-di-graph](./28-composition-root-di-graph.png) + +--- + +## Composite Pipeline Workflow + +![29-composite-pipeline-workflow](./29-composite-pipeline-workflow.png) + +--- + +## Port Adapter Mapping + +![30-port-adapter-mapping](./30-port-adapter-mapping.png) + +--- + +## Pipeline Run Lifecycle + +![31-pipeline-run-lifecycle](./31-pipeline-run-lifecycle.png) + +--- + +## Single Record Journey + +![32-single-record-journey](./32-single-record-journey.png) + +--- + +## Cli Run Interaction + +![33-cli-run-interaction](./33-cli-run-interaction.png) + +--- + +## Batch Processing Flow + +![34-batch-processing-flow](./34-batch-processing-flow.png) + +--- + +## Architecture Principles Mindmap + +![36-architecture-principles-mindmap](./36-architecture-principles-mindmap.png) + +--- + +## Cli Entry Full Chain + +![37-cli-entry-full-chain](./37-cli-entry-full-chain.png) + +--- + +## Runtime Assembly Sequence + +![38-runtime-assembly-sequence](./38-runtime-assembly-sequence.png) + +--- + +## Medallion Invariants + +![39-medallion-invariants](./39-medallion-invariants.png) + +--- + +## Application Core Collaboration + +![40-application-core-collaboration](./40-application-core-collaboration.png) + +--- + +## Error Classification Tree + +![41-error-classification-tree](./41-error-classification-tree.png) + +--- + +## Pipeline Runner Class + +![42-pipeline-runner-class](./42-pipeline-runner-class.png) + +--- + +## Fan Out Fan In Pattern + +![43-fan-out-fan-in-pattern](./43-fan-out-fan-in-pattern.png) + +--- + +## Cross Provider Enrichment + +![44-cross-provider-enrichment](./44-cross-provider-enrichment.png) + +--- + +## Yaml Config Resolution + +![46-yaml-config-resolution](./46-yaml-config-resolution.png) + +--- + +## Publication Merge Sources + +![47-publication-merge-sources](./47-publication-merge-sources.png) + +--- + +## Composite Phase Lifecycle + +![48-composite-phase-lifecycle](./48-composite-phase-lifecycle.png) + +--- + +## Composite Runner Class + +![49-composite-runner-class](./49-composite-runner-class.png) + +--- + +## Exception Hierarchy + +![50-exception-hierarchy](./50-exception-hierarchy.png) + +--- + diff --git a/docs/02-architecture/mmd-diagrams/foundation/svg/INDEX.md b/docs/02-architecture/mmd-diagrams/foundation/svg/INDEX.md new file mode 100644 index 0000000000..4694a79d7a --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/foundation/svg/INDEX.md @@ -0,0 +1,328 @@ +# BioETL Diagrams — SVG Index + +_Generated: 2026-03-01T18:07:54+03:00_ + +## Full System Component + +![01-full-system-component](./01-full-system-component.svg) + +--- + +## High Level + +![01-high-level](./01-high-level.svg) + +--- + +## Full Medallion Data Flow + +![02-full-medallion-data-flow](./02-full-medallion-data-flow.svg) + +--- + +## Pipeline Execution Happy Path + +![03-pipeline-execution-happy-path](./03-pipeline-execution-happy-path.svg) + +--- + +## Domain Layer Class Diagram + +![04-domain-layer-class-diagram](./04-domain-layer-class-diagram.svg) + +--- + +## Error Flow + +![04-error-flow](./04-error-flow.svg) + +--- + +## Layers Interaction + +![05-layers-interaction](./05-layers-interaction.svg) + +--- + +## Pipeline Lifecycle States + +![05-pipeline-lifecycle-states](./05-pipeline-lifecycle-states.svg) + +--- + +## Application Layer Class Diagram + +![06-application-layer-class-diagram](./06-application-layer-class-diagram.svg) + +--- + +## Pipeline Execution + +![06-pipeline-execution](./06-pipeline-execution.svg) + +--- + +## Circuit Breaker States + +![07-circuit-breaker-states](./07-circuit-breaker-states.svg) + +--- + +## Medallion Flow + +![07-medallion-flow](./07-medallion-flow.svg) + +--- + +## Complete Etl Workflow + +![08-complete-etl-workflow](./08-complete-etl-workflow.svg) + +--- + +## Domain Ddd + +![08-domain-ddd](./08-domain-ddd.svg) + +--- + +## Full Er Diagram + +![09-full-er-diagram](./09-full-er-diagram.svg) + +--- + +## Infrastructure Layer Class Diagram + +![10-infrastructure-layer-class-diagram](./10-infrastructure-layer-class-diagram.svg) + +--- + +## Lock Acquisition Sequence + +![11-lock-acquisition-sequence](./11-lock-acquisition-sequence.svg) + +--- + +## Local Deployment Architecture + +![12-local-deployment-architecture](./12-local-deployment-architecture.svg) + +--- + +## Domain Models Relationship + +![13-domain-models-relationship](./13-domain-models-relationship.svg) + +--- + +## Provider Health States + +![14-provider-health-states](./14-provider-health-states.svg) + +--- + +## Dq Check Workflow + +![15-dq-check-workflow](./15-dq-check-workflow.svg) + +--- + +## Memory Lock Class + +![16-memory-lock-class](./16-memory-lock-class.svg) + +--- + +## Pipeline Hierarchy + +![17-pipeline-hierarchy](./17-pipeline-hierarchy.svg) + +--- + +## Bronze Write Sequence + +![18-bronze-write-sequence](./18-bronze-write-sequence.svg) + +--- + +## Delta Lake Write Sequence + +![19-delta-lake-write-sequence](./19-delta-lake-write-sequence.svg) + +--- + +## Quarantine Record States + +![20-quarantine-record-states](./20-quarantine-record-states.svg) + +--- + +## Activity Entity Data Flow + +![21-activity-entity-data-flow](./21-activity-entity-data-flow.svg) + +--- + +## Client Api Request Sequence + +![22-client-api-request-sequence](./22-client-api-request-sequence.svg) + +--- + +## Silver Writer Class + +![23-silver-writer-class](./23-silver-writer-class.svg) + +--- + +## Hash Service Class + +![24-hash-service-class](./24-hash-service-class.svg) + +--- + +## Circuit Breaker Observer Class + +![25-circuit-breaker-observer-class](./25-circuit-breaker-observer-class.svg) + +--- + +## Hexagonal Ports Adapters + +![26-hexagonal-ports-adapters](./26-hexagonal-ports-adapters.svg) + +--- + +## Import Matrix Enforcement + +![27-import-matrix-enforcement](./27-import-matrix-enforcement.svg) + +--- + +## Composition Root Di Graph + +![28-composition-root-di-graph](./28-composition-root-di-graph.svg) + +--- + +## Composite Pipeline Workflow + +![29-composite-pipeline-workflow](./29-composite-pipeline-workflow.svg) + +--- + +## Port Adapter Mapping + +![30-port-adapter-mapping](./30-port-adapter-mapping.svg) + +--- + +## Pipeline Run Lifecycle + +![31-pipeline-run-lifecycle](./31-pipeline-run-lifecycle.svg) + +--- + +## Single Record Journey + +![32-single-record-journey](./32-single-record-journey.svg) + +--- + +## Cli Run Interaction + +![33-cli-run-interaction](./33-cli-run-interaction.svg) + +--- + +## Batch Processing Flow + +![34-batch-processing-flow](./34-batch-processing-flow.svg) + +--- + +## Architecture Principles Mindmap + +![36-architecture-principles-mindmap](./36-architecture-principles-mindmap.svg) + +--- + +## Cli Entry Full Chain + +![37-cli-entry-full-chain](./37-cli-entry-full-chain.svg) + +--- + +## Runtime Assembly Sequence + +![38-runtime-assembly-sequence](./38-runtime-assembly-sequence.svg) + +--- + +## Medallion Invariants + +![39-medallion-invariants](./39-medallion-invariants.svg) + +--- + +## Application Core Collaboration + +![40-application-core-collaboration](./40-application-core-collaboration.svg) + +--- + +## Error Classification Tree + +![41-error-classification-tree](./41-error-classification-tree.svg) + +--- + +## Pipeline Runner Class + +![42-pipeline-runner-class](./42-pipeline-runner-class.svg) + +--- + +## Fan Out Fan In Pattern + +![43-fan-out-fan-in-pattern](./43-fan-out-fan-in-pattern.svg) + +--- + +## Cross Provider Enrichment + +![44-cross-provider-enrichment](./44-cross-provider-enrichment.svg) + +--- + +## Yaml Config Resolution + +![46-yaml-config-resolution](./46-yaml-config-resolution.svg) + +--- + +## Publication Merge Sources + +![47-publication-merge-sources](./47-publication-merge-sources.svg) + +--- + +## Composite Phase Lifecycle + +![48-composite-phase-lifecycle](./48-composite-phase-lifecycle.svg) + +--- + +## Composite Runner Class + +![49-composite-runner-class](./49-composite-runner-class.svg) + +--- + +## Exception Hierarchy + +![50-exception-hierarchy](./50-exception-hierarchy.svg) + +--- + diff --git a/docs/02-architecture/mmd-diagrams/render.sh b/docs/02-architecture/mmd-diagrams/render.sh index 8d22e1afd6..394cff8e7e 100644 --- a/docs/02-architecture/mmd-diagrams/render.sh +++ b/docs/02-architecture/mmd-diagrams/render.sh @@ -35,6 +35,7 @@ PUPPETEER_CFG="$THEME_DIR/puppeteer-config.json" [[ -f "$PUPPETEER_CFG" ]] || PUPPETEER_CFG="" JOBS=4 # parallel jobs FIT=1 # adaptive sizing by default +TEXT_LAYER="fallback-only" # dual | fo-only | fallback-only EXCLUDE_PATHS=("docs/99-archive") # ── Diagram source directories ────────────────────────────── @@ -81,6 +82,8 @@ Options: --exclude PATH Exclude path (repeatable, relative to repo root or absolute path; default: docs/99-archive) --jobs N Parallel render jobs (default: $JOBS) + --text-layer MODE Text layer mode: dual | fo-only | fallback-only + (default: $TEXT_LAYER) --puppeteer FILE Puppeteer config JSON (CI sandboxing; defaults to theme/puppeteer-config.json if present) -h, --help Show this help EOF @@ -118,6 +121,7 @@ while [[ $# -gt 0 ]]; do --dir) require_option_value "$1" "$#"; EXTRA_DIRS+=("$2"); shift 2 ;; --exclude) require_option_value "$1" "$#"; EXCLUDE_PATHS+=("$2"); shift 2 ;; --jobs) require_option_value "$1" "$#"; JOBS="$2"; shift 2 ;; + --text-layer) require_option_value "$1" "$#"; TEXT_LAYER="$2"; shift 2 ;; --no-fit) FIT=0; shift ;; --puppeteer) require_option_value "$1" "$#"; PUPPETEER_CFG="$2"; shift 2 ;; -h|--help) usage; exit 0 ;; @@ -157,6 +161,10 @@ if ! [[ "$JOBS" =~ ^[0-9]+$ ]] || [[ "$JOBS" -lt 1 ]]; then log_err "--jobs must be an integer >= 1 (got: $JOBS)" exit 1 fi +if [[ "$TEXT_LAYER" != "dual" && "$TEXT_LAYER" != "fo-only" && "$TEXT_LAYER" != "fallback-only" ]]; then + log_err "--text-layer must be one of: dual | fo-only | fallback-only (got: $TEXT_LAYER)" + exit 1 +fi if [[ $FIT -eq 0 ]]; then # In fixed mode, treat zero values as "use defaults". @@ -350,18 +358,40 @@ render_one() { mkdir -p "$svg_dir" local svg_out="$svg_dir/${base}.svg" if mmdc -i "$src" -o "$svg_out" "${MMDC_ARGS[@]}" "${size_args[@]}" -b "$BG" 2>/dev/null; then - # Add plain SVG text fallback under foreignObject labels for renderers - # that do not support foreignObject. - if [[ -n "$PYTHON_BIN" ]]; then - "$PYTHON_BIN" "$REPO_ROOT/scripts/add_svg_text_fallback.py" --fix -f "$svg_out" >/dev/null 2>&1 || true - fi + # Manage text rendering layers to avoid duplicate labels in viewers + # that support both foreignObject and fallback text. + case "$TEXT_LAYER" in + dual) + if [[ -n "$PYTHON_BIN" ]]; then + "$PYTHON_BIN" "$REPO_ROOT/scripts/diagrams/add_svg_text_fallback.py" --fix -f "$svg_out" >/dev/null 2>&1 || true + fi + ;; + fo-only) + : + ;; + fallback-only) + if [[ -n "$PYTHON_BIN" ]]; then + if ! "$PYTHON_BIN" "$REPO_ROOT/scripts/diagrams/add_svg_text_fallback.py" --fix -f "$svg_out" >/dev/null 2>&1; then + log_err "Failed to add SVG fallback text: $svg_out" + return 1 + fi + if ! "$PYTHON_BIN" "$REPO_ROOT/scripts/diagrams/strip_svg_foreign_object.py" --fix -f "$svg_out" >/dev/null 2>&1; then + log_err "Failed to strip foreignObject labels: $svg_out" + return 1 + fi + else + log_err "fallback-only requires python for SVG post-processing" + return 1 + fi + ;; + esac # Optimize SVG with svgo if available if [[ $HAS_SVGO -eq 1 ]]; then svgo --quiet --config "$THEME_DIR/../svgo.config.js" "$svg_out" -o "$svg_out" 2>/dev/null || true fi # Inject CSS overrides for edge label readability if [[ -n "$PYTHON_BIN" ]]; then - "$PYTHON_BIN" "$REPO_ROOT/scripts/inject_svg_styles.py" --fix -f "$svg_out" >/dev/null 2>&1 || true + "$PYTHON_BIN" "$REPO_ROOT/scripts/diagrams/inject_svg_styles.py" --fix -f "$svg_out" >/dev/null 2>&1 || true fi echo -e " ${GREEN}✓${NC} SVG [$idx/$TOTAL] $base" else @@ -374,22 +404,82 @@ render_one() { if [[ $FORMAT_PNG -eq 1 ]]; then mkdir -p "$png_dir" local png_out="$png_dir/${base}.png" + local png_svg_source="$svg_dir/${base}.svg" + local temp_png_svg="" + + # In --png-only mode with SVG converters available, render a temporary SVG first + # and run the same text post-processing pipeline to preserve readable labels. + if [[ $FORMAT_SVG -eq 0 && ( $HAS_RSVG -eq 1 || $HAS_RSVG -eq 2 ) ]]; then + temp_png_svg="$(mktemp "${TMPDIR:-/tmp}/bioetl-render-${base}-XXXXXX.svg")" + if ! mmdc -i "$src" -o "$temp_png_svg" "${MMDC_ARGS[@]}" "${size_args[@]}" -b "$BG" 2>/dev/null; then + echo -e " ${RED}✗${NC} PNG [$idx/$TOTAL] $base" + rm -f "$temp_png_svg" + return 1 + fi + case "$TEXT_LAYER" in + dual) + if [[ -n "$PYTHON_BIN" ]]; then + "$PYTHON_BIN" "$REPO_ROOT/scripts/diagrams/add_svg_text_fallback.py" --fix -f "$temp_png_svg" >/dev/null 2>&1 || true + fi + ;; + fo-only) + : + ;; + fallback-only) + if [[ -n "$PYTHON_BIN" ]]; then + if ! "$PYTHON_BIN" "$REPO_ROOT/scripts/diagrams/add_svg_text_fallback.py" --fix -f "$temp_png_svg" >/dev/null 2>&1; then + echo -e " ${RED}✗${NC} PNG [$idx/$TOTAL] $base" + rm -f "$temp_png_svg" + return 1 + fi + if ! "$PYTHON_BIN" "$REPO_ROOT/scripts/diagrams/strip_svg_foreign_object.py" --fix -f "$temp_png_svg" >/dev/null 2>&1; then + echo -e " ${RED}✗${NC} PNG [$idx/$TOTAL] $base" + rm -f "$temp_png_svg" + return 1 + fi + else + echo -e " ${RED}✗${NC} PNG [$idx/$TOTAL] $base" + rm -f "$temp_png_svg" + return 1 + fi + ;; + esac + if [[ -n "$PYTHON_BIN" ]]; then + "$PYTHON_BIN" "$REPO_ROOT/scripts/diagrams/inject_svg_styles.py" --fix -f "$temp_png_svg" >/dev/null 2>&1 || true + fi + png_svg_source="$temp_png_svg" + fi if [[ $FORMAT_SVG -eq 1 && $HAS_RSVG -eq 1 ]]; then # SVG → PNG via rsvg-convert (adaptive: use SVG intrinsic size) if [[ $FIT -eq 0 ]]; then - rsvg-convert -b "$BG" -w "$WIDTH" -h "$HEIGHT" "$svg_dir/${base}.svg" -o "$png_out" 2>/dev/null + rsvg-convert -b "$BG" -w "$WIDTH" -h "$HEIGHT" "$png_svg_source" -o "$png_out" 2>/dev/null else - rsvg-convert -b "$BG" -d "$dpi_for_file" -p "$dpi_for_file" "$svg_dir/${base}.svg" -o "$png_out" 2>/dev/null + rsvg-convert -b "$BG" -d "$dpi_for_file" -p "$dpi_for_file" "$png_svg_source" -o "$png_out" 2>/dev/null fi elif [[ $FORMAT_SVG -eq 1 && $HAS_RSVG -eq 2 ]]; then # SVG → PNG via inkscape if [[ $FIT -eq 0 ]]; then - inkscape "$svg_dir/${base}.svg" --export-type=png --export-width="$WIDTH" \ + inkscape "$png_svg_source" --export-type=png --export-width="$WIDTH" \ --export-height="$HEIGHT" --export-background="$BG" --export-background-opacity=1 \ --export-filename="$png_out" 2>/dev/null else - inkscape "$svg_dir/${base}.svg" --export-type=png --export-dpi="$dpi_for_file" \ + inkscape "$png_svg_source" --export-type=png --export-dpi="$dpi_for_file" \ + --export-background="$BG" --export-background-opacity=1 --export-filename="$png_out" 2>/dev/null + fi + elif [[ $FORMAT_SVG -eq 0 && $HAS_RSVG -eq 1 ]]; then + if [[ $FIT -eq 0 ]]; then + rsvg-convert -b "$BG" -w "$WIDTH" -h "$HEIGHT" "$png_svg_source" -o "$png_out" 2>/dev/null + else + rsvg-convert -b "$BG" -d "$dpi_for_file" -p "$dpi_for_file" "$png_svg_source" -o "$png_out" 2>/dev/null + fi + elif [[ $FORMAT_SVG -eq 0 && $HAS_RSVG -eq 2 ]]; then + if [[ $FIT -eq 0 ]]; then + inkscape "$png_svg_source" --export-type=png --export-width="$WIDTH" \ + --export-height="$HEIGHT" --export-background="$BG" --export-background-opacity=1 \ + --export-filename="$png_out" 2>/dev/null + else + inkscape "$png_svg_source" --export-type=png --export-dpi="$dpi_for_file" \ --export-background="$BG" --export-background-opacity=1 --export-filename="$png_out" 2>/dev/null fi else @@ -398,6 +488,10 @@ render_one() { "${size_args[@]}" -s "$scale_for_file" -b "$BG" 2>/dev/null fi + if [[ -n "$temp_png_svg" ]]; then + rm -f "$temp_png_svg" + fi + if [[ -f "$png_out" ]]; then local size size=$(du -h "$png_out" | cut -f1) @@ -537,6 +631,7 @@ echo -e " ${GREEN}Rendered OK:${NC} $success" echo "" echo -e " Theme: ${CONFIG:-'(default)'}" echo -e " CSS: ${CSS:-'(none)'}" +echo -e " Text: ${TEXT_LAYER}" echo "" formats="" diff --git a/docs/02-architecture/mmd-diagrams/theme/_custom.css b/docs/02-architecture/mmd-diagrams/theme/_custom.css new file mode 100644 index 0000000000..beb344c189 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/theme/_custom.css @@ -0,0 +1,423 @@ +/* + * Пользовательские стили диаграмм BioETL (структурированная копия) + * Источник: custom.css + * Цель: сгруппировать правила по типам элементов и документировать назначение каждого CSS-параметра. + */ + +/* ========================================================= + * 1) Глобальная типографика и базовое поведение текста + * ========================================================= */ +svg { + /* Задаёт основной стек шрифтов для всего текста в SVG. */ + font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + Oxygen, Ubuntu, sans-serif; +} + +/* Нормализует вес текста в узлах и заголовках слоёв (без полужирного акцента). */ +.node .label text, +.node .label tspan, +.node .label .nodeLabel, +.cluster-label text, +.cluster-label tspan, +.cluster-label .nodeLabel, +text.fo-fallback { + font-weight: 400 !important; +} + +/* ========================================================= + * 2) Общая геометрия узлов (для нескольких типов диаграмм) + * ========================================================= */ +.node rect, +.node circle, +.node ellipse, +.node polygon, +.node path { + /* Единая толщина контура для фигур узлов. */ + stroke-width: 1.5px !important; + /* Скругляет углы по горизонтали для более мягкого вида. */ + rx: 8; + /* Скругляет углы по вертикали в паре с rx. */ + ry: 8; + /* Добавляет лёгкую тень и отделяет узлы от фона. */ + filter: drop-shadow(2px 4px 6px rgba(0, 0, 0, 0.05)); +} + +/* ========================================================= + * 3) Контейнеры subgraph / cluster + * ========================================================= */ +.cluster rect, +.cluster path { + /* Увеличивает радиус углов у контейнеров-групп. */ + rx: 10; + /* Поддерживает симметрию скругления по вертикали. */ + ry: 10; + /* Нейтральная заливка контейнера для снижения визуального шума. */ + fill: #f8fafc; + /* Приглушённая обводка, чтобы границы были заметны, но не доминировали. */ + stroke: #94a3b8; + /* Толщина границы контейнера в тон большинству узлов. */ + stroke-width: 1.5px; + /* Убирает пунктир у рамок контейнеров. */ + stroke-dasharray: none; + /* Делает фон контейнера полностью непрозрачным. */ + fill-opacity: 1; + /* Отключает тень контейнера, чтобы акцент оставался на узлах. */ + filter: none; +} + +.cluster text { + /* Нормальный вес шрифта для заголовков групп. */ + font-weight: 400; + /* Увеличенный размер заголовка относительно текста узлов. */ + font-size: 14px; +} + +/* ========================================================= + * 4) Стили линий связей (edges/links) + * ========================================================= */ +.edgePath .path { + /* Делает основные ребра более заметными в плотных графах. */ + stroke-width: 2.5px; + /* Скругляет соединения сегментов линий. */ + stroke-linejoin: round; + /* Скругляет окончания линий. */ + stroke-linecap: round; +} + +.edgePath path, +.flowchart-link, +.relation, +.messageLine0, +.messageLine1, +.transition path { + /* Унифицированные скруглённые соединения для всех типов линий. */ + stroke-linejoin: round; + /* Унифицированные скруглённые окончания для всех типов линий. */ + stroke-linecap: round; +} + +.transition path { + /* Выравнивает толщину переходов state diagram с основными ребрами. */ + stroke-width: 2.5px; +} + +/* ========================================================= + * 5) Подписи ребер и fallback-текст + * ========================================================= */ +.edgeLabel { + /* Компактный размер шрифта для подписей на связях. */ + font-size: 12px; + /* Плотная межстрочность для экономии места. */ + line-height: 1.1; + /* Базовый непрозрачный фон под подписью. */ + background-color: #ffffff; + /* Небольшие внутренние отступы вокруг текста. */ + padding: 1px 3px; + /* Мягкое скругление фона подписи. */ + border-radius: 2px; +} + +.edgeLabel span, +.edgeLabel p, +text.fo-fallback { + /* Принудительный тёмный fill для контраста в SVG-рендерах. */ + fill: #111827 !important; + /* Принудительный тёмный цвет для HTML-подписей. */ + color: #111827 !important; + /* Полная непрозрачность текста. */ + opacity: 1 !important; + /* Компактная межстрочность для многострочных подписей. */ + line-height: 1.1; + /* Убирает стандартные внешние отступы HTML-параграфов. */ + margin: 0; + /* Убирает стандартные внутренние отступы HTML-параграфов. */ + padding: 0; +} + +.edgeLabel .labelBkg, +.labelBkg { + /* Жёстко задаёт белый фон под текстом подписей. */ + background-color: #ffffff !important; + /* Делает фон полностью непрозрачным во всех просмотрщиках. */ + opacity: 1 !important; +} + +.edgeLabel rect { + /* Переопределяет полупрозрачный фон по умолчанию у Mermaid. */ + opacity: 1 !important; + /* Жёстко фиксирует белую заливку прямоугольника под подписью. */ + fill: #ffffff !important; +} + +/* ========================================================= + * 6) Элементы sequence diagram + * ========================================================= */ +.actor { + /* Толщина границы actor-блоков. */ + stroke-width: 1.5px; + /* Скругление углов actor-блоков по горизонтали. */ + rx: 4; + /* Скругление углов actor-блоков по вертикали. */ + ry: 4; +} + +.messageLine0, +.messageLine1 { + /* Толщина линий сообщений в sequence diagram. */ + stroke-width: 1.6px; +} + +.messageText { + /* Базовый размер текста сообщений. */ + font-size: 13px; +} + +.activation0 { + /* Более тонкая линия activation bar, чтобы не перегружать схему. */ + stroke-width: 1px; +} + +.note { + /* Скругление углов заметки по горизонтали. */ + rx: 4; + /* Скругление углов заметки по вертикали. */ + ry: 4; + /* Тонкая граница для вторичных блоков. */ + stroke-width: 1px; + /* Лёгкая тень для визуального отделения заметок. */ + filter: drop-shadow(1px 1px 2px rgba(0, 0, 0, 0.06)); +} + +/* ========================================================= + * 7) Базовые элементы class diagram + * ========================================================= */ +g.classGroup rect { + /* Скругление углов class box по горизонтали. */ + rx: 4; + /* Скругление углов class box по вертикали. */ + ry: 4; + /* Толщина границы class box. */ + stroke-width: 1.5px; + /* Мягкая тень у class box без агрессивного контраста. */ + filter: drop-shadow(1px 1px 2px rgba(0, 0, 0, 0.06)); +} + +g.classGroup text { + /* Базовый размер текста внутри class diagram. */ + font-size: 14px; +} + +g.classGroup line { + /* Толщина внутренних разделителей класса. */ + stroke-width: 1px; +} + +.relation { + /* Толщина связей между классами на уровне основных ребер. */ + stroke-width: 2.5px; +} + +/* ========================================================= + * 8) Типографика HTML-лейблов class diagram + * ========================================================= */ +g.label-group .nodeLabel { + /* Увеличенный размер названия класса для иерархии. */ + font-size: 16px !important; + /* Полужирный акцент на имени класса. */ + font-weight: 700 !important; + /* Лёгкое межбуквенное расстояние для читаемости заголовка. */ + letter-spacing: 0.01em; +} + +g.annotation-group .nodeLabel { + /* Уменьшенный размер для стереотипов/аннотаций. */ + font-size: 11px !important; + /* Курсив для визуального отделения аннотаций. */ + font-style: italic !important; + /* Небольшое ослабление контраста вторичного текста. */ + opacity: 0.8; +} + +g.members-group .nodeLabel, +g.methods-group .nodeLabel { + /* Компактный размер для атрибутов и методов. */ + font-size: 12px !important; + /* Нормальный вес шрифта для плотного структурного текста. */ + font-weight: 400 !important; +} + +/* ========================================================= + * 9) Помощники размеров foreignObject (class/flowchart) + * ========================================================= */ +g.members-group foreignObject, +g.methods-group foreignObject { + /* Минимальная высота областей members/methods. */ + min-height: 40px; +} + +.node foreignObject > div, +g.classGroup foreignObject > div { + /* Стабилизирует вычисление размеров с учётом отступов/границ. */ + box-sizing: border-box; +} + +.node.size-sm foreignObject > div { + /* Минимальная высота для малого размерного уровня узла. */ + min-height: 80px; + /* Минимальная ширина для малого размерного уровня узла. */ + min-width: 180px; +} + +.node.size-md foreignObject > div { + /* Минимальная высота для среднего размерного уровня узла. */ + min-height: 140px; + /* Минимальная ширина для среднего размерного уровня узла. */ + min-width: 260px; +} + +.node.size-lg foreignObject > div { + /* Минимальная высота для большого размерного уровня узла. */ + min-height: 200px; + /* Минимальная ширина для большого размерного уровня узла. */ + min-width: 340px; +} + +/* ========================================================= + * 10) Элементы state diagram + * ========================================================= */ +g.stateGroup rect { + /* Скругление углов контейнеров состояний по горизонтали. */ + rx: 8; + /* Скругление углов контейнеров состояний по вертикали. */ + ry: 8; +} + +.statediagram-state rect { + /* Скругление углов узлов состояния по горизонтали. */ + rx: 8; + /* Скругление углов узлов состояния по вертикали. */ + ry: 8; + /* Толщина границы узла состояния. */ + stroke-width: 1.5px; + /* Лёгкая тень для визуального отделения state box. */ + filter: drop-shadow(1px 2px 3px rgba(0, 0, 0, 0.08)); +} + +/* ========================================================= + * 11) Элементы ER diagram + * ========================================================= */ +.er.entityBox { + /* Толщина границы сущности ER-диаграммы. */ + stroke-width: 1.5px; + /* Скругление углов сущности по горизонтали. */ + rx: 4; + /* Скругление углов сущности по вертикали. */ + ry: 4; + /* Лёгкая тень для отделения блоков сущностей. */ + filter: drop-shadow(1px 2px 3px rgba(0, 0, 0, 0.08)); +} + +/* ========================================================= + * 12) Узлы mindmap + * ========================================================= */ +.mindmap-node rect, +.mindmap-node circle { + /* Толщина контура узлов mindmap. */ + stroke-width: 1.5px; + /* Чуть более выраженная тень для плотных радиальных веток. */ + filter: drop-shadow(1px 2px 2px rgba(0, 0, 0, 0.1)); +} + +/* ========================================================= + * 13) Маркеры стрелок + * ========================================================= */ +marker path { + /* Единый нейтральный цвет наконечников стрелок. */ + fill: #475569; +} + +/* ========================================================= + * 14) Цветовая карта архитектурных слоёв (fallback-селекторы) + * ========================================================= */ +[id*="Domain"] > rect, +[id*="Domain"] > path { + /* Цвет фона для доменного слоя. */ + fill: #f5f3ff !important; + /* Цвет границы для доменного слоя. */ + stroke: #7c3aed !important; +} + +[id*="Application"] > rect, +[id*="Application"] > path { + /* Цвет фона для application-слоя. */ + fill: #f0fdf4 !important; + /* Цвет границы для application-слоя. */ + stroke: #16a34a !important; +} + +[id*="Infrastructure"] > rect, +[id*="Infrastructure"] > path { + /* Цвет фона для infrastructure-слоя. */ + fill: #fff1f2 !important; + /* Цвет границы для infrastructure-слоя. */ + stroke: #dc2626 !important; +} + +[id*="Composition"] > rect, +[id*="Composition"] > path { + /* Цвет фона для composition-слоя. */ + fill: #fff7ed !important; + /* Цвет границы для composition-слоя. */ + stroke: #f59e0b !important; +} + +[id*="Interfaces"] > rect, +[id*="Interfaces"] > path { + /* Цвет фона для слоя интерфейсов. */ + fill: #eff6ff !important; + /* Цвет границы для слоя интерфейсов. */ + stroke: #2563eb !important; +} + +[id*="External"] > rect, +[id*="External"] > path { + /* Цвет фона для внешних систем. */ + fill: #f1f5f9 !important; + /* Цвет границы для внешних систем. */ + stroke: #64748b !important; +} + +/* ========================================================= + * 15) Цветовая карта слоёв Medallion + * ========================================================= */ +[id*="Bronze"] > rect, +[id*="Bronze"] > path { + /* Цвет фона Bronze-слоя. */ + fill: #fff7ed !important; + /* Цвет границы Bronze-слоя. */ + stroke: #f59e0b !important; +} + +[id*="Silver"] > rect, +[id*="Silver"] > path { + /* Цвет фона Silver-слоя. */ + fill: #f8fafc !important; + /* Цвет границы Silver-слоя. */ + stroke: #475569 !important; +} + +[id*="Gold"] > rect, +[id*="Gold"] > path { + /* Цвет фона Gold-слоя. */ + fill: #fefce8 !important; + /* Цвет границы Gold-слоя. */ + stroke: #ca8a04 !important; +} + +[id*="Quarantine"] > rect, +[id*="Quarantine"] > path { + /* Цвет фона для карантинных/проблемных потоков данных. */ + fill: #ffe4e6 !important; + /* Цвет границы для карантинных/проблемных потоков данных. */ + stroke: #e11d48 !important; +} diff --git a/docs/02-architecture/mmd-diagrams/theme/custom.css b/docs/02-architecture/mmd-diagrams/theme/custom.css index 40356a3cc1..66451f1e2f 100644 --- a/docs/02-architecture/mmd-diagrams/theme/custom.css +++ b/docs/02-architecture/mmd-diagrams/theme/custom.css @@ -1,314 +1,493 @@ /* - * BioETL Diagram Custom Styles - * Applied on top of mermaid-config.json theme. - * Passed to mmdc via --cssFile flag. + * Пользовательские стили диаграмм BioETL (структурированная копия) + * Источник: custom.css + * Цель: сгруппировать правила по типам элементов и документировать назначение каждого CSS-параметра. */ -/* ── Global ─────────────────────────────────────────── */ +/* ========================================================= + * 1) Глобальная типографика и базовое поведение текста + * ========================================================= */ svg { + /* Задаёт основной стек шрифтов для всего текста в SVG. */ font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; } -/* ── Nodes ──────────────────────────────────────────── */ + + +/* ========================================================= + * 2) Общая геометрия узлов (для нескольких типов диаграмм) + * ========================================================= */ .node rect, .node circle, .node ellipse, .node polygon, .node path { + /* Единая толщина контура для фигур узлов. */ stroke-width: 1.5px !important; + /* Скругляет углы по горизонтали для более мягкого вида. */ rx: 8; + /* Скругляет углы по вертикали в паре с rx. */ ry: 8; - filter: drop-shadow(2px 4px 6px rgba(0, 0, 0, 0.05)); + /* Добавляет лёгкую тень и отделяет узлы от фона. */ + filter: none; /* drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.05));*/ } -/* ── Subgraph / cluster ─────────────────────────────── */ +/* ========================================================= + * 3) Контейнеры subgraph / cluster + * ========================================================= */ .cluster rect, .cluster path { + /* Увеличивает радиус углов у контейнеров-групп. */ rx: 10; + /* Поддерживает симметрию скругления по вертикали. */ ry: 10; + /* Нейтральная заливка контейнера для снижения визуального шума. */ fill: #f8fafc; + /* Приглушённая обводка, чтобы границы были заметны, но не доминировали. */ stroke: #94a3b8; + /* Толщина границы контейнера в тон большинству узлов. */ stroke-width: 1.5px; + /* Убирает пунктир у рамок контейнеров. */ stroke-dasharray: none; + /* Делает фон контейнера полностью непрозрачным. */ fill-opacity: 1; + /* Отключает тень контейнера, чтобы акцент оставался на узлах. */ filter: none; } .cluster text { - font-weight: 600; - font-size: 15px; + /* Нормальный вес шрифта для заголовков групп. */ + font-weight: 400; + /* Увеличенный размер заголовка относительно текста узлов. */ + font-size: 16px; } -/* ── Edges / links ──────────────────────────────────── */ +/* ========================================================= + * 4) Стили линий связей (edges/links) + * ========================================================= */ .edgePath .path { + /* Делает основные ребра более заметными в плотных графах. */ stroke-width: 2.5px; + /* Скругляет соединения сегментов линий. */ stroke-linejoin: round; + /* Скругляет окончания линий. */ stroke-linecap: round; } -/* Global rounded joins/caps for link-like paths across diagram types */ .edgePath path, .flowchart-link, .relation, .messageLine0, .messageLine1, .transition path { + /* Унифицированные скруглённые соединения для всех типов линий. */ stroke-linejoin: round; + /* Унифицированные скруглённые окончания для всех типов линий. */ stroke-linecap: round; } -/* State diagram transitions — match edge stroke for consistent rounding */ .transition path { + /* Выравнивает толщину переходов state diagram с основными ребрами. */ stroke-width: 2.5px; } +/* ========================================================= + * 5) Подписи ребер и fallback-текст + * ========================================================= */ .edgeLabel { + /* Компактный размер шрифта для подписей на связях. */ font-size: 12px; + /* Плотная межстрочность для экономии места. */ line-height: 1.1; + /* Базовый непрозрачный фон под подписью. */ background-color: #ffffff; + /* Небольшие внутренние отступы вокруг текста. */ padding: 1px 3px; + /* Мягкое скругление фона подписи. */ border-radius: 2px; } .edgeLabel span, .edgeLabel p, text.fo-fallback { + /* Принудительный тёмный fill для контраста в SVG-рендерах. */ fill: #111827 !important; + /* Принудительный тёмный цвет для HTML-подписей. */ color: #111827 !important; + /* Полная непрозрачность текста. */ opacity: 1 !important; + /* Компактная межстрочность для многострочных подписей. */ line-height: 1.1; + /* Убирает стандартные внешние отступы HTML-параграфов. */ margin: 0; + /* Убирает стандартные внутренние отступы HTML-параграфов. */ padding: 0; } -/* Force opaque background on edge labels — Mermaid generates - #id .edgeLabel rect { opacity: .5 } and - #id .labelBkg { background-color: rgba(255,255,255,.5) } - with ID-scoped selectors, making labels invisible on white/transparent BG. */ .edgeLabel .labelBkg, .labelBkg { + /* Жёстко задаёт белый фон под текстом подписей. */ background-color: #ffffff !important; + /* Делает фон полностью непрозрачным во всех просмотрщиках. */ opacity: 1 !important; } -/* SVG rect behind edge label text — override Mermaid's 50% opacity */ .edgeLabel rect { + /* Переопределяет полупрозрачный фон по умолчанию у Mermaid. */ opacity: 1 !important; + /* Жёстко фиксирует белую заливку прямоугольника под подписью. */ fill: #ffffff !important; } -/* ── Sequence diagram ───────────────────────────────── */ +/* ========================================================= + * 6) Элементы sequence diagram + * ========================================================= */ .actor { + /* Толщина границы actor-блоков. */ stroke-width: 1.5px; + /* Скругление углов actor-блоков по горизонтали. */ rx: 4; + /* Скругление углов actor-блоков по вертикали. */ ry: 4; } .messageLine0, .messageLine1 { + /* Толщина линий сообщений в sequence diagram. */ stroke-width: 1.6px; } .messageText { + /* Базовый размер текста сообщений. */ font-size: 13px; } .activation0 { + /* Более тонкая линия activation bar, чтобы не перегружать схему. */ stroke-width: 1px; } .note { + /* Скругление углов заметки по горизонтали. */ rx: 4; + /* Скругление углов заметки по вертикали. */ ry: 4; + /* Тонкая граница для вторичных блоков. */ stroke-width: 1px; + /* Лёгкая тень для визуального отделения заметок. */ filter: drop-shadow(1px 1px 2px rgba(0, 0, 0, 0.06)); } -/* ── Class diagram ──────────────────────────────────── */ +/* ========================================================= + * 7) Базовые элементы class diagram + * ========================================================= */ g.classGroup rect { - rx: 4; - ry: 4; + /* Скругление углов class box по горизонтали. */ + rx: 10; + /* Скругление углов class box по вертикали. */ + ry: 10; + /* Толщина границы class box. */ stroke-width: 1.5px; - filter: drop-shadow(1px 2px 3px rgba(0, 0, 0, 0.08)); + /* Мягкая тень у class box без агрессивного контраста. */ + filter: drop-shadow(1px 1px 2px rgba(0, 0, 0, 0.06)); } g.classGroup text { - font-size: 13px; + /* Базовый размер текста внутри class diagram. */ + font-size: 14px; } g.classGroup line { + /* Толщина внутренних разделителей класса. */ stroke-width: 1px; } .relation { + /* Толщина связей между классами на уровне основных ребер. */ stroke-width: 2.5px; } -/* - * Class diagram — adaptive font sizes (foreignObject / HTML path). - * - * Mermaid renders class boxes via foreignObject → HTML, so we target - * .nodeLabel (the HTML ) scoped to each group: - * - * g.label-group → class name e.g. "BaseFieldExtractor" - * g.annotation-group → stereotype e.g. "<>" - * g.members-group → attributes e.g. "+ field : str" - * g.methods-group → methods e.g. "+ extract() str" - */ - -/* Class name — larger and bold */ +/* ========================================================= + * 8) Типографика HTML-лейблов class diagram + * ========================================================= */ g.label-group .nodeLabel { - font-size: 15px !important; - font-weight: 700 !important; + /* Увеличенный размер названия класса для иерархии. */ + font-size: 16px !important; + /* Полужирный акцент на имени класса. */ + font-weight: 200 !important; + /* Лёгкое межбуквенное расстояние для читаемости заголовка. */ letter-spacing: 0.01em; } -/* Stereotype annotation — small italic */ g.annotation-group .nodeLabel { + /* Уменьшенный размер для стереотипов/аннотаций. */ font-size: 11px !important; + /* Курсив для визуального отделения аннотаций. */ font-style: italic !important; + /* Небольшое ослабление контраста вторичного текста. */ opacity: 0.8; } -/* Attributes and methods — compact, keep readable */ g.members-group .nodeLabel, g.methods-group .nodeLabel { + /* Компактный размер для атрибутов и методов. */ font-size: 12px !important; + /* Нормальный вес шрифта для плотного структурного текста. */ font-weight: 400 !important; } -/* - * CSS-based minimum sizing (P1: replaces   padding). - * - * SVG does NOT support min-width/min-height (CSS Box Model). - * Instead, we target the HTML
inside — Mermaid - * measures this content during rendering, so CSS min-* dimensions - * expand the foreignObject → rect is sized accordingly. - * - * Requires htmlLabels: true (set in mermaid-config.json). - * - * Usage in .mmd classDiagram: - * classDef size-sm fill:#eff6ff,stroke:#2563eb - * class MySmallClass size-sm - * - * The classDef applies fill/stroke to the rect; the CSS below provides - * the minimum dimension via the HTML label content path. - */ - -/* Baseline: all class member groups get consistent min-height */ +/* ========================================================= + * 9) Помощники размеров foreignObject (class/flowchart) + * ========================================================= */ g.members-group foreignObject, g.methods-group foreignObject { + /* Минимальная высота областей members/methods. */ min-height: 40px; } -/* Size tiers — target the foreignObject HTML content divs */ -/* Small: compact protocols, simple value objects */ .node foreignObject > div, g.classGroup foreignObject > div { + /* Стабилизирует вычисление размеров с учётом отступов/границ. */ box-sizing: border-box; } -/* Flowchart node sizing tiers */ -.node.size-sm foreignObject > div { min-height: 80px; min-width: 180px; } -.node.size-md foreignObject > div { min-height: 140px; min-width: 260px; } -.node.size-lg foreignObject > div { min-height: 200px; min-width: 340px; } +.node.size-sm foreignObject > div { + /* Минимальная высота для малого размерного уровня узла. */ + min-height: 80px; + /* Минимальная ширина для малого размерного уровня узла. */ + min-width: 180px; +} + +.node.size-md foreignObject > div { + /* Минимальная высота для среднего размерного уровня узла. */ + min-height: 140px; + /* Минимальная ширина для среднего размерного уровня узла. */ + min-width: 260px; +} + +.node.size-lg foreignObject > div { + /* Минимальная высота для большого размерного уровня узла. */ + min-height: 200px; + /* Минимальная ширина для большого размерного уровня узла. */ + min-width: 340px; +} -/* ── State diagram ──────────────────────────────────── */ +/* ========================================================= + * 10) Элементы state diagram + * ========================================================= */ g.stateGroup rect { + /* Скругление углов контейнеров состояний по горизонтали. */ rx: 8; + /* Скругление углов контейнеров состояний по вертикали. */ ry: 8; } .statediagram-state rect { + /* Скругление углов узлов состояния по горизонтали. */ rx: 8; + /* Скругление углов узлов состояния по вертикали. */ ry: 8; + /* Толщина границы узла состояния. */ stroke-width: 1.5px; + /* Лёгкая тень для визуального отделения state box. */ filter: drop-shadow(1px 2px 3px rgba(0, 0, 0, 0.08)); } -/* ── ER diagram ─────────────────────────────────────── */ +/* ========================================================= + * 11) Элементы ER diagram + * ========================================================= */ .er.entityBox { + /* Толщина границы сущности ER-диаграммы. */ stroke-width: 1.5px; + /* Скругление углов сущности по горизонтали. */ rx: 4; + /* Скругление углов сущности по вертикали. */ ry: 4; + /* Лёгкая тень для отделения блоков сущностей. */ filter: drop-shadow(1px 2px 3px rgba(0, 0, 0, 0.08)); } -/* ── Mindmap ────────────────────────────────────────── */ +/* ========================================================= + * 12) Узлы mindmap + * ========================================================= */ .mindmap-node rect, .mindmap-node circle { + /* Толщина контура узлов mindmap. */ stroke-width: 1.5px; + /* Чуть более выраженная тень для плотных радиальных веток. */ filter: drop-shadow(1px 2px 2px rgba(0, 0, 0, 0.1)); } -/* ── Markers / arrowheads ───────────────────────────── */ +/* ========================================================= + * 13) Маркеры стрелок + * ========================================================= */ marker path { + /* Единый нейтральный цвет наконечников стрелок. */ fill: #475569; } -/* ── BioETL-specific layer colours ──────────────────── */ -/* Use classDef in .mmd files for best results. - These selectors are fallback targets for - subgraphs whose id starts with a known prefix. */ - +/* ========================================================= + * 14) Цветовая карта архитектурных слоёв (fallback-селекторы) + * ========================================================= */ [id*="Domain"] > rect, [id*="Domain"] > path { + /* Цвет фона для доменного слоя. */ fill: #f5f3ff !important; + /* Цвет границы для доменного слоя. */ stroke: #7c3aed !important; } +.cluster[id*="Domain"] > rect, +.cluster[id*="Domain"] > path { + fill: #ffffff !important; +} + [id*="Application"] > rect, [id*="Application"] > path { + /* Цвет фона для application-слоя. */ fill: #f0fdf4 !important; + /* Цвет границы для application-слоя. */ stroke: #16a34a !important; } +.cluster[id*="Application"] > rect, +.cluster[id*="Application"] > path { + fill: #ffffff !important; +} + [id*="Infrastructure"] > rect, [id*="Infrastructure"] > path { + /* Цвет фона для infrastructure-слоя. */ fill: #fff1f2 !important; + /* Цвет границы для infrastructure-слоя. */ stroke: #dc2626 !important; } +.cluster[id*="Infrastructure"] > rect, +.cluster[id*="Infrastructure"] > path { + fill: #ffffff !important; +} + [id*="Composition"] > rect, [id*="Composition"] > path { + /* Цвет фона для composition-слоя. */ fill: #fff7ed !important; + /* Цвет границы для composition-слоя. */ stroke: #f59e0b !important; } +.cluster[id*="Composition"] > rect, +.cluster[id*="Composition"] > path { + fill: #ffffff !important; +} + [id*="Interfaces"] > rect, [id*="Interfaces"] > path { + /* Цвет фона для слоя интерфейсов. */ fill: #eff6ff !important; + /* Цвет границы для слоя интерфейсов. */ stroke: #2563eb !important; } +.cluster[id*="Interfaces"] > rect, +.cluster[id*="Interfaces"] > path { + fill: #ffffff !important; +} + [id*="External"] > rect, [id*="External"] > path { + /* Цвет фона для внешних систем. */ fill: #f1f5f9 !important; + /* Цвет границы для внешних систем. */ stroke: #64748b !important; } -/* Medallion colours for data-flow diagrams */ +.cluster[id*="External"] > rect, +.cluster[id*="External"] > path { + fill: #ffffff !important; +} + +/* Белая подложка под подписи всех архитектурных/medallion слоёв */ +g.cluster[id*="Domain"] .cluster-label foreignObject > div, +g.cluster[id*="Application"] .cluster-label foreignObject > div, +g.cluster[id*="Infrastructure"] .cluster-label foreignObject > div, +g.cluster[id*="Composition"] .cluster-label foreignObject > div, +g.cluster[id*="Interfaces"] .cluster-label foreignObject > div, +g.cluster[id*="External"] .cluster-label foreignObject > div, +g.cluster[id*="Bronze"] .cluster-label foreignObject > div, +g.cluster[id*="Silver"] .cluster-label foreignObject > div, +g.cluster[id*="Gold"] .cluster-label foreignObject > div, +g.cluster[id*="Quarantine"] .cluster-label foreignObject > div { + background: #ffffff !important; + padding: 0 6px !important; + border-radius: 4px; +} + +/* Fallback для рендеров без foreignObject: не рисуем толстую обводку */ +g.cluster[id*="Domain"] .cluster-label text.fo-fallback, +g.cluster[id*="Application"] .cluster-label text.fo-fallback, +g.cluster[id*="Infrastructure"] .cluster-label text.fo-fallback, +g.cluster[id*="Composition"] .cluster-label text.fo-fallback, +g.cluster[id*="Interfaces"] .cluster-label text.fo-fallback, +g.cluster[id*="External"] .cluster-label text.fo-fallback, +g.cluster[id*="Bronze"] .cluster-label text.fo-fallback, +g.cluster[id*="Silver"] .cluster-label text.fo-fallback, +g.cluster[id*="Gold"] .cluster-label text.fo-fallback, +g.cluster[id*="Quarantine"] .cluster-label text.fo-fallback { + fill: #111827 !important; + stroke: none !important; +} + +/* ========================================================= + * 15) Цветовая карта слоёв Medallion + * ========================================================= */ [id*="Bronze"] > rect, [id*="Bronze"] > path { + /* Цвет фона Bronze-слоя. */ fill: #fff7ed !important; + /* Цвет границы Bronze-слоя. */ stroke: #f59e0b !important; } [id*="Silver"] > rect, [id*="Silver"] > path { + /* Цвет фона Silver-слоя. */ fill: #f8fafc !important; + /* Цвет границы Silver-слоя. */ stroke: #475569 !important; } [id*="Gold"] > rect, [id*="Gold"] > path { + /* Цвет фона Gold-слоя. */ fill: #fefce8 !important; + /* Цвет границы Gold-слоя. */ stroke: #ca8a04 !important; } [id*="Quarantine"] > rect, [id*="Quarantine"] > path { + /* Цвет фона для карантинных/проблемных потоков данных. */ fill: #ffe4e6 !important; + /* Цвет границы для карантинных/проблемных потоков данных. */ stroke: #e11d48 !important; } +/* Нормализует вес текста в узлах и заголовках слоёв (без полужирного акцента). */ +.node .label text, +.node .label tspan, +.node .label .nodeLabel, +text.fo-fallback { + stroke: none !important; + stroke-width: 0 !important; + fill: #111827 !important; + font-weight: 400 !important; +} +/* Single text layer (fallback-only) */ +text.fo-fallback { + display: inline !important; +} + +foreignObject { + display: none !important; +} diff --git a/docs/02-architecture/mmd-diagrams/theme/mermaid-config.json b/docs/02-architecture/mmd-diagrams/theme/mermaid-config.json index fef3b6a83d..1e822e7dfb 100644 --- a/docs/02-architecture/mmd-diagrams/theme/mermaid-config.json +++ b/docs/02-architecture/mmd-diagrams/theme/mermaid-config.json @@ -19,7 +19,7 @@ "mainBkg": "#eff6ff", "fontFamily": "Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif", - "fontSize": "14px", + "fontSize": "16px", "nodeBorder": "#2563eb", "clusterBkg": "#f8fafc", @@ -80,7 +80,7 @@ "htmlLabels": true, "useMaxWidth": true, "diagramPadding": 16, - "wrappingWidth": 200 + "wrappingWidth": 240 }, "sequence": { "mirrorActors": false, diff --git a/docs/02-architecture/mmd-diagrams/theme/ref_custom.css b/docs/02-architecture/mmd-diagrams/theme/ref_custom.css new file mode 100644 index 0000000000..d4f431bc16 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/theme/ref_custom.css @@ -0,0 +1,314 @@ +/* + * BioETL Diagram Custom Styles + * Applied on top of mermaid-config.json theme. + * Passed to mmdc via --cssFile flag. + */ + +/* ── Global ─────────────────────────────────────────── */ +svg { + font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + Oxygen, Ubuntu, sans-serif; +} + +/* ── Nodes ──────────────────────────────────────────── */ +.node rect, +.node circle, +.node ellipse, +.node polygon, +.node path { + stroke-width: 1.5px !important; + rx: 8; + ry: 8; + filter: drop-shadow(2px 4px 6px rgba(0, 0, 0, 0.05)); +} + +/* ── Subgraph / cluster ─────────────────────────────── */ +.cluster rect, +.cluster path { + rx: 10; + ry: 10; + fill: #f8fafc; + stroke: #94a3b8; + stroke-width: 1.5px; + stroke-dasharray: none; + fill-opacity: 1; + filter: none; +} + +.cluster text { + font-weight: 400; + font-size: 15px; +} + +/* ── Edges / links ──────────────────────────────────── */ +.edgePath .path { + stroke-width: 2.5px; + stroke-linejoin: round; + stroke-linecap: round; +} + +/* Global rounded joins/caps for link-like paths across diagram types */ +.edgePath path, +.flowchart-link, +.relation, +.messageLine0, +.messageLine1, +.transition path { + stroke-linejoin: round; + stroke-linecap: round; +} + +/* State diagram transitions — match edge stroke for consistent rounding */ +.transition path { + stroke-width: 2.5px; +} + +.edgeLabel { + font-size: 12px; + line-height: 1.1; + background-color: #ffffff; + padding: 1px 3px; + border-radius: 2px; +} + +.edgeLabel span, +.edgeLabel p, +text.fo-fallback { + fill: #111827 !important; + color: #111827 !important; + opacity: 1 !important; + line-height: 1.1; + margin: 0; + padding: 0; +} + +/* Force opaque background on edge labels — Mermaid generates + #id .edgeLabel rect { opacity: .5 } and + #id .labelBkg { background-color: rgba(255,255,255,.5) } + with ID-scoped selectors, making labels invisible on white/transparent BG. */ +.edgeLabel .labelBkg, +.labelBkg { + background-color: #ffffff !important; + opacity: 1 !important; +} + +/* SVG rect behind edge label text — override Mermaid's 50% opacity */ +.edgeLabel rect { + opacity: 1 !important; + fill: #ffffff !important; +} + +/* ── Sequence diagram ───────────────────────────────── */ +.actor { + stroke-width: 1.5px; + rx: 4; + ry: 4; +} + +.messageLine0, +.messageLine1 { + stroke-width: 1.6px; +} + +.messageText { + font-size: 13px; +} + +.activation0 { + stroke-width: 1px; +} + +.note { + rx: 4; + ry: 4; + stroke-width: 1px; + filter: drop-shadow(1px 1px 2px rgba(0, 0, 0, 0.06)); +} + +/* ── Class diagram ──────────────────────────────────── */ +g.classGroup rect { + rx: 4; + ry: 4; + stroke-width: 1.5px; + filter: drop-shadow(1px 1px 2px rgba(0, 0, 0, 0.06)); +} + +g.classGroup text { + font-size: 14px; +} + +g.classGroup line { + stroke-width: 1px; +} + +.relation { + stroke-width: 2.5px; +} + +/* + * Class diagram — adaptive font sizes (foreignObject / HTML path). + * + * Mermaid renders class boxes via foreignObject → HTML, so we target + * .nodeLabel (the HTML ) scoped to each group: + * + * g.label-group → class name e.g. "BaseFieldExtractor" + * g.annotation-group → stereotype e.g. "<>" + * g.members-group → attributes e.g. "+ field : str" + * g.methods-group → methods e.g. "+ extract() str" + */ + +/* Class name — larger and bold */ +g.label-group .nodeLabel { + font-size: 16px !important; + font-weight: 700 !important; + letter-spacing: 0.01em; +} + +/* Stereotype annotation — small italic */ +g.annotation-group .nodeLabel { + font-size: 11px !important; + font-style: italic !important; + opacity: 0.8; +} + +/* Attributes and methods — compact, keep readable */ +g.members-group .nodeLabel, +g.methods-group .nodeLabel { + font-size: 12px !important; + font-weight: 400 !important; +} + +/* + * CSS-based minimum sizing (P1: replaces   padding). + * + * SVG does NOT support min-width/min-height (CSS Box Model). + * Instead, we target the HTML
inside — Mermaid + * measures this content during rendering, so CSS min-* dimensions + * expand the foreignObject → rect is sized accordingly. + * + * Requires htmlLabels: true (set in mermaid-config.json). + * + * Usage in .mmd classDiagram: + * classDef size-sm fill:#eff6ff,stroke:#2563eb + * class MySmallClass size-sm + * + * The classDef applies fill/stroke to the rect; the CSS below provides + * the minimum dimension via the HTML label content path. + */ + +/* Baseline: all class member groups get consistent min-height */ +g.members-group foreignObject, +g.methods-group foreignObject { + min-height: 40px; +} + +/* Size tiers — target the foreignObject HTML content divs */ +/* Small: compact protocols, simple value objects */ +.node foreignObject > div, +g.classGroup foreignObject > div { + box-sizing: border-box; +} + +/* Flowchart node sizing tiers */ +.node.size-sm foreignObject > div { min-height: 80px; min-width: 180px; } +.node.size-md foreignObject > div { min-height: 140px; min-width: 260px; } +.node.size-lg foreignObject > div { min-height: 200px; min-width: 340px; } + +/* ── State diagram ──────────────────────────────────── */ +g.stateGroup rect { + rx: 8; + ry: 8; +} + +.statediagram-state rect { + rx: 8; + ry: 8; + stroke-width: 1.5px; + filter: drop-shadow(1px 2px 3px rgba(0, 0, 0, 0.08)); +} + +/* ── ER diagram ─────────────────────────────────────── */ +.er.entityBox { + stroke-width: 1.5px; + rx: 4; + ry: 4; + filter: drop-shadow(1px 2px 3px rgba(0, 0, 0, 0.08)); +} + +/* ── Mindmap ────────────────────────────────────────── */ +.mindmap-node rect, +.mindmap-node circle { + stroke-width: 1.5px; + filter: drop-shadow(1px 2px 2px rgba(0, 0, 0, 0.1)); +} + +/* ── Markers / arrowheads ───────────────────────────── */ +marker path { + fill: #475569; +} + +/* ── BioETL-specific layer colours ──────────────────── */ +/* Use classDef in .mmd files for best results. + These selectors are fallback targets for + subgraphs whose id starts with a known prefix. */ + +[id*="Domain"] > rect, +[id*="Domain"] > path { + fill: #f5f3ff !important; + stroke: #7c3aed !important; +} + +[id*="Application"] > rect, +[id*="Application"] > path { + fill: #f0fdf4 !important; + stroke: #16a34a !important; +} + +[id*="Infrastructure"] > rect, +[id*="Infrastructure"] > path { + fill: #fff1f2 !important; + stroke: #dc2626 !important; +} + +[id*="Composition"] > rect, +[id*="Composition"] > path { + fill: #fff7ed !important; + stroke: #f59e0b !important; +} + +[id*="Interfaces"] > rect, +[id*="Interfaces"] > path { + fill: #eff6ff !important; + stroke: #2563eb !important; +} + +[id*="External"] > rect, +[id*="External"] > path { + fill: #f1f5f9 !important; + stroke: #64748b !important; +} + +/* Medallion colours for data-flow diagrams */ +[id*="Bronze"] > rect, +[id*="Bronze"] > path { + fill: #fff7ed !important; + stroke: #f59e0b !important; +} + +[id*="Silver"] > rect, +[id*="Silver"] > path { + fill: #f8fafc !important; + stroke: #475569 !important; +} + +[id*="Gold"] > rect, +[id*="Gold"] > path { + fill: #fefce8 !important; + stroke: #ca8a04 !important; +} + +[id*="Quarantine"] > rect, +[id*="Quarantine"] > path { + fill: #ffe4e6 !important; + stroke: #e11d48 !important; +} diff --git a/docs/02-architecture/mmd-diagrams/views-diagrams-catalog.html b/docs/02-architecture/mmd-diagrams/views-diagrams-catalog.html new file mode 100644 index 0000000000..a541082f50 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/views-diagrams-catalog.html @@ -0,0 +1,171 @@ + +BioETL Diagram Catalog + + +

BioETL views Diagrams

Source: docs/02-architecture/mmd-diagrams/views/png/*.png

Total images: 156

Generated: 2026-03-01T17:35:32+03:00

+

001. views/png/00-legend.png

views/png/00-legend.png
+

002. views/png/01-full-system-component-dataflow.png

views/png/01-full-system-component-dataflow.png
+

003. views/png/01-full-system-component-domain.png

views/png/01-full-system-component-domain.png
+

004. views/png/01-full-system-component-full.png

views/png/01-full-system-component-full.png
+

005. views/png/01-full-system-component-infra.png

views/png/01-full-system-component-infra.png
+

006. views/png/01-full-system-component-overview.png

views/png/01-full-system-component-overview.png
+

007. views/png/01-high-level-dataflow.png

views/png/01-high-level-dataflow.png
+

008. views/png/01-high-level-domain.png

views/png/01-high-level-domain.png
+

009. views/png/01-high-level-full.png

views/png/01-high-level-full.png
+

010. views/png/01-high-level-infra.png

views/png/01-high-level-infra.png
+

011. views/png/01-high-level-overview.png

views/png/01-high-level-overview.png
+

012. views/png/02-medallion-dataflow.png

views/png/02-medallion-dataflow.png
+

013. views/png/02-medallion-domain.png

views/png/02-medallion-domain.png
+

014. views/png/02-medallion-full.png

views/png/02-medallion-full.png
+

015. views/png/02-medallion-infra.png

views/png/02-medallion-infra.png
+

016. views/png/02-medallion-overview.png

views/png/02-medallion-overview.png
+

017. views/png/04-domain-layer-class-diagram-dataflow.png

views/png/04-domain-layer-class-diagram-dataflow.png
+

018. views/png/04-domain-layer-class-diagram-domain.png

views/png/04-domain-layer-class-diagram-domain.png
+

019. views/png/04-domain-layer-class-diagram-full.png

views/png/04-domain-layer-class-diagram-full.png
+

020. views/png/04-domain-layer-class-diagram-infra.png

views/png/04-domain-layer-class-diagram-infra.png
+

021. views/png/04-domain-layer-class-diagram-overview.png

views/png/04-domain-layer-class-diagram-overview.png
+

022. views/png/05-layers-interaction-dataflow.png

views/png/05-layers-interaction-dataflow.png
+

023. views/png/05-layers-interaction-domain.png

views/png/05-layers-interaction-domain.png
+

024. views/png/05-layers-interaction-full.png

views/png/05-layers-interaction-full.png
+

025. views/png/05-layers-interaction-infra.png

views/png/05-layers-interaction-infra.png
+

026. views/png/05-layers-interaction-overview.png

views/png/05-layers-interaction-overview.png
+

027. views/png/05-pipeline-lifecycle-states-dataflow.png

views/png/05-pipeline-lifecycle-states-dataflow.png
+

028. views/png/05-pipeline-lifecycle-states-domain.png

views/png/05-pipeline-lifecycle-states-domain.png
+

029. views/png/05-pipeline-lifecycle-states-full.png

views/png/05-pipeline-lifecycle-states-full.png
+

030. views/png/05-pipeline-lifecycle-states-infra.png

views/png/05-pipeline-lifecycle-states-infra.png
+

031. views/png/05-pipeline-lifecycle-states-overview.png

views/png/05-pipeline-lifecycle-states-overview.png
+

032. views/png/06-application-layer-class-diagram-dataflow.png

views/png/06-application-layer-class-diagram-dataflow.png
+

033. views/png/06-application-layer-class-diagram-domain.png

views/png/06-application-layer-class-diagram-domain.png
+

034. views/png/06-application-layer-class-diagram-full.png

views/png/06-application-layer-class-diagram-full.png
+

035. views/png/06-application-layer-class-diagram-infra.png

views/png/06-application-layer-class-diagram-infra.png
+

036. views/png/06-application-layer-class-diagram-overview.png

views/png/06-application-layer-class-diagram-overview.png
+

037. views/png/07-circuit-breaker-states-dataflow.png

views/png/07-circuit-breaker-states-dataflow.png
+

038. views/png/07-circuit-breaker-states-domain.png

views/png/07-circuit-breaker-states-domain.png
+

039. views/png/07-circuit-breaker-states-full.png

views/png/07-circuit-breaker-states-full.png
+

040. views/png/07-circuit-breaker-states-infra.png

views/png/07-circuit-breaker-states-infra.png
+

041. views/png/07-circuit-breaker-states-overview.png

views/png/07-circuit-breaker-states-overview.png
+

042. views/png/08-complete-etl-workflow-dataflow.png

views/png/08-complete-etl-workflow-dataflow.png
+

043. views/png/08-complete-etl-workflow-domain.png

views/png/08-complete-etl-workflow-domain.png
+

044. views/png/08-complete-etl-workflow-full.png

views/png/08-complete-etl-workflow-full.png
+

045. views/png/08-complete-etl-workflow-infra.png

views/png/08-complete-etl-workflow-infra.png
+

046. views/png/08-complete-etl-workflow-overview.png

views/png/08-complete-etl-workflow-overview.png
+

047. views/png/08-domain-ddd-dataflow.png

views/png/08-domain-ddd-dataflow.png
+

048. views/png/08-domain-ddd-domain.png

views/png/08-domain-ddd-domain.png
+

049. views/png/08-domain-ddd-full.png

views/png/08-domain-ddd-full.png
+

050. views/png/08-domain-ddd-infra.png

views/png/08-domain-ddd-infra.png
+

051. views/png/08-domain-ddd-overview.png

views/png/08-domain-ddd-overview.png
+

052. views/png/10-infrastructure-layer-class-diagram-dataflow.png

views/png/10-infrastructure-layer-class-diagram-dataflow.png
+

053. views/png/10-infrastructure-layer-class-diagram-domain.png

views/png/10-infrastructure-layer-class-diagram-domain.png
+

054. views/png/10-infrastructure-layer-class-diagram-full.png

views/png/10-infrastructure-layer-class-diagram-full.png
+

055. views/png/10-infrastructure-layer-class-diagram-infra.png

views/png/10-infrastructure-layer-class-diagram-infra.png
+

056. views/png/10-infrastructure-layer-class-diagram-overview.png

views/png/10-infrastructure-layer-class-diagram-overview.png
+

057. views/png/12-local-deployment-architecture-dataflow.png

views/png/12-local-deployment-architecture-dataflow.png
+

058. views/png/12-local-deployment-architecture-domain.png

views/png/12-local-deployment-architecture-domain.png
+

059. views/png/12-local-deployment-architecture-full.png

views/png/12-local-deployment-architecture-full.png
+

060. views/png/12-local-deployment-architecture-infra.png

views/png/12-local-deployment-architecture-infra.png
+

061. views/png/12-local-deployment-architecture-overview.png

views/png/12-local-deployment-architecture-overview.png
+

062. views/png/14-provider-health-states-dataflow.png

views/png/14-provider-health-states-dataflow.png
+

063. views/png/14-provider-health-states-domain.png

views/png/14-provider-health-states-domain.png
+

064. views/png/14-provider-health-states-full.png

views/png/14-provider-health-states-full.png
+

065. views/png/14-provider-health-states-infra.png

views/png/14-provider-health-states-infra.png
+

066. views/png/14-provider-health-states-overview.png

views/png/14-provider-health-states-overview.png
+

067. views/png/15-dq-check-workflow-dataflow.png

views/png/15-dq-check-workflow-dataflow.png
+

068. views/png/15-dq-check-workflow-domain.png

views/png/15-dq-check-workflow-domain.png
+

069. views/png/15-dq-check-workflow-full.png

views/png/15-dq-check-workflow-full.png
+

070. views/png/15-dq-check-workflow-infra.png

views/png/15-dq-check-workflow-infra.png
+

071. views/png/15-dq-check-workflow-overview.png

views/png/15-dq-check-workflow-overview.png
+

072. views/png/21-activity-entity-data-flow-dataflow.png

views/png/21-activity-entity-data-flow-dataflow.png
+

073. views/png/21-activity-entity-data-flow-domain.png

views/png/21-activity-entity-data-flow-domain.png
+

074. views/png/21-activity-entity-data-flow-full.png

views/png/21-activity-entity-data-flow-full.png
+

075. views/png/21-activity-entity-data-flow-infra.png

views/png/21-activity-entity-data-flow-infra.png
+

076. views/png/21-activity-entity-data-flow-overview.png

views/png/21-activity-entity-data-flow-overview.png
+

077. views/png/26-hexagonal-ports-adapters-dataflow.png

views/png/26-hexagonal-ports-adapters-dataflow.png
+

078. views/png/26-hexagonal-ports-adapters-domain.png

views/png/26-hexagonal-ports-adapters-domain.png
+

079. views/png/26-hexagonal-ports-adapters-full.png

views/png/26-hexagonal-ports-adapters-full.png
+

080. views/png/26-hexagonal-ports-adapters-infra.png

views/png/26-hexagonal-ports-adapters-infra.png
+

081. views/png/26-hexagonal-ports-adapters-overview.png

views/png/26-hexagonal-ports-adapters-overview.png
+

082. views/png/28-composition-root-di-graph-dataflow.png

views/png/28-composition-root-di-graph-dataflow.png
+

083. views/png/28-composition-root-di-graph-domain.png

views/png/28-composition-root-di-graph-domain.png
+

084. views/png/28-composition-root-di-graph-full.png

views/png/28-composition-root-di-graph-full.png
+

085. views/png/28-composition-root-di-graph-infra.png

views/png/28-composition-root-di-graph-infra.png
+

086. views/png/28-composition-root-di-graph-overview.png

views/png/28-composition-root-di-graph-overview.png
+

087. views/png/29-composite-pipeline-workflow-dataflow.png

views/png/29-composite-pipeline-workflow-dataflow.png
+

088. views/png/29-composite-pipeline-workflow-domain.png

views/png/29-composite-pipeline-workflow-domain.png
+

089. views/png/29-composite-pipeline-workflow-full.png

views/png/29-composite-pipeline-workflow-full.png
+

090. views/png/29-composite-pipeline-workflow-infra.png

views/png/29-composite-pipeline-workflow-infra.png
+

091. views/png/29-composite-pipeline-workflow-overview.png

views/png/29-composite-pipeline-workflow-overview.png
+

092. views/png/30-port-adapter-mapping-dataflow.png

views/png/30-port-adapter-mapping-dataflow.png
+

093. views/png/30-port-adapter-mapping-domain.png

views/png/30-port-adapter-mapping-domain.png
+

094. views/png/30-port-adapter-mapping-full.png

views/png/30-port-adapter-mapping-full.png
+

095. views/png/30-port-adapter-mapping-infra.png

views/png/30-port-adapter-mapping-infra.png
+

096. views/png/30-port-adapter-mapping-overview.png

views/png/30-port-adapter-mapping-overview.png
+

097. views/png/31-pipeline-run-lifecycle-dataflow.png

views/png/31-pipeline-run-lifecycle-dataflow.png
+

098. views/png/31-pipeline-run-lifecycle-domain.png

views/png/31-pipeline-run-lifecycle-domain.png
+

099. views/png/31-pipeline-run-lifecycle-full.png

views/png/31-pipeline-run-lifecycle-full.png
+

100. views/png/31-pipeline-run-lifecycle-infra.png

views/png/31-pipeline-run-lifecycle-infra.png
+

101. views/png/31-pipeline-run-lifecycle-overview.png

views/png/31-pipeline-run-lifecycle-overview.png
+

102. views/png/32-single-record-journey-dataflow.png

views/png/32-single-record-journey-dataflow.png
+

103. views/png/32-single-record-journey-domain.png

views/png/32-single-record-journey-domain.png
+

104. views/png/32-single-record-journey-full.png

views/png/32-single-record-journey-full.png
+

105. views/png/32-single-record-journey-infra.png

views/png/32-single-record-journey-infra.png
+

106. views/png/32-single-record-journey-overview.png

views/png/32-single-record-journey-overview.png
+

107. views/png/33-cli-run-interaction-dataflow.png

views/png/33-cli-run-interaction-dataflow.png
+

108. views/png/33-cli-run-interaction-domain.png

views/png/33-cli-run-interaction-domain.png
+

109. views/png/33-cli-run-interaction-full.png

views/png/33-cli-run-interaction-full.png
+

110. views/png/33-cli-run-interaction-infra.png

views/png/33-cli-run-interaction-infra.png
+

111. views/png/33-cli-run-interaction-overview.png

views/png/33-cli-run-interaction-overview.png
+

112. views/png/34-batch-processing-flow-dataflow.png

views/png/34-batch-processing-flow-dataflow.png
+

113. views/png/34-batch-processing-flow-domain.png

views/png/34-batch-processing-flow-domain.png
+

114. views/png/34-batch-processing-flow-full.png

views/png/34-batch-processing-flow-full.png
+

115. views/png/34-batch-processing-flow-infra.png

views/png/34-batch-processing-flow-infra.png
+

116. views/png/34-batch-processing-flow-overview.png

views/png/34-batch-processing-flow-overview.png
+

117. views/png/35-bootstrap-sequence-dataflow.png

views/png/35-bootstrap-sequence-dataflow.png
+

118. views/png/35-bootstrap-sequence-domain.png

views/png/35-bootstrap-sequence-domain.png
+

119. views/png/35-bootstrap-sequence-full.png

views/png/35-bootstrap-sequence-full.png
+

120. views/png/35-bootstrap-sequence-infra.png

views/png/35-bootstrap-sequence-infra.png
+

121. views/png/35-bootstrap-sequence-overview.png

views/png/35-bootstrap-sequence-overview.png
+

122. views/png/36-architecture-principles-mindmap-dataflow.png

views/png/36-architecture-principles-mindmap-dataflow.png
+

123. views/png/36-architecture-principles-mindmap-domain.png

views/png/36-architecture-principles-mindmap-domain.png
+

124. views/png/36-architecture-principles-mindmap-full.png

views/png/36-architecture-principles-mindmap-full.png
+

125. views/png/36-architecture-principles-mindmap-infra.png

views/png/36-architecture-principles-mindmap-infra.png
+

126. views/png/36-architecture-principles-mindmap-overview.png

views/png/36-architecture-principles-mindmap-overview.png
+

127. views/png/39-medallion-invariants-dataflow.png

views/png/39-medallion-invariants-dataflow.png
+

128. views/png/39-medallion-invariants-domain.png

views/png/39-medallion-invariants-domain.png
+

129. views/png/39-medallion-invariants-full.png

views/png/39-medallion-invariants-full.png
+

130. views/png/39-medallion-invariants-infra.png

views/png/39-medallion-invariants-infra.png
+

131. views/png/39-medallion-invariants-overview.png

views/png/39-medallion-invariants-overview.png
+

132. views/png/41-error-classification-tree-dataflow.png

views/png/41-error-classification-tree-dataflow.png
+

133. views/png/41-error-classification-tree-domain.png

views/png/41-error-classification-tree-domain.png
+

134. views/png/41-error-classification-tree-full.png

views/png/41-error-classification-tree-full.png
+

135. views/png/41-error-classification-tree-infra.png

views/png/41-error-classification-tree-infra.png
+

136. views/png/41-error-classification-tree-overview.png

views/png/41-error-classification-tree-overview.png
+

137. views/png/44-cross-provider-enrichment-dataflow.png

views/png/44-cross-provider-enrichment-dataflow.png
+

138. views/png/44-cross-provider-enrichment-domain.png

views/png/44-cross-provider-enrichment-domain.png
+

139. views/png/44-cross-provider-enrichment-full.png

views/png/44-cross-provider-enrichment-full.png
+

140. views/png/44-cross-provider-enrichment-infra.png

views/png/44-cross-provider-enrichment-infra.png
+

141. views/png/44-cross-provider-enrichment-overview.png

views/png/44-cross-provider-enrichment-overview.png
+

142. views/png/46-yaml-config-resolution-dataflow.png

views/png/46-yaml-config-resolution-dataflow.png
+

143. views/png/46-yaml-config-resolution-domain.png

views/png/46-yaml-config-resolution-domain.png
+

144. views/png/46-yaml-config-resolution-full.png

views/png/46-yaml-config-resolution-full.png
+

145. views/png/46-yaml-config-resolution-infra.png

views/png/46-yaml-config-resolution-infra.png
+

146. views/png/46-yaml-config-resolution-overview.png

views/png/46-yaml-config-resolution-overview.png
+

147. views/png/48-composite-phase-lifecycle-dataflow.png

views/png/48-composite-phase-lifecycle-dataflow.png
+

148. views/png/48-composite-phase-lifecycle-domain.png

views/png/48-composite-phase-lifecycle-domain.png
+

149. views/png/48-composite-phase-lifecycle-full.png

views/png/48-composite-phase-lifecycle-full.png
+

150. views/png/48-composite-phase-lifecycle-infra.png

views/png/48-composite-phase-lifecycle-infra.png
+

151. views/png/48-composite-phase-lifecycle-overview.png

views/png/48-composite-phase-lifecycle-overview.png
+

152. views/png/50-exception-hierarchy-dataflow.png

views/png/50-exception-hierarchy-dataflow.png
+

153. views/png/50-exception-hierarchy-domain.png

views/png/50-exception-hierarchy-domain.png
+

154. views/png/50-exception-hierarchy-full.png

views/png/50-exception-hierarchy-full.png
+

155. views/png/50-exception-hierarchy-infra.png

views/png/50-exception-hierarchy-infra.png
+

156. views/png/50-exception-hierarchy-overview.png

views/png/50-exception-hierarchy-overview.png
+ diff --git a/docs/02-architecture/mmd-diagrams/views-diagrams-catalog.pdf b/docs/02-architecture/mmd-diagrams/views-diagrams-catalog.pdf new file mode 100644 index 0000000000..019f4e2a26 Binary files /dev/null and b/docs/02-architecture/mmd-diagrams/views-diagrams-catalog.pdf differ diff --git a/docs/02-architecture/mmd-diagrams/views/00-legend.mermaid b/docs/02-architecture/mmd-diagrams/views/00-legend.mermaid index e8cfe77b27..43a37f995d 100644 --- a/docs/02-architecture/mmd-diagrams/views/00-legend.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/00-legend.mermaid @@ -13,6 +13,13 @@ flowchart TB LW7[" "] -->|"observability"| LW8[" "] LW9[" "] -->|"error / quarantine"| LW10[" "] end + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:2px linkStyle 1 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 linkStyle 2 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/01-full-system-component-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/01-full-system-component-dataflow.mermaid index cfdf9017c2..dc16eec251 100644 --- a/docs/02-architecture/mmd-diagrams/views/01-full-system-component-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/01-full-system-component-dataflow.mermaid @@ -27,7 +27,7 @@ flowchart TB N12["Silver"] end - N1 --> N3 + N1 ==> N3 N3 --> N4 N4 --> N2 N2 --> N5 @@ -40,6 +40,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/01-full-system-component-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/01-full-system-component-domain.mermaid index 29d4b59413..8af076081d 100644 --- a/docs/02-architecture/mmd-diagrams/views/01-full-system-component-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/01-full-system-component-domain.mermaid @@ -31,7 +31,7 @@ flowchart TB N13["TargetTransformer"] end - N1 --> N3 + N1 ==> N3 N1 --> N5 N1 --> N6 N3 --> N4 @@ -45,6 +45,12 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/01-full-system-component-full.mermaid b/docs/02-architecture/mmd-diagrams/views/01-full-system-component-full.mermaid index 0991530742..9341c6f69f 100644 --- a/docs/02-architecture/mmd-diagrams/views/01-full-system-component-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/01-full-system-component-full.mermaid @@ -25,25 +25,16 @@ %% @uniform width=272 groups=6 width_strategy=group %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'flowchart': { -%% 'nodeSpacing': 64, -%% 'rankSpacing': 72, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'DOWN', -%% 'spacing.nodeNode': 48, -%% 'spacing.edgeNode': 36, -%% 'spacing.edgeEdge': 24, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB %% keep-orphan: DQConfig, PipelineConfig, Publication, RuntimeConfig diff --git a/docs/02-architecture/mmd-diagrams/views/01-full-system-component-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/01-full-system-component-infra.mermaid index ab7d829aed..5756dd2cb0 100644 --- a/docs/02-architecture/mmd-diagrams/views/01-full-system-component-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/01-full-system-component-infra.mermaid @@ -46,4 +46,10 @@ flowchart TB style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/01-full-system-component-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/01-full-system-component-overview.mermaid index 10b83818dd..72b5f6d27c 100644 --- a/docs/02-architecture/mmd-diagrams/views/01-full-system-component-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/01-full-system-component-overview.mermaid @@ -59,6 +59,8 @@ flowchart TB classDef layer_composition fill:#fff7ed,stroke:#f59e0b,stroke-width:1.8px; classDef layer_interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:1.8px; classDef layer_external fill:#f1f5f9,stroke:#64748b,stroke-width:1.8px; + classDef service fill:#f0fdf4,stroke:#16a34a,stroke-width:1.6px; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1.4px,stroke-dasharray:3 2; class DSP,STP layer_domain; class RUN,EXEC,PROC layer_application; diff --git a/docs/02-architecture/mmd-diagrams/views/01-high-level-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/01-high-level-dataflow.mermaid index b8e24643c4..5f64f3125c 100644 --- a/docs/02-architecture/mmd-diagrams/views/01-high-level-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/01-high-level-dataflow.mermaid @@ -27,8 +27,8 @@ flowchart TB N10["Factory"] end - N4 --> N8 - N11 ==> N10 + N4 ==> N8 + N11 --> N10 N10 --> N9 N9 --> N7 N7 --> N12 @@ -42,6 +42,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/01-high-level-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/01-high-level-domain.mermaid index e6ba9eea55..5b6c7665a4 100644 --- a/docs/02-architecture/mmd-diagrams/views/01-high-level-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/01-high-level-domain.mermaid @@ -62,6 +62,13 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: data 0,6-10 | orchestration 3-4 | di 1,5 | generic 2 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:2px linkStyle 1 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/01-high-level-full.mermaid b/docs/02-architecture/mmd-diagrams/views/01-high-level-full.mermaid index c695493d1f..7f80fb6578 100644 --- a/docs/02-architecture/mmd-diagrams/views/01-high-level-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/01-high-level-full.mermaid @@ -11,7 +11,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=200 height=56 max_title_len=20 max_desc_lines=1 flowchart TD subgraph Sources["External Data Sources"] diff --git a/docs/02-architecture/mmd-diagrams/views/01-high-level-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/01-high-level-infra.mermaid index 46fa72cb3f..f0fc5fceb5 100644 --- a/docs/02-architecture/mmd-diagrams/views/01-high-level-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/01-high-level-infra.mermaid @@ -39,8 +39,8 @@ flowchart TB N10["CLI"] end - N9 --> N3 - N10 ==> N6 + N9 ==> N3 + N10 --> N6 N6 --> N2 N2 --> N7 N7 --> N5 @@ -56,6 +56,12 @@ flowchart TB style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/01-high-level-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/01-high-level-overview.mermaid index 470954ad9b..ff5481e09d 100644 --- a/docs/02-architecture/mmd-diagrams/views/01-high-level-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/01-high-level-overview.mermaid @@ -52,6 +52,13 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: data 0,6-10 | orchestration 1,3-5 | generic 2 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:2px linkStyle 1 stroke:#16a34a,stroke-width:2px linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/02-medallion-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/02-medallion-dataflow.mermaid index dbc3e54220..637e952725 100644 --- a/docs/02-architecture/mmd-diagrams/views/02-medallion-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/02-medallion-dataflow.mermaid @@ -19,5 +19,11 @@ flowchart TB N1 --> N4 N2 --> N5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/02-medallion-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/02-medallion-domain.mermaid index efa5ff8cb1..58e0dc704d 100644 --- a/docs/02-architecture/mmd-diagrams/views/02-medallion-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/02-medallion-domain.mermaid @@ -37,5 +37,11 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/02-medallion-full.mermaid b/docs/02-architecture/mmd-diagrams/views/02-medallion-full.mermaid index 06ccdcd588..486e86c4b3 100644 --- a/docs/02-architecture/mmd-diagrams/views/02-medallion-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/02-medallion-full.mermaid @@ -12,7 +12,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=224 height=56 max_title_len=23 max_desc_lines=1 flowchart LR subgraph Bronze["Bronze Layer"] diff --git a/docs/02-architecture/mmd-diagrams/views/02-medallion-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/02-medallion-infra.mermaid index 6d199dea47..18ada6f44e 100644 --- a/docs/02-architecture/mmd-diagrams/views/02-medallion-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/02-medallion-infra.mermaid @@ -27,5 +27,11 @@ flowchart TB N2 --> N3 N4 --> N5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/02-medallion-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/02-medallion-overview.mermaid index 652e3101dd..f9da7cf320 100644 --- a/docs/02-architecture/mmd-diagrams/views/02-medallion-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/02-medallion-overview.mermaid @@ -32,5 +32,11 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-dataflow.mermaid index c39d0a0e2d..68422dcf75 100644 --- a/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-dataflow.mermaid @@ -23,7 +23,7 @@ flowchart TB N12["Molecule"] end - N9 --> N11 + N9 ==> N11 N9 --> N12 N9 --> N10 N3 -.-> N2 @@ -35,6 +35,12 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-domain.mermaid index 663855095c..2085ebaf57 100644 --- a/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-domain.mermaid @@ -32,6 +32,12 @@ flowchart TB N4 --> N2 N4 --> N9 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-infra.mermaid index 0b51f37c5c..27d2c04777 100644 --- a/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-infra.mermaid @@ -45,6 +45,12 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-overview.mermaid index ea017edaa6..5ff6b8008e 100644 --- a/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-overview.mermaid @@ -47,6 +47,13 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: data 9-10 | di 4,6-8 | generic 0-3,5 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-dataflow.mermaid index 52552b24d6..9b223fbe7f 100644 --- a/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-dataflow.mermaid @@ -35,8 +35,8 @@ flowchart TB N11["CLI"] end - N7 --> N8 - N7 ==> N6 + N7 ==> N8 + N7 --> N6 N4 --> N1 N1 --> N2 N4 --> N9 @@ -51,6 +51,12 @@ flowchart TB style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-domain.mermaid index bc6a0c17db..5927496828 100644 --- a/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-domain.mermaid @@ -61,6 +61,13 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: orchestration 0,2-4,6-7 | di 1,5,9 | generic 8 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#16a34a,stroke-width:2px linkStyle 1 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 linkStyle 2 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-full.mermaid b/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-full.mermaid index f708569fad..f7637aead5 100644 --- a/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-full.mermaid @@ -11,6 +11,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) %% @uniform width=224 height=56 max_title_len=23 max_desc_lines=0 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB %% keep-orphan: Entities, Exceptions, Locking, Types diff --git a/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-infra.mermaid index b5363dfa27..094a53461c 100644 --- a/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-infra.mermaid @@ -61,6 +61,13 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: data 1,5,8 | orchestration 0,2-4,6-7 | di 9 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#16a34a,stroke-width:2px linkStyle 1 stroke:#1E293B,stroke-width:2px linkStyle 2 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-overview.mermaid index f34df68562..dd925582dc 100644 --- a/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/05-layers-interaction-overview.mermaid @@ -34,7 +34,7 @@ flowchart TB N7["CLI"] end - N1 --> N5 + N1 ==> N5 N1 --> N2 N3 --> N4 N4 --> N8 @@ -50,6 +50,12 @@ flowchart TB style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-dataflow.mermaid index 138fdf22ec..00aa7e280a 100644 --- a/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-dataflow.mermaid @@ -40,6 +40,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-domain.mermaid index ad2aa99291..989d8a9933 100644 --- a/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-domain.mermaid @@ -67,5 +67,12 @@ flowchart TB style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px %% linkStyle: primary=19 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 stroke:#1E293B,stroke-width:4px linkStyle 19,20 stroke:#7c3aed,stroke-width:3px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-infra.mermaid index 055bdf23b0..9a65545872 100644 --- a/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-infra.mermaid @@ -64,5 +64,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary=21 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 stroke:#1E293B,stroke-width:4px linkStyle 21,22 stroke:#7c3aed,stroke-width:3px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-overview.mermaid index 3e797c6495..0e01f54ba5 100644 --- a/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-overview.mermaid @@ -51,5 +51,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary=14 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13 stroke:#1E293B,stroke-width:4px linkStyle 14,15 stroke:#7c3aed,stroke-width:3px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-dataflow.mermaid index f46361f0ca..805a2634d0 100644 --- a/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-dataflow.mermaid @@ -23,7 +23,7 @@ flowchart TB N11["BatchMetricsRecorder"] end - N1 --> N7 + N1 ==> N7 N12 --> N1 N4 --> N3 N5 --> N3 @@ -37,6 +37,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-domain.mermaid index 2d38999a25..ec5dcf24e8 100644 --- a/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-domain.mermaid @@ -54,5 +54,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary=17 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 17,18 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-infra.mermaid index 20f22357be..4739ccc7c1 100644 --- a/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-infra.mermaid @@ -53,5 +53,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary=15 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 15,16 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-overview.mermaid index ca7f4e6e51..60225ba122 100644 --- a/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-overview.mermaid @@ -42,5 +42,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary=10 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 10,11 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-dataflow.mermaid index 0a732ce363..106aa86a1d 100644 --- a/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-dataflow.mermaid @@ -30,5 +30,12 @@ flowchart TB N8 --> N7 %% linkStyle: primary=11 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10 stroke:#1E293B,stroke-width:4px linkStyle 11,12 stroke:#7c3aed,stroke-width:3px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-domain.mermaid index 17166059d2..dd6417411f 100644 --- a/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-domain.mermaid @@ -54,5 +54,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary=16 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 16,17 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-infra.mermaid index efbf09ad13..9d18a7bc5e 100644 --- a/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-infra.mermaid @@ -54,5 +54,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary=16 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 16,17 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-overview.mermaid index 6aab121ef3..f0a26d5c47 100644 --- a/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-overview.mermaid @@ -46,5 +46,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary=14 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 14,15 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-dataflow.mermaid index 3726fc8f68..12fd2c013e 100644 --- a/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-dataflow.mermaid @@ -16,7 +16,7 @@ flowchart TB N11["B8"] N12["D7"] - N5 --> N1 + N5 ==> N1 N6 --> N1 N1 --> N2 N2 --> N3 @@ -26,6 +26,12 @@ flowchart TB N11 --> N8 N3 ==> N4 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-domain.mermaid index ddb692a94f..623cd29d0c 100644 --- a/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-domain.mermaid @@ -52,5 +52,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary=14 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13 stroke:#1E293B,stroke-width:4px linkStyle 14,15 stroke:#7c3aed,stroke-width:3px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-full.mermaid b/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-full.mermaid index f81323c2e0..684f5be385 100644 --- a/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-full.mermaid @@ -11,7 +11,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'},'layout':'elk','flowchart':{'curve':'linear'},'elk':{'nodePlacementStrategy':'BRANDES_KOEPF','mergeEdges':true,'edgeRouting':'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=352 height=56 max_title_len=39 max_desc_lines=1 flowchart TD %% keep-orphan: M1, M2, M3, M4, N1, N2, N3, N4, P1, P2 @@ -120,10 +130,69 @@ flowchart TD style Transform fill:#fff7ed style Validate fill:#ffe4e6 style Load fill:#f5f3ff - style Finalize fill:#f8fafc - style Parallel fill:#fefce8 + style Finalize fill:#ecfeff + style Parallel fill:#FFFDE7 - linkStyle 0,1,3,5,6,7,8,9,11,12,13,14,16,17,18,19,20,21,22,23,24,25,26,28,32,34,35,36,38,41,42,43,44,46,49,51,52,53,54,55,56 stroke:#1E293B,stroke-width:4px - linkStyle 2,4,39,45,48 stroke:#475569,stroke-width:2px,stroke-dasharray:5 - linkStyle 10,15,27,29,30,31,33,37,40 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 - linkStyle 47,50 stroke:#94A3B8,stroke-width:1px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#1E293B,stroke-width:4px + linkStyle 1 stroke:#1E293B,stroke-width:4px + linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 3 stroke:#1E293B,stroke-width:4px + linkStyle 4 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 5 stroke:#1E293B,stroke-width:4px + linkStyle 6 stroke:#1E293B,stroke-width:4px + linkStyle 7 stroke:#1E293B,stroke-width:4px + linkStyle 8 stroke:#1E293B,stroke-width:4px + linkStyle 9 stroke:#1E293B,stroke-width:4px + linkStyle 10 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 11 stroke:#1E293B,stroke-width:4px + linkStyle 12 stroke:#1E293B,stroke-width:4px + linkStyle 13 stroke:#1E293B,stroke-width:4px + linkStyle 14 stroke:#1E293B,stroke-width:4px + linkStyle 15 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 16 stroke:#1E293B,stroke-width:4px + linkStyle 17 stroke:#1E293B,stroke-width:4px + linkStyle 18 stroke:#1E293B,stroke-width:4px + linkStyle 19 stroke:#1E293B,stroke-width:4px + linkStyle 20 stroke:#1E293B,stroke-width:4px + linkStyle 21 stroke:#1E293B,stroke-width:4px + linkStyle 22 stroke:#1E293B,stroke-width:4px + linkStyle 23 stroke:#1E293B,stroke-width:4px + linkStyle 24 stroke:#1E293B,stroke-width:4px + linkStyle 25 stroke:#1E293B,stroke-width:4px + linkStyle 26 stroke:#1E293B,stroke-width:4px + linkStyle 27 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 28 stroke:#1E293B,stroke-width:4px + linkStyle 29 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 30 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 31 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 32 stroke:#1E293B,stroke-width:4px + linkStyle 33 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 34 stroke:#1E293B,stroke-width:4px + linkStyle 35 stroke:#1E293B,stroke-width:4px + linkStyle 36 stroke:#1E293B,stroke-width:4px + linkStyle 37 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 38 stroke:#1E293B,stroke-width:4px + linkStyle 39 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 40 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 41 stroke:#1E293B,stroke-width:4px + linkStyle 42 stroke:#1E293B,stroke-width:4px + linkStyle 43 stroke:#1E293B,stroke-width:4px + linkStyle 44 stroke:#1E293B,stroke-width:4px + linkStyle 45 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 46 stroke:#1E293B,stroke-width:4px + linkStyle 47 stroke:#94A3B8,stroke-width:1px + linkStyle 48 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 49 stroke:#1E293B,stroke-width:4px + linkStyle 50 stroke:#94A3B8,stroke-width:1px + linkStyle 51 stroke:#1E293B,stroke-width:4px + linkStyle 52 stroke:#1E293B,stroke-width:4px + linkStyle 53 stroke:#1E293B,stroke-width:4px + linkStyle 54 stroke:#1E293B,stroke-width:4px + linkStyle 55 stroke:#1E293B,stroke-width:4px + linkStyle 56 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-infra.mermaid index beed5d6172..91601c11c5 100644 --- a/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-infra.mermaid @@ -42,5 +42,12 @@ flowchart TB N12 --> N15 %% linkStyle: primary=14 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13 stroke:#1E293B,stroke-width:4px linkStyle 14,15 stroke:#7c3aed,stroke-width:3px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-overview.mermaid index bdeea6db87..5de283337d 100644 --- a/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-overview.mermaid @@ -25,7 +25,7 @@ flowchart TB N11["A8"] end - N9 --> N5 + N9 ==> N5 N10 --> N5 N5 --> N6 N6 --> N11 @@ -40,6 +40,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-dataflow.mermaid index 2f0458070a..72c9154b3b 100644 --- a/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-dataflow.mermaid @@ -26,7 +26,7 @@ flowchart TB N11["RunCompleted"] end - N1 --> N5 + N1 ==> N5 N1 --> N6 N1 --> N7 N1 ==> N8 @@ -41,6 +41,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-domain.mermaid index e914d08392..d4554479ad 100644 --- a/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-domain.mermaid @@ -56,6 +56,25 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: data 3 | orchestration 0-2 | di 4-14 - linkStyle 0,1,2 stroke:#16a34a,stroke-width:2px + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#16a34a,stroke-width:2px + linkStyle 1 stroke:#16a34a,stroke-width:2px + linkStyle 2 stroke:#16a34a,stroke-width:2px linkStyle 3 stroke:#1E293B,stroke-width:2px - linkStyle 4,5,6,7,8,9,10,11,12,13,14 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 4 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 5 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 6 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 7 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 8 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 9 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 10 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 11 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 12 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 13 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 14 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-full.mermaid b/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-full.mermaid index ab7c5cd311..97b8c7b294 100644 --- a/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-full.mermaid @@ -11,6 +11,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) %% @uniform width=240 height=126 max_title_len=25 max_desc_lines=5 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB %% keep-orphan: CheckpointPort, CriticalError, DataQualityError, DataSourcePort, HealthStatus, InvalidStateError, LockPort, Measurement, MetricsPort, QuarantinePort, RecoverableError, RunType, StoragePort, TracingPort @@ -26,11 +37,11 @@ flowchart TB end subgraph aggregates["aggregates/"] - Batch["Batch Aggregate
───────────────
• add_record()
• quarantine_record()
• seal()
• mark_committed()"] + Batch["Batch Aggregate
add_record(), quarantine_record()
seal(), mark_committed()"] - PipelineRun["PipelineRun Aggregate
───────────────
• start()
• record_stage_success()
• complete()
• fail()"] + PipelineRun["PipelineRun Aggregate
start(), record_stage_success()
complete(), fail()"] - QuarantineEntry["QuarantineEntry Aggregate
───────────────
• mark_retrying()
• mark_recovered()
• mark_dead_letter()
"] + QuarantineEntry["QuarantineEntry Aggregate
mark_retrying(), mark_recovered()
mark_dead_letter()"] end subgraph events["Domain Events"] @@ -43,16 +54,16 @@ flowchart TB end subgraph value_objects["value_objects/"] - RunID["RunID (UUID)




"] - BatchID["BatchID (UUID)




"] - EntityID["EntityID (str)




"] - ContentHash["ContentHash (str)




"] - Measurement["Measurement
(value, unit, relation)



"] + RunID["RunID (UUID)



"] + BatchID["BatchID (UUID)



"] + EntityID["EntityID (str)



"] + ContentHash["ContentHash (str)



"] + Measurement["Measurement
(value, unit, relation)


"] end subgraph types["types.py"] - RunType["RunType Enum
(INCREMENTAL, BACKFILL, REBUILD)



"] - HealthStatus["HealthStatus Enum
(HEALTHY, DEGRADED, UNHEALTHY)



"] + RunType["RunType Enum
(INCREMENTAL, BACKFILL, REBUILD)


"] + HealthStatus["HealthStatus Enum
(HEALTHY, DEGRADED, UNHEALTHY)


"] end subgraph exceptions["exceptions/"] @@ -92,6 +103,28 @@ flowchart TB R_RUNNING --> R_SHUTDOWN["SHUTDOWN"] end - linkStyle 0,1,2,4,5,6,7,8 stroke:#1E293B,stroke-width:4px - linkStyle 3,9,10,14,17 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 - linkStyle 11,12,13,15,16,18 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#1E293B,stroke-width:4px + linkStyle 1 stroke:#1E293B,stroke-width:4px + linkStyle 2 stroke:#1E293B,stroke-width:4px + linkStyle 3 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 4 stroke:#1E293B,stroke-width:4px + linkStyle 5 stroke:#1E293B,stroke-width:4px + linkStyle 6 stroke:#1E293B,stroke-width:4px + linkStyle 7 stroke:#1E293B,stroke-width:4px + linkStyle 8 stroke:#1E293B,stroke-width:4px + linkStyle 9 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 10 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 11 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 12 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 13 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 14 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 15 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 16 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 17 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 18 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-infra.mermaid index 88b710a587..b70a3e89e1 100644 --- a/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-infra.mermaid @@ -56,6 +56,26 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: data 3-5,10-15 | orchestration 0-2 | di 6-9 - linkStyle 0,1,2 stroke:#16a34a,stroke-width:2px - linkStyle 3,4,5,10,11,12,13,14,15 stroke:#1E293B,stroke-width:2px - linkStyle 6,7,8,9 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#16a34a,stroke-width:2px + linkStyle 1 stroke:#16a34a,stroke-width:2px + linkStyle 2 stroke:#16a34a,stroke-width:2px + linkStyle 3 stroke:#1E293B,stroke-width:2px + linkStyle 4 stroke:#1E293B,stroke-width:2px + linkStyle 5 stroke:#1E293B,stroke-width:2px + linkStyle 6 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 7 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 8 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 9 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 10 stroke:#1E293B,stroke-width:2px + linkStyle 11 stroke:#1E293B,stroke-width:2px + linkStyle 12 stroke:#1E293B,stroke-width:2px + linkStyle 13 stroke:#1E293B,stroke-width:2px + linkStyle 14 stroke:#1E293B,stroke-width:2px + linkStyle 15 stroke:#1E293B,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-overview.mermaid index a50892e382..55b26fdcba 100644 --- a/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/08-domain-ddd-overview.mermaid @@ -47,6 +47,22 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: data 3 | orchestration 0-2,7-11 | di 4-6 - linkStyle 0,1,2,7,8,9,10,11 stroke:#16a34a,stroke-width:2px + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#16a34a,stroke-width:2px + linkStyle 1 stroke:#16a34a,stroke-width:2px + linkStyle 2 stroke:#16a34a,stroke-width:2px linkStyle 3 stroke:#1E293B,stroke-width:2px - linkStyle 4,5,6 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 4 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 5 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 6 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 7 stroke:#16a34a,stroke-width:2px + linkStyle 8 stroke:#16a34a,stroke-width:2px + linkStyle 9 stroke:#16a34a,stroke-width:2px + linkStyle 10 stroke:#16a34a,stroke-width:2px + linkStyle 11 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-dataflow.mermaid index 57db0a39b8..dfa4183ebf 100644 --- a/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-dataflow.mermaid @@ -26,7 +26,7 @@ flowchart TB N9["UnifiedHTTPClient"] end - N8 -.-> N1 + N8 ==> N1 N8 --> N6 N11 --> N1 N12 --> N1 @@ -42,6 +42,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-domain.mermaid index 3dcdd58960..5522262f10 100644 --- a/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-domain.mermaid @@ -57,5 +57,12 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: primary=14 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 14,15 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-infra.mermaid index e8709e2709..a09bcf801c 100644 --- a/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-infra.mermaid @@ -53,5 +53,12 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: primary=11 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 11,12 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-overview.mermaid index 2d3e1b9421..c7b7796f50 100644 --- a/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-overview.mermaid @@ -52,5 +52,12 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: primary=15 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 15,16 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-dataflow.mermaid index e7887a960c..0edf948cc3 100644 --- a/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-dataflow.mermaid @@ -22,7 +22,7 @@ flowchart TB N6["CLI"] end - N9 --> N5 + N9 ==> N5 N10 --> N7 N11 --> N8 N12 --> N5 @@ -37,6 +37,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-domain.mermaid index e28bc83527..ba50323a08 100644 --- a/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-domain.mermaid @@ -59,6 +59,29 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: data 11-15,18 | di 0-9,16-17 | generic 10 - linkStyle 0,1,2,3,4,5,6,7,8,9,16,17 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 1 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 2 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 3 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 4 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 5 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 6 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 7 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 8 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 9 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 linkStyle 10 stroke:#475569,stroke-width:2px,stroke-dasharray:5 - linkStyle 11,12,13,14,15,18 stroke:#1E293B,stroke-width:2px + linkStyle 11 stroke:#1E293B,stroke-width:2px + linkStyle 12 stroke:#1E293B,stroke-width:2px + linkStyle 13 stroke:#1E293B,stroke-width:2px + linkStyle 14 stroke:#1E293B,stroke-width:2px + linkStyle 15 stroke:#1E293B,stroke-width:2px + linkStyle 16 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 17 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 18 stroke:#1E293B,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-full.mermaid b/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-full.mermaid index 96404e2765..f6084d45d0 100644 --- a/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-full.mermaid @@ -11,7 +11,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=200 height=56 max_title_len=20 max_desc_lines=1 flowchart TB subgraph External["External APIs"] @@ -89,13 +99,38 @@ flowchart TB chembl_activity --> Metrics %% Styling - style Bronze fill:#fff7ed,stroke:#f59e0b,color:#212121 - style Silver fill:#f8fafc,stroke:#475569,color:#212121 - style Gold fill:#fefce8,stroke:#ca8a04,color:#212121 - style Quarantine fill:#ffe4e6,stroke:#e11d48,color:#212121 - style MemoryLock fill:#eff6ff,stroke:#2563eb,color:#212121 + style Bronze fill:#CD7F32,color:#fff + style Silver fill:#C0C0C0,color:#000 + style Gold fill:#FFD700,color:#000 + style Quarantine fill:#e11d48,color:#fff + style MemoryLock fill:#4B7BEC,color:#fff - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,19,20 stroke:#475569,stroke-width:2px,stroke-dasharray:5 - linkStyle 15,16,17 stroke:#1E293B,stroke-width:4px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 3 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 4 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 5 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 6 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 7 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 8 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 9 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 10 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 11 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 12 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 13 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 14 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 15 stroke:#1E293B,stroke-width:4px + linkStyle 16 stroke:#1E293B,stroke-width:4px + linkStyle 17 stroke:#1E293B,stroke-width:4px linkStyle 18 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 - linkStyle 21,22 stroke:#94A3B8,stroke-width:1px + linkStyle 19 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 20 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 21 stroke:#94A3B8,stroke-width:1px + linkStyle 22 stroke:#94A3B8,stroke-width:1px diff --git a/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-infra.mermaid index 052387494a..09208d81d8 100644 --- a/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-infra.mermaid @@ -54,5 +54,12 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: primary=16 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 16,17 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-overview.mermaid index b761aea37b..b047556f36 100644 --- a/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-overview.mermaid @@ -49,5 +49,12 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: primary=12 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 12,13 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-dataflow.mermaid index f6de8e9934..5a5eca50bc 100644 --- a/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-dataflow.mermaid @@ -43,5 +43,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary=14 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13 stroke:#1E293B,stroke-width:4px linkStyle 14,15 stroke:#7c3aed,stroke-width:3px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-domain.mermaid index 5f91a7bd28..5c2ae16082 100644 --- a/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-domain.mermaid @@ -57,5 +57,12 @@ flowchart TB style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px %% linkStyle: primary=19 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 19,20 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-infra.mermaid index a6d561e8ff..77531d2cd0 100644 --- a/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-infra.mermaid @@ -62,5 +62,12 @@ flowchart TB style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px %% linkStyle: primary=19 edge(s) | secondary=2 edge(s) + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 19,20 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-overview.mermaid index 8f86a3ffef..c37293136e 100644 --- a/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/14-provider-health-states-overview.mermaid @@ -54,6 +54,29 @@ flowchart TB style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px %% linkStyle: orchestration 0-3,5-7,13-17 | di 4,8-9,11-12 | generic 10,18 - linkStyle 0,1,2,3,5,6,7,13,14,15,16,17 stroke:#16a34a,stroke-width:2px - linkStyle 4,8,9,11,12 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 - linkStyle 10,18 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#16a34a,stroke-width:2px + linkStyle 1 stroke:#16a34a,stroke-width:2px + linkStyle 2 stroke:#16a34a,stroke-width:2px + linkStyle 3 stroke:#16a34a,stroke-width:2px + linkStyle 4 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 5 stroke:#16a34a,stroke-width:2px + linkStyle 6 stroke:#16a34a,stroke-width:2px + linkStyle 7 stroke:#16a34a,stroke-width:2px + linkStyle 8 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 9 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 10 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 11 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 12 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 13 stroke:#16a34a,stroke-width:2px + linkStyle 14 stroke:#16a34a,stroke-width:2px + linkStyle 15 stroke:#16a34a,stroke-width:2px + linkStyle 16 stroke:#16a34a,stroke-width:2px + linkStyle 17 stroke:#16a34a,stroke-width:2px + linkStyle 18 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-full.mermaid b/docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-full.mermaid index 3705f8339d..b5e2c77a14 100644 --- a/docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-full.mermaid @@ -11,7 +11,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'},'layout':'elk','flowchart':{'curve':'linear'},'elk':{'nodePlacementStrategy':'BRANDES_KOEPF','mergeEdges':true,'edgeRouting':'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=288 height=56 max_title_len=31 max_desc_lines=1 flowchart TD %% keep-orphan: CFG1, CFG2, CFG3 diff --git a/docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-dataflow.mermaid index 0180fe78e8..fc8a0c4b87 100644 --- a/docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-dataflow.mermaid @@ -27,5 +27,11 @@ flowchart TB N9 --> N10 N10 --> N11 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9 stroke:#1E293B,stroke-width:4px linkStyle 10 stroke:#1E293B,stroke-width:4px,opacity:0.85 diff --git a/docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-full.mermaid b/docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-full.mermaid index ebd54e3ecb..db202b08e8 100644 --- a/docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-full.mermaid @@ -14,7 +14,17 @@ %% @png-scale 6 %% @png-dpi 600 -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=264 height=72 max_title_len=28 max_desc_lines=2 flowchart LR %% keep-orphan: LocalFS, S1, S10, S11, S12, S2, S4, S5, S6, S7, S8, S9 @@ -88,10 +98,10 @@ flowchart LR %% Styling style API fill:#eff6ff - style E3 fill:#fff7ed,stroke:#f59e0b,color:#212121 - style L1 fill:#f8fafc,stroke:#475569,color:#212121 - style L2 fill:#fefce8,stroke:#ca8a04,color:#212121 - style Q fill:#ffe4e6,stroke:#e11d48,color:#fff + style E3 fill:#CD7F32,color:#fff + style L1 fill:#C0C0C0,color:#000 + style L2 fill:#FFD700,color:#000 + style Q fill:#e11d48,color:#fff %% Activity Schema annotation subgraph Schema["Activity Silver Schema"] @@ -110,5 +120,27 @@ flowchart LR S12["_ingestion_ts: datetime

"] end - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 3 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 4 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 5 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 6 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 7 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 8 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 9 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 10 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 11 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 12 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 13 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 14 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 15 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 16 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 17 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-dataflow.mermaid index ccc2146b01..e94b6f2650 100644 --- a/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-dataflow.mermaid @@ -36,5 +36,11 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 9 stroke:#475569,stroke-width:2px,stroke-dasharray:5,opacity:0.85 diff --git a/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-full.mermaid b/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-full.mermaid index 57e7e002ca..6da5e582b0 100644 --- a/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-full.mermaid @@ -13,7 +13,17 @@ %% @png-scale 6 %% @png-dpi 600 -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=232 height=90 max_title_len=24 max_desc_lines=3 flowchart TB %% keep-orphan: CBP, FDSP, HCP, INP, MCP2, RLMP, SHP, SRLP diff --git a/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-infra.mermaid index 2b1972eba5..873a6167df 100644 --- a/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-infra.mermaid @@ -48,5 +48,11 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 13 stroke:#475569,stroke-width:2px,stroke-dasharray:5,opacity:0.85 diff --git a/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-overview.mermaid index 0b48372d35..8ca6211e8c 100644 --- a/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-overview.mermaid @@ -41,5 +41,11 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 10 stroke:#475569,stroke-width:2px,stroke-dasharray:5,opacity:0.85 diff --git a/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-dataflow.mermaid index 6bb20bf2a8..39ceb9f6e4 100644 --- a/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-dataflow.mermaid @@ -39,4 +39,10 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12 stroke:#1E293B,stroke-width:4px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-domain.mermaid index 7768bd0a3d..57043a3b7b 100644 --- a/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-domain.mermaid @@ -59,4 +59,10 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-full.mermaid b/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-full.mermaid index 9e4316a400..998e75b928 100644 --- a/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-full.mermaid @@ -24,76 +24,66 @@ %% @uniform-stats registry width=200 height=144 max_desc_lines=6 %% @uniform-stats created width=176 height=144 max_desc_lines=6 %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'themeVariables': {'lineWidth': '2'}, -%% 'flowchart': { -%% 'nodeSpacing': 64, -%% 'rankSpacing': 80, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'DOWN', -%% 'spacing.nodeNode': 52, -%% 'spacing.edgeNode': 36, -%% 'spacing.edgeEdge': 24, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB %% keep-orphan: OB subgraph Entry["Entry Point"] - CLI["CLI run command




"] - BOOT["bootstrap/runtime/assembly.py




"] + CLI["CLI run command

"] + BOOT["bootstrap/runtime/assembly.py

"] end subgraph Factories["Composition Factories"] direction LR subgraph LoggerFactories["Logger & Observability"] - BL["BootstrapLogger
• configure structlog



"] - DQF["DQServicesFactory
• create()
→ DQ analyzers + monitor


"] + BL["BootstrapLogger
• configure structlog

"] + DQF["DQServicesFactory
• create()
→ DQ analyzers + monitor

"] end subgraph ClientFactories["Client & Data Source"] - HCF["HttpClientFactory
• create(provider)
→ UnifiedHTTPClient


"] - DSF["DataSourceFactory
• create(provider, config)
→ DataSourcePort impl


"] + HCF["HttpClientFactory
• create(provider)
→ UnifiedHTTPClient

"] + DSF["DataSourceFactory
• create(provider, config)
→ DataSourcePort impl

"] end subgraph StorageFactories["Storage & Services"] - STF["StorageFactory
• create(config)
→ BronzeWriter + SilverWriter
+ GoldWriter

"] - STA["StorageAdapter
• create_bronze()
• create_silver()
• create_gold()

"] - SB["ServicesBuilder
• with_storage()
• with_lock()
• with_logger()
• with_metrics()
• build() → PipelineServices"] + STF["StorageFactory
• create(config)
→ Bronze/Silver/Gold writers
"] + STA["StorageAdapter
• create_bronze/silver/gold
"] + SB["ServicesBuilder
• wire storage/lock/obs
• build() → PipelineServices"] end subgraph PipelineFactories["Pipeline Construction"] - RF["RunnerFactory
• create_runner()
→ PipelineRunner


"] - GPF["GenericPipelineFactory
• _pipeline_class
• _transformer_class
• _gold_schema

"] + RF["RunnerFactory
• create_runner()
→ PipelineRunner

"] + GPF["GenericPipelineFactory
• pipeline/transformer/schema bindings
"] end end subgraph Registry["Registration"] - PR["ProviderRegistry
• 8 providers registered



"] - OB["ObservabilityBundle
• logger + metrics + tracing



"] + PR["ProviderRegistry
• 8 providers registered

"] + OB["ObservabilityBundle
• logger + metrics + tracing

"] end subgraph Created["Created Instances"] direction TB subgraph RuntimeInfra["Infra Instances"] direction TB - UHC["[A] UnifiedHTTPClient
+ TokenBucket
+ CircuitBreaker


"] - ADP["[A] Provider Adapter
(ChemblAdapter, etc.)



"] - BW["BronzeWriter




"] - SLL["StructlogLogger




"] + UHC["[A] UnifiedHTTPClient
+ TokenBucket
+ CircuitBreaker

"] + ADP["[A] Provider Adapter
(ChemblAdapter, etc.)

"] + BW["BronzeWriter

"] + SLL["StructlogLogger

"] end subgraph RuntimeCore["Application Instances"] direction TB - PS["PipelineServices
(frozen bundle)



"] - RUN["PipelineRunner
(fully assembled)



"] + PS["PipelineServices
(frozen bundle)

"] + RUN["PipelineRunner
(fully assembled)

"] end end @@ -151,6 +141,8 @@ flowchart TB classDef layer_infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:1.8px; classDef layer_composition fill:#fff7ed,stroke:#f59e0b,stroke-width:1.8px; classDef layer_interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:1.8px; + classDef service fill:#f0fdf4,stroke:#16a34a,stroke-width:1.6px; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1.4px,stroke-dasharray:3 2; class CLI layer_interfaces; class BOOT,BL,DQF,HCF,DSF,STF,STA,SB,RF,GPF,PR,OB layer_composition; diff --git a/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-infra.mermaid index 9a0adec285..4eb3b461e7 100644 --- a/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-infra.mermaid @@ -59,4 +59,10 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-overview.mermaid index 732dade521..41338e10c9 100644 --- a/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-overview.mermaid @@ -47,6 +47,8 @@ flowchart LR classDef layer_infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:1.8px; classDef layer_composition fill:#fff7ed,stroke:#f59e0b,stroke-width:1.8px; classDef layer_interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:1.8px; + classDef service fill:#f0fdf4,stroke:#16a34a,stroke-width:1.6px; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1.4px,stroke-dasharray:3 2; class RUN layer_application; class ADP,WR,OBS layer_infrastructure; diff --git a/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-dataflow.mermaid index 7c59fadb53..b2b567b097 100644 --- a/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-dataflow.mermaid @@ -41,6 +41,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-domain.mermaid index cab81181d3..a8e50ec86d 100644 --- a/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-domain.mermaid @@ -23,7 +23,7 @@ flowchart TB N19["ES4"] N20["MS"] - N8 --> N7 + N8 ==> N7 N7 --> N6 N6 --> N4 N4 --> N5 @@ -44,6 +44,12 @@ flowchart TB N17 --> N16 N18 --> N16 N19 --> N16 - N16 ==> N20 + N16 --> N20 - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21 stroke:#1E293B,stroke-width:4px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-full.mermaid b/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-full.mermaid index 4a9d848027..56eb14c748 100644 --- a/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-full.mermaid @@ -32,26 +32,16 @@ %% @uniform-stats gold width=240 height=112 max_desc_lines=4 %% @uniform-stats ckp width=264 height=112 max_desc_lines=4 %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'themeVariables': {'lineWidth': '2'}, -%% 'flowchart': { -%% 'nodeSpacing': 64, -%% 'rankSpacing': 80, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'DOWN', -%% 'spacing.nodeNode': 52, -%% 'spacing.edgeNode': 36, -%% 'spacing.edgeEdge': 24, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB subgraph Init["Phase 1: Initialization"] CFG["[S] Load CompositeConfig
from YAML

"] @@ -157,7 +147,9 @@ flowchart TB classDef layer_domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:1.8px; classDef layer_application fill:#f0fdf4,stroke:#16a34a,stroke-width:1.8px; classDef layer_infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:1.8px; - classDef layer_composition fill:#fff7ed,stroke:#f59e0b,stroke-width:1.8px; + classDef layer_composition fill:#fff7ed,stroke:#d97706,stroke-width:1.8px; + classDef service fill:#f0fdf4,stroke:#16a34a,stroke-width:1.6px; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1.4px,stroke-dasharray:3 2; class CFG,PFV,BOOT,SP,DC,DEP1,DEP2,KE,KEYS,EC,E1,E2,E3,E4,DD,MS,CO,CR,XV,CCM layer_application; class SB,DS1,DS2,ES1,ES2,ES3,ES4,GW,GT layer_infrastructure; diff --git a/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-infra.mermaid index aed8534750..db5a5eb4b2 100644 --- a/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-infra.mermaid @@ -30,8 +30,8 @@ flowchart TB N20["MS"] end - N8 --> N7 - N7 ==> N6 + N8 ==> N7 + N7 --> N6 N6 --> N4 N4 --> N5 N5 --> N9 @@ -56,4 +56,10 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21 stroke:#1E293B,stroke-width:4px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-overview.mermaid index e91f9e5890..a0d82f2a5d 100644 --- a/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-overview.mermaid @@ -24,6 +24,8 @@ flowchart LR classDef layer_application fill:#f0fdf4,stroke:#16a34a,stroke-width:1.8px; classDef layer_infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:1.8px; + classDef service fill:#f0fdf4,stroke:#16a34a,stroke-width:1.6px; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1.4px,stroke-dasharray:3 2; class CFG,PFV,SEED,DEP,KEYS,ENR,MERGE,CONTRACT,GW,CKP layer_application; class SS,GOLD layer_infrastructure; diff --git a/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-dataflow.mermaid index 80e7677154..af11906130 100644 --- a/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-dataflow.mermaid @@ -32,6 +32,12 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-domain.mermaid index 756ca47eb1..a74ea08093 100644 --- a/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-domain.mermaid @@ -44,6 +44,12 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-full.mermaid b/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-full.mermaid index 444bce327b..db351deb9e 100644 --- a/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-full.mermaid @@ -22,25 +22,16 @@ %% @uniform-stats adapters width=400 height=168 max_desc_lines=7 %% Tooltip: Nodes with aggregated adapter lists (e.g. A1/A21) are summarized; see provider docs for full breakdown. %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'flowchart': { -%% 'nodeSpacing': 72, -%% 'rankSpacing': 96, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'RIGHT', -%% 'spacing.nodeNode': 56, -%% 'spacing.edgeNode': 36, -%% 'spacing.edgeEdge': 26, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart LR subgraph Ports["Domain Ports (domain/ports/)"] direction TB diff --git a/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-infra.mermaid index 8818de8b32..5a36cc76b2 100644 --- a/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-infra.mermaid @@ -44,6 +44,12 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-dataflow.mermaid index b9f7d84492..1ad68e9ac6 100644 --- a/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-dataflow.mermaid @@ -27,9 +27,9 @@ flowchart TB N12["DRAINING"] end - N7 --> N5 + N7 ==> N5 N8 --> N9 - N8 ==> N5 + N8 --> N5 N9 --> N1 N1 --> N2 N2 --> N10 @@ -46,4 +46,10 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13 stroke:#1E293B,stroke-width:4px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-domain.mermaid index 5b6f51f746..bb12e0c08b 100644 --- a/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-domain.mermaid @@ -69,6 +69,13 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary 0-2,4-12,15-19,24,26 | quarantine 13-14 | shutdown 20-21 | failure 3,6,22-23,25 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,4,5,7,8,9,10,11,12,15,16,17,18,19,24,26 stroke:#1E293B,stroke-width:3px linkStyle 13,14 stroke:#7c3aed,stroke-width:2px,stroke-dasharray:5 linkStyle 20,21 stroke:#f59e0b,stroke-width:2px,stroke-dasharray:6 diff --git a/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-overview.mermaid index 165279c31e..83d2f8efde 100644 --- a/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-overview.mermaid @@ -57,6 +57,13 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary 0-1,3,5-10,12-14,20 | quarantine 11 | shutdown 15-16 | failure 2,4,17-19 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,3,5,6,7,8,9,10,12,13,14,20 stroke:#1E293B,stroke-width:3px linkStyle 11 stroke:#7c3aed,stroke-width:2px,stroke-dasharray:5 linkStyle 15,16 stroke:#f59e0b,stroke-width:2px,stroke-dasharray:6 diff --git a/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-dataflow.mermaid index eea1317654..f71a394647 100644 --- a/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-dataflow.mermaid @@ -28,5 +28,12 @@ flowchart TB N5 --> N8 %% linkStyle: primary 0-2,5-9 | routing 3-4 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,5,6,7,8,9 stroke:#1E293B,stroke-width:3px linkStyle 3,4 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-domain.mermaid index fc232425d4..a7282b3b53 100644 --- a/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-domain.mermaid @@ -53,6 +53,13 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary 0-8,11-15 | routing 9-10 | quarantine 16 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,11,12,13,14,15 stroke:#1E293B,stroke-width:3px linkStyle 9,10 stroke:#16a34a,stroke-width:2px linkStyle 16 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 diff --git a/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-full.mermaid b/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-full.mermaid index 63a6f63520..cb9d949835 100644 --- a/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-full.mermaid @@ -12,7 +12,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=304 height=108 max_title_len=33 max_desc_lines=4 flowchart TB subgraph Source["1. External API"] @@ -20,7 +30,7 @@ flowchart TB end subgraph Bronze["2. Bronze Layer"] - BW["BronzeWriter.write_bronze()
• JSONL serialization
• zstd compression
• atomic rename
• _manifest.json"] + BW["BronzeWriter.write_bronze()
JSONL + zstd + atomic rename
manifest update"] BF[("Bronze File
bronze/chembl/activity/
2026-02-17/batch_001.jsonl.zst"

)] end @@ -28,7 +38,7 @@ flowchart TB BT["BatchTransformer.transform()



"] TI["BaseTransformer._transform_impl()
(e.g., ActivityTransformer)


"] NORM["Data Normalization
• NaN → null
• strip strings
• dates → ISO
• floats → round(10)"] - META["Add Metadata
• _run_id (UUID)
• _run_type (incremental/backfill)
• _source_batch_id (FK)
• _ingestion_ts (UTC now)"] + META["Add Metadata
_run_id, _run_type
_source_batch_id, _ingestion_ts"] HASH["Compute _content_hash
• exclude META_FIELDS
• canonical JSON (sort_keys)
• sha256 digest
"] end @@ -45,12 +55,12 @@ flowchart TB end subgraph Silver["6. Silver Layer"] - SW["SilverWriter.write_silver()
• merge/upsert by PK
• content_hash dedup
• Delta Lake transaction
"] + SW["SilverWriter.write_silver()
merge/upsert by PK
content_hash dedup + Delta tx"] ST[("Silver Table
silver/chembl/activity/
_delta_log/"

)] end subgraph GoldLayer["7. Gold Layer"] - TFG["transform_for_gold()
• exclude JSON fields
(molecule_properties,
molecule_structures, etc.)
"] + TFG["transform_for_gold()
exclude bulky JSON fields
for Gold contract"] GV["PanderaGoldValidator.validate()
ChEMBLActivityGoldSchema
(strict mode)

"] GW["GoldWriter.write_gold()



"] GT[("Gold Table
gold/chembl/activity/
_delta_log/"

)] @@ -78,10 +88,26 @@ flowchart TB QUAR --> QT %% Styling - style Bronze fill:#fff7ed,stroke:#f59e0b,color:#000 - style Silver fill:#f8fafc,stroke:#475569,color:#000 - style GoldLayer fill:#fefce8,stroke:#ca8a04,color:#000 - style QuarDB fill:#ffe4e6,stroke:#e11d48,color:#000 + style Bronze fill:#FFA500,stroke:#cc8400,color:#000 + style Silver fill:#C0C0C0,stroke:#808080,color:#000 + style GoldLayer fill:#FFD700,stroke:#ccac00,color:#000 + style QuarDB fill:#e11d48,stroke:#cc4444,color:#000 - linkStyle 0,1,2,7,8,9,10,11 stroke:#1E293B,stroke-width:4px - linkStyle 3,4,5,6 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#1E293B,stroke-width:4px + linkStyle 1 stroke:#1E293B,stroke-width:4px + linkStyle 2 stroke:#1E293B,stroke-width:4px + linkStyle 3 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 4 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 5 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 6 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + linkStyle 7 stroke:#1E293B,stroke-width:4px + linkStyle 8 stroke:#1E293B,stroke-width:4px + linkStyle 9 stroke:#1E293B,stroke-width:4px + linkStyle 10 stroke:#1E293B,stroke-width:4px + linkStyle 11 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-infra.mermaid index b3cb5c955a..1c7eaa2847 100644 --- a/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-infra.mermaid @@ -43,6 +43,13 @@ flowchart TB N19 --> N20 %% linkStyle: primary 0-8,11-15 | routing 9-10 | quarantine 16 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,11,12,13,14,15 stroke:#1E293B,stroke-width:3px linkStyle 9,10 stroke:#16a34a,stroke-width:2px linkStyle 16 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 diff --git a/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-overview.mermaid index c05a8fda3a..0807a328fb 100644 --- a/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/32-single-record-journey-overview.mermaid @@ -44,5 +44,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: primary 0-6,9-12 | routing 7-8 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,9,10,11,12 stroke:#1E293B,stroke-width:3px linkStyle 7,8 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-dataflow.mermaid index 924ff854bf..39175b3e5f 100644 --- a/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-dataflow.mermaid @@ -53,6 +53,13 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: orchestration 0,19 | di 3-7 | primary 1-2,8-18 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,19 stroke:#16a34a,stroke-width:2px linkStyle 3,4,5,6,7 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 linkStyle 1,2,8,9,10,11,12,13,14,15,16,17,18 stroke:#1E293B,stroke-width:3px diff --git a/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-domain.mermaid index f2d415cc34..4ec0ee3fab 100644 --- a/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-domain.mermaid @@ -69,6 +69,13 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: orchestration 0,27 | di 1-11,13-14,16-18,20,22-25 | generic 12,15,19,21,26 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,27 stroke:#16a34a,stroke-width:2px linkStyle 1,2,3,4,5,6,7,8,9,10,11,13,14,16,17,18,20,22,23,24,25 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 linkStyle 12,15,19,21,26 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-infra.mermaid index ecb91e488a..80277c3ae5 100644 --- a/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-infra.mermaid @@ -74,6 +74,13 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: data 1-4,6-13,15-26 | orchestration 0,27 | di 5,14 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,27 stroke:#16a34a,stroke-width:2px linkStyle 1,2,3,4,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26 stroke:#1E293B,stroke-width:2px linkStyle 5,14 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-overview.mermaid index 416ce2fee4..de234abc50 100644 --- a/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-overview.mermaid @@ -58,6 +58,13 @@ flowchart TB style Interfaces fill:#eff6ff,stroke:#2563eb,stroke-width:2px %% linkStyle: orchestration 0,21 | di 4-6,10-12 | primary 1-3,7-9,13-20 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,21 stroke:#16a34a,stroke-width:2px linkStyle 4,5,6,10,11,12 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 linkStyle 1,2,3,7,8,9,13,14,15,16,17,18,19,20 stroke:#1E293B,stroke-width:3px diff --git a/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-dataflow.mermaid index 6d918176e3..0db1bde6b2 100644 --- a/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-dataflow.mermaid @@ -48,4 +48,10 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 stroke:#1E293B,stroke-width:4px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-domain.mermaid index 89c6c1c1fb..4af37362b9 100644 --- a/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-domain.mermaid @@ -65,5 +65,11 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 stroke:#1E293B,stroke-width:4px linkStyle 24 stroke:#1E293B,stroke-width:4px,opacity:0.85 diff --git a/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-infra.mermaid index 7ce39f1979..7fb3868d2d 100644 --- a/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-infra.mermaid @@ -65,5 +65,11 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 stroke:#1E293B,stroke-width:4px linkStyle 24 stroke:#1E293B,stroke-width:4px,opacity:0.85 diff --git a/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-overview.mermaid index fc8759ac32..6746b03c3b 100644 --- a/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-overview.mermaid @@ -29,11 +29,11 @@ flowchart TB N3["BW"] end - N4 --> N1 + N4 ==> N1 N1 --> N5 N1 --> N6 N1 --> N8 - N1 ==> N9 + N1 --> N9 N6 --> N1 N1 --> N2 N2 --> N13 @@ -54,4 +54,10 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 stroke:#1E293B,stroke-width:4px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-dataflow.mermaid index 051c05aa1d..a7732a8861 100644 --- a/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-dataflow.mermaid @@ -15,7 +15,7 @@ flowchart TB N11["S4F"] N12["S6A"] - N2 --> N1 + N2 ==> N1 N1 --> N3 N3 --> N4 N4 --> N5 @@ -27,6 +27,12 @@ flowchart TB N8 --> N9 N9 ==> N12 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-domain.mermaid index 2ec43bb77d..8e3fb22714 100644 --- a/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-domain.mermaid @@ -23,7 +23,7 @@ flowchart TB N19["S8B"] N20["S8C"] - N2 --> N1 + N2 ==> N1 N1 --> N3 N3 --> N4 N4 --> N5 @@ -43,6 +43,12 @@ flowchart TB N17 --> N16 N18 --> N16 N16 --> N19 - N19 ==> N20 + N19 --> N20 - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-full.mermaid b/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-full.mermaid index cc699517df..c287f311b9 100644 --- a/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-full.mermaid @@ -11,7 +11,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'},'layout':'elk','flowchart':{'curve':'linear'},'elk':{'nodePlacementStrategy':'BRANDES_KOEPF','mergeEdges':true,'edgeRouting':'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=328 height=56 max_title_len=36 max_desc_lines=1 flowchart TB subgraph Step1["Step 1: Logger"] @@ -102,5 +112,11 @@ flowchart TB style Step8 fill:#ffe4e6,stroke:#dc2626 style Step9 fill:#f0fdf4,stroke:#16a34a + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 18 stroke:#475569,stroke-width:2px,stroke-dasharray:5,opacity:0.85 diff --git a/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-infra.mermaid index 8b7af19de2..b09a028f43 100644 --- a/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-infra.mermaid @@ -23,7 +23,7 @@ flowchart TB N19["S8B"] N20["S8C"] - N2 --> N1 + N2 ==> N1 N1 --> N3 N3 --> N4 N4 --> N5 @@ -43,6 +43,12 @@ flowchart TB N17 --> N16 N18 --> N16 N16 --> N19 - N19 ==> N20 + N19 --> N20 - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-overview.mermaid index 2a27403c01..bc758ce9e7 100644 --- a/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-overview.mermaid @@ -18,7 +18,7 @@ flowchart TB N14["S7C"] N15["S8A"] - N3 --> N4 + N3 ==> N4 N4 --> N5 N6 --> N1 N7 --> N1 @@ -32,6 +32,12 @@ flowchart TB N11 --> N14 N12 --> N15 N13 --> N15 - N14 ==> N15 + N14 --> N15 - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-dataflow.mermaid index 1ccb71210e..787f12c4aa 100644 --- a/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-dataflow.mermaid @@ -30,7 +30,7 @@ flowchart TB N9["PipelineRegistry"] end - N1 --> N2 + N1 ==> N2 N2 --> N3 N3 --> N4 N4 --> N5 @@ -47,6 +47,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-domain.mermaid index a3e720c321..06df9b3bf6 100644 --- a/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-domain.mermaid @@ -35,7 +35,7 @@ flowchart TB N20["GenericPipelineFactory"] end - N1 -.-> N6 + N1 ==> N6 N1 --> N7 N1 --> N8 N1 --> N9 @@ -51,6 +51,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-infra.mermaid index cdbc80f7a7..7713743eeb 100644 --- a/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-infra.mermaid @@ -45,6 +45,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-overview.mermaid index 135e1b9564..90234d9bf3 100644 --- a/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-overview.mermaid @@ -54,7 +54,24 @@ flowchart TB style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px %% linkStyle: data 2 | orchestration 0,3,5-8,11-13 | di 1,9 | generic 4,10 - linkStyle 0,3,5,6,7,8,11,12,13 stroke:#16a34a,stroke-width:2px - linkStyle 1,9 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#16a34a,stroke-width:2px + linkStyle 1 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 linkStyle 2 stroke:#1E293B,stroke-width:2px - linkStyle 4,10 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 3 stroke:#16a34a,stroke-width:2px + linkStyle 4 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 5 stroke:#16a34a,stroke-width:2px + linkStyle 6 stroke:#16a34a,stroke-width:2px + linkStyle 7 stroke:#16a34a,stroke-width:2px + linkStyle 8 stroke:#16a34a,stroke-width:2px + linkStyle 9 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 10 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 11 stroke:#16a34a,stroke-width:2px + linkStyle 12 stroke:#16a34a,stroke-width:2px + linkStyle 13 stroke:#16a34a,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-dataflow.mermaid index 6376858c8b..872d2909e5 100644 --- a/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-dataflow.mermaid @@ -15,7 +15,7 @@ flowchart TB N11["B3"] N12["B1"] - N2 --> N1 + N2 ==> N1 N3 --> N1 N4 --> N1 N8 --> N6 @@ -25,6 +25,12 @@ flowchart TB N10 --> N11 N5 ==> N1 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-domain.mermaid index 81552641bc..afacbce47d 100644 --- a/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-domain.mermaid @@ -24,7 +24,7 @@ flowchart TB N19["R4"] N20["E3"] - N4 --> N3 + N4 ==> N3 N5 --> N3 N6 --> N3 N10 --> N8 @@ -37,6 +37,12 @@ flowchart TB N16 --> N17 N17 --> N19 N7 --> N3 - N2 ==> N1 + N2 --> N1 - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13 stroke:#1E293B,stroke-width:4px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-full.mermaid b/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-full.mermaid index 3f880269b4..0669092992 100644 --- a/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-full.mermaid @@ -12,7 +12,17 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=256 height=90 max_title_len=27 max_desc_lines=3 flowchart TB %% keep-orphan: E3, E4 @@ -55,7 +65,7 @@ flowchart TB end subgraph Bronze["Bronze Layer (Always Append)"] - BZ["BronzeWriter.write_bronze()
• ALWAYS append-only
• Never cleared by run_type
• 90-day retention policy"] + BZ["BronzeWriter.write_bronze()
append-only, never cleared by run_type
90-day retention policy"] end %% Flow @@ -81,8 +91,24 @@ flowchart TB style IncPath fill:#f0fdf4,stroke:#16a34a style BFPath fill:#fff7ed,stroke:#f59e0b style RBPath fill:#ffe4e6,stroke:#dc2626 - style Bronze fill:#fff7ed,stroke:#f59e0b,color:#000 + style Bronze fill:#FFA500,stroke:#cc8400,color:#000 style Policy fill:#eff6ff,stroke:#2563eb - linkStyle 0,1,2,3,4,5,6,7,8 stroke:#1E293B,stroke-width:4px - linkStyle 9,10,11 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#1E293B,stroke-width:4px + linkStyle 1 stroke:#1E293B,stroke-width:4px + linkStyle 2 stroke:#1E293B,stroke-width:4px + linkStyle 3 stroke:#1E293B,stroke-width:4px + linkStyle 4 stroke:#1E293B,stroke-width:4px + linkStyle 5 stroke:#1E293B,stroke-width:4px + linkStyle 6 stroke:#1E293B,stroke-width:4px + linkStyle 7 stroke:#1E293B,stroke-width:4px + linkStyle 8 stroke:#1E293B,stroke-width:4px + linkStyle 9 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 10 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle 11 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-infra.mermaid index 4f2204b7e7..2090df69e9 100644 --- a/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-infra.mermaid @@ -31,7 +31,7 @@ flowchart TB N20["E3"] end - N2 --> N1 + N2 ==> N1 N3 --> N1 N4 --> N1 N8 --> N6 @@ -44,9 +44,15 @@ flowchart TB N14 --> N15 N15 --> N17 N5 --> N1 - N18 ==> N19 + N18 --> N19 style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13 stroke:#1E293B,stroke-width:4px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-overview.mermaid index df17866139..eaac90317a 100644 --- a/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-overview.mermaid @@ -18,7 +18,7 @@ flowchart TB N14["B1"] N15["B4"] - N1 --> N2 + N1 ==> N2 N3 --> N2 N4 --> N2 N12 --> N6 @@ -30,6 +30,12 @@ flowchart TB N10 --> N11 N5 ==> N2 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-dataflow.mermaid index f4ee64b5a0..e32e462ef8 100644 --- a/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-dataflow.mermaid @@ -26,8 +26,8 @@ flowchart TB N12["classify"] end - N8 --> N7 - N8 ==> N10 + N8 ==> N7 + N8 --> N10 N8 --> N9 N7 --> N11 N7 --> N12 @@ -40,6 +40,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 linkStyle 1 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 linkStyle 2 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 diff --git a/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-domain.mermaid index a40797ae4a..30a5b530fd 100644 --- a/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-domain.mermaid @@ -34,12 +34,12 @@ flowchart TB N18["LOCK"] end - N1 --> N5 + N1 ==> N5 N1 --> N2 N1 --> N6 N5 --> N7 N5 --> N8 - N5 ==> N9 + N5 --> N9 N6 --> N10 N17 --> N16 N12 --> N11 @@ -55,4 +55,10 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 diff --git a/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-full.mermaid b/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-full.mermaid index 2986254f96..b2728b63bc 100644 --- a/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-full.mermaid @@ -25,26 +25,16 @@ %% @uniform-stats root width=144 height=112 max_desc_lines=4 %% @uniform-stats actions width=168 height=112 max_desc_lines=4 %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'themeVariables': {'lineWidth': '2'}, -%% 'flowchart': { -%% 'nodeSpacing': 60, -%% 'rankSpacing': 76, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'DOWN', -%% 'spacing.nodeNode': 48, -%% 'spacing.edgeNode': 34, -%% 'spacing.edgeEdge': 22, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% flowchart TB ERROR["Error Occurred


"] @@ -53,9 +43,9 @@ flowchart TB ERROR --> INFRA{{"Infrastructure Error?"}} %% HTTP errors - HTTP -->|"auth"| AUTH["[E] ServiceAuthenticationError\n(CriticalError)\n→ FAIL FAST, no retry\n→ Check API key config"] + HTTP -->|"auth"| AUTH["[E] ServiceAuthenticationError\n(CriticalError)\n→ FAIL FAST\n→ Verify API key"] HTTP -->|"404"| NOTFOUND["[E] ApiError\n(RecoverableError)\n→ Log warning\n→ Skip entity"] - HTTP -->|"429"| RATE["[E] RateLimitExceededError\n(RecoverableError)\n→ Check Retry-After header\n→ Exponential backoff"] + HTTP -->|"429"| RATE["[E] RateLimitExceededError\n(RecoverableError)\n→ Honor Retry-After\n→ Backoff"] HTTP -->|"5xx"| SERVER["[E] ServiceUnavailableError\n(RecoverableError)\n→ Retry with backoff\n→ Max 3 attempts"] HTTP -.->|"other"| UNKNOWN_HTTP["[E] ExternalServiceError\n→ Log, classify, retry"] @@ -69,7 +59,7 @@ flowchart TB INFRA -->|"lock-lost"| LOCK["[E] LockLostError\n(CriticalError)\n→ ABORT immediately\n→ No partial write"] INFRA -->|"lock-timeout"| LOCKACQ["[E] LockAcquisitionError\n(CriticalError)\n→ FAIL, another instance running"] INFRA -->|"storage"| STORE["[E] StorageError\n(RecoverableError)\n→ Retry Delta write"] - INFRA -->|"cb-open"| CB["[E] CircuitBreakerOpenError\n(RecoverableError)\n→ Wait recovery_timeout (300s)\n→ HALF_OPEN probe"] + INFRA -->|"cb-open"| CB["[E] CircuitBreakerOpenError\n(RecoverableError)\n→ Wait recovery timeout\n→ HALF_OPEN"] %% Branch groups subgraph HTTPBranch["HTTP Branch Outcomes"] @@ -138,6 +128,8 @@ flowchart TB classDef layer_application fill:#f0fdf4,stroke:#16a34a,stroke-width:1.8px; classDef layer_infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:1.8px; classDef layer_external fill:#eff6ff,stroke:#2563eb,stroke-width:1.8px; + classDef service fill:#f0fdf4,stroke:#16a34a,stroke-width:1.6px; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1.4px,stroke-dasharray:3 2; class DOMAIN,SCHEMA,MISSING,FORMAT,DQTHRESH layer_domain; class INFRA,LOCK,LOCKACQ,STORE,CB layer_infrastructure; diff --git a/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-infra.mermaid index 1f5668b79f..9953b82f42 100644 --- a/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-infra.mermaid @@ -30,8 +30,8 @@ flowchart TB N20["SERVER"] end - N6 --> N1 - N6 ==> N8 + N6 ==> N1 + N6 --> N8 N6 --> N7 N1 --> N9 N1 --> N10 @@ -50,4 +50,10 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 diff --git a/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-overview.mermaid index 96fbeda5c9..85346f9302 100644 --- a/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-overview.mermaid @@ -36,6 +36,8 @@ flowchart TB classDef layer_application fill:#f0fdf4,stroke:#16a34a,stroke-width:1.8px; classDef layer_infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:1.8px; classDef layer_external fill:#eff6ff,stroke:#2563eb,stroke-width:1.8px; + classDef service fill:#f0fdf4,stroke:#16a34a,stroke-width:1.6px; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1.4px,stroke-dasharray:3 2; class DOMAIN,QUAR,BATCH layer_domain; class INFRA layer_infrastructure; diff --git a/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-dataflow.mermaid index d0360cd0fe..ca5f2ab53d 100644 --- a/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-dataflow.mermaid @@ -23,7 +23,7 @@ flowchart TB N12["PMS"] end - N3 --> N2 + N3 ==> N2 N2 --> N1 N9 --> N8 N8 --> N7 @@ -36,6 +36,12 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-domain.mermaid index 1543438797..45502a862f 100644 --- a/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-domain.mermaid @@ -50,4 +50,10 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-full.mermaid b/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-full.mermaid index 3a65562ac3..bc96ee8199 100644 --- a/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-full.mermaid @@ -12,47 +12,57 @@ %% @type flowchart %% @level Mixed (System / Component / Class) -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=336 height=162 max_title_len=37 max_desc_lines=7 flowchart LR subgraph ChEMBL["ChEMBL (Seed)"] - CA["ChemblAdapter
/document endpoint





"] - CT["PublicationTransformer






"] - CS[("Silver
chembl/publication"





)] + CA["ChemblAdapter
/document endpoint"] + CT["PublicationTransformer"] + CS[("Silver
chembl/publication")] end subgraph CrossRef["CrossRef (Enricher)"] - CRA["CrossRefAdapter
/works?filter=doi:...





"] - CRT["CrossRefPublicationTransformer






"] - CRS[("Silver
crossref/publication"





)] + CRA["CrossRefAdapter
/works?filter=doi:..."] + CRT["CrossRefPublicationTransformer"] + CRS[("Silver
crossref/publication")] end subgraph PubMed["PubMed (Enricher)"] - PMA["PubMedAdapter
efetch(PMIDs)





"] - PMT["PubMedPublicationTransformer






"] - PMS[("Silver
pubmed/publication"





)] + PMA["PubMedAdapter
efetch(PMIDs)"] + PMT["PubMedPublicationTransformer"] + PMS[("Silver
pubmed/publication")] end subgraph OpenAlex["OpenAlex (Enricher)"] - OAA["OpenAlexAdapter
/works?filter=doi:...





"] - OAT["OpenAlexPublicationTransformer






"] - OAS[("Silver
openalex/publication"





)] + OAA["OpenAlexAdapter
/works?filter=doi:..."] + OAT["OpenAlexPublicationTransformer"] + OAS[("Silver
openalex/publication")] end subgraph S2["Semantic Scholar (Enricher)"] - SSA["SemanticScholarAdapter
/paper/batch





"] - SST["SemanticScholarPublicationTransformer






"] - S2S[("Silver
semanticscholar/publication"





)] + SSA["SemanticScholarAdapter
/paper/batch"] + SST["SemanticScholarPublicationTransformer"] + S2S[("Silver
semanticscholar/publication")] end subgraph Merge["Merge Phase"] - MS["MergeService
LEFT OUTER JOIN
conflict: coalesce




"] - FIELDS["Field Groups:
• ID_AND_STATUS
• BIBLIOGRAPHY
• AUTHOR
• TERMS
• CITATIONS
• DATES
• PUB_TYPES"] + MS["MergeService
LEFT OUTER JOIN
conflict: coalesce"] + FIELDS["Field Groups
ID_STATUS, BIBLIOGRAPHY, AUTHOR
TERMS, CITATIONS, DATES, PUB_TYPES"] end subgraph Gold["Gold Output"] - GS["CompositePublicationGoldSchema
(Pandera strict validation)





"] - GT[("Gold
composite/publication"





)] + GS["CompositePublicationGoldSchema
(Pandera strict validation)"] + GT[("Gold
composite/publication")] end %% Flows @@ -62,7 +72,7 @@ flowchart LR OAA --> OAT --> OAS SSA --> SST --> S2S - CS ==>|K27| MS + CS -->|K27| MS CRS -->|K28| MS PMS -->|K29| MS OAS -->|K30| MS @@ -72,8 +82,14 @@ flowchart LR FIELDS --> GS --> GT %% Styling - style ChEMBL fill:#fff7ed,stroke:#f59e0b,color:#000 - style Merge fill:#f8fafc,stroke:#475569,color:#000 - style Gold fill:#fefce8,stroke:#ca8a04,color:#000 + style ChEMBL fill:#FFA500,stroke:#cc8400,color:#000 + style Merge fill:#C0C0C0,stroke:#808080,color:#000 + style Gold fill:#FFD700,stroke:#ccac00,color:#000 - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-infra.mermaid index d0845324ee..13601d46b8 100644 --- a/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-infra.mermaid @@ -30,7 +30,7 @@ flowchart TB N20["ninstitutions"] end - N3 --> N2 + N3 ==> N2 N2 --> N1 N9 --> N8 N8 --> N7 @@ -38,7 +38,7 @@ flowchart TB N13 --> N12 N19 --> N18 N18 --> N17 - N1 ==> N4 + N1 --> N4 N1 --> N5 N1 --> N6 N7 --> N10 @@ -50,4 +50,10 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-overview.mermaid index 095d13e235..0b8a09c0ce 100644 --- a/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-overview.mermaid @@ -25,7 +25,7 @@ flowchart TB N15["references"] end - N1 --> N2 + N1 ==> N2 N3 --> N4 N5 --> N6 N7 --> N8 @@ -39,6 +39,12 @@ flowchart TB style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-dataflow.mermaid index 0bc237a700..4575b634a8 100644 --- a/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-dataflow.mermaid @@ -36,6 +36,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-domain.mermaid index bf503f53ce..990633738d 100644 --- a/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-domain.mermaid @@ -44,6 +44,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-full.mermaid b/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-full.mermaid index d1b825c737..d8eff8fb25 100644 --- a/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-full.mermaid @@ -15,25 +15,16 @@ %% @png-dpi 600 %%{init: { -%% 'layout': 'elk', -%% 'theme': 'base', -%% 'flowchart': { -%% 'nodeSpacing': 56, -%% 'rankSpacing': 84, -%% 'padding': 24, -%% 'curve': 'linear' -%% }, -%% 'elk': { -%% 'mergeEdges': true, -%% 'nodePlacementStrategy': 'BRANDES_KOEPF', -%% 'cycleBreakingStrategy': 'GREEDY', -%% 'direction': 'DOWN', -%% 'spacing.nodeNode': 44, -%% 'spacing.edgeNode': 34, -%% 'spacing.edgeEdge': 24, -%% 'edgeRouting': 'ORTHOGONAL' -%% } -%%}}%% + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL' + } +}}%% %% @uniform width=420 height=108 max_title_len=49 max_desc_lines=4 flowchart TD %% keep-orphan: SOURCE_YAML_CFG diff --git a/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-infra.mermaid index 24f181ab49..6ee4db8f05 100644 --- a/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-infra.mermaid @@ -49,6 +49,12 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-overview.mermaid index 0ae2ab919d..83f58c36a2 100644 --- a/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-overview.mermaid @@ -39,6 +39,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Composition fill:#fff7ed,stroke:#f59e0b,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 1 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 2 stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-dataflow.mermaid index 6689df6253..870266fa9d 100644 --- a/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-dataflow.mermaid @@ -1,48 +1,66 @@ %% View: Data-Flow | Parent: 48-composite-phase-lifecycle-full.mermaid -%% @uniform width=312 height=56 max_title_len=34 max_desc_lines=0 -flowchart TB -%% keep-orphan: N4 +%% @uniform width=240 height=64 max_title_len=28 max_desc_lines=0 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL', + 'spacing.nodeNode': 34, + 'spacing.edgeNode': 24, + 'spacing.edgeEdge': 12 + } +}}%% +flowchart LR subgraph Domain["Domain Layer"] direction TB - N4["FSMStateHelper.validate_transition"] + PHASE_STATE["CompositePipelineState"] + FAILURE_TYPE["ErrorType (CRITICAL/RECOVERABLE/DQ)"] end subgraph Application["Application Layer"] direction TB - N3["merge_active"] + KEY_EXTRACTOR["KeyExtractorService"] + ENRICHMENT_PLAN["Enrichment Plan"] + MERGE_PLAN["Merge Plan"] end subgraph Infrastructure["Infrastructure Layer"] direction TB - N1["extracting_seed"] - N2["keys_extracted"] - N5["*"] - N6["FAILED"] - N7["ENRICHING"] - N8["SEED_RUNNING"] - N9["SEED_COMPLETED"] - N10["DEPENDENCIES_RUNNING"] - N11["MERGING"] - N12["NOT_STARTED"] + BRONZE_SEED["Bronze: seed dataset"] + SILVER_SEED["Silver: seed table"] + SILVER_DEPS["Silver: dependency tables"] + SILVER_ENRICHED["Silver: enriched fragments"] + GOLD_COMPOSITE["Gold: composite record"] + CHECKPOINT["Checkpoint snapshot"] + QUARANTINE["Quarantine records"] end - N5 --> N12 - N12 --> N8 - N8 --> N9 - N8 --> N6 - N9 --> N10 - N9 --> N7 - N10 --> N6 - N7 --> N6 - N11 --> N6 - N6 --> N5 - N5 --> N1 - N5 --> N2 - N5 ==> N3 + BRONZE_SEED --> SILVER_SEED + SILVER_SEED --> KEY_EXTRACTOR + KEY_EXTRACTOR --> ENRICHMENT_PLAN + ENRICHMENT_PLAN --> SILVER_DEPS + SILVER_DEPS --> SILVER_ENRICHED + SILVER_ENRICHED --> MERGE_PLAN + MERGE_PLAN --> GOLD_COMPOSITE + + PHASE_STATE -. persisted .-> CHECKPOINT + CHECKPOINT -. resume context .-> ENRICHMENT_PLAN + FAILURE_TYPE -. routes invalid data .-> QUARANTINE + SILVER_ENRICHED -. dq failure .-> QUARANTINE style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12 stroke:#1E293B,stroke-width:4px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-domain.mermaid index d386152243..e04c330443 100644 --- a/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-domain.mermaid @@ -1,64 +1,74 @@ %% View: Domain-Focus | Parent: 48-composite-phase-lifecycle-full.mermaid -%% @uniform width=216 height=56 max_title_len=22 max_desc_lines=0 -%%{init: {'theme':'base','layout':'elk','flowchart':{'curve':'linear'},'elk':{'nodePlacementStrategy':'BRANDES_KOEPF','mergeEdges':true,'edgeRouting':'ORTHOGONAL'}}}%% -flowchart TB +%% @uniform width=232 height=64 max_title_len=26 max_desc_lines=0 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL', + 'spacing.nodeNode': 34, + 'spacing.edgeNode': 24, + 'spacing.edgeEdge': 12 + } +}}%% +flowchart LR subgraph Domain["Domain Layer"] - direction TB - N1["error"] - N2["*"] - N3["FAILED"] - N4["ENRICHING"] - N5["SEED_RUNNING"] - N6["SEED_COMPLETED"] - N7["DEPENDENCIES_RUNNING"] - N8["MERGING"] - N9["NOT_STARTED"] - N10["DEPENDENCIES_COMPLETED"] - N11["ENRICHMENT_COMPLETED"] - N12["COMPLETED"] - N13["idle"] - N14["extracting_seed"] - N15["keys_extracted"] - N16["running_deps"] - N17["deps_done"] - N18["fan_out"] - N19["enrichers_done"] + direction LR + NOT_STARTED["NOT_STARTED"] + SEED_RUNNING["SEED_RUNNING"] + SEED_COMPLETED["SEED_COMPLETED"] + DEPENDENCIES_RUNNING["DEPENDENCIES_RUNNING"] + DEPENDENCIES_COMPLETED["DEPENDENCIES_COMPLETED"] + ENRICHING["ENRICHING"] + ENRICHMENT_COMPLETED["ENRICHMENT_COMPLETED"] + MERGING["MERGING"] + COMPLETED["COMPLETED"] + FAILED["FAILED"] + HAS_DEPS{"has dependencies?"} + ENRICH_FAIL{"all enrichers failed?"} end subgraph Application["Application Layer"] direction TB - N20["merge_active"] + FSM_HELPER["FSMStateHelper.validate_transition()"] end - N2 --> N9 - N9 --> N5 - N5 --> N6 - N5 --> N3 - N6 --> N7 - N6 --> N4 - N7 --> N10 - N7 --> N3 - N10 --> N4 - N4 --> N11 - N4 --> N3 - N11 --> N8 - N8 --> N12 - N8 --> N3 - N12 --> N2 - N3 --> N2 - N2 --> N13 - N2 --> N14 - N2 --> N15 - N2 --> N16 - N2 --> N17 - N2 --> N18 - N2 --> N19 - N2 --> N20 - N2 --> N1 + NOT_STARTED --> SEED_RUNNING + SEED_RUNNING --> SEED_COMPLETED + SEED_RUNNING -. seed error .-> FAILED + + SEED_COMPLETED --> HAS_DEPS + HAS_DEPS -->|yes| DEPENDENCIES_RUNNING + HAS_DEPS -->|no| ENRICHING + + DEPENDENCIES_RUNNING --> DEPENDENCIES_COMPLETED + DEPENDENCIES_RUNNING -. dep error .-> FAILED + DEPENDENCIES_COMPLETED --> ENRICHING + + ENRICHING --> ENRICH_FAIL + ENRICH_FAIL -->|yes| FAILED + ENRICH_FAIL -->|no| ENRICHMENT_COMPLETED + + ENRICHMENT_COMPLETED --> MERGING + MERGING --> COMPLETED + MERGING -. merge error .-> FAILED + + FAILED -. resume .-> SEED_COMPLETED + + FSM_HELPER -. validates guards .-> HAS_DEPS + FSM_HELPER -. validates guards .-> ENRICH_FAIL style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 stroke:#475569,stroke-width:2px,stroke-dasharray:5 - linkStyle 24 stroke:#475569,stroke-width:2px,stroke-dasharray:5,opacity:0.85 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-infra.mermaid index 5f53e16cbd..84ef297554 100644 --- a/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-infra.mermaid @@ -1,69 +1,70 @@ %% View: Infrastructure-Mapping | Parent: 48-composite-phase-lifecycle-full.mermaid -%% @uniform width=216 height=56 max_title_len=22 max_desc_lines=0 -%%{init: {'theme':'base','layout':'elk','flowchart':{'curve':'linear'},'elk':{'nodePlacementStrategy':'BRANDES_KOEPF','mergeEdges':true,'edgeRouting':'ORTHOGONAL'}}}%% -flowchart TB +%% @uniform width=232 height=64 max_title_len=24 max_desc_lines=0 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL', + 'spacing.nodeNode': 34, + 'spacing.edgeNode': 24, + 'spacing.edgeEdge': 12 + } +}}%% +flowchart LR subgraph Domain["Domain Layer"] direction TB - N12["idle"] + STATE["CompositePipelineState"] end subgraph Application["Application Layer"] direction TB - N19["merge_active"] + RUNNER["CompositePipelineRunner"] + DISPATCHER["PhaseDispatcher"] end subgraph Infrastructure["Infrastructure Layer"] direction TB - N1["*"] - N2["FAILED"] - N3["ENRICHING"] - N4["SEED_RUNNING"] - N5["SEED_COMPLETED"] - N6["DEPENDENCIES_RUNNING"] - N7["MERGING"] - N8["NOT_STARTED"] - N9["DEPENDENCIES_COMPLETED"] - N10["ENRICHMENT_COMPLETED"] - N11["COMPLETED"] - N13["extracting_seed"] - N14["keys_extracted"] - N15["running_deps"] - N16["deps_done"] - N17["fan_out"] - N18["enrichers_done"] - N20["success"] + SEED_RUNNER["PipelineRunner (seed)"] + DEP_COORD["DependencyCoordinator"] + ENRICH_COORD["EnrichmentCoordinator"] + MERGE_SERVICE["MergeService"] + CHECKPOINT["CheckpointStore"] + METRICS["Metrics/Tracing"] end - N1 --> N8 - N8 --> N4 - N4 --> N5 - N4 --> N2 - N5 --> N6 - N5 --> N3 - N6 --> N9 - N6 --> N2 - N9 --> N3 - N3 --> N10 - N3 --> N2 - N10 --> N7 - N7 --> N11 - N7 --> N2 - N11 --> N1 - N2 --> N1 - N1 --> N12 - N1 --> N13 - N1 --> N14 - N1 --> N15 - N1 --> N16 - N1 --> N17 - N1 --> N18 - N1 --> N19 - N1 --> N20 + RUNNER --> DISPATCHER + DISPATCHER --> SEED_RUNNER + DISPATCHER --> DEP_COORD + DISPATCHER --> ENRICH_COORD + DISPATCHER --> MERGE_SERVICE + + SEED_RUNNER --> CHECKPOINT + DEP_COORD --> CHECKPOINT + ENRICH_COORD --> CHECKPOINT + MERGE_SERVICE --> CHECKPOINT + + SEED_RUNNER -. updates .-> STATE + DEP_COORD -. updates .-> STATE + ENRICH_COORD -. updates .-> STATE + MERGE_SERVICE -. updates .-> STATE + + RUNNER -. emits .-> METRICS + DISPATCHER -. emits .-> METRICS + CHECKPOINT -. recovery state .-> RUNNER style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 stroke:#475569,stroke-width:2px,stroke-dasharray:5 - linkStyle 24 stroke:#475569,stroke-width:2px,stroke-dasharray:5,opacity:0.85 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-overview.mermaid index db78433b94..8d5f43183f 100644 --- a/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-overview.mermaid @@ -1,46 +1,68 @@ %% View: Overview | Parent: 48-composite-phase-lifecycle-full.mermaid -%% @uniform width=160 height=56 max_title_len=15 max_desc_lines=0 -flowchart TB +%% @uniform width=220 height=64 max_title_len=24 max_desc_lines=0 +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL', + 'spacing.nodeNode': 34, + 'spacing.edgeNode': 24, + 'spacing.edgeEdge': 12 + } +}}%% +flowchart LR subgraph Domain["Domain Layer"] - direction TB - N14["error"] - N5["idle"] + direction LR + SEED["SEED"] + DEPENDENCIES["DEPENDENCIES"] + ENRICHING["ENRICHING"] + MERGING["MERGING"] + COMPLETED["COMPLETED"] + FAILED["FAILED"] end subgraph Application["Application Layer"] direction TB - N1["FAILED"] - N2["*"] - N3["NOT_STARTED"] - N4["COMPLETED"] - N6["extracting_seed"] - N7["keys_extracted"] - N8["running_deps"] - N9["deps_done"] - N10["fan_out"] - N11["enrichers_done"] - N12["merge_active"] - N13["success"] - N15["ENRICHING"] + ORCH["CompositePipelineOrchestrator"] + FSM_HELPER["FSMStateHelper.validate_transition()"] + end + + subgraph Infrastructure["Infrastructure Layer"] + direction TB + CHECKPOINT["CheckpointStore"] end - N2 --> N3 - N15 --> N1 - N4 --> N2 - N1 --> N2 - N2 ==> N5 - N2 --> N6 - N2 --> N7 - N2 --> N8 - N2 --> N9 - N2 --> N10 - N2 --> N11 - N2 --> N12 - N2 --> N13 - N2 --> N14 + START(("Start")) --> SEED + SEED --> DEPENDENCIES + SEED -->|skip deps| ENRICHING + DEPENDENCIES --> ENRICHING + MERGING --> COMPLETED + ENRICHING --> MERGING + COMPLETED --> END(("End")) + + SEED -. seed error .-> FAILED + DEPENDENCIES -. dep error .-> FAILED + ENRICHING -. all enrichers failed .-> FAILED + MERGING -. merge error .-> FAILED + + ORCH -. drives phases .-> SEED + FSM_HELPER -. validates .-> ORCH + CHECKPOINT -. persist/resume .-> ENRICHING + CHECKPOINT -. resume .-> FAILED style Domain fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px + style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + linkStyle default stroke:#475569,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-dataflow.mermaid b/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-dataflow.mermaid index 85fefedfe0..e9d5110499 100644 --- a/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-dataflow.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-dataflow.mermaid @@ -40,6 +40,12 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0 stroke:#1E293B,stroke-width:4px linkStyle 1 stroke:#1E293B,stroke-width:4px linkStyle 2 stroke:#1E293B,stroke-width:4px diff --git a/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-domain.mermaid b/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-domain.mermaid index f7754ca27c..bb7b18bbc6 100644 --- a/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-domain.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-domain.mermaid @@ -62,6 +62,13 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: data 16 | di 0-6,8-12,14-15,17-20 | generic 7,13 + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + linkStyle 0,1,2,3,4,5,6,8,9,10,11,12,14,15,17,18,19,20 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 linkStyle 7,13 stroke:#475569,stroke-width:2px,stroke-dasharray:5 linkStyle 16 stroke:#1E293B,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-full.mermaid b/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-full.mermaid index 64d7870b68..e838726aac 100644 --- a/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-full.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-full.mermaid @@ -14,7 +14,21 @@ %% @png-scale 6 %% @png-dpi 600 -%%{init: {'theme': 'neutral', 'themeVariables': {'fontFamily': 'Inter, system-ui', 'lineWidth': '2'},'layout':'elk','flowchart':{'curve':'linear'},'elk':{'nodePlacementStrategy':'BRANDES_KOEPF','mergeEdges':true,'edgeRouting':'ORTHOGONAL'}}}%% +%%{init: { + 'flowchart': { + 'subGraphTitleMargin': { 'top': 12, 'bottom': 12 } + }, + 'layout': 'elk', + 'elk': { + 'direction': 'DOWN', + 'mergeEdges': true, + 'nodePlacementStrategy': 'BRANDES_KOEPF', + 'edgeRouting': 'ORTHOGONAL', + 'spacing.nodeNode': 32, + 'spacing.edgeNode': 22, + 'spacing.edgeEdge': 12 + } +}}%% %% @uniform width=192 height=90 max_title_len=19 max_desc_lines=3 flowchart TD ROOT["Exception
(Python built-in)

"] @@ -24,7 +38,7 @@ flowchart TD ROOT --> BIOETL %% Three main branches - BIOETL --> CRITICAL["CriticalError
error_type = CRITICAL
Action: ABORT pipeline"] + BIOETL ==> CRITICAL["CriticalError
error_type = CRITICAL
Action: ABORT pipeline"] BIOETL --> RECOVERABLE["RecoverableError
error_type = RECOVERABLE
Action: RETRY with backoff"] BIOETL --> DQ_ERROR["DataQualityError
error_type = DATA_QUALITY
Action: QUARANTINE record"] @@ -93,7 +107,7 @@ flowchart TD ACTION_RETRY["Action: RETRY
Exponential backoff
Max retries from AdapterConfig
"] ACTION_QUARANTINE["Action: QUARANTINE
Record → QuarantineEntry
Pipeline continues
"] - CRITICAL -.->|"triggers"| ACTION_ABORT + CRITICAL ==>|"triggers"| ACTION_ABORT RECOVERABLE -.->|"triggers"| ACTION_RETRY DQ_ERROR -.->|"triggers"| ACTION_QUARANTINE @@ -109,5 +123,10 @@ flowchart TD style ACTION_RETRY fill:#fff7ed,stroke:#f59e0b style ACTION_QUARANTINE fill:#ffe4e6,stroke:#e11d48 - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48 stroke:#1E293B,stroke-width:4px - linkStyle 49 stroke:#EF4444,stroke-width:2px,stroke-dasharray:4 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#334155,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-infra.mermaid b/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-infra.mermaid index 44d9bbfabf..ffc2846d91 100644 --- a/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-infra.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-infra.mermaid @@ -35,9 +35,9 @@ flowchart TB N20["expected"] end - N15 --> N12 + N15 ==> N12 N15 --> N13 - N15 ==> N17 + N15 --> N17 N12 --> N2 N12 --> N3 N12 --> N4 @@ -62,4 +62,10 @@ flowchart TB style Application fill:#f0fdf4,stroke:#16a34a,stroke-width:2px style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px - linkStyle 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21 stroke:#475569,stroke-width:2px,stroke-dasharray:5 + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle default stroke:#475569,stroke-width:2px,stroke-dasharray:5 diff --git a/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-overview.mermaid b/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-overview.mermaid index 69355bec1c..3b12a8f122 100644 --- a/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-overview.mermaid +++ b/docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-overview.mermaid @@ -52,6 +52,27 @@ flowchart TB style Infrastructure fill:#fff1f2,stroke:#dc2626,stroke-width:2px %% linkStyle: data 6,16 | orchestration 0-1,3,5,8-15 | di 2,4,7 - linkStyle 0,1,3,5,8,9,10,11,12,13,14,15 stroke:#16a34a,stroke-width:2px - linkStyle 2,4,7 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 - linkStyle 6,16 stroke:#1E293B,stroke-width:2px + + classDef port fill:#f5f3ff,stroke:#7c3aed,stroke-width:1px,color:#111827; + classDef adapter fill:#fff1f2,stroke:#dc2626,stroke-width:1px,color:#111827; + classDef service fill:#eff6ff,stroke:#2563eb,stroke-width:1px,color:#111827; + classDef process fill:#f0fdf4,stroke:#16a34a,stroke-width:1px,color:#111827; + classDef storage fill:#fff7ed,stroke:#f59e0b,stroke-width:1px,color:#111827; + + linkStyle 0 stroke:#16a34a,stroke-width:2px + linkStyle 1 stroke:#16a34a,stroke-width:2px + linkStyle 2 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 3 stroke:#16a34a,stroke-width:2px + linkStyle 4 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 5 stroke:#16a34a,stroke-width:2px + linkStyle 6 stroke:#1E293B,stroke-width:2px + linkStyle 7 stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 + linkStyle 8 stroke:#16a34a,stroke-width:2px + linkStyle 9 stroke:#16a34a,stroke-width:2px + linkStyle 10 stroke:#16a34a,stroke-width:2px + linkStyle 11 stroke:#16a34a,stroke-width:2px + linkStyle 12 stroke:#16a34a,stroke-width:2px + linkStyle 13 stroke:#16a34a,stroke-width:2px + linkStyle 14 stroke:#16a34a,stroke-width:2px + linkStyle 15 stroke:#16a34a,stroke-width:2px + linkStyle 16 stroke:#1E293B,stroke-width:2px diff --git a/docs/02-architecture/mmd-diagrams/views/png/INDEX.md b/docs/02-architecture/mmd-diagrams/views/png/INDEX.md new file mode 100644 index 0000000000..68dc7f6d05 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/views/png/INDEX.md @@ -0,0 +1,940 @@ +# BioETL Diagrams — PNG Index + +_Generated: 2026-03-01T18:07:55+03:00_ + +## Legend + +![00-legend](./00-legend.png) + +--- + +## Full System Component Dataflow + +![01-full-system-component-dataflow](./01-full-system-component-dataflow.png) + +--- + +## Full System Component Domain + +![01-full-system-component-domain](./01-full-system-component-domain.png) + +--- + +## Full System Component Full + +![01-full-system-component-full](./01-full-system-component-full.png) + +--- + +## Full System Component Infra + +![01-full-system-component-infra](./01-full-system-component-infra.png) + +--- + +## Full System Component Overview + +![01-full-system-component-overview](./01-full-system-component-overview.png) + +--- + +## High Level Dataflow + +![01-high-level-dataflow](./01-high-level-dataflow.png) + +--- + +## High Level Domain + +![01-high-level-domain](./01-high-level-domain.png) + +--- + +## High Level Full + +![01-high-level-full](./01-high-level-full.png) + +--- + +## High Level Infra + +![01-high-level-infra](./01-high-level-infra.png) + +--- + +## High Level Overview + +![01-high-level-overview](./01-high-level-overview.png) + +--- + +## Medallion Dataflow + +![02-medallion-dataflow](./02-medallion-dataflow.png) + +--- + +## Medallion Domain + +![02-medallion-domain](./02-medallion-domain.png) + +--- + +## Medallion Full + +![02-medallion-full](./02-medallion-full.png) + +--- + +## Medallion Infra + +![02-medallion-infra](./02-medallion-infra.png) + +--- + +## Medallion Overview + +![02-medallion-overview](./02-medallion-overview.png) + +--- + +## Domain Layer Class Diagram Dataflow + +![04-domain-layer-class-diagram-dataflow](./04-domain-layer-class-diagram-dataflow.png) + +--- + +## Domain Layer Class Diagram Domain + +![04-domain-layer-class-diagram-domain](./04-domain-layer-class-diagram-domain.png) + +--- + +## Domain Layer Class Diagram Full + +![04-domain-layer-class-diagram-full](./04-domain-layer-class-diagram-full.png) + +--- + +## Domain Layer Class Diagram Infra + +![04-domain-layer-class-diagram-infra](./04-domain-layer-class-diagram-infra.png) + +--- + +## Domain Layer Class Diagram Overview + +![04-domain-layer-class-diagram-overview](./04-domain-layer-class-diagram-overview.png) + +--- + +## Layers Interaction Dataflow + +![05-layers-interaction-dataflow](./05-layers-interaction-dataflow.png) + +--- + +## Layers Interaction Domain + +![05-layers-interaction-domain](./05-layers-interaction-domain.png) + +--- + +## Layers Interaction Full + +![05-layers-interaction-full](./05-layers-interaction-full.png) + +--- + +## Layers Interaction Infra + +![05-layers-interaction-infra](./05-layers-interaction-infra.png) + +--- + +## Layers Interaction Overview + +![05-layers-interaction-overview](./05-layers-interaction-overview.png) + +--- + +## Pipeline Lifecycle States Dataflow + +![05-pipeline-lifecycle-states-dataflow](./05-pipeline-lifecycle-states-dataflow.png) + +--- + +## Pipeline Lifecycle States Domain + +![05-pipeline-lifecycle-states-domain](./05-pipeline-lifecycle-states-domain.png) + +--- + +## Pipeline Lifecycle States Full + +![05-pipeline-lifecycle-states-full](./05-pipeline-lifecycle-states-full.png) + +--- + +## Pipeline Lifecycle States Infra + +![05-pipeline-lifecycle-states-infra](./05-pipeline-lifecycle-states-infra.png) + +--- + +## Pipeline Lifecycle States Overview + +![05-pipeline-lifecycle-states-overview](./05-pipeline-lifecycle-states-overview.png) + +--- + +## Application Layer Class Diagram Dataflow + +![06-application-layer-class-diagram-dataflow](./06-application-layer-class-diagram-dataflow.png) + +--- + +## Application Layer Class Diagram Domain + +![06-application-layer-class-diagram-domain](./06-application-layer-class-diagram-domain.png) + +--- + +## Application Layer Class Diagram Full + +![06-application-layer-class-diagram-full](./06-application-layer-class-diagram-full.png) + +--- + +## Application Layer Class Diagram Infra + +![06-application-layer-class-diagram-infra](./06-application-layer-class-diagram-infra.png) + +--- + +## Application Layer Class Diagram Overview + +![06-application-layer-class-diagram-overview](./06-application-layer-class-diagram-overview.png) + +--- + +## Circuit Breaker States Dataflow + +![07-circuit-breaker-states-dataflow](./07-circuit-breaker-states-dataflow.png) + +--- + +## Circuit Breaker States Domain + +![07-circuit-breaker-states-domain](./07-circuit-breaker-states-domain.png) + +--- + +## Circuit Breaker States Full + +![07-circuit-breaker-states-full](./07-circuit-breaker-states-full.png) + +--- + +## Circuit Breaker States Infra + +![07-circuit-breaker-states-infra](./07-circuit-breaker-states-infra.png) + +--- + +## Circuit Breaker States Overview + +![07-circuit-breaker-states-overview](./07-circuit-breaker-states-overview.png) + +--- + +## Complete Etl Workflow Dataflow + +![08-complete-etl-workflow-dataflow](./08-complete-etl-workflow-dataflow.png) + +--- + +## Complete Etl Workflow Domain + +![08-complete-etl-workflow-domain](./08-complete-etl-workflow-domain.png) + +--- + +## Complete Etl Workflow Full + +![08-complete-etl-workflow-full](./08-complete-etl-workflow-full.png) + +--- + +## Complete Etl Workflow Infra + +![08-complete-etl-workflow-infra](./08-complete-etl-workflow-infra.png) + +--- + +## Complete Etl Workflow Overview + +![08-complete-etl-workflow-overview](./08-complete-etl-workflow-overview.png) + +--- + +## Domain Ddd Dataflow + +![08-domain-ddd-dataflow](./08-domain-ddd-dataflow.png) + +--- + +## Domain Ddd Domain + +![08-domain-ddd-domain](./08-domain-ddd-domain.png) + +--- + +## Domain Ddd Full + +![08-domain-ddd-full](./08-domain-ddd-full.png) + +--- + +## Domain Ddd Infra + +![08-domain-ddd-infra](./08-domain-ddd-infra.png) + +--- + +## Domain Ddd Overview + +![08-domain-ddd-overview](./08-domain-ddd-overview.png) + +--- + +## Infrastructure Layer Class Diagram Dataflow + +![10-infrastructure-layer-class-diagram-dataflow](./10-infrastructure-layer-class-diagram-dataflow.png) + +--- + +## Infrastructure Layer Class Diagram Domain + +![10-infrastructure-layer-class-diagram-domain](./10-infrastructure-layer-class-diagram-domain.png) + +--- + +## Infrastructure Layer Class Diagram Full + +![10-infrastructure-layer-class-diagram-full](./10-infrastructure-layer-class-diagram-full.png) + +--- + +## Infrastructure Layer Class Diagram Infra + +![10-infrastructure-layer-class-diagram-infra](./10-infrastructure-layer-class-diagram-infra.png) + +--- + +## Infrastructure Layer Class Diagram Overview + +![10-infrastructure-layer-class-diagram-overview](./10-infrastructure-layer-class-diagram-overview.png) + +--- + +## Local Deployment Architecture Dataflow + +![12-local-deployment-architecture-dataflow](./12-local-deployment-architecture-dataflow.png) + +--- + +## Local Deployment Architecture Domain + +![12-local-deployment-architecture-domain](./12-local-deployment-architecture-domain.png) + +--- + +## Local Deployment Architecture Full + +![12-local-deployment-architecture-full](./12-local-deployment-architecture-full.png) + +--- + +## Local Deployment Architecture Infra + +![12-local-deployment-architecture-infra](./12-local-deployment-architecture-infra.png) + +--- + +## Local Deployment Architecture Overview + +![12-local-deployment-architecture-overview](./12-local-deployment-architecture-overview.png) + +--- + +## Provider Health States Dataflow + +![14-provider-health-states-dataflow](./14-provider-health-states-dataflow.png) + +--- + +## Provider Health States Domain + +![14-provider-health-states-domain](./14-provider-health-states-domain.png) + +--- + +## Provider Health States Full + +![14-provider-health-states-full](./14-provider-health-states-full.png) + +--- + +## Provider Health States Infra + +![14-provider-health-states-infra](./14-provider-health-states-infra.png) + +--- + +## Provider Health States Overview + +![14-provider-health-states-overview](./14-provider-health-states-overview.png) + +--- + +## Dq Check Workflow Dataflow + +![15-dq-check-workflow-dataflow](./15-dq-check-workflow-dataflow.png) + +--- + +## Dq Check Workflow Domain + +![15-dq-check-workflow-domain](./15-dq-check-workflow-domain.png) + +--- + +## Dq Check Workflow Full + +![15-dq-check-workflow-full](./15-dq-check-workflow-full.png) + +--- + +## Dq Check Workflow Infra + +![15-dq-check-workflow-infra](./15-dq-check-workflow-infra.png) + +--- + +## Dq Check Workflow Overview + +![15-dq-check-workflow-overview](./15-dq-check-workflow-overview.png) + +--- + +## Activity Entity Data Flow Dataflow + +![21-activity-entity-data-flow-dataflow](./21-activity-entity-data-flow-dataflow.png) + +--- + +## Activity Entity Data Flow Domain + +![21-activity-entity-data-flow-domain](./21-activity-entity-data-flow-domain.png) + +--- + +## Activity Entity Data Flow Full + +![21-activity-entity-data-flow-full](./21-activity-entity-data-flow-full.png) + +--- + +## Activity Entity Data Flow Infra + +![21-activity-entity-data-flow-infra](./21-activity-entity-data-flow-infra.png) + +--- + +## Activity Entity Data Flow Overview + +![21-activity-entity-data-flow-overview](./21-activity-entity-data-flow-overview.png) + +--- + +## Hexagonal Ports Adapters Dataflow + +![26-hexagonal-ports-adapters-dataflow](./26-hexagonal-ports-adapters-dataflow.png) + +--- + +## Hexagonal Ports Adapters Domain + +![26-hexagonal-ports-adapters-domain](./26-hexagonal-ports-adapters-domain.png) + +--- + +## Hexagonal Ports Adapters Full + +![26-hexagonal-ports-adapters-full](./26-hexagonal-ports-adapters-full.png) + +--- + +## Hexagonal Ports Adapters Infra + +![26-hexagonal-ports-adapters-infra](./26-hexagonal-ports-adapters-infra.png) + +--- + +## Hexagonal Ports Adapters Overview + +![26-hexagonal-ports-adapters-overview](./26-hexagonal-ports-adapters-overview.png) + +--- + +## Composition Root Di Graph Dataflow + +![28-composition-root-di-graph-dataflow](./28-composition-root-di-graph-dataflow.png) + +--- + +## Composition Root Di Graph Domain + +![28-composition-root-di-graph-domain](./28-composition-root-di-graph-domain.png) + +--- + +## Composition Root Di Graph Full + +![28-composition-root-di-graph-full](./28-composition-root-di-graph-full.png) + +--- + +## Composition Root Di Graph Infra + +![28-composition-root-di-graph-infra](./28-composition-root-di-graph-infra.png) + +--- + +## Composition Root Di Graph Overview + +![28-composition-root-di-graph-overview](./28-composition-root-di-graph-overview.png) + +--- + +## Composite Pipeline Workflow Dataflow + +![29-composite-pipeline-workflow-dataflow](./29-composite-pipeline-workflow-dataflow.png) + +--- + +## Composite Pipeline Workflow Domain + +![29-composite-pipeline-workflow-domain](./29-composite-pipeline-workflow-domain.png) + +--- + +## Composite Pipeline Workflow Full + +![29-composite-pipeline-workflow-full](./29-composite-pipeline-workflow-full.png) + +--- + +## Composite Pipeline Workflow Infra + +![29-composite-pipeline-workflow-infra](./29-composite-pipeline-workflow-infra.png) + +--- + +## Composite Pipeline Workflow Overview + +![29-composite-pipeline-workflow-overview](./29-composite-pipeline-workflow-overview.png) + +--- + +## Port Adapter Mapping Dataflow + +![30-port-adapter-mapping-dataflow](./30-port-adapter-mapping-dataflow.png) + +--- + +## Port Adapter Mapping Domain + +![30-port-adapter-mapping-domain](./30-port-adapter-mapping-domain.png) + +--- + +## Port Adapter Mapping Full + +![30-port-adapter-mapping-full](./30-port-adapter-mapping-full.png) + +--- + +## Port Adapter Mapping Infra + +![30-port-adapter-mapping-infra](./30-port-adapter-mapping-infra.png) + +--- + +## Port Adapter Mapping Overview + +![30-port-adapter-mapping-overview](./30-port-adapter-mapping-overview.png) + +--- + +## Pipeline Run Lifecycle Dataflow + +![31-pipeline-run-lifecycle-dataflow](./31-pipeline-run-lifecycle-dataflow.png) + +--- + +## Pipeline Run Lifecycle Domain + +![31-pipeline-run-lifecycle-domain](./31-pipeline-run-lifecycle-domain.png) + +--- + +## Pipeline Run Lifecycle Full + +![31-pipeline-run-lifecycle-full](./31-pipeline-run-lifecycle-full.png) + +--- + +## Pipeline Run Lifecycle Infra + +![31-pipeline-run-lifecycle-infra](./31-pipeline-run-lifecycle-infra.png) + +--- + +## Pipeline Run Lifecycle Overview + +![31-pipeline-run-lifecycle-overview](./31-pipeline-run-lifecycle-overview.png) + +--- + +## Single Record Journey Dataflow + +![32-single-record-journey-dataflow](./32-single-record-journey-dataflow.png) + +--- + +## Single Record Journey Domain + +![32-single-record-journey-domain](./32-single-record-journey-domain.png) + +--- + +## Single Record Journey Full + +![32-single-record-journey-full](./32-single-record-journey-full.png) + +--- + +## Single Record Journey Infra + +![32-single-record-journey-infra](./32-single-record-journey-infra.png) + +--- + +## Single Record Journey Overview + +![32-single-record-journey-overview](./32-single-record-journey-overview.png) + +--- + +## Cli Run Interaction Dataflow + +![33-cli-run-interaction-dataflow](./33-cli-run-interaction-dataflow.png) + +--- + +## Cli Run Interaction Domain + +![33-cli-run-interaction-domain](./33-cli-run-interaction-domain.png) + +--- + +## Cli Run Interaction Full + +![33-cli-run-interaction-full](./33-cli-run-interaction-full.png) + +--- + +## Cli Run Interaction Infra + +![33-cli-run-interaction-infra](./33-cli-run-interaction-infra.png) + +--- + +## Cli Run Interaction Overview + +![33-cli-run-interaction-overview](./33-cli-run-interaction-overview.png) + +--- + +## Batch Processing Flow Dataflow + +![34-batch-processing-flow-dataflow](./34-batch-processing-flow-dataflow.png) + +--- + +## Batch Processing Flow Domain + +![34-batch-processing-flow-domain](./34-batch-processing-flow-domain.png) + +--- + +## Batch Processing Flow Full + +![34-batch-processing-flow-full](./34-batch-processing-flow-full.png) + +--- + +## Batch Processing Flow Infra + +![34-batch-processing-flow-infra](./34-batch-processing-flow-infra.png) + +--- + +## Batch Processing Flow Overview + +![34-batch-processing-flow-overview](./34-batch-processing-flow-overview.png) + +--- + +## Bootstrap Sequence Dataflow + +![35-bootstrap-sequence-dataflow](./35-bootstrap-sequence-dataflow.png) + +--- + +## Bootstrap Sequence Domain + +![35-bootstrap-sequence-domain](./35-bootstrap-sequence-domain.png) + +--- + +## Bootstrap Sequence Full + +![35-bootstrap-sequence-full](./35-bootstrap-sequence-full.png) + +--- + +## Bootstrap Sequence Infra + +![35-bootstrap-sequence-infra](./35-bootstrap-sequence-infra.png) + +--- + +## Bootstrap Sequence Overview + +![35-bootstrap-sequence-overview](./35-bootstrap-sequence-overview.png) + +--- + +## Architecture Principles Mindmap Dataflow + +![36-architecture-principles-mindmap-dataflow](./36-architecture-principles-mindmap-dataflow.png) + +--- + +## Architecture Principles Mindmap Domain + +![36-architecture-principles-mindmap-domain](./36-architecture-principles-mindmap-domain.png) + +--- + +## Architecture Principles Mindmap Full + +![36-architecture-principles-mindmap-full](./36-architecture-principles-mindmap-full.png) + +--- + +## Architecture Principles Mindmap Infra + +![36-architecture-principles-mindmap-infra](./36-architecture-principles-mindmap-infra.png) + +--- + +## Architecture Principles Mindmap Overview + +![36-architecture-principles-mindmap-overview](./36-architecture-principles-mindmap-overview.png) + +--- + +## Medallion Invariants Dataflow + +![39-medallion-invariants-dataflow](./39-medallion-invariants-dataflow.png) + +--- + +## Medallion Invariants Domain + +![39-medallion-invariants-domain](./39-medallion-invariants-domain.png) + +--- + +## Medallion Invariants Full + +![39-medallion-invariants-full](./39-medallion-invariants-full.png) + +--- + +## Medallion Invariants Infra + +![39-medallion-invariants-infra](./39-medallion-invariants-infra.png) + +--- + +## Medallion Invariants Overview + +![39-medallion-invariants-overview](./39-medallion-invariants-overview.png) + +--- + +## Error Classification Tree Dataflow + +![41-error-classification-tree-dataflow](./41-error-classification-tree-dataflow.png) + +--- + +## Error Classification Tree Domain + +![41-error-classification-tree-domain](./41-error-classification-tree-domain.png) + +--- + +## Error Classification Tree Full + +![41-error-classification-tree-full](./41-error-classification-tree-full.png) + +--- + +## Error Classification Tree Infra + +![41-error-classification-tree-infra](./41-error-classification-tree-infra.png) + +--- + +## Error Classification Tree Overview + +![41-error-classification-tree-overview](./41-error-classification-tree-overview.png) + +--- + +## Cross Provider Enrichment Dataflow + +![44-cross-provider-enrichment-dataflow](./44-cross-provider-enrichment-dataflow.png) + +--- + +## Cross Provider Enrichment Domain + +![44-cross-provider-enrichment-domain](./44-cross-provider-enrichment-domain.png) + +--- + +## Cross Provider Enrichment Full + +![44-cross-provider-enrichment-full](./44-cross-provider-enrichment-full.png) + +--- + +## Cross Provider Enrichment Infra + +![44-cross-provider-enrichment-infra](./44-cross-provider-enrichment-infra.png) + +--- + +## Cross Provider Enrichment Overview + +![44-cross-provider-enrichment-overview](./44-cross-provider-enrichment-overview.png) + +--- + +## Yaml Config Resolution Dataflow + +![46-yaml-config-resolution-dataflow](./46-yaml-config-resolution-dataflow.png) + +--- + +## Yaml Config Resolution Domain + +![46-yaml-config-resolution-domain](./46-yaml-config-resolution-domain.png) + +--- + +## Yaml Config Resolution Full + +![46-yaml-config-resolution-full](./46-yaml-config-resolution-full.png) + +--- + +## Yaml Config Resolution Infra + +![46-yaml-config-resolution-infra](./46-yaml-config-resolution-infra.png) + +--- + +## Yaml Config Resolution Overview + +![46-yaml-config-resolution-overview](./46-yaml-config-resolution-overview.png) + +--- + +## Composite Phase Lifecycle Dataflow + +![48-composite-phase-lifecycle-dataflow](./48-composite-phase-lifecycle-dataflow.png) + +--- + +## Composite Phase Lifecycle Domain + +![48-composite-phase-lifecycle-domain](./48-composite-phase-lifecycle-domain.png) + +--- + +## Composite Phase Lifecycle Full + +![48-composite-phase-lifecycle-full](./48-composite-phase-lifecycle-full.png) + +--- + +## Composite Phase Lifecycle Infra + +![48-composite-phase-lifecycle-infra](./48-composite-phase-lifecycle-infra.png) + +--- + +## Composite Phase Lifecycle Overview + +![48-composite-phase-lifecycle-overview](./48-composite-phase-lifecycle-overview.png) + +--- + +## Exception Hierarchy Dataflow + +![50-exception-hierarchy-dataflow](./50-exception-hierarchy-dataflow.png) + +--- + +## Exception Hierarchy Domain + +![50-exception-hierarchy-domain](./50-exception-hierarchy-domain.png) + +--- + +## Exception Hierarchy Full + +![50-exception-hierarchy-full](./50-exception-hierarchy-full.png) + +--- + +## Exception Hierarchy Infra + +![50-exception-hierarchy-infra](./50-exception-hierarchy-infra.png) + +--- + +## Exception Hierarchy Overview + +![50-exception-hierarchy-overview](./50-exception-hierarchy-overview.png) + +--- + diff --git a/docs/02-architecture/mmd-diagrams/views/svg/INDEX.md b/docs/02-architecture/mmd-diagrams/views/svg/INDEX.md new file mode 100644 index 0000000000..ed64fa1df3 --- /dev/null +++ b/docs/02-architecture/mmd-diagrams/views/svg/INDEX.md @@ -0,0 +1,940 @@ +# BioETL Diagrams — SVG Index + +_Generated: 2026-03-01T18:07:54+03:00_ + +## Legend + +![00-legend](./00-legend.svg) + +--- + +## Full System Component Dataflow + +![01-full-system-component-dataflow](./01-full-system-component-dataflow.svg) + +--- + +## Full System Component Domain + +![01-full-system-component-domain](./01-full-system-component-domain.svg) + +--- + +## Full System Component Full + +![01-full-system-component-full](./01-full-system-component-full.svg) + +--- + +## Full System Component Infra + +![01-full-system-component-infra](./01-full-system-component-infra.svg) + +--- + +## Full System Component Overview + +![01-full-system-component-overview](./01-full-system-component-overview.svg) + +--- + +## High Level Dataflow + +![01-high-level-dataflow](./01-high-level-dataflow.svg) + +--- + +## High Level Domain + +![01-high-level-domain](./01-high-level-domain.svg) + +--- + +## High Level Full + +![01-high-level-full](./01-high-level-full.svg) + +--- + +## High Level Infra + +![01-high-level-infra](./01-high-level-infra.svg) + +--- + +## High Level Overview + +![01-high-level-overview](./01-high-level-overview.svg) + +--- + +## Medallion Dataflow + +![02-medallion-dataflow](./02-medallion-dataflow.svg) + +--- + +## Medallion Domain + +![02-medallion-domain](./02-medallion-domain.svg) + +--- + +## Medallion Full + +![02-medallion-full](./02-medallion-full.svg) + +--- + +## Medallion Infra + +![02-medallion-infra](./02-medallion-infra.svg) + +--- + +## Medallion Overview + +![02-medallion-overview](./02-medallion-overview.svg) + +--- + +## Domain Layer Class Diagram Dataflow + +![04-domain-layer-class-diagram-dataflow](./04-domain-layer-class-diagram-dataflow.svg) + +--- + +## Domain Layer Class Diagram Domain + +![04-domain-layer-class-diagram-domain](./04-domain-layer-class-diagram-domain.svg) + +--- + +## Domain Layer Class Diagram Full + +![04-domain-layer-class-diagram-full](./04-domain-layer-class-diagram-full.svg) + +--- + +## Domain Layer Class Diagram Infra + +![04-domain-layer-class-diagram-infra](./04-domain-layer-class-diagram-infra.svg) + +--- + +## Domain Layer Class Diagram Overview + +![04-domain-layer-class-diagram-overview](./04-domain-layer-class-diagram-overview.svg) + +--- + +## Layers Interaction Dataflow + +![05-layers-interaction-dataflow](./05-layers-interaction-dataflow.svg) + +--- + +## Layers Interaction Domain + +![05-layers-interaction-domain](./05-layers-interaction-domain.svg) + +--- + +## Layers Interaction Full + +![05-layers-interaction-full](./05-layers-interaction-full.svg) + +--- + +## Layers Interaction Infra + +![05-layers-interaction-infra](./05-layers-interaction-infra.svg) + +--- + +## Layers Interaction Overview + +![05-layers-interaction-overview](./05-layers-interaction-overview.svg) + +--- + +## Pipeline Lifecycle States Dataflow + +![05-pipeline-lifecycle-states-dataflow](./05-pipeline-lifecycle-states-dataflow.svg) + +--- + +## Pipeline Lifecycle States Domain + +![05-pipeline-lifecycle-states-domain](./05-pipeline-lifecycle-states-domain.svg) + +--- + +## Pipeline Lifecycle States Full + +![05-pipeline-lifecycle-states-full](./05-pipeline-lifecycle-states-full.svg) + +--- + +## Pipeline Lifecycle States Infra + +![05-pipeline-lifecycle-states-infra](./05-pipeline-lifecycle-states-infra.svg) + +--- + +## Pipeline Lifecycle States Overview + +![05-pipeline-lifecycle-states-overview](./05-pipeline-lifecycle-states-overview.svg) + +--- + +## Application Layer Class Diagram Dataflow + +![06-application-layer-class-diagram-dataflow](./06-application-layer-class-diagram-dataflow.svg) + +--- + +## Application Layer Class Diagram Domain + +![06-application-layer-class-diagram-domain](./06-application-layer-class-diagram-domain.svg) + +--- + +## Application Layer Class Diagram Full + +![06-application-layer-class-diagram-full](./06-application-layer-class-diagram-full.svg) + +--- + +## Application Layer Class Diagram Infra + +![06-application-layer-class-diagram-infra](./06-application-layer-class-diagram-infra.svg) + +--- + +## Application Layer Class Diagram Overview + +![06-application-layer-class-diagram-overview](./06-application-layer-class-diagram-overview.svg) + +--- + +## Circuit Breaker States Dataflow + +![07-circuit-breaker-states-dataflow](./07-circuit-breaker-states-dataflow.svg) + +--- + +## Circuit Breaker States Domain + +![07-circuit-breaker-states-domain](./07-circuit-breaker-states-domain.svg) + +--- + +## Circuit Breaker States Full + +![07-circuit-breaker-states-full](./07-circuit-breaker-states-full.svg) + +--- + +## Circuit Breaker States Infra + +![07-circuit-breaker-states-infra](./07-circuit-breaker-states-infra.svg) + +--- + +## Circuit Breaker States Overview + +![07-circuit-breaker-states-overview](./07-circuit-breaker-states-overview.svg) + +--- + +## Complete Etl Workflow Dataflow + +![08-complete-etl-workflow-dataflow](./08-complete-etl-workflow-dataflow.svg) + +--- + +## Complete Etl Workflow Domain + +![08-complete-etl-workflow-domain](./08-complete-etl-workflow-domain.svg) + +--- + +## Complete Etl Workflow Full + +![08-complete-etl-workflow-full](./08-complete-etl-workflow-full.svg) + +--- + +## Complete Etl Workflow Infra + +![08-complete-etl-workflow-infra](./08-complete-etl-workflow-infra.svg) + +--- + +## Complete Etl Workflow Overview + +![08-complete-etl-workflow-overview](./08-complete-etl-workflow-overview.svg) + +--- + +## Domain Ddd Dataflow + +![08-domain-ddd-dataflow](./08-domain-ddd-dataflow.svg) + +--- + +## Domain Ddd Domain + +![08-domain-ddd-domain](./08-domain-ddd-domain.svg) + +--- + +## Domain Ddd Full + +![08-domain-ddd-full](./08-domain-ddd-full.svg) + +--- + +## Domain Ddd Infra + +![08-domain-ddd-infra](./08-domain-ddd-infra.svg) + +--- + +## Domain Ddd Overview + +![08-domain-ddd-overview](./08-domain-ddd-overview.svg) + +--- + +## Infrastructure Layer Class Diagram Dataflow + +![10-infrastructure-layer-class-diagram-dataflow](./10-infrastructure-layer-class-diagram-dataflow.svg) + +--- + +## Infrastructure Layer Class Diagram Domain + +![10-infrastructure-layer-class-diagram-domain](./10-infrastructure-layer-class-diagram-domain.svg) + +--- + +## Infrastructure Layer Class Diagram Full + +![10-infrastructure-layer-class-diagram-full](./10-infrastructure-layer-class-diagram-full.svg) + +--- + +## Infrastructure Layer Class Diagram Infra + +![10-infrastructure-layer-class-diagram-infra](./10-infrastructure-layer-class-diagram-infra.svg) + +--- + +## Infrastructure Layer Class Diagram Overview + +![10-infrastructure-layer-class-diagram-overview](./10-infrastructure-layer-class-diagram-overview.svg) + +--- + +## Local Deployment Architecture Dataflow + +![12-local-deployment-architecture-dataflow](./12-local-deployment-architecture-dataflow.svg) + +--- + +## Local Deployment Architecture Domain + +![12-local-deployment-architecture-domain](./12-local-deployment-architecture-domain.svg) + +--- + +## Local Deployment Architecture Full + +![12-local-deployment-architecture-full](./12-local-deployment-architecture-full.svg) + +--- + +## Local Deployment Architecture Infra + +![12-local-deployment-architecture-infra](./12-local-deployment-architecture-infra.svg) + +--- + +## Local Deployment Architecture Overview + +![12-local-deployment-architecture-overview](./12-local-deployment-architecture-overview.svg) + +--- + +## Provider Health States Dataflow + +![14-provider-health-states-dataflow](./14-provider-health-states-dataflow.svg) + +--- + +## Provider Health States Domain + +![14-provider-health-states-domain](./14-provider-health-states-domain.svg) + +--- + +## Provider Health States Full + +![14-provider-health-states-full](./14-provider-health-states-full.svg) + +--- + +## Provider Health States Infra + +![14-provider-health-states-infra](./14-provider-health-states-infra.svg) + +--- + +## Provider Health States Overview + +![14-provider-health-states-overview](./14-provider-health-states-overview.svg) + +--- + +## Dq Check Workflow Dataflow + +![15-dq-check-workflow-dataflow](./15-dq-check-workflow-dataflow.svg) + +--- + +## Dq Check Workflow Domain + +![15-dq-check-workflow-domain](./15-dq-check-workflow-domain.svg) + +--- + +## Dq Check Workflow Full + +![15-dq-check-workflow-full](./15-dq-check-workflow-full.svg) + +--- + +## Dq Check Workflow Infra + +![15-dq-check-workflow-infra](./15-dq-check-workflow-infra.svg) + +--- + +## Dq Check Workflow Overview + +![15-dq-check-workflow-overview](./15-dq-check-workflow-overview.svg) + +--- + +## Activity Entity Data Flow Dataflow + +![21-activity-entity-data-flow-dataflow](./21-activity-entity-data-flow-dataflow.svg) + +--- + +## Activity Entity Data Flow Domain + +![21-activity-entity-data-flow-domain](./21-activity-entity-data-flow-domain.svg) + +--- + +## Activity Entity Data Flow Full + +![21-activity-entity-data-flow-full](./21-activity-entity-data-flow-full.svg) + +--- + +## Activity Entity Data Flow Infra + +![21-activity-entity-data-flow-infra](./21-activity-entity-data-flow-infra.svg) + +--- + +## Activity Entity Data Flow Overview + +![21-activity-entity-data-flow-overview](./21-activity-entity-data-flow-overview.svg) + +--- + +## Hexagonal Ports Adapters Dataflow + +![26-hexagonal-ports-adapters-dataflow](./26-hexagonal-ports-adapters-dataflow.svg) + +--- + +## Hexagonal Ports Adapters Domain + +![26-hexagonal-ports-adapters-domain](./26-hexagonal-ports-adapters-domain.svg) + +--- + +## Hexagonal Ports Adapters Full + +![26-hexagonal-ports-adapters-full](./26-hexagonal-ports-adapters-full.svg) + +--- + +## Hexagonal Ports Adapters Infra + +![26-hexagonal-ports-adapters-infra](./26-hexagonal-ports-adapters-infra.svg) + +--- + +## Hexagonal Ports Adapters Overview + +![26-hexagonal-ports-adapters-overview](./26-hexagonal-ports-adapters-overview.svg) + +--- + +## Composition Root Di Graph Dataflow + +![28-composition-root-di-graph-dataflow](./28-composition-root-di-graph-dataflow.svg) + +--- + +## Composition Root Di Graph Domain + +![28-composition-root-di-graph-domain](./28-composition-root-di-graph-domain.svg) + +--- + +## Composition Root Di Graph Full + +![28-composition-root-di-graph-full](./28-composition-root-di-graph-full.svg) + +--- + +## Composition Root Di Graph Infra + +![28-composition-root-di-graph-infra](./28-composition-root-di-graph-infra.svg) + +--- + +## Composition Root Di Graph Overview + +![28-composition-root-di-graph-overview](./28-composition-root-di-graph-overview.svg) + +--- + +## Composite Pipeline Workflow Dataflow + +![29-composite-pipeline-workflow-dataflow](./29-composite-pipeline-workflow-dataflow.svg) + +--- + +## Composite Pipeline Workflow Domain + +![29-composite-pipeline-workflow-domain](./29-composite-pipeline-workflow-domain.svg) + +--- + +## Composite Pipeline Workflow Full + +![29-composite-pipeline-workflow-full](./29-composite-pipeline-workflow-full.svg) + +--- + +## Composite Pipeline Workflow Infra + +![29-composite-pipeline-workflow-infra](./29-composite-pipeline-workflow-infra.svg) + +--- + +## Composite Pipeline Workflow Overview + +![29-composite-pipeline-workflow-overview](./29-composite-pipeline-workflow-overview.svg) + +--- + +## Port Adapter Mapping Dataflow + +![30-port-adapter-mapping-dataflow](./30-port-adapter-mapping-dataflow.svg) + +--- + +## Port Adapter Mapping Domain + +![30-port-adapter-mapping-domain](./30-port-adapter-mapping-domain.svg) + +--- + +## Port Adapter Mapping Full + +![30-port-adapter-mapping-full](./30-port-adapter-mapping-full.svg) + +--- + +## Port Adapter Mapping Infra + +![30-port-adapter-mapping-infra](./30-port-adapter-mapping-infra.svg) + +--- + +## Port Adapter Mapping Overview + +![30-port-adapter-mapping-overview](./30-port-adapter-mapping-overview.svg) + +--- + +## Pipeline Run Lifecycle Dataflow + +![31-pipeline-run-lifecycle-dataflow](./31-pipeline-run-lifecycle-dataflow.svg) + +--- + +## Pipeline Run Lifecycle Domain + +![31-pipeline-run-lifecycle-domain](./31-pipeline-run-lifecycle-domain.svg) + +--- + +## Pipeline Run Lifecycle Full + +![31-pipeline-run-lifecycle-full](./31-pipeline-run-lifecycle-full.svg) + +--- + +## Pipeline Run Lifecycle Infra + +![31-pipeline-run-lifecycle-infra](./31-pipeline-run-lifecycle-infra.svg) + +--- + +## Pipeline Run Lifecycle Overview + +![31-pipeline-run-lifecycle-overview](./31-pipeline-run-lifecycle-overview.svg) + +--- + +## Single Record Journey Dataflow + +![32-single-record-journey-dataflow](./32-single-record-journey-dataflow.svg) + +--- + +## Single Record Journey Domain + +![32-single-record-journey-domain](./32-single-record-journey-domain.svg) + +--- + +## Single Record Journey Full + +![32-single-record-journey-full](./32-single-record-journey-full.svg) + +--- + +## Single Record Journey Infra + +![32-single-record-journey-infra](./32-single-record-journey-infra.svg) + +--- + +## Single Record Journey Overview + +![32-single-record-journey-overview](./32-single-record-journey-overview.svg) + +--- + +## Cli Run Interaction Dataflow + +![33-cli-run-interaction-dataflow](./33-cli-run-interaction-dataflow.svg) + +--- + +## Cli Run Interaction Domain + +![33-cli-run-interaction-domain](./33-cli-run-interaction-domain.svg) + +--- + +## Cli Run Interaction Full + +![33-cli-run-interaction-full](./33-cli-run-interaction-full.svg) + +--- + +## Cli Run Interaction Infra + +![33-cli-run-interaction-infra](./33-cli-run-interaction-infra.svg) + +--- + +## Cli Run Interaction Overview + +![33-cli-run-interaction-overview](./33-cli-run-interaction-overview.svg) + +--- + +## Batch Processing Flow Dataflow + +![34-batch-processing-flow-dataflow](./34-batch-processing-flow-dataflow.svg) + +--- + +## Batch Processing Flow Domain + +![34-batch-processing-flow-domain](./34-batch-processing-flow-domain.svg) + +--- + +## Batch Processing Flow Full + +![34-batch-processing-flow-full](./34-batch-processing-flow-full.svg) + +--- + +## Batch Processing Flow Infra + +![34-batch-processing-flow-infra](./34-batch-processing-flow-infra.svg) + +--- + +## Batch Processing Flow Overview + +![34-batch-processing-flow-overview](./34-batch-processing-flow-overview.svg) + +--- + +## Bootstrap Sequence Dataflow + +![35-bootstrap-sequence-dataflow](./35-bootstrap-sequence-dataflow.svg) + +--- + +## Bootstrap Sequence Domain + +![35-bootstrap-sequence-domain](./35-bootstrap-sequence-domain.svg) + +--- + +## Bootstrap Sequence Full + +![35-bootstrap-sequence-full](./35-bootstrap-sequence-full.svg) + +--- + +## Bootstrap Sequence Infra + +![35-bootstrap-sequence-infra](./35-bootstrap-sequence-infra.svg) + +--- + +## Bootstrap Sequence Overview + +![35-bootstrap-sequence-overview](./35-bootstrap-sequence-overview.svg) + +--- + +## Architecture Principles Mindmap Dataflow + +![36-architecture-principles-mindmap-dataflow](./36-architecture-principles-mindmap-dataflow.svg) + +--- + +## Architecture Principles Mindmap Domain + +![36-architecture-principles-mindmap-domain](./36-architecture-principles-mindmap-domain.svg) + +--- + +## Architecture Principles Mindmap Full + +![36-architecture-principles-mindmap-full](./36-architecture-principles-mindmap-full.svg) + +--- + +## Architecture Principles Mindmap Infra + +![36-architecture-principles-mindmap-infra](./36-architecture-principles-mindmap-infra.svg) + +--- + +## Architecture Principles Mindmap Overview + +![36-architecture-principles-mindmap-overview](./36-architecture-principles-mindmap-overview.svg) + +--- + +## Medallion Invariants Dataflow + +![39-medallion-invariants-dataflow](./39-medallion-invariants-dataflow.svg) + +--- + +## Medallion Invariants Domain + +![39-medallion-invariants-domain](./39-medallion-invariants-domain.svg) + +--- + +## Medallion Invariants Full + +![39-medallion-invariants-full](./39-medallion-invariants-full.svg) + +--- + +## Medallion Invariants Infra + +![39-medallion-invariants-infra](./39-medallion-invariants-infra.svg) + +--- + +## Medallion Invariants Overview + +![39-medallion-invariants-overview](./39-medallion-invariants-overview.svg) + +--- + +## Error Classification Tree Dataflow + +![41-error-classification-tree-dataflow](./41-error-classification-tree-dataflow.svg) + +--- + +## Error Classification Tree Domain + +![41-error-classification-tree-domain](./41-error-classification-tree-domain.svg) + +--- + +## Error Classification Tree Full + +![41-error-classification-tree-full](./41-error-classification-tree-full.svg) + +--- + +## Error Classification Tree Infra + +![41-error-classification-tree-infra](./41-error-classification-tree-infra.svg) + +--- + +## Error Classification Tree Overview + +![41-error-classification-tree-overview](./41-error-classification-tree-overview.svg) + +--- + +## Cross Provider Enrichment Dataflow + +![44-cross-provider-enrichment-dataflow](./44-cross-provider-enrichment-dataflow.svg) + +--- + +## Cross Provider Enrichment Domain + +![44-cross-provider-enrichment-domain](./44-cross-provider-enrichment-domain.svg) + +--- + +## Cross Provider Enrichment Full + +![44-cross-provider-enrichment-full](./44-cross-provider-enrichment-full.svg) + +--- + +## Cross Provider Enrichment Infra + +![44-cross-provider-enrichment-infra](./44-cross-provider-enrichment-infra.svg) + +--- + +## Cross Provider Enrichment Overview + +![44-cross-provider-enrichment-overview](./44-cross-provider-enrichment-overview.svg) + +--- + +## Yaml Config Resolution Dataflow + +![46-yaml-config-resolution-dataflow](./46-yaml-config-resolution-dataflow.svg) + +--- + +## Yaml Config Resolution Domain + +![46-yaml-config-resolution-domain](./46-yaml-config-resolution-domain.svg) + +--- + +## Yaml Config Resolution Full + +![46-yaml-config-resolution-full](./46-yaml-config-resolution-full.svg) + +--- + +## Yaml Config Resolution Infra + +![46-yaml-config-resolution-infra](./46-yaml-config-resolution-infra.svg) + +--- + +## Yaml Config Resolution Overview + +![46-yaml-config-resolution-overview](./46-yaml-config-resolution-overview.svg) + +--- + +## Composite Phase Lifecycle Dataflow + +![48-composite-phase-lifecycle-dataflow](./48-composite-phase-lifecycle-dataflow.svg) + +--- + +## Composite Phase Lifecycle Domain + +![48-composite-phase-lifecycle-domain](./48-composite-phase-lifecycle-domain.svg) + +--- + +## Composite Phase Lifecycle Full + +![48-composite-phase-lifecycle-full](./48-composite-phase-lifecycle-full.svg) + +--- + +## Composite Phase Lifecycle Infra + +![48-composite-phase-lifecycle-infra](./48-composite-phase-lifecycle-infra.svg) + +--- + +## Composite Phase Lifecycle Overview + +![48-composite-phase-lifecycle-overview](./48-composite-phase-lifecycle-overview.svg) + +--- + +## Exception Hierarchy Dataflow + +![50-exception-hierarchy-dataflow](./50-exception-hierarchy-dataflow.svg) + +--- + +## Exception Hierarchy Domain + +![50-exception-hierarchy-domain](./50-exception-hierarchy-domain.svg) + +--- + +## Exception Hierarchy Full + +![50-exception-hierarchy-full](./50-exception-hierarchy-full.svg) + +--- + +## Exception Hierarchy Infra + +![50-exception-hierarchy-infra](./50-exception-hierarchy-infra.svg) + +--- + +## Exception Hierarchy Overview + +![50-exception-hierarchy-overview](./50-exception-hierarchy-overview.svg) + +--- + diff --git a/docs/plans/config-unification-plan.md b/docs/plans/config-unification-plan.md index 6b57f79b69..f9c64b7b80 100644 --- a/docs/plans/config-unification-plan.md +++ b/docs/plans/config-unification-plan.md @@ -18,9 +18,9 @@ - RF-CFG-032 выполнен в backward-compat режиме: `load-pipeline-config()` и секционные loaders читают unified entity sections (`pipeline/schema/quality/filters/contracts`) с fallback на legacy paths. - RF-CFG-033 пока **не завершен**: `PipelineContractPolicyLoader` сохранен и переведен на режим unified-first + legacy fallback. - Технический эффект Phase 3: `DQConfigLoader` вырос до 322 LOC; добавлены явные архитектурные exemptions в `tests/architecture/test-code-metrics.py` как переходная мера до декомпозиции (RF-CFG-031/RF-CFG-037). -- RF-CFG-036 выполнен: composite configs перенесены в `configs/composites/*.yaml`, `load-composite-config()` переведен на new-first path (`configs/composites`) с legacy fallback (`configs/pipelines/composite`). +- RF-CFG-036 выполнен: composite configs перенесены в `configs/composites/*.yaml`, `load-composite-config()` переведен на new-first path (`configs/composites`) с fallback на legacy composite path (старый каталог composite pipeline configs). - RF-CFG-037 выполнен: 3 реализации `deep-merge` унифицированы через `src/bioetl/infrastructure/config-merge.py::config-merge` с параметризуемыми list-стратегиями (concat keys, resolver-based merge для DQ validations). -- RF-CFG-035 выполнен (без backward-compat периода по решению): удалены legacy dirs `configs/pipelines/{providers}`, `configs/schemas/{providers}`, `configs/quality/entities/`, `configs/filters/entities/`, `configs/contracts/`; тесты/инварианты переведены на unified `configs/entities/` + `configs/composites/`. +- RF-CFG-035 выполнен (без backward-compat периода по решению): удалены legacy dirs provider pipeline configs, `configs/schemas/{providers}`, `configs/quality/entities/`, `configs/filters/entities/`, `configs/contracts/`; тесты/инварианты переведены на unified `configs/entities/` + `configs/composites/`. --- diff --git a/docs/reports/branch-full-diff-matrix-2026-03-01.csv b/docs/reports/branch-full-diff-matrix-2026-03-01.csv new file mode 100644 index 0000000000..02fea61803 --- /dev/null +++ b/docs/reports/branch-full-diff-matrix-2026-03-01.csv @@ -0,0 +1,479 @@ +file,bioetl-architecture-prompts-v3-lLJJu,audit-fix-diagrams-hZglG,audit-diagram-docs-scripts-fUJUM,improve-diagram-design-K2XMN +"""2_10_\321\203\320\273\321\203\321\207\321\210\320\265\320\275\320\270\320\271_\320\264\320\273\321\217_\320\276\320\277\321\202\320\270\320\274\320\270\320\267\320\260\321\206\320\270\320\270_\321\200\320\260.md""",D +0/-57,-,D +0/-57,D +0/-57 +"""3_10_\321\203\320\273\321\203\321\207\321\210\320\265\320\275\320\270\320\271_\320\264\320\273\321\217_\320\276\320\277\321\202\320\270\320\274\320\270\320\267\320\260\321\206\320\270\320\270_\321\200\320\260.md""",D +0/-52,-,D +0/-52,D +0/-52 +.claude/agents/ORCHESTRATION.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/agents/py-audit-bot.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/agents/py-doc-bot.md,M +2/-2,-,M +2/-2,M +2/-2 +.claude/prompts/00-Audit/02-architecture-audit.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/00-Audit/02-file-structure-audit-standardization.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/00-Audit/03-code-inventory-audit.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/00-Documentation/00-documentation-audit-update-task.md,M +2/-2,-,M +2/-2,M +2/-2 +.claude/prompts/00-Documentation/01-docstrings-completion.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/00-Documentation/04-naming-compliance-audit-prompt.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/01-documentation-update-prompt.md,M +8/-8,-,M +8/-8,M +8/-8 +.claude/prompts/02-Sync/01-xwalk.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/02-Sync/02-docs-PR.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/02-Sync/03-pk-issue.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/02-Sync/04-schema-review.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/02-Sync/05-vcr-tests.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/02-Sync/06-manual-EP.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/02-Sync/07-bot-xwalk.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/prompts/03-repository-cleanup-assistant.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/settings.local.json,-,M +2/-1,-,- +.claude/skills/documentation-audit.audit-checklist.md,M +2/-2,-,M +2/-2,M +2/-2 +.claude/skills/documentation-audit.openai.yaml,M +2/-2,-,M +2/-2,M +2/-2 +.claude/skills/documentation-audit.report-template.md,M +1/-1,-,M +1/-1,M +1/-1 +.claude/skills/documentation-audit.skill.md,M +3/-3,-,M +3/-3,M +3/-3 +.claude/skills/mermaid-design.md,-,M +22/-14,M +22/-17,- +.github/workflows/contract-tests.yml,M +1/-1,-,M +1/-1,M +1/-1 +.github/workflows/docs.yml,M +4/-0,-,-,- +.github/workflows/port-contracts.yml,M +2/-2,-,M +2/-2,M +2/-2 +.gitignore,M +2/-1,-,M +2/-1,M +2/-1 +Makefile,-,-,M +1/-1,- +assets/javascripts/MERMAID_VERSION,-,-,M +1/-1,- +assets/javascripts/download_mermaid.ps1,-,-,M +2/-2,- +assets/javascripts/mermaid-loader.js,-,-,M +1/-1,- +assets/stylesheets/mermaid.css,-,-,-,M +34/-0 +chrome-headless-shell/.metadata,D +0/-5,-,D +0/-5,D +0/-5 +chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/ABOUT,D +0/-9,-,D +0/-9,D +0/-9 +chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/LICENSE.headless_shell,D +0/-37908,-,D +0/-37908,D +0/-37908 +chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/deb.deps,D +0/-30,-,D +0/-30,D +0/-30 +chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/icudtl.dat,D +-/--,-,D +-/--,D +-/-- +chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/libvulkan.so.1,D +-/--,-,D +-/--,D +-/-- +chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/rpm.deps,D +0/-92,-,D +0/-92,D +0/-92 +chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/v8_context_snapshot.bin,D +-/--,-,D +-/--,D +-/-- +docs/00-project/00-map.md,M +1/-1,-,M +1/-1,M +1/-1 +docs/00-project/agents/AGENT.md,M +1/-1,-,M +1/-1,M +1/-1 +docs/00-project/agents/CLAUDE.md,M +3/-3,-,M +3/-3,M +3/-3 +docs/00-project/agents/orchestration/ORCHESTRATION.md,M +1/-1,-,M +1/-1,M +1/-1 +docs/00-project/glossary.md,M +1/-0,-,M +1/-0,M +1/-0 +docs/02-architecture/00-overview.md,M +7/-1,-,M +7/-1,M +7/-1 +docs/02-architecture/06-diagram-policy.md,-,-,M +4/-15,- +docs/02-architecture/architecture-diagrams.md,-,-,M +15/-15,- +docs/02-architecture/decisions/ADR-040-diagram-governance.md,-,M +24/-8,M +2/-2,- +docs/02-architecture/diagrams/architecture-diagrams-prompts-v4.md,A +392/-0,-,-,- +docs/02-architecture/diagrams/mermaid/01-full-system-component-full.mermaid,-,-,M +8/-38,M +160/-190 +docs/02-architecture/diagrams/mermaid/04-domain-layer-class-diagram-full.mermaid,-,-,-,M +284/-284 +docs/02-architecture/diagrams/mermaid/21-activity-entity-data-flow-full.mermaid,-,-,M +6/-22,M +97/-113 +docs/02-architecture/diagrams/mermaid/26-hexagonal-ports-adapters-full.mermaid,-,-,M +7/-22,M +123/-138 +docs/02-architecture/diagrams/mermaid/28-composition-root-di-graph-full.mermaid,-,-,M +10/-35,M +91/-116 +docs/02-architecture/diagrams/mermaid/29-composite-pipeline-workflow-full.mermaid,-,-,M +6/-23,M +91/-108 +docs/02-architecture/diagrams/mermaid/30-port-adapter-mapping-full.mermaid,-,-,M +4/-33,M +108/-137 +docs/02-architecture/diagrams/mermaid/32-single-record-journey-full.mermaid,-,-,M +6/-16,M +60/-70 +docs/02-architecture/diagrams/mermaid/35-bootstrap-sequence-full.mermaid,-,-,M +5/-23,M +81/-99 +docs/02-architecture/diagrams/mermaid/39-medallion-invariants-full.mermaid,-,-,M +8/-18,M +73/-83 +docs/02-architecture/diagrams/mermaid/44-cross-provider-enrichment-full.mermaid,-,-,M +5/-16,M +54/-65 +docs/02-architecture/diagrams/mermaid/46-yaml-config-resolution-full.mermaid,-,-,M +8/-33,M +83/-108 +docs/02-architecture/diagrams/mermaid/png/INDEX.md,D +0/-76,-,D +0/-76,D +0/-76 +docs/02-architecture/diagrams/mermaid/svg/INDEX.md,D +0/-76,-,D +0/-76,D +0/-76 +docs/02-architecture/mmd-diagrams/00-legend.mmd,A +54/-0,-,-,- +docs/02-architecture/mmd-diagrams/_template.mmd,-,-,M +1/-0,M +85/-79 +docs/02-architecture/mmd-diagrams/architecture/01-high-level-hexagonal.mmd,-,M +4/-4,M +1/-0,M +127/-122 +docs/02-architecture/mmd-diagrams/architecture/01a-hexagonal-overview.mmd,-,M +7/-13,-,M +57/-54 +docs/02-architecture/mmd-diagrams/architecture/01b-hexagonal-domain-app.mmd,-,M +3/-3,-,M +37/-34 +docs/02-architecture/mmd-diagrams/architecture/01c-hexagonal-infra-comp.mmd,-,M +3/-6,M +1/-1,M +48/-45 +docs/02-architecture/mmd-diagrams/architecture/02-layer-dependency-matrix.mmd,-,M +2/-1,-,M +54/-51 +docs/02-architecture/mmd-diagrams/architecture/03-medallion-data-flow.mmd,-,M +8/-10,M +7/-6,M +125/-103 +docs/02-architecture/mmd-diagrams/architecture/03a-medallion-layers-overview.mmd,-,M +4/-3,-,M +35/-32 +docs/02-architecture/mmd-diagrams/architecture/04-pipeline-execution-flow.mmd,-,M +1/-0,M +1/-1,M +101/-98 +docs/02-architecture/mmd-diagrams/architecture/05-provider-adapter-hierarchy.mmd,-,M +3/-14,M +1/-0,M +110/-106 +docs/02-architecture/mmd-diagrams/architecture/05a-adapter-hierarchy-base.mmd,-,M +3/-3,-,M +33/-30 +docs/02-architecture/mmd-diagrams/architecture/05b-adapter-hierarchy-providers.mmd,-,M +2/-2,M +1/-1,M +40/-37 +docs/02-architecture/mmd-diagrams/architecture/06-storage-layer.mmd,-,M +4/-10,M +1/-0,M +100/-96 +docs/02-architecture/mmd-diagrams/architecture/06a-storage-writers.mmd,-,-,A +65/-0,A +68/-0 +docs/02-architecture/mmd-diagrams/architecture/06b-storage-support.mmd,-,-,A +45/-0,A +48/-0 +docs/02-architecture/mmd-diagrams/architecture/07-dq-system.mmd,-,M +4/-4,M +1/-0,M +107/-106 +docs/02-architecture/mmd-diagrams/architecture/07a-dq-analysis.mmd,-,-,A +60/-0,A +63/-0 +docs/02-architecture/mmd-diagrams/architecture/07b-dq-pipeline.mmd,-,-,A +47/-0,A +50/-0 +docs/02-architecture/mmd-diagrams/architecture/08-composite-pipeline.mmd,-,M +7/-13,M +3/-2,M +136/-124 +docs/02-architecture/mmd-diagrams/architecture/08a-composite-config.mmd,-,-,A +56/-0,A +59/-0 +docs/02-architecture/mmd-diagrams/architecture/08b-composite-execution.mmd,-,-,A +99/-0,A +102/-0 +docs/02-architecture/mmd-diagrams/architecture/09-observability-stack.mmd,-,M +6/-12,M +2/-1,M +85/-81 +docs/02-architecture/mmd-diagrams/architecture/09a-observability-app.mmd,-,-,A +44/-0,A +47/-0 +docs/02-architecture/mmd-diagrams/architecture/09b-observability-infra.mmd,-,-,A +62/-0,A +65/-0 +docs/02-architecture/mmd-diagrams/architecture/10-resilience-patterns.mmd,-,M +5/-9,M +2/-2,M +74/-71 +docs/02-architecture/mmd-diagrams/architecture/11-configuration-system.mmd,-,M +3/-6,M +1/-0,M +112/-108 +docs/02-architecture/mmd-diagrams/architecture/11a-config-loading.mmd,-,-,A +58/-0,A +61/-0 +docs/02-architecture/mmd-diagrams/architecture/11b-config-domain.mmd,-,-,A +63/-0,A +66/-0 +docs/02-architecture/mmd-diagrams/architecture/12-bootstrap-di-container.mmd,-,M +3/-5,M +2/-1,M +134/-121 +docs/02-architecture/mmd-diagrams/architecture/12a-bootstrap-factories.mmd,-,M +3/-2,M +1/-1,M +37/-34 +docs/02-architecture/mmd-diagrams/architecture/12b-bootstrap-wiring.mmd,-,M +4/-4,M +1/-1,M +58/-55 +docs/02-architecture/mmd-diagrams/architecture/13-port-protocol-contracts.mmd,-,M +4/-4,M +1/-0,M +136/-135 +docs/02-architecture/mmd-diagrams/architecture/13a-data-storage-ports.mmd,-,M +2/-16,-,M +44/-44 +docs/02-architecture/mmd-diagrams/architecture/13a-port-contracts-data-sources.mmd,-,M +3/-4,-,M +18/-18 +docs/02-architecture/mmd-diagrams/architecture/13b-operational-ports.mmd,-,M +2/-16,M +1/-0,M +48/-47 +docs/02-architecture/mmd-diagrams/architecture/13b-port-contracts-storage.mmd,-,M +3/-2,-,M +23/-23 +docs/02-architecture/mmd-diagrams/architecture/13c-port-contracts-observability.mmd,-,M +3/-3,-,M +29/-29 +docs/02-architecture/mmd-diagrams/architecture/13c-validation-dq-ports.mmd,-,M +2/-16,-,M +50/-50 +docs/02-architecture/mmd-diagrams/architecture/13d-port-contracts-services.mmd,-,M +5/-5,M +1/-1,M +61/-61 +docs/02-architecture/mmd-diagrams/architecture/13e-operational-ports-domain.mmd,-,-,A +26/-0,A +26/-0 +docs/02-architecture/mmd-diagrams/architecture/13f-operational-ports-infra.mmd,-,-,A +25/-0,A +25/-0 +docs/02-architecture/mmd-diagrams/architecture/14-cli-interface-layer.mmd,-,M +3/-9,M +1/-0,M +91/-87 +docs/02-architecture/mmd-diagrams/architecture/14a-cli-commands.mmd,-,-,A +60/-0,A +63/-0 +docs/02-architecture/mmd-diagrams/architecture/14b-cli-routing.mmd,-,-,A +62/-0,A +65/-0 +docs/02-architecture/mmd-diagrams/architecture/15-batch-executor-internals.mmd,-,M +6/-12,M +2/-2,M +61/-61 +docs/02-architecture/mmd-diagrams/architecture/16-transformer-hierarchy.mmd,-,M +7/-9,M +2/-1,M +54/-50 +docs/02-architecture/mmd-diagrams/architecture/16a-transformer-base.mmd,-,-,A +50/-0,A +50/-0 +docs/02-architecture/mmd-diagrams/architecture/16b-transformer-pub-other.mmd,-,-,A +59/-0,A +62/-0 +docs/02-architecture/mmd-diagrams/architecture/17-security-pii-audit.mmd,-,M +5/-7,M +1/-1,M +74/-71 +docs/02-architecture/mmd-diagrams/architecture/18-lock-checkpoint-shutdown.mmd,-,M +3/-11,M +2/-1,M +88/-84 +docs/02-architecture/mmd-diagrams/architecture/18a-lock-system.mmd,-,-,A +57/-0,A +60/-0 +docs/02-architecture/mmd-diagrams/architecture/18b-checkpoint-shutdown.mmd,-,-,A +63/-0,A +66/-0 +docs/02-architecture/mmd-diagrams/architecture/png/INDEX.md,D +0/-202,-,D +0/-202,D +0/-202 +docs/02-architecture/mmd-diagrams/architecture/svg/INDEX.md,D +0/-202,-,D +0/-202,D +0/-202 +docs/02-architecture/mmd-diagrams/class-diagrams/01-domain-ports.mmd,M +1/-0,M +2/-0,-,M +252/-252 +docs/02-architecture/mmd-diagrams/class-diagrams/02-entities-aggregates.mmd,M +1/-0,M +2/-0,-,M +237/-237 +docs/02-architecture/mmd-diagrams/class-diagrams/03-value-objects.mmd,M +1/-0,M +2/-0,-,M +278/-278 +docs/02-architecture/mmd-diagrams/class-diagrams/04-types-enums.mmd,M +1/-0,M +2/-0,-,M +231/-231 +docs/02-architecture/mmd-diagrams/class-diagrams/05-exceptions.mmd,M +1/-0,M +3/-1,M +1/-1,M +161/-161 +docs/02-architecture/mmd-diagrams/class-diagrams/06-config-classes.mmd,M +1/-0,M +16/-14,M +14/-14,M +177/-177 +docs/02-architecture/mmd-diagrams/class-diagrams/07-application-core-services.mmd,M +1/-0,M +2/-0,-,M +229/-229 +docs/02-architecture/mmd-diagrams/class-diagrams/08-application-services.mmd,M +1/-0,M +2/-0,-,M +198/-198 +docs/02-architecture/mmd-diagrams/class-diagrams/09-transformers.mmd,M +1/-0,M +2/-0,-,M +152/-152 +docs/02-architecture/mmd-diagrams/class-diagrams/10-adapters.mmd,M +1/-0,M +2/-0,-,M +225/-225 +docs/02-architecture/mmd-diagrams/class-diagrams/11-storage.mmd,M +1/-0,M +3/-1,-,M +248/-248 +docs/02-architecture/mmd-diagrams/class-diagrams/12-composite-pipeline.mmd,M +1/-0,M +2/-0,-,M +187/-187 +docs/02-architecture/mmd-diagrams/class-diagrams/13-domain-services.mmd,M +1/-0,M +2/-0,-,M +57/-57 +docs/02-architecture/mmd-diagrams/class-diagrams/14-observability.mmd,M +1/-0,M +5/-3,-,M +246/-246 +docs/02-architecture/mmd-diagrams/class-diagrams/15-extractors.mmd,M +1/-0,M +2/-0,-,M +107/-107 +docs/02-architecture/mmd-diagrams/class-diagrams/16-factories-bootstrap.mmd,M +1/-0,M +2/-0,M +1/-1,M +136/-136 +docs/02-architecture/mmd-diagrams/class-diagrams/png/INDEX.md,D +0/-100,-,D +0/-100,D +0/-100 +docs/02-architecture/mmd-diagrams/class-diagrams/svg/INDEX.md,D +0/-100,-,D +0/-100,D +0/-100 +docs/02-architecture/mmd-diagrams/docs/00-diagramming-policy.md,-,-,M +15/-274,- +docs/02-architecture/mmd-diagrams/foundation/01-full-system-component.mmd,-,M +8/-32,M +1/-1,M +263/-260 +docs/02-architecture/mmd-diagrams/foundation/01-high-level.mmd,-,M +11/-12,-,M +60/-57 +docs/02-architecture/mmd-diagrams/foundation/01a-system-overview.mmd,A +28/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/01b-system-data-pipeline.mmd,A +33/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/01c-system-cross-cutting.mmd,A +39/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/02-full-medallion-data-flow.mmd,-,M +7/-11,M +1/-1,M +59/-56 +docs/02-architecture/mmd-diagrams/foundation/03-pipeline-execution-happy-path.mmd,-,M +2/-1,M +1/-1,M +87/-84 +docs/02-architecture/mmd-diagrams/foundation/04-domain-layer-class-diagram.mmd,-,M +2/-1,-,M +344/-341 +docs/02-architecture/mmd-diagrams/foundation/04-error-flow.mmd,-,M +6/-5,M +4/-4,M +47/-44 +docs/02-architecture/mmd-diagrams/foundation/05-layers-interaction.mmd,-,M +7/-7,-,M +63/-60 +docs/02-architecture/mmd-diagrams/foundation/05-pipeline-lifecycle-states.mmd,-,M +2/-1,M +1/-1,M +177/-174 +docs/02-architecture/mmd-diagrams/foundation/06-application-layer-class-diagram.mmd,-,M +2/-1,M +1/-1,M +364/-361 +docs/02-architecture/mmd-diagrams/foundation/06-pipeline-execution.mmd,-,M +2/-0,M +3/-3,M +64/-61 +docs/02-architecture/mmd-diagrams/foundation/07-circuit-breaker-states.mmd,-,M +2/-1,M +1/-1,M +67/-64 +docs/02-architecture/mmd-diagrams/foundation/07-medallion-flow.mmd,-,M +6/-4,M +1/-1,M +52/-49 +docs/02-architecture/mmd-diagrams/foundation/08-complete-etl-workflow.mmd,-,M +11/-10,M +1/-1,M +99/-99 +docs/02-architecture/mmd-diagrams/foundation/08-domain-ddd.mmd,-,M +2/-0,M +1/-1,M +70/-67 +docs/02-architecture/mmd-diagrams/foundation/09-full-er-diagram.mmd,-,M +2/-1,-,M +234/-234 +docs/02-architecture/mmd-diagrams/foundation/10-infrastructure-layer-class-diagram.mmd,-,M +2/-1,M +1/-1,M +372/-369 +docs/02-architecture/mmd-diagrams/foundation/11-lock-acquisition-sequence.mmd,-,M +2/-1,M +29/-29,M +85/-82 +docs/02-architecture/mmd-diagrams/foundation/12-local-deployment-architecture.mmd,-,M +7/-9,-,M +74/-71 +docs/02-architecture/mmd-diagrams/foundation/13-domain-models-relationship.mmd,-,M +2/-1,-,M +399/-396 +docs/02-architecture/mmd-diagrams/foundation/14-provider-health-states.mmd,-,M +2/-1,M +1/-1,M +101/-98 +docs/02-architecture/mmd-diagrams/foundation/15-dq-check-workflow.mmd,-,M +11/-12,-,M +100/-100 +docs/02-architecture/mmd-diagrams/foundation/16-memory-lock-class.mmd,-,M +2/-1,-,M +136/-133 +docs/02-architecture/mmd-diagrams/foundation/17-pipeline-hierarchy.mmd,-,M +2/-1,-,M +233/-233 +docs/02-architecture/mmd-diagrams/foundation/18-bronze-write-sequence.mmd,-,M +2/-1,-,M +63/-60 +docs/02-architecture/mmd-diagrams/foundation/19-delta-lake-write-sequence.mmd,-,M +2/-1,M +1/-1,M +103/-100 +docs/02-architecture/mmd-diagrams/foundation/20-quarantine-record-states.mmd,-,M +2/-1,M +1/-1,M +122/-119 +docs/02-architecture/mmd-diagrams/foundation/21-activity-entity-data-flow.mmd,-,M +6/-13,-,M +93/-90 +docs/02-architecture/mmd-diagrams/foundation/22-client-api-request-sequence.mmd,-,M +2/-1,M +1/-1,M +83/-80 +docs/02-architecture/mmd-diagrams/foundation/23-silver-writer-class.mmd,-,M +2/-1,M +2/-68,M +180/-243 +docs/02-architecture/mmd-diagrams/foundation/24-hash-service-class.mmd,-,M +2/-1,-,M +70/-67 +docs/02-architecture/mmd-diagrams/foundation/25-circuit-breaker-observer-class.mmd,-,M +2/-1,-,M +251/-248 +docs/02-architecture/mmd-diagrams/foundation/26-hexagonal-ports-adapters.mmd,-,M +8/-9,M +5/-5,M +115/-115 +docs/02-architecture/mmd-diagrams/foundation/27-import-matrix-enforcement.mmd,-,M +4/-3,-,M +53/-50 +docs/02-architecture/mmd-diagrams/foundation/28-composition-root-di-graph.mmd,-,M +15/-34,M +3/-3,M +147/-144 +docs/02-architecture/mmd-diagrams/foundation/29-composite-pipeline-workflow.mmd,-,M +11/-32,M +1/-1,M +153/-150 +docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd,-,M +8/-26,-,M +179/-176 +docs/02-architecture/mmd-diagrams/foundation/31-pipeline-run-lifecycle.mmd,-,M +2/-1,M +1/-1,M +50/-47 +docs/02-architecture/mmd-diagrams/foundation/32-single-record-journey.mmd,-,M +6/-9,M +2/-2,M +59/-56 +docs/02-architecture/mmd-diagrams/foundation/33-cli-run-interaction.mmd,-,M +2/-1,M +1/-1,M +58/-55 +docs/02-architecture/mmd-diagrams/foundation/34-batch-processing-flow.mmd,-,M +2/-1,-,M +50/-47 +docs/02-architecture/mmd-diagrams/foundation/36-architecture-principles-mindmap.mmd,-,M +2/-1,-,M +84/-84 +docs/02-architecture/mmd-diagrams/foundation/37-cli-entry-full-chain.mmd,-,M +6/-5,M +2/-2,M +57/-54 +docs/02-architecture/mmd-diagrams/foundation/38-runtime-assembly-sequence.mmd,-,M +2/-1,M +1/-1,M +66/-63 +docs/02-architecture/mmd-diagrams/foundation/39-medallion-invariants.mmd,-,M +7/-15,M +1/-1,M +73/-70 +docs/02-architecture/mmd-diagrams/foundation/40-application-core-collaboration.mmd,-,M +5/-10,M +2/-2,M +49/-46 +docs/02-architecture/mmd-diagrams/foundation/41-error-classification-tree.mmd,-,M +10/-29,-,M +134/-131 +docs/02-architecture/mmd-diagrams/foundation/42-pipeline-runner-class.mmd,-,M +2/-1,M +1/-1,M +158/-155 +docs/02-architecture/mmd-diagrams/foundation/43-fan-out-fan-in-pattern.mmd,-,M +5/-6,M +2/-2,M +57/-54 +docs/02-architecture/mmd-diagrams/foundation/44-cross-provider-enrichment.mmd,-,M +5/-6,M +5/-5,M +55/-52 +docs/02-architecture/mmd-diagrams/foundation/46-yaml-config-resolution.mmd,-,M +8/-26,M +4/-4,M +128/-125 +docs/02-architecture/mmd-diagrams/foundation/47-publication-merge-sources.mmd,-,M +2/-1,M +1/-1,M +60/-57 +docs/02-architecture/mmd-diagrams/foundation/48-composite-phase-lifecycle.mmd,-,M +2/-1,M +1/-1,M +115/-112 +docs/02-architecture/mmd-diagrams/foundation/49-composite-runner-class.mmd,-,M +2/-1,M +1/-1,M +332/-329 +docs/02-architecture/mmd-diagrams/foundation/50-exception-hierarchy.mmd,-,M +10/-9,M +5/-5,M +95/-92 +docs/02-architecture/mmd-diagrams/foundation/50a-exceptions-critical.mmd,A +33/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/50b-exceptions-recoverable.mmd,A +39/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/50c-exceptions-data-quality.mmd,A +35/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/png/INDEX.md,D +0/-328,-,D +0/-328,D +0/-328 +docs/02-architecture/mmd-diagrams/foundation/svg/INDEX.md,D +0/-328,-,D +0/-328,D +0/-328 +docs/02-architecture/mmd-diagrams/render.sh,M +6/-0,-,-,M +21/-0 +docs/02-architecture/mmd-diagrams/theme/custom-dark.css,-,-,-,A +260/-0 +docs/02-architecture/mmd-diagrams/theme/custom.css,-,-,M +9/-0,M +66/-12 +docs/02-architecture/mmd-diagrams/theme/mermaid-config.json,-,-,M +1/-1,M +7/-7 +docs/02-architecture/mmd-diagrams/views/00-legend.mermaid,-,M +3/-1,-,M +61/-61 +docs/02-architecture/mmd-diagrams/views/01-full-system-component-dataflow.mermaid,M +9/-8,M +13/-14,M +1/-1,M +40/-40 +docs/02-architecture/mmd-diagrams/views/01-full-system-component-domain.mermaid,M +11/-10,M +4/-2,M +1/-1,M +48/-48 +docs/02-architecture/mmd-diagrams/views/01-full-system-component-full.mermaid,-,M +8/-32,M +1/-1,M +260/-260 +docs/02-architecture/mmd-diagrams/views/01-full-system-component-infra.mermaid,M +2/-1,M +6/-10,-,M +38/-38 +docs/02-architecture/mmd-diagrams/views/01-full-system-component-overview.mermaid,-,M +8/-13,M +1/-1,M +54/-54 +docs/02-architecture/mmd-diagrams/views/01-high-level-dataflow.mermaid,M +11/-10,M +15/-16,M +1/-1,M +44/-44 +docs/02-architecture/mmd-diagrams/views/01-high-level-domain.mermaid,-,M +7/-11,-,M +63/-63 +docs/02-architecture/mmd-diagrams/views/01-high-level-full.mermaid,-,M +19/-20,M +6/-15,M +72/-81 +docs/02-architecture/mmd-diagrams/views/01-high-level-infra.mermaid,M +12/-11,M +6/-10,M +1/-1,M +58/-58 +docs/02-architecture/mmd-diagrams/views/01-high-level-overview.mermaid,-,M +6/-10,-,M +54/-54 +docs/02-architecture/mmd-diagrams/views/02-medallion-dataflow.mermaid,M +3/-2,M +4/-2,-,M +16/-16 +docs/02-architecture/mmd-diagrams/views/02-medallion-domain.mermaid,M +3/-2,M +6/-4,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/02-medallion-full.mermaid,-,M +11/-10,M +3/-3,M +49/-49 +docs/02-architecture/mmd-diagrams/views/02-medallion-infra.mermaid,M +3/-2,M +4/-2,-,M +24/-24 +docs/02-architecture/mmd-diagrams/views/02-medallion-overview.mermaid,M +3/-2,M +6/-4,-,M +27/-27 +docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-dataflow.mermaid,M +9/-8,M +12/-10,M +1/-1,M +36/-36 +docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-domain.mermaid,M +8/-7,M +2/-0,-,M +34/-34 +docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-full.mermaid,-,M +2/-1,-,M +312/-312 +docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-infra.mermaid,M +11/-10,M +4/-2,M +1/-1,M +48/-48 +docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-overview.mermaid,-,M +5/-3,-,M +50/-50 +docs/02-architecture/mmd-diagrams/views/05-layers-interaction-dataflow.mermaid,M +10/-9,M +17/-21,M +1/-1,M +57/-57 +docs/02-architecture/mmd-diagrams/views/05-layers-interaction-domain.mermaid,-,M +7/-8,-,M +61/-61 +docs/02-architecture/mmd-diagrams/views/05-layers-interaction-full.mermaid,-,M +15/-15,M +2/-13,M +68/-79 +docs/02-architecture/mmd-diagrams/views/05-layers-interaction-infra.mermaid,-,M +7/-8,-,M +61/-61 +docs/02-architecture/mmd-diagrams/views/05-layers-interaction-overview.mermaid,M +11/-10,M +6/-7,M +1/-1,M +51/-51 +docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-dataflow.mermaid,M +9/-8,M +13/-14,M +1/-1,M +40/-40 +docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-domain.mermaid,-,M +8/-9,-,M +60/-60 +docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-full.mermaid,-,M +2/-1,M +1/-1,M +174/-174 +docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-infra.mermaid,-,M +7/-5,-,M +58/-58 +docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-overview.mermaid,-,M +7/-5,-,M +46/-46 +docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-dataflow.mermaid,M +11/-10,M +14/-12,M +1/-1,M +40/-40 +docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-domain.mermaid,-,M +4/-2,-,M +50/-50 +docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-full.mermaid,-,M +2/-1,M +1/-1,M +361/-361 +docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-infra.mermaid,-,M +4/-2,-,M +48/-48 +docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-overview.mermaid,-,M +4/-5,-,M +38/-38 +docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-dataflow.mermaid,-,M +4/-2,-,M +28/-28 +docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-domain.mermaid,-,M +4/-5,-,M +49/-49 +docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-full.mermaid,-,M +2/-1,M +1/-1,M +64/-64 +docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-infra.mermaid,-,M +4/-5,-,M +49/-49 +docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-overview.mermaid,-,M +4/-5,-,M +42/-42 +docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-dataflow.mermaid,M +10/-9,M +11/-9,M +1/-1,M +30/-30 +docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-domain.mermaid,-,M +6/-4,-,M +47/-47 +docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-full.mermaid,-,M +59/-58,M +6/-59,M +103/-156 +docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-infra.mermaid,-,M +4/-2,-,M +39/-39 +docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-overview.mermaid,M +12/-11,M +15/-13,M +1/-1,M +45/-45 +docs/02-architecture/mmd-diagrams/views/08-domain-ddd-dataflow.mermaid,M +11/-10,M +15/-13,M +1/-1,M +44/-44 +docs/02-architecture/mmd-diagrams/views/08-domain-ddd-domain.mermaid,-,M +5/-3,M +2/-14,M +51/-63 +docs/02-architecture/mmd-diagrams/views/08-domain-ddd-full.mermaid,-,M +15/-13,M +3/-19,M +72/-88 +docs/02-architecture/mmd-diagrams/views/08-domain-ddd-infra.mermaid,-,M +5/-3,M +3/-16,M +52/-65 +docs/02-architecture/mmd-diagrams/views/08-domain-ddd-overview.mermaid,-,M +5/-6,M +2/-11,M +43/-52 +docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-dataflow.mermaid,M +12/-11,M +16/-17,M +1/-1,M +46/-46 +docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-domain.mermaid,-,M +5/-6,-,M +51/-51 +docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-full.mermaid,-,M +2/-1,M +1/-1,M +369/-369 +docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-infra.mermaid,-,M +5/-6,-,M +48/-48 +docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-overview.mermaid,-,M +5/-6,-,M +47/-47 +docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-dataflow.mermaid,M +12/-11,M +15/-16,M +1/-1,M +42/-42 +docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-domain.mermaid,-,M +5/-6,M +2/-18,M +55/-71 +docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-full.mermaid,-,M +11/-12,M +8/-27,M +76/-95 +docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-infra.mermaid,-,M +4/-5,-,M +49/-49 +docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-overview.mermaid,-,M +5/-6,-,M +44/-44 +docs/02-architecture/mmd-diagrams/views/14-provider-health-states-dataflow.mermaid,-,M +6/-4,-,M +39/-39 +docs/02-architecture/mmd-diagrams/views/14-provider-health-states-domain.mermaid,-,M +4/-5,-,M +52/-52 +docs/02-architecture/mmd-diagrams/views/14-provider-health-states-full.mermaid,-,M +2/-1,M +1/-1,M +98/-98 +docs/02-architecture/mmd-diagrams/views/14-provider-health-states-infra.mermaid,-,M +5/-6,-,M +56/-56 +docs/02-architecture/mmd-diagrams/views/14-provider-health-states-overview.mermaid,-,M +5/-6,M +3/-19,M +50/-66 +docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-dataflow.mermaid,-,M +6/-7,-,M +37/-37 +docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-domain.mermaid,-,M +4/-2,-,M +46/-46 +docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-full.mermaid,-,M +11/-12,M +7/-7,M +103/-103 +docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-infra.mermaid,-,M +6/-7,-,M +54/-54 +docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-overview.mermaid,-,M +6/-7,-,M +44/-44 +docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-dataflow.mermaid,-,M +4/-2,-,M +25/-25 +docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-domain.mermaid,-,M +2/-0,-,M +37/-37 +docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-full.mermaid,-,M +7/-10,M +5/-21,M +98/-114 +docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-infra.mermaid,-,M +2/-0,-,M +37/-37 +docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-overview.mermaid,-,M +2/-0,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-dataflow.mermaid,-,M +4/-2,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-domain.mermaid,-,M +4/-2,-,M +46/-46 +docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-full.mermaid,-,M +7/-6,M +4/-4,M +128/-128 +docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-infra.mermaid,-,M +4/-2,-,M +44/-44 +docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-overview.mermaid,-,M +4/-2,-,M +36/-36 +docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-dataflow.mermaid,M +14/-13,M +17/-18,M +2/-14,M +34/-46 +docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-domain.mermaid,M +20/-19,M +5/-6,M +2/-20,M +52/-70 +docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-full.mermaid,-,M +15/-34,M +3/-3,M +144/-144 +docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-infra.mermaid,M +20/-19,M +5/-9,M +2/-20,M +52/-70 +docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-overview.mermaid,-,M +6/-5,M +1/-1,M +43/-43 +docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-dataflow.mermaid,M +11/-10,M +15/-19,M +1/-1,M +44/-44 +docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-domain.mermaid,M +23/-22,M +24/-22,M +2/-23,M +43/-64 +docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-full.mermaid,-,M +11/-32,M +1/-1,M +150/-150 +docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-infra.mermaid,M +23/-22,M +26/-27,M +2/-23,M +51/-72 +docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-overview.mermaid,-,M +4/-3,-,M +19/-19 +docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-dataflow.mermaid,M +7/-6,M +4/-2,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-domain.mermaid,M +11/-10,M +4/-2,M +1/-1,M +48/-48 +docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-full.mermaid,-,M +8/-26,-,M +176/-176 +docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-infra.mermaid,M +11/-10,M +4/-2,M +1/-1,M +48/-48 +docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-overview.mermaid,-,M +5/-7,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-dataflow.mermaid,M +15/-14,M +19/-20,M +2/-15,M +39/-52 +docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-domain.mermaid,-,M +9/-8,M +1/-1,M +64/-64 +docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-full.mermaid,-,M +2/-1,M +1/-1,M +47/-47 +docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-infra.mermaid,-,M +9/-31,-,M +96/-96 +docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-overview.mermaid,-,M +9/-11,M +1/-1,M +53/-53 +docs/02-architecture/mmd-diagrams/views/32-single-record-journey-dataflow.mermaid,-,M +3/-2,-,M +25/-25 +docs/02-architecture/mmd-diagrams/views/32-single-record-journey-domain.mermaid,-,M +6/-5,-,M +49/-49 +docs/02-architecture/mmd-diagrams/views/32-single-record-journey-full.mermaid,-,M +18/-21,M +6/-16,M +60/-70 +docs/02-architecture/mmd-diagrams/views/32-single-record-journey-infra.mermaid,-,M +4/-3,-,M +41/-41 +docs/02-architecture/mmd-diagrams/views/32-single-record-journey-overview.mermaid,-,M +5/-4,-,M +39/-39 +docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-dataflow.mermaid,-,M +6/-8,-,M +48/-48 +docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-domain.mermaid,-,M +5/-7,-,M +64/-64 +docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-full.mermaid,-,M +2/-1,M +1/-1,M +61/-61 +docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-infra.mermaid,-,M +6/-8,-,M +68/-68 +docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-overview.mermaid,-,M +6/-5,-,M +53/-53 +docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-dataflow.mermaid,M +18/-17,M +22/-23,M +2/-18,M +42/-58 +docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-domain.mermaid,-,M +7/-6,-,M +59/-59 +docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-full.mermaid,-,M +2/-1,-,M +51/-51 +docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-infra.mermaid,-,M +7/-9,-,M +59/-59 +docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-overview.mermaid,M +21/-20,M +25/-26,M +2/-21,M +48/-67 +docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-dataflow.mermaid,M +12/-11,M +2/-0,M +1/-1,M +34/-34 +docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-domain.mermaid,M +22/-21,M +2/-0,M +2/-22,M +42/-62 +docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-full.mermaid,-,M +5/-4,-,M +82/-82 +docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-infra.mermaid,M +22/-21,M +2/-0,M +2/-22,M +42/-62 +docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-overview.mermaid,M +16/-15,M +2/-0,M +2/-16,M +31/-45 +docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-dataflow.mermaid,M +12/-11,M +17/-21,M +1/-1,M +50/-50 +docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-domain.mermaid,M +12/-11,M +5/-3,M +1/-1,M +54/-54 +docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-full.mermaid,-,M +2/-1,-,M +84/-84 +docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-infra.mermaid,M +6/-5,M +5/-3,-,M +42/-42 +docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-overview.mermaid,-,M +6/-7,M +3/-13,M +50/-60 +docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-dataflow.mermaid,M +10/-9,M +11/-9,M +1/-1,M +30/-30 +docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-domain.mermaid,M +15/-14,M +16/-14,M +2/-15,M +35/-48 +docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-full.mermaid,-,M +17/-25,M +3/-13,M +73/-83 +docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-infra.mermaid,M +15/-14,M +18/-19,M +2/-15,M +43/-56 +docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-overview.mermaid,M +12/-11,M +13/-11,M +1/-1,M +37/-37 +docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-dataflow.mermaid,M +10/-9,M +14/-15,M +1/-1,M +42/-42 +docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-domain.mermaid,M +17/-16,M +21/-22,M +2/-17,M +49/-64 +docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-full.mermaid,-,M +10/-29,-,M +131/-131 +docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-infra.mermaid,M +17/-16,M +20/-18,M +2/-17,M +45/-60 +docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-overview.mermaid,-,M +6/-5,-,M +38/-38 +docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-dataflow.mermaid,M +10/-9,M +13/-14,M +1/-1,M +38/-38 +docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-domain.mermaid,M +17/-16,M +4/-2,M +2/-17,M +45/-60 +docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-full.mermaid,-,M +5/-4,M +5/-16,M +54/-65 +docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-infra.mermaid,M +17/-16,M +4/-2,M +2/-17,M +45/-60 +docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-overview.mermaid,M +11/-10,M +4/-5,M +1/-1,M +43/-43 +docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-dataflow.mermaid,M +5/-4,M +9/-7,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-domain.mermaid,M +5/-4,M +5/-6,-,M +40/-40 +docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-full.mermaid,-,M +8/-26,M +1/-1,M +116/-116 +docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-infra.mermaid,M +5/-4,M +6/-7,-,M +44/-44 +docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-overview.mermaid,M +5/-4,M +5/-3,-,M +35/-35 +docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-dataflow.mermaid,M +14/-13,M +18/-22,M +2/-14,M +38/-50 +docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-domain.mermaid,-,M +4/-6,-,M +55/-55 +docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-full.mermaid,-,M +2/-1,M +1/-1,M +112/-112 +docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-infra.mermaid,-,M +5/-10,-,M +59/-59 +docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-overview.mermaid,M +15/-14,M +4/-2,M +2/-15,M +38/-51 +docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-dataflow.mermaid,M +9/-8,M +13/-11,M +1/-1,M +40/-40 +docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-domain.mermaid,-,M +5/-6,M +2/-20,M +57/-75 +docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-full.mermaid,-,M +12/-11,M +7/-7,M +98/-98 +docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-infra.mermaid,M +23/-22,M +5/-6,M +2/-23,M +55/-76 +docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-overview.mermaid,-,M +5/-3,M +3/-17,M +48/-62 +docs/02-architecture/mmd-diagrams/views/png/INDEX.md,D +0/-940,-,D +0/-940,D +0/-940 +docs/02-architecture/mmd-diagrams/views/svg/INDEX.md,D +0/-940,-,D +0/-940,D +0/-940 +docs/05-operations/verification/gold-contracts-export-diff-2026-02-17.json,M +26/-26,-,M +26/-26,M +26/-26 +docs/reports/diagram-audit-consolidated-2026-02-28.md,-,-,A +171/-0,- +docs/reports/diagram-refactoring-plan-2026-02-28.md,-,-,A +241/-0,- +docs/reports/documentation-cascade-audit-2026-02-27.md,A +106/-0,-,A +106/-0,A +106/-0 +docs/skills/global/documentation-audit/SKILL.md,M +3/-3,-,M +3/-3,M +3/-3 +docs/skills/global/documentation-audit/agents/openai.yaml,M +2/-2,-,M +2/-2,M +2/-2 +docs/skills/global/documentation-audit/references/audit-checklist.md,M +2/-2,-,M +2/-2,M +2/-2 +docs/skills/global/documentation-audit/references/report-template.md,M +1/-1,-,M +1/-1,M +1/-1 +docs/skills/local/documentation-audit/SKILL.md,M +3/-3,-,M +3/-3,M +3/-3 +docs/skills/local/documentation-audit/agents/openai.yaml,M +2/-2,-,M +2/-2,M +2/-2 +docs/skills/local/documentation-audit/references/audit-checklist.md,M +2/-2,-,M +2/-2,M +2/-2 +docs/skills/local/documentation-audit/references/report-template.md,M +1/-1,-,M +1/-1,M +1/-1 +mkdocs.yml,M +18/-8,-,M +0/-8,M +0/-8 +pyproject.toml,M +2/-0,-,M +2/-0,M +2/-0 +reports/review/FINAL-REVIEW.md,A +339/-0,-,A +339/-0,A +339/-0 +reports/review/S1-domain.md,A +135/-0,-,A +135/-0,A +135/-0 +reports/review/S1.1-ports-contracts.md,A +79/-0,-,A +79/-0,A +79/-0 +reports/review/S1.2-entities-value-objects.md,A +72/-0,-,A +72/-0,A +72/-0 +reports/review/S1.3-schemas.md,A +77/-0,-,A +77/-0,A +77/-0 +reports/review/S1.4-services-filtering-mapping.md,A +81/-0,-,A +81/-0,A +81/-0 +reports/review/S1.5-config-composite-aggregates-misc.md,A +95/-0,-,A +95/-0,A +95/-0 +reports/review/S2-application.md,A +153/-0,-,A +153/-0,A +153/-0 +reports/review/S2.1-chembl-common.md,A +44/-0,-,A +44/-0,A +44/-0 +reports/review/S2.2-pubmed-crossref-openalex.md,A +41/-0,-,A +41/-0,A +41/-0 +reports/review/S2.3-pubchem-semanticscholar-uniprot.md,A +46/-0,-,A +46/-0,A +46/-0 +reports/review/S2.4-core.md,A +76/-0,-,A +76/-0,A +76/-0 +reports/review/S2.5-composite-services-observability.md,A +58/-0,-,A +58/-0,A +58/-0 +reports/review/S3-infrastructure.md,A +244/-0,-,A +244/-0,A +244/-0 +reports/review/S3.1-chembl-pubmed-crossref.md,A +77/-0,-,A +77/-0,A +77/-0 +reports/review/S3.2-pubchem-openalex-semanticscholar-uniprot.md,A +77/-0,-,A +77/-0,A +77/-0 +reports/review/S3.3-base-http-common-decorators-input.md,A +99/-0,-,A +99/-0,A +99/-0 +reports/review/S3.4-storage-config-schemas.md,A +132/-0,-,A +132/-0,A +132/-0 +reports/review/S3.5-observability-remaining.md,A +115/-0,-,A +115/-0,A +115/-0 +reports/review/S4-composition-interfaces.md,A +192/-0,-,A +192/-0,A +192/-0 +reports/review/S4.1-bootstrap-factories.md,A +185/-0,-,A +185/-0,A +185/-0 +reports/review/S4.2-composition-remaining.md,A +241/-0,-,A +241/-0,A +241/-0 +reports/review/S4.3-interfaces.md,A +285/-0,-,A +285/-0,A +285/-0 +reports/review/S5-crosscutting.md,A +400/-0,-,A +400/-0,A +400/-0 +reports/review/S6-tests.md,A +173/-0,-,A +173/-0,A +173/-0 +reports/review/S6.1-architecture-tests.md,A +61/-0,-,A +61/-0,A +61/-0 +reports/review/S6.2-unit-domain.md,A +50/-0,-,A +50/-0,A +50/-0 +reports/review/S6.3-unit-application.md,A +55/-0,-,A +55/-0,A +55/-0 +reports/review/S6.4-unit-infrastructure.md,A +62/-0,-,A +62/-0,A +62/-0 +reports/review/S6.5-unit-remaining.md,A +78/-0,-,A +78/-0,A +78/-0 +reports/review/S6.6-integration-e2e-other.md,A +128/-0,-,A +128/-0,A +128/-0 +reports/review/S7-configs.md,A +261/-0,-,A +261/-0,A +261/-0 +reports/review/S8-documentation.md,A +160/-0,-,A +160/-0,A +160/-0 +reports/review/S8.1-project-requirements.md,A +41/-0,-,A +41/-0,A +41/-0 +reports/review/S8.2-architecture.md,A +61/-0,-,A +61/-0,A +61/-0 +reports/review/S8.3-reference.md,A +51/-0,-,A +51/-0,A +51/-0 +reports/review/S8.4-guides-operations-datamodel.md,A +45/-0,-,A +45/-0,A +45/-0 +scripts/add_svg_text_fallback.py,-,-,M +15/-9,- +scripts/check_diagram_quality_gates.py,-,-,M +9/-3,- +scripts/extract_diagram_params.py,-,A +2113/-0,-,- +scripts/fix_diagram_links.py,-,-,M +35/-19,- +scripts/fix_link_warnings.py,-,-,A +269/-0,A +269/-0 +scripts/fix_sequence_nbsp.py,M +1/-1,-,M +1/-1,M +1/-1 +scripts/lint_diagrams.py,M +27/-0,-,M +71/-12,M +71/-12 +scripts/reindex_linkstyles.py,-,-,-,A +180/-0 +scripts/uniform_diagram_sizes.py,-,-,M +1/-1,- +src/bioetl/application/core/base.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/application/core/dict_transformers.py,M +55/-55,-,M +55/-55,M +55/-55 +src/bioetl/application/core/pipeline_services.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/application/core/quarantine_manager.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/application/pipelines/chembl/publication_transformer.py,M +3/-3,-,M +3/-3,M +3/-3 +src/bioetl/application/pipelines/generic.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/application/pipelines/pubmed/__init__.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/application/pipelines/pubmed/extractors/abstract.py,M +2/-2,-,M +2/-2,M +2/-2 +src/bioetl/application/pipelines/pubmed/extractors/author.py,M +3/-4,-,M +3/-4,M +3/-4 +src/bioetl/application/pipelines/pubmed/extractors/base.py,M +12/-12,-,M +12/-12,M +12/-12 +src/bioetl/application/pipelines/pubmed/extractors/classification.py,M +2/-2,-,M +2/-2,M +2/-2 +src/bioetl/application/pipelines/pubmed/extractors/date.py,M +2/-2,-,M +2/-2,M +2/-2 +src/bioetl/composition/__init__.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/composition/factories/pipeline_factories.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/composition/factories/pipeline_factory.py,M +101/-5,-,M +101/-5,M +101/-5 +src/bioetl/composition/factories/storage_adapter.py,M +10/-0,-,M +10/-0,M +10/-0 +src/bioetl/composition/factories/storage_factory.py,M +39/-0,-,M +39/-0,M +39/-0 +src/bioetl/composition/providers/decorators.py,M +20/-20,-,M +20/-20,M +20/-20 +src/bioetl/composition/providers/provider_registry.py,M +74/-73,-,M +74/-73,M +74/-73 +src/bioetl/composition/providers/registration.py,M +79/-13,-,M +79/-13,M +79/-13 +src/bioetl/composition/runtime_builders/runner_builder.py,M +49/-0,-,M +49/-0,M +49/-0 +src/bioetl/domain/config/pipeline.py,M +2/-2,-,M +2/-2,M +2/-2 +src/bioetl/domain/configs/__init__.py,M +2/-2,-,M +2/-2,M +2/-2 +src/bioetl/domain/configs/base.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/domain/entities/bioactivity.py,M +22/-1,-,M +22/-1,M +22/-1 +src/bioetl/domain/entities/chembl_structures.py,M +2/-2,-,M +2/-2,M +2/-2 +src/bioetl/domain/exceptions/data_quality.py,M +3/-3,-,M +3/-3,M +3/-3 +src/bioetl/domain/exceptions/infrastructure.py,M +2/-2,-,M +2/-2,M +2/-2 +src/bioetl/domain/exceptions/internal.py,M +3/-3,-,M +3/-3,M +3/-3 +src/bioetl/domain/exceptions/network.py,M +3/-3,-,M +3/-3,M +3/-3 +src/bioetl/domain/exceptions/validation.py,M +2/-2,-,M +2/-2,M +2/-2 +src/bioetl/domain/filtering/_base_filter_config.py,M +26/-26,-,M +26/-26,M +26/-26 +src/bioetl/domain/filtering/column_filter.py,M +12/-12,-,M +12/-12,M +12/-12 +src/bioetl/domain/filtering/gold_config.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/domain/filtering/list_filters.py,M +8/-8,-,M +8/-8,M +8/-8 +src/bioetl/domain/filtering/load_result.py,M +7/-7,-,M +7/-7,M +7/-7 +src/bioetl/domain/filtering/range_filter.py,M +6/-6,-,M +6/-6,M +6/-6 +src/bioetl/domain/filtering/silver_config.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/domain/mapping/publication_fields.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/domain/medallion.py,M +3/-3,-,M +3/-3,M +3/-3 +src/bioetl/domain/resilience.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/domain/validation.py,M +6/-4,-,M +6/-4,M +6/-4 +src/bioetl/infrastructure/adapters/chembl/client.py,M +31/-4,-,M +31/-4,M +31/-4 +src/bioetl/infrastructure/adapters/chembl/health.py,M +35/-2,-,M +35/-2,M +35/-2 +src/bioetl/infrastructure/schemas/__init__.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/infrastructure/schemas/pipeline_config.py,M +4/-4,-,M +4/-4,M +4/-4 +src/bioetl/infrastructure/schemas/source_config.py,M +4/-4,-,M +4/-4,M +4/-4 +src/bioetl/infrastructure/storage/silver_writer.py,M +1/-1,-,M +1/-1,M +1/-1 +src/bioetl/interfaces/http/health_server.py,M +4/-4,-,M +4/-4,M +4/-4 +src/tools/apply_elk_layout.py,M +9/-3,-,M +9/-3,M +9/-3 +src/tools/harmonize_link_styles.py,M +1/-1,-,M +1/-1,M +1/-1 +tests/architecture/test_code_metrics.py,M +8/-4,-,M +8/-4,M +8/-4 +tests/architecture/test_run_diagram_checks_script.py,M +1/-1,-,M +1/-1,M +1/-1 diff --git a/docs/reports/branch-full-diff-matrix-2026-03-01.md b/docs/reports/branch-full-diff-matrix-2026-03-01.md new file mode 100644 index 0000000000..1975ddc7b5 --- /dev/null +++ b/docs/reports/branch-full-diff-matrix-2026-03-01.md @@ -0,0 +1,221 @@ +# Full Branch Diff Matrix (vs local HEAD) — 2026-03-01 + +Baseline: local branch `TMP01-01` (`HEAD`).\ +Cell format: `STATUS +added/-deleted` from `git diff HEAD..origin/`. + +Total union files: **478**.\ +Full machine-readable matrix: `docs/reports/branch-full-diff-matrix-2026-03-01.csv`. + +## Totals + +| Branch | Changed files | +|---|---:| +| `bioetl-architecture-prompts-v3-lLJJu` | 240 | +| `audit-fix-diagrams-hZglG` | 263 | +| `audit-diagram-docs-scripts-fUJUM` | 349 | +| `improve-diagram-design-K2XMN` | 452 | + +## Preview (first 200 files) + +| File | `bioetl-architecture-prompts-v3-lLJJu` | `audit-fix-diagrams-hZglG` | `audit-diagram-docs-scripts-fUJUM` | `improve-diagram-design-K2XMN` | +|---|---|---|---|---| +| `"2_10_\321\203\320\273\321\203\321\207\321\210\320\265\320\275\320\270\320\271_\320\264\320\273\321\217_\320\276\320\277\321\202\320\270\320\274\320\270\320\267\320\260\321\206\320\270\320\270_\321\200\320\260.md"` | D +0/-57 | - | D +0/-57 | D +0/-57 | +| `"3_10_\321\203\320\273\321\203\321\207\321\210\320\265\320\275\320\270\320\271_\320\264\320\273\321\217_\320\276\320\277\321\202\320\270\320\274\320\270\320\267\320\260\321\206\320\270\320\270_\321\200\320\260.md"` | D +0/-52 | - | D +0/-52 | D +0/-52 | +| `.claude/agents/ORCHESTRATION.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/agents/py-audit-bot.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/agents/py-doc-bot.md` | M +2/-2 | - | M +2/-2 | M +2/-2 | +| `.claude/prompts/00-Audit/02-architecture-audit.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/00-Audit/02-file-structure-audit-standardization.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/00-Audit/03-code-inventory-audit.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/00-Documentation/00-documentation-audit-update-task.md` | M +2/-2 | - | M +2/-2 | M +2/-2 | +| `.claude/prompts/00-Documentation/01-docstrings-completion.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/00-Documentation/04-naming-compliance-audit-prompt.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/01-documentation-update-prompt.md` | M +8/-8 | - | M +8/-8 | M +8/-8 | +| `.claude/prompts/02-Sync/01-xwalk.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/02-Sync/02-docs-PR.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/02-Sync/03-pk-issue.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/02-Sync/04-schema-review.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/02-Sync/05-vcr-tests.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/02-Sync/06-manual-EP.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/02-Sync/07-bot-xwalk.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/prompts/03-repository-cleanup-assistant.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/settings.local.json` | - | M +2/-1 | - | - | +| `.claude/skills/documentation-audit.audit-checklist.md` | M +2/-2 | - | M +2/-2 | M +2/-2 | +| `.claude/skills/documentation-audit.openai.yaml` | M +2/-2 | - | M +2/-2 | M +2/-2 | +| `.claude/skills/documentation-audit.report-template.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.claude/skills/documentation-audit.skill.md` | M +3/-3 | - | M +3/-3 | M +3/-3 | +| `.claude/skills/mermaid-design.md` | - | M +22/-14 | M +22/-17 | - | +| `.github/workflows/contract-tests.yml` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `.github/workflows/docs.yml` | M +4/-0 | - | - | - | +| `.github/workflows/port-contracts.yml` | M +2/-2 | - | M +2/-2 | M +2/-2 | +| `.gitignore` | M +2/-1 | - | M +2/-1 | M +2/-1 | +| `Makefile` | - | - | M +1/-1 | - | +| `assets/javascripts/MERMAID_VERSION` | - | - | M +1/-1 | - | +| `assets/javascripts/download_mermaid.ps1` | - | - | M +2/-2 | - | +| `assets/javascripts/mermaid-loader.js` | - | - | M +1/-1 | - | +| `assets/stylesheets/mermaid.css` | - | - | - | M +34/-0 | +| `chrome-headless-shell/.metadata` | D +0/-5 | - | D +0/-5 | D +0/-5 | +| `chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/ABOUT` | D +0/-9 | - | D +0/-9 | D +0/-9 | +| `chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/LICENSE.headless_shell` | D +0/-37908 | - | D +0/-37908 | D +0/-37908 | +| `chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/deb.deps` | D +0/-30 | - | D +0/-30 | D +0/-30 | +| `chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/icudtl.dat` | D +-/-- | - | D +-/-- | D +-/-- | +| `chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/libvulkan.so.1` | D +-/-- | - | D +-/-- | D +-/-- | +| `chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/rpm.deps` | D +0/-92 | - | D +0/-92 | D +0/-92 | +| `chrome-headless-shell/linux-146.0.7680.31/chrome-headless-shell-linux64/v8_context_snapshot.bin` | D +-/-- | - | D +-/-- | D +-/-- | +| `docs/00-project/00-map.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `docs/00-project/agents/AGENT.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `docs/00-project/agents/CLAUDE.md` | M +3/-3 | - | M +3/-3 | M +3/-3 | +| `docs/00-project/agents/orchestration/ORCHESTRATION.md` | M +1/-1 | - | M +1/-1 | M +1/-1 | +| `docs/00-project/glossary.md` | M +1/-0 | - | M +1/-0 | M +1/-0 | +| `docs/02-architecture/00-overview.md` | M +7/-1 | - | M +7/-1 | M +7/-1 | +| `docs/02-architecture/06-diagram-policy.md` | - | - | M +4/-15 | - | +| `docs/02-architecture/architecture-diagrams.md` | - | - | M +15/-15 | - | +| `docs/02-architecture/decisions/ADR-040-diagram-governance.md` | - | M +24/-8 | M +2/-2 | - | +| `docs/02-architecture/diagrams/architecture-diagrams-prompts-v4.md` | A +392/-0 | - | - | - | +| `docs/02-architecture/diagrams/mermaid/01-full-system-component-full.mermaid` | - | - | M +8/-38 | M +160/-190 | +| `docs/02-architecture/diagrams/mermaid/04-domain-layer-class-diagram-full.mermaid` | - | - | - | M +284/-284 | +| `docs/02-architecture/diagrams/mermaid/21-activity-entity-data-flow-full.mermaid` | - | - | M +6/-22 | M +97/-113 | +| `docs/02-architecture/diagrams/mermaid/26-hexagonal-ports-adapters-full.mermaid` | - | - | M +7/-22 | M +123/-138 | +| `docs/02-architecture/diagrams/mermaid/28-composition-root-di-graph-full.mermaid` | - | - | M +10/-35 | M +91/-116 | +| `docs/02-architecture/diagrams/mermaid/29-composite-pipeline-workflow-full.mermaid` | - | - | M +6/-23 | M +91/-108 | +| `docs/02-architecture/diagrams/mermaid/30-port-adapter-mapping-full.mermaid` | - | - | M +4/-33 | M +108/-137 | +| `docs/02-architecture/diagrams/mermaid/32-single-record-journey-full.mermaid` | - | - | M +6/-16 | M +60/-70 | +| `docs/02-architecture/diagrams/mermaid/35-bootstrap-sequence-full.mermaid` | - | - | M +5/-23 | M +81/-99 | +| `docs/02-architecture/diagrams/mermaid/39-medallion-invariants-full.mermaid` | - | - | M +8/-18 | M +73/-83 | +| `docs/02-architecture/diagrams/mermaid/44-cross-provider-enrichment-full.mermaid` | - | - | M +5/-16 | M +54/-65 | +| `docs/02-architecture/diagrams/mermaid/46-yaml-config-resolution-full.mermaid` | - | - | M +8/-33 | M +83/-108 | +| `docs/02-architecture/diagrams/mermaid/png/INDEX.md` | D +0/-76 | - | D +0/-76 | D +0/-76 | +| `docs/02-architecture/diagrams/mermaid/svg/INDEX.md` | D +0/-76 | - | D +0/-76 | D +0/-76 | +| `docs/02-architecture/mmd-diagrams/00-legend.mmd` | A +54/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/_template.mmd` | - | - | M +1/-0 | M +85/-79 | +| `docs/02-architecture/mmd-diagrams/architecture/01-high-level-hexagonal.mmd` | - | M +4/-4 | M +1/-0 | M +127/-122 | +| `docs/02-architecture/mmd-diagrams/architecture/01a-hexagonal-overview.mmd` | - | M +7/-13 | - | M +57/-54 | +| `docs/02-architecture/mmd-diagrams/architecture/01b-hexagonal-domain-app.mmd` | - | M +3/-3 | - | M +37/-34 | +| `docs/02-architecture/mmd-diagrams/architecture/01c-hexagonal-infra-comp.mmd` | - | M +3/-6 | M +1/-1 | M +48/-45 | +| `docs/02-architecture/mmd-diagrams/architecture/02-layer-dependency-matrix.mmd` | - | M +2/-1 | - | M +54/-51 | +| `docs/02-architecture/mmd-diagrams/architecture/03-medallion-data-flow.mmd` | - | M +8/-10 | M +7/-6 | M +125/-103 | +| `docs/02-architecture/mmd-diagrams/architecture/03a-medallion-layers-overview.mmd` | - | M +4/-3 | - | M +35/-32 | +| `docs/02-architecture/mmd-diagrams/architecture/04-pipeline-execution-flow.mmd` | - | M +1/-0 | M +1/-1 | M +101/-98 | +| `docs/02-architecture/mmd-diagrams/architecture/05-provider-adapter-hierarchy.mmd` | - | M +3/-14 | M +1/-0 | M +110/-106 | +| `docs/02-architecture/mmd-diagrams/architecture/05a-adapter-hierarchy-base.mmd` | - | M +3/-3 | - | M +33/-30 | +| `docs/02-architecture/mmd-diagrams/architecture/05b-adapter-hierarchy-providers.mmd` | - | M +2/-2 | M +1/-1 | M +40/-37 | +| `docs/02-architecture/mmd-diagrams/architecture/06-storage-layer.mmd` | - | M +4/-10 | M +1/-0 | M +100/-96 | +| `docs/02-architecture/mmd-diagrams/architecture/06a-storage-writers.mmd` | - | - | A +65/-0 | A +68/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/06b-storage-support.mmd` | - | - | A +45/-0 | A +48/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/07-dq-system.mmd` | - | M +4/-4 | M +1/-0 | M +107/-106 | +| `docs/02-architecture/mmd-diagrams/architecture/07a-dq-analysis.mmd` | - | - | A +60/-0 | A +63/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/07b-dq-pipeline.mmd` | - | - | A +47/-0 | A +50/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/08-composite-pipeline.mmd` | - | M +7/-13 | M +3/-2 | M +136/-124 | +| `docs/02-architecture/mmd-diagrams/architecture/08a-composite-config.mmd` | - | - | A +56/-0 | A +59/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/08b-composite-execution.mmd` | - | - | A +99/-0 | A +102/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/09-observability-stack.mmd` | - | M +6/-12 | M +2/-1 | M +85/-81 | +| `docs/02-architecture/mmd-diagrams/architecture/09a-observability-app.mmd` | - | - | A +44/-0 | A +47/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/09b-observability-infra.mmd` | - | - | A +62/-0 | A +65/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/10-resilience-patterns.mmd` | - | M +5/-9 | M +2/-2 | M +74/-71 | +| `docs/02-architecture/mmd-diagrams/architecture/11-configuration-system.mmd` | - | M +3/-6 | M +1/-0 | M +112/-108 | +| `docs/02-architecture/mmd-diagrams/architecture/11a-config-loading.mmd` | - | - | A +58/-0 | A +61/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/11b-config-domain.mmd` | - | - | A +63/-0 | A +66/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/12-bootstrap-di-container.mmd` | - | M +3/-5 | M +2/-1 | M +134/-121 | +| `docs/02-architecture/mmd-diagrams/architecture/12a-bootstrap-factories.mmd` | - | M +3/-2 | M +1/-1 | M +37/-34 | +| `docs/02-architecture/mmd-diagrams/architecture/12b-bootstrap-wiring.mmd` | - | M +4/-4 | M +1/-1 | M +58/-55 | +| `docs/02-architecture/mmd-diagrams/architecture/13-port-protocol-contracts.mmd` | - | M +4/-4 | M +1/-0 | M +136/-135 | +| `docs/02-architecture/mmd-diagrams/architecture/13a-data-storage-ports.mmd` | - | M +2/-16 | - | M +44/-44 | +| `docs/02-architecture/mmd-diagrams/architecture/13a-port-contracts-data-sources.mmd` | - | M +3/-4 | - | M +18/-18 | +| `docs/02-architecture/mmd-diagrams/architecture/13b-operational-ports.mmd` | - | M +2/-16 | M +1/-0 | M +48/-47 | +| `docs/02-architecture/mmd-diagrams/architecture/13b-port-contracts-storage.mmd` | - | M +3/-2 | - | M +23/-23 | +| `docs/02-architecture/mmd-diagrams/architecture/13c-port-contracts-observability.mmd` | - | M +3/-3 | - | M +29/-29 | +| `docs/02-architecture/mmd-diagrams/architecture/13c-validation-dq-ports.mmd` | - | M +2/-16 | - | M +50/-50 | +| `docs/02-architecture/mmd-diagrams/architecture/13d-port-contracts-services.mmd` | - | M +5/-5 | M +1/-1 | M +61/-61 | +| `docs/02-architecture/mmd-diagrams/architecture/13e-operational-ports-domain.mmd` | - | - | A +26/-0 | A +26/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/13f-operational-ports-infra.mmd` | - | - | A +25/-0 | A +25/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/14-cli-interface-layer.mmd` | - | M +3/-9 | M +1/-0 | M +91/-87 | +| `docs/02-architecture/mmd-diagrams/architecture/14a-cli-commands.mmd` | - | - | A +60/-0 | A +63/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/14b-cli-routing.mmd` | - | - | A +62/-0 | A +65/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/15-batch-executor-internals.mmd` | - | M +6/-12 | M +2/-2 | M +61/-61 | +| `docs/02-architecture/mmd-diagrams/architecture/16-transformer-hierarchy.mmd` | - | M +7/-9 | M +2/-1 | M +54/-50 | +| `docs/02-architecture/mmd-diagrams/architecture/16a-transformer-base.mmd` | - | - | A +50/-0 | A +50/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/16b-transformer-pub-other.mmd` | - | - | A +59/-0 | A +62/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/17-security-pii-audit.mmd` | - | M +5/-7 | M +1/-1 | M +74/-71 | +| `docs/02-architecture/mmd-diagrams/architecture/18-lock-checkpoint-shutdown.mmd` | - | M +3/-11 | M +2/-1 | M +88/-84 | +| `docs/02-architecture/mmd-diagrams/architecture/18a-lock-system.mmd` | - | - | A +57/-0 | A +60/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/18b-checkpoint-shutdown.mmd` | - | - | A +63/-0 | A +66/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/png/INDEX.md` | D +0/-202 | - | D +0/-202 | D +0/-202 | +| `docs/02-architecture/mmd-diagrams/architecture/svg/INDEX.md` | D +0/-202 | - | D +0/-202 | D +0/-202 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/01-domain-ports.mmd` | M +1/-0 | M +2/-0 | - | M +252/-252 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/02-entities-aggregates.mmd` | M +1/-0 | M +2/-0 | - | M +237/-237 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/03-value-objects.mmd` | M +1/-0 | M +2/-0 | - | M +278/-278 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/04-types-enums.mmd` | M +1/-0 | M +2/-0 | - | M +231/-231 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/05-exceptions.mmd` | M +1/-0 | M +3/-1 | M +1/-1 | M +161/-161 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/06-config-classes.mmd` | M +1/-0 | M +16/-14 | M +14/-14 | M +177/-177 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/07-application-core-services.mmd` | M +1/-0 | M +2/-0 | - | M +229/-229 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/08-application-services.mmd` | M +1/-0 | M +2/-0 | - | M +198/-198 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/09-transformers.mmd` | M +1/-0 | M +2/-0 | - | M +152/-152 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/10-adapters.mmd` | M +1/-0 | M +2/-0 | - | M +225/-225 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/11-storage.mmd` | M +1/-0 | M +3/-1 | - | M +248/-248 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/12-composite-pipeline.mmd` | M +1/-0 | M +2/-0 | - | M +187/-187 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/13-domain-services.mmd` | M +1/-0 | M +2/-0 | - | M +57/-57 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/14-observability.mmd` | M +1/-0 | M +5/-3 | - | M +246/-246 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/15-extractors.mmd` | M +1/-0 | M +2/-0 | - | M +107/-107 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/16-factories-bootstrap.mmd` | M +1/-0 | M +2/-0 | M +1/-1 | M +136/-136 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/png/INDEX.md` | D +0/-100 | - | D +0/-100 | D +0/-100 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/svg/INDEX.md` | D +0/-100 | - | D +0/-100 | D +0/-100 | +| `docs/02-architecture/mmd-diagrams/docs/00-diagramming-policy.md` | - | - | M +15/-274 | - | +| `docs/02-architecture/mmd-diagrams/foundation/01-full-system-component.mmd` | - | M +8/-32 | M +1/-1 | M +263/-260 | +| `docs/02-architecture/mmd-diagrams/foundation/01-high-level.mmd` | - | M +11/-12 | - | M +60/-57 | +| `docs/02-architecture/mmd-diagrams/foundation/01a-system-overview.mmd` | A +28/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/foundation/01b-system-data-pipeline.mmd` | A +33/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/foundation/01c-system-cross-cutting.mmd` | A +39/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/foundation/02-full-medallion-data-flow.mmd` | - | M +7/-11 | M +1/-1 | M +59/-56 | +| `docs/02-architecture/mmd-diagrams/foundation/03-pipeline-execution-happy-path.mmd` | - | M +2/-1 | M +1/-1 | M +87/-84 | +| `docs/02-architecture/mmd-diagrams/foundation/04-domain-layer-class-diagram.mmd` | - | M +2/-1 | - | M +344/-341 | +| `docs/02-architecture/mmd-diagrams/foundation/04-error-flow.mmd` | - | M +6/-5 | M +4/-4 | M +47/-44 | +| `docs/02-architecture/mmd-diagrams/foundation/05-layers-interaction.mmd` | - | M +7/-7 | - | M +63/-60 | +| `docs/02-architecture/mmd-diagrams/foundation/05-pipeline-lifecycle-states.mmd` | - | M +2/-1 | M +1/-1 | M +177/-174 | +| `docs/02-architecture/mmd-diagrams/foundation/06-application-layer-class-diagram.mmd` | - | M +2/-1 | M +1/-1 | M +364/-361 | +| `docs/02-architecture/mmd-diagrams/foundation/06-pipeline-execution.mmd` | - | M +2/-0 | M +3/-3 | M +64/-61 | +| `docs/02-architecture/mmd-diagrams/foundation/07-circuit-breaker-states.mmd` | - | M +2/-1 | M +1/-1 | M +67/-64 | +| `docs/02-architecture/mmd-diagrams/foundation/07-medallion-flow.mmd` | - | M +6/-4 | M +1/-1 | M +52/-49 | +| `docs/02-architecture/mmd-diagrams/foundation/08-complete-etl-workflow.mmd` | - | M +11/-10 | M +1/-1 | M +99/-99 | +| `docs/02-architecture/mmd-diagrams/foundation/08-domain-ddd.mmd` | - | M +2/-0 | M +1/-1 | M +70/-67 | +| `docs/02-architecture/mmd-diagrams/foundation/09-full-er-diagram.mmd` | - | M +2/-1 | - | M +234/-234 | +| `docs/02-architecture/mmd-diagrams/foundation/10-infrastructure-layer-class-diagram.mmd` | - | M +2/-1 | M +1/-1 | M +372/-369 | +| `docs/02-architecture/mmd-diagrams/foundation/11-lock-acquisition-sequence.mmd` | - | M +2/-1 | M +29/-29 | M +85/-82 | +| `docs/02-architecture/mmd-diagrams/foundation/12-local-deployment-architecture.mmd` | - | M +7/-9 | - | M +74/-71 | +| `docs/02-architecture/mmd-diagrams/foundation/13-domain-models-relationship.mmd` | - | M +2/-1 | - | M +399/-396 | +| `docs/02-architecture/mmd-diagrams/foundation/14-provider-health-states.mmd` | - | M +2/-1 | M +1/-1 | M +101/-98 | +| `docs/02-architecture/mmd-diagrams/foundation/15-dq-check-workflow.mmd` | - | M +11/-12 | - | M +100/-100 | +| `docs/02-architecture/mmd-diagrams/foundation/16-memory-lock-class.mmd` | - | M +2/-1 | - | M +136/-133 | +| `docs/02-architecture/mmd-diagrams/foundation/17-pipeline-hierarchy.mmd` | - | M +2/-1 | - | M +233/-233 | +| `docs/02-architecture/mmd-diagrams/foundation/18-bronze-write-sequence.mmd` | - | M +2/-1 | - | M +63/-60 | +| `docs/02-architecture/mmd-diagrams/foundation/19-delta-lake-write-sequence.mmd` | - | M +2/-1 | M +1/-1 | M +103/-100 | +| `docs/02-architecture/mmd-diagrams/foundation/20-quarantine-record-states.mmd` | - | M +2/-1 | M +1/-1 | M +122/-119 | +| `docs/02-architecture/mmd-diagrams/foundation/21-activity-entity-data-flow.mmd` | - | M +6/-13 | - | M +93/-90 | +| `docs/02-architecture/mmd-diagrams/foundation/22-client-api-request-sequence.mmd` | - | M +2/-1 | M +1/-1 | M +83/-80 | +| `docs/02-architecture/mmd-diagrams/foundation/23-silver-writer-class.mmd` | - | M +2/-1 | M +2/-68 | M +180/-243 | +| `docs/02-architecture/mmd-diagrams/foundation/24-hash-service-class.mmd` | - | M +2/-1 | - | M +70/-67 | +| `docs/02-architecture/mmd-diagrams/foundation/25-circuit-breaker-observer-class.mmd` | - | M +2/-1 | - | M +251/-248 | +| `docs/02-architecture/mmd-diagrams/foundation/26-hexagonal-ports-adapters.mmd` | - | M +8/-9 | M +5/-5 | M +115/-115 | +| `docs/02-architecture/mmd-diagrams/foundation/27-import-matrix-enforcement.mmd` | - | M +4/-3 | - | M +53/-50 | +| `docs/02-architecture/mmd-diagrams/foundation/28-composition-root-di-graph.mmd` | - | M +15/-34 | M +3/-3 | M +147/-144 | +| `docs/02-architecture/mmd-diagrams/foundation/29-composite-pipeline-workflow.mmd` | - | M +11/-32 | M +1/-1 | M +153/-150 | +| `docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd` | - | M +8/-26 | - | M +179/-176 | +| `docs/02-architecture/mmd-diagrams/foundation/31-pipeline-run-lifecycle.mmd` | - | M +2/-1 | M +1/-1 | M +50/-47 | +| `docs/02-architecture/mmd-diagrams/foundation/32-single-record-journey.mmd` | - | M +6/-9 | M +2/-2 | M +59/-56 | +| `docs/02-architecture/mmd-diagrams/foundation/33-cli-run-interaction.mmd` | - | M +2/-1 | M +1/-1 | M +58/-55 | +| `docs/02-architecture/mmd-diagrams/foundation/34-batch-processing-flow.mmd` | - | M +2/-1 | - | M +50/-47 | +| `docs/02-architecture/mmd-diagrams/foundation/36-architecture-principles-mindmap.mmd` | - | M +2/-1 | - | M +84/-84 | +| `docs/02-architecture/mmd-diagrams/foundation/37-cli-entry-full-chain.mmd` | - | M +6/-5 | M +2/-2 | M +57/-54 | +| `docs/02-architecture/mmd-diagrams/foundation/38-runtime-assembly-sequence.mmd` | - | M +2/-1 | M +1/-1 | M +66/-63 | +| `docs/02-architecture/mmd-diagrams/foundation/39-medallion-invariants.mmd` | - | M +7/-15 | M +1/-1 | M +73/-70 | +| `docs/02-architecture/mmd-diagrams/foundation/40-application-core-collaboration.mmd` | - | M +5/-10 | M +2/-2 | M +49/-46 | +| `docs/02-architecture/mmd-diagrams/foundation/41-error-classification-tree.mmd` | - | M +10/-29 | - | M +134/-131 | +| `docs/02-architecture/mmd-diagrams/foundation/42-pipeline-runner-class.mmd` | - | M +2/-1 | M +1/-1 | M +158/-155 | +| `docs/02-architecture/mmd-diagrams/foundation/43-fan-out-fan-in-pattern.mmd` | - | M +5/-6 | M +2/-2 | M +57/-54 | +| `docs/02-architecture/mmd-diagrams/foundation/44-cross-provider-enrichment.mmd` | - | M +5/-6 | M +5/-5 | M +55/-52 | +| `docs/02-architecture/mmd-diagrams/foundation/46-yaml-config-resolution.mmd` | - | M +8/-26 | M +4/-4 | M +128/-125 | +| `docs/02-architecture/mmd-diagrams/foundation/47-publication-merge-sources.mmd` | - | M +2/-1 | M +1/-1 | M +60/-57 | +| `docs/02-architecture/mmd-diagrams/foundation/48-composite-phase-lifecycle.mmd` | - | M +2/-1 | M +1/-1 | M +115/-112 | +| `docs/02-architecture/mmd-diagrams/foundation/49-composite-runner-class.mmd` | - | M +2/-1 | M +1/-1 | M +332/-329 | +| `docs/02-architecture/mmd-diagrams/foundation/50-exception-hierarchy.mmd` | - | M +10/-9 | M +5/-5 | M +95/-92 | +| `docs/02-architecture/mmd-diagrams/foundation/50a-exceptions-critical.mmd` | A +33/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/foundation/50b-exceptions-recoverable.mmd` | A +39/-0 | - | - | - | diff --git a/docs/reports/branch-full-diff-matrix-diagram-scope-2026-03-01.csv b/docs/reports/branch-full-diff-matrix-diagram-scope-2026-03-01.csv new file mode 100644 index 0000000000..01507c3f92 --- /dev/null +++ b/docs/reports/branch-full-diff-matrix-diagram-scope-2026-03-01.csv @@ -0,0 +1,314 @@ +file,bioetl-architecture-prompts-v3-lLJJu,audit-fix-diagrams-hZglG,audit-diagram-docs-scripts-fUJUM,improve-diagram-design-K2XMN +.github/workflows/docs.yml,M +4/-0,-,-,- +assets/javascripts/MERMAID_VERSION,-,-,M +1/-1,- +assets/javascripts/mermaid-loader.js,-,-,M +1/-1,- +assets/stylesheets/mermaid.css,-,-,-,M +34/-0 +docs/02-architecture/06-diagram-policy.md,-,-,M +4/-15,- +docs/02-architecture/architecture-diagrams.md,-,-,M +15/-15,- +docs/02-architecture/decisions/ADR-040-diagram-governance.md,-,M +24/-8,M +2/-2,- +docs/02-architecture/mmd-diagrams/00-legend.mmd,A +54/-0,-,-,- +docs/02-architecture/mmd-diagrams/_template.mmd,-,-,M +1/-0,M +85/-79 +docs/02-architecture/mmd-diagrams/architecture/01-high-level-hexagonal.mmd,-,M +4/-4,M +1/-0,M +127/-122 +docs/02-architecture/mmd-diagrams/architecture/01a-hexagonal-overview.mmd,-,M +7/-13,-,M +57/-54 +docs/02-architecture/mmd-diagrams/architecture/01b-hexagonal-domain-app.mmd,-,M +3/-3,-,M +37/-34 +docs/02-architecture/mmd-diagrams/architecture/01c-hexagonal-infra-comp.mmd,-,M +3/-6,M +1/-1,M +48/-45 +docs/02-architecture/mmd-diagrams/architecture/02-layer-dependency-matrix.mmd,-,M +2/-1,-,M +54/-51 +docs/02-architecture/mmd-diagrams/architecture/03-medallion-data-flow.mmd,-,M +8/-10,M +7/-6,M +125/-103 +docs/02-architecture/mmd-diagrams/architecture/03a-medallion-layers-overview.mmd,-,M +4/-3,-,M +35/-32 +docs/02-architecture/mmd-diagrams/architecture/04-pipeline-execution-flow.mmd,-,M +1/-0,M +1/-1,M +101/-98 +docs/02-architecture/mmd-diagrams/architecture/05-provider-adapter-hierarchy.mmd,-,M +3/-14,M +1/-0,M +110/-106 +docs/02-architecture/mmd-diagrams/architecture/05a-adapter-hierarchy-base.mmd,-,M +3/-3,-,M +33/-30 +docs/02-architecture/mmd-diagrams/architecture/05b-adapter-hierarchy-providers.mmd,-,M +2/-2,M +1/-1,M +40/-37 +docs/02-architecture/mmd-diagrams/architecture/06-storage-layer.mmd,-,M +4/-10,M +1/-0,M +100/-96 +docs/02-architecture/mmd-diagrams/architecture/06a-storage-writers.mmd,-,-,A +65/-0,A +68/-0 +docs/02-architecture/mmd-diagrams/architecture/06b-storage-support.mmd,-,-,A +45/-0,A +48/-0 +docs/02-architecture/mmd-diagrams/architecture/07-dq-system.mmd,-,M +4/-4,M +1/-0,M +107/-106 +docs/02-architecture/mmd-diagrams/architecture/07a-dq-analysis.mmd,-,-,A +60/-0,A +63/-0 +docs/02-architecture/mmd-diagrams/architecture/07b-dq-pipeline.mmd,-,-,A +47/-0,A +50/-0 +docs/02-architecture/mmd-diagrams/architecture/08-composite-pipeline.mmd,-,M +7/-13,M +3/-2,M +136/-124 +docs/02-architecture/mmd-diagrams/architecture/08a-composite-config.mmd,-,-,A +56/-0,A +59/-0 +docs/02-architecture/mmd-diagrams/architecture/08b-composite-execution.mmd,-,-,A +99/-0,A +102/-0 +docs/02-architecture/mmd-diagrams/architecture/09-observability-stack.mmd,-,M +6/-12,M +2/-1,M +85/-81 +docs/02-architecture/mmd-diagrams/architecture/09a-observability-app.mmd,-,-,A +44/-0,A +47/-0 +docs/02-architecture/mmd-diagrams/architecture/09b-observability-infra.mmd,-,-,A +62/-0,A +65/-0 +docs/02-architecture/mmd-diagrams/architecture/10-resilience-patterns.mmd,-,M +5/-9,M +2/-2,M +74/-71 +docs/02-architecture/mmd-diagrams/architecture/11-configuration-system.mmd,-,M +3/-6,M +1/-0,M +112/-108 +docs/02-architecture/mmd-diagrams/architecture/11a-config-loading.mmd,-,-,A +58/-0,A +61/-0 +docs/02-architecture/mmd-diagrams/architecture/11b-config-domain.mmd,-,-,A +63/-0,A +66/-0 +docs/02-architecture/mmd-diagrams/architecture/12-bootstrap-di-container.mmd,-,M +3/-5,M +2/-1,M +134/-121 +docs/02-architecture/mmd-diagrams/architecture/12a-bootstrap-factories.mmd,-,M +3/-2,M +1/-1,M +37/-34 +docs/02-architecture/mmd-diagrams/architecture/12b-bootstrap-wiring.mmd,-,M +4/-4,M +1/-1,M +58/-55 +docs/02-architecture/mmd-diagrams/architecture/13-port-protocol-contracts.mmd,-,M +4/-4,M +1/-0,M +136/-135 +docs/02-architecture/mmd-diagrams/architecture/13a-data-storage-ports.mmd,-,M +2/-16,-,M +44/-44 +docs/02-architecture/mmd-diagrams/architecture/13a-port-contracts-data-sources.mmd,-,M +3/-4,-,M +18/-18 +docs/02-architecture/mmd-diagrams/architecture/13b-operational-ports.mmd,-,M +2/-16,M +1/-0,M +48/-47 +docs/02-architecture/mmd-diagrams/architecture/13b-port-contracts-storage.mmd,-,M +3/-2,-,M +23/-23 +docs/02-architecture/mmd-diagrams/architecture/13c-port-contracts-observability.mmd,-,M +3/-3,-,M +29/-29 +docs/02-architecture/mmd-diagrams/architecture/13c-validation-dq-ports.mmd,-,M +2/-16,-,M +50/-50 +docs/02-architecture/mmd-diagrams/architecture/13d-port-contracts-services.mmd,-,M +5/-5,M +1/-1,M +61/-61 +docs/02-architecture/mmd-diagrams/architecture/13e-operational-ports-domain.mmd,-,-,A +26/-0,A +26/-0 +docs/02-architecture/mmd-diagrams/architecture/13f-operational-ports-infra.mmd,-,-,A +25/-0,A +25/-0 +docs/02-architecture/mmd-diagrams/architecture/14-cli-interface-layer.mmd,-,M +3/-9,M +1/-0,M +91/-87 +docs/02-architecture/mmd-diagrams/architecture/14a-cli-commands.mmd,-,-,A +60/-0,A +63/-0 +docs/02-architecture/mmd-diagrams/architecture/14b-cli-routing.mmd,-,-,A +62/-0,A +65/-0 +docs/02-architecture/mmd-diagrams/architecture/15-batch-executor-internals.mmd,-,M +6/-12,M +2/-2,M +61/-61 +docs/02-architecture/mmd-diagrams/architecture/16-transformer-hierarchy.mmd,-,M +7/-9,M +2/-1,M +54/-50 +docs/02-architecture/mmd-diagrams/architecture/16a-transformer-base.mmd,-,-,A +50/-0,A +50/-0 +docs/02-architecture/mmd-diagrams/architecture/16b-transformer-pub-other.mmd,-,-,A +59/-0,A +62/-0 +docs/02-architecture/mmd-diagrams/architecture/17-security-pii-audit.mmd,-,M +5/-7,M +1/-1,M +74/-71 +docs/02-architecture/mmd-diagrams/architecture/18-lock-checkpoint-shutdown.mmd,-,M +3/-11,M +2/-1,M +88/-84 +docs/02-architecture/mmd-diagrams/architecture/18a-lock-system.mmd,-,-,A +57/-0,A +60/-0 +docs/02-architecture/mmd-diagrams/architecture/18b-checkpoint-shutdown.mmd,-,-,A +63/-0,A +66/-0 +docs/02-architecture/mmd-diagrams/architecture/png/INDEX.md,D +0/-202,-,D +0/-202,D +0/-202 +docs/02-architecture/mmd-diagrams/architecture/svg/INDEX.md,D +0/-202,-,D +0/-202,D +0/-202 +docs/02-architecture/mmd-diagrams/class-diagrams/01-domain-ports.mmd,M +1/-0,M +2/-0,-,M +252/-252 +docs/02-architecture/mmd-diagrams/class-diagrams/02-entities-aggregates.mmd,M +1/-0,M +2/-0,-,M +237/-237 +docs/02-architecture/mmd-diagrams/class-diagrams/03-value-objects.mmd,M +1/-0,M +2/-0,-,M +278/-278 +docs/02-architecture/mmd-diagrams/class-diagrams/04-types-enums.mmd,M +1/-0,M +2/-0,-,M +231/-231 +docs/02-architecture/mmd-diagrams/class-diagrams/05-exceptions.mmd,M +1/-0,M +3/-1,M +1/-1,M +161/-161 +docs/02-architecture/mmd-diagrams/class-diagrams/06-config-classes.mmd,M +1/-0,M +16/-14,M +14/-14,M +177/-177 +docs/02-architecture/mmd-diagrams/class-diagrams/07-application-core-services.mmd,M +1/-0,M +2/-0,-,M +229/-229 +docs/02-architecture/mmd-diagrams/class-diagrams/08-application-services.mmd,M +1/-0,M +2/-0,-,M +198/-198 +docs/02-architecture/mmd-diagrams/class-diagrams/09-transformers.mmd,M +1/-0,M +2/-0,-,M +152/-152 +docs/02-architecture/mmd-diagrams/class-diagrams/10-adapters.mmd,M +1/-0,M +2/-0,-,M +225/-225 +docs/02-architecture/mmd-diagrams/class-diagrams/11-storage.mmd,M +1/-0,M +3/-1,-,M +248/-248 +docs/02-architecture/mmd-diagrams/class-diagrams/12-composite-pipeline.mmd,M +1/-0,M +2/-0,-,M +187/-187 +docs/02-architecture/mmd-diagrams/class-diagrams/13-domain-services.mmd,M +1/-0,M +2/-0,-,M +57/-57 +docs/02-architecture/mmd-diagrams/class-diagrams/14-observability.mmd,M +1/-0,M +5/-3,-,M +246/-246 +docs/02-architecture/mmd-diagrams/class-diagrams/15-extractors.mmd,M +1/-0,M +2/-0,-,M +107/-107 +docs/02-architecture/mmd-diagrams/class-diagrams/16-factories-bootstrap.mmd,M +1/-0,M +2/-0,M +1/-1,M +136/-136 +docs/02-architecture/mmd-diagrams/class-diagrams/png/INDEX.md,D +0/-100,-,D +0/-100,D +0/-100 +docs/02-architecture/mmd-diagrams/class-diagrams/svg/INDEX.md,D +0/-100,-,D +0/-100,D +0/-100 +docs/02-architecture/mmd-diagrams/docs/00-diagramming-policy.md,-,-,M +15/-274,- +docs/02-architecture/mmd-diagrams/foundation/01-full-system-component.mmd,-,M +8/-32,M +1/-1,M +263/-260 +docs/02-architecture/mmd-diagrams/foundation/01-high-level.mmd,-,M +11/-12,-,M +60/-57 +docs/02-architecture/mmd-diagrams/foundation/01a-system-overview.mmd,A +28/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/01b-system-data-pipeline.mmd,A +33/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/01c-system-cross-cutting.mmd,A +39/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/02-full-medallion-data-flow.mmd,-,M +7/-11,M +1/-1,M +59/-56 +docs/02-architecture/mmd-diagrams/foundation/03-pipeline-execution-happy-path.mmd,-,M +2/-1,M +1/-1,M +87/-84 +docs/02-architecture/mmd-diagrams/foundation/04-domain-layer-class-diagram.mmd,-,M +2/-1,-,M +344/-341 +docs/02-architecture/mmd-diagrams/foundation/04-error-flow.mmd,-,M +6/-5,M +4/-4,M +47/-44 +docs/02-architecture/mmd-diagrams/foundation/05-layers-interaction.mmd,-,M +7/-7,-,M +63/-60 +docs/02-architecture/mmd-diagrams/foundation/05-pipeline-lifecycle-states.mmd,-,M +2/-1,M +1/-1,M +177/-174 +docs/02-architecture/mmd-diagrams/foundation/06-application-layer-class-diagram.mmd,-,M +2/-1,M +1/-1,M +364/-361 +docs/02-architecture/mmd-diagrams/foundation/06-pipeline-execution.mmd,-,M +2/-0,M +3/-3,M +64/-61 +docs/02-architecture/mmd-diagrams/foundation/07-circuit-breaker-states.mmd,-,M +2/-1,M +1/-1,M +67/-64 +docs/02-architecture/mmd-diagrams/foundation/07-medallion-flow.mmd,-,M +6/-4,M +1/-1,M +52/-49 +docs/02-architecture/mmd-diagrams/foundation/08-complete-etl-workflow.mmd,-,M +11/-10,M +1/-1,M +99/-99 +docs/02-architecture/mmd-diagrams/foundation/08-domain-ddd.mmd,-,M +2/-0,M +1/-1,M +70/-67 +docs/02-architecture/mmd-diagrams/foundation/09-full-er-diagram.mmd,-,M +2/-1,-,M +234/-234 +docs/02-architecture/mmd-diagrams/foundation/10-infrastructure-layer-class-diagram.mmd,-,M +2/-1,M +1/-1,M +372/-369 +docs/02-architecture/mmd-diagrams/foundation/11-lock-acquisition-sequence.mmd,-,M +2/-1,M +29/-29,M +85/-82 +docs/02-architecture/mmd-diagrams/foundation/12-local-deployment-architecture.mmd,-,M +7/-9,-,M +74/-71 +docs/02-architecture/mmd-diagrams/foundation/13-domain-models-relationship.mmd,-,M +2/-1,-,M +399/-396 +docs/02-architecture/mmd-diagrams/foundation/14-provider-health-states.mmd,-,M +2/-1,M +1/-1,M +101/-98 +docs/02-architecture/mmd-diagrams/foundation/15-dq-check-workflow.mmd,-,M +11/-12,-,M +100/-100 +docs/02-architecture/mmd-diagrams/foundation/16-memory-lock-class.mmd,-,M +2/-1,-,M +136/-133 +docs/02-architecture/mmd-diagrams/foundation/17-pipeline-hierarchy.mmd,-,M +2/-1,-,M +233/-233 +docs/02-architecture/mmd-diagrams/foundation/18-bronze-write-sequence.mmd,-,M +2/-1,-,M +63/-60 +docs/02-architecture/mmd-diagrams/foundation/19-delta-lake-write-sequence.mmd,-,M +2/-1,M +1/-1,M +103/-100 +docs/02-architecture/mmd-diagrams/foundation/20-quarantine-record-states.mmd,-,M +2/-1,M +1/-1,M +122/-119 +docs/02-architecture/mmd-diagrams/foundation/21-activity-entity-data-flow.mmd,-,M +6/-13,-,M +93/-90 +docs/02-architecture/mmd-diagrams/foundation/22-client-api-request-sequence.mmd,-,M +2/-1,M +1/-1,M +83/-80 +docs/02-architecture/mmd-diagrams/foundation/23-silver-writer-class.mmd,-,M +2/-1,M +2/-68,M +180/-243 +docs/02-architecture/mmd-diagrams/foundation/24-hash-service-class.mmd,-,M +2/-1,-,M +70/-67 +docs/02-architecture/mmd-diagrams/foundation/25-circuit-breaker-observer-class.mmd,-,M +2/-1,-,M +251/-248 +docs/02-architecture/mmd-diagrams/foundation/26-hexagonal-ports-adapters.mmd,-,M +8/-9,M +5/-5,M +115/-115 +docs/02-architecture/mmd-diagrams/foundation/27-import-matrix-enforcement.mmd,-,M +4/-3,-,M +53/-50 +docs/02-architecture/mmd-diagrams/foundation/28-composition-root-di-graph.mmd,-,M +15/-34,M +3/-3,M +147/-144 +docs/02-architecture/mmd-diagrams/foundation/29-composite-pipeline-workflow.mmd,-,M +11/-32,M +1/-1,M +153/-150 +docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd,-,M +8/-26,-,M +179/-176 +docs/02-architecture/mmd-diagrams/foundation/31-pipeline-run-lifecycle.mmd,-,M +2/-1,M +1/-1,M +50/-47 +docs/02-architecture/mmd-diagrams/foundation/32-single-record-journey.mmd,-,M +6/-9,M +2/-2,M +59/-56 +docs/02-architecture/mmd-diagrams/foundation/33-cli-run-interaction.mmd,-,M +2/-1,M +1/-1,M +58/-55 +docs/02-architecture/mmd-diagrams/foundation/34-batch-processing-flow.mmd,-,M +2/-1,-,M +50/-47 +docs/02-architecture/mmd-diagrams/foundation/36-architecture-principles-mindmap.mmd,-,M +2/-1,-,M +84/-84 +docs/02-architecture/mmd-diagrams/foundation/37-cli-entry-full-chain.mmd,-,M +6/-5,M +2/-2,M +57/-54 +docs/02-architecture/mmd-diagrams/foundation/38-runtime-assembly-sequence.mmd,-,M +2/-1,M +1/-1,M +66/-63 +docs/02-architecture/mmd-diagrams/foundation/39-medallion-invariants.mmd,-,M +7/-15,M +1/-1,M +73/-70 +docs/02-architecture/mmd-diagrams/foundation/40-application-core-collaboration.mmd,-,M +5/-10,M +2/-2,M +49/-46 +docs/02-architecture/mmd-diagrams/foundation/41-error-classification-tree.mmd,-,M +10/-29,-,M +134/-131 +docs/02-architecture/mmd-diagrams/foundation/42-pipeline-runner-class.mmd,-,M +2/-1,M +1/-1,M +158/-155 +docs/02-architecture/mmd-diagrams/foundation/43-fan-out-fan-in-pattern.mmd,-,M +5/-6,M +2/-2,M +57/-54 +docs/02-architecture/mmd-diagrams/foundation/44-cross-provider-enrichment.mmd,-,M +5/-6,M +5/-5,M +55/-52 +docs/02-architecture/mmd-diagrams/foundation/46-yaml-config-resolution.mmd,-,M +8/-26,M +4/-4,M +128/-125 +docs/02-architecture/mmd-diagrams/foundation/47-publication-merge-sources.mmd,-,M +2/-1,M +1/-1,M +60/-57 +docs/02-architecture/mmd-diagrams/foundation/48-composite-phase-lifecycle.mmd,-,M +2/-1,M +1/-1,M +115/-112 +docs/02-architecture/mmd-diagrams/foundation/49-composite-runner-class.mmd,-,M +2/-1,M +1/-1,M +332/-329 +docs/02-architecture/mmd-diagrams/foundation/50-exception-hierarchy.mmd,-,M +10/-9,M +5/-5,M +95/-92 +docs/02-architecture/mmd-diagrams/foundation/50a-exceptions-critical.mmd,A +33/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/50b-exceptions-recoverable.mmd,A +39/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/50c-exceptions-data-quality.mmd,A +35/-0,-,-,- +docs/02-architecture/mmd-diagrams/foundation/png/INDEX.md,D +0/-328,-,D +0/-328,D +0/-328 +docs/02-architecture/mmd-diagrams/foundation/svg/INDEX.md,D +0/-328,-,D +0/-328,D +0/-328 +docs/02-architecture/mmd-diagrams/render.sh,M +6/-0,-,-,M +21/-0 +docs/02-architecture/mmd-diagrams/theme/custom-dark.css,-,-,-,A +260/-0 +docs/02-architecture/mmd-diagrams/theme/custom.css,-,-,M +9/-0,M +66/-12 +docs/02-architecture/mmd-diagrams/theme/mermaid-config.json,-,-,M +1/-1,M +7/-7 +docs/02-architecture/mmd-diagrams/views/00-legend.mermaid,-,M +3/-1,-,M +61/-61 +docs/02-architecture/mmd-diagrams/views/01-full-system-component-dataflow.mermaid,M +9/-8,M +13/-14,M +1/-1,M +40/-40 +docs/02-architecture/mmd-diagrams/views/01-full-system-component-domain.mermaid,M +11/-10,M +4/-2,M +1/-1,M +48/-48 +docs/02-architecture/mmd-diagrams/views/01-full-system-component-full.mermaid,-,M +8/-32,M +1/-1,M +260/-260 +docs/02-architecture/mmd-diagrams/views/01-full-system-component-infra.mermaid,M +2/-1,M +6/-10,-,M +38/-38 +docs/02-architecture/mmd-diagrams/views/01-full-system-component-overview.mermaid,-,M +8/-13,M +1/-1,M +54/-54 +docs/02-architecture/mmd-diagrams/views/01-high-level-dataflow.mermaid,M +11/-10,M +15/-16,M +1/-1,M +44/-44 +docs/02-architecture/mmd-diagrams/views/01-high-level-domain.mermaid,-,M +7/-11,-,M +63/-63 +docs/02-architecture/mmd-diagrams/views/01-high-level-full.mermaid,-,M +19/-20,M +6/-15,M +72/-81 +docs/02-architecture/mmd-diagrams/views/01-high-level-infra.mermaid,M +12/-11,M +6/-10,M +1/-1,M +58/-58 +docs/02-architecture/mmd-diagrams/views/01-high-level-overview.mermaid,-,M +6/-10,-,M +54/-54 +docs/02-architecture/mmd-diagrams/views/02-medallion-dataflow.mermaid,M +3/-2,M +4/-2,-,M +16/-16 +docs/02-architecture/mmd-diagrams/views/02-medallion-domain.mermaid,M +3/-2,M +6/-4,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/02-medallion-full.mermaid,-,M +11/-10,M +3/-3,M +49/-49 +docs/02-architecture/mmd-diagrams/views/02-medallion-infra.mermaid,M +3/-2,M +4/-2,-,M +24/-24 +docs/02-architecture/mmd-diagrams/views/02-medallion-overview.mermaid,M +3/-2,M +6/-4,-,M +27/-27 +docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-dataflow.mermaid,M +9/-8,M +12/-10,M +1/-1,M +36/-36 +docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-domain.mermaid,M +8/-7,M +2/-0,-,M +34/-34 +docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-full.mermaid,-,M +2/-1,-,M +312/-312 +docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-infra.mermaid,M +11/-10,M +4/-2,M +1/-1,M +48/-48 +docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-overview.mermaid,-,M +5/-3,-,M +50/-50 +docs/02-architecture/mmd-diagrams/views/05-layers-interaction-dataflow.mermaid,M +10/-9,M +17/-21,M +1/-1,M +57/-57 +docs/02-architecture/mmd-diagrams/views/05-layers-interaction-domain.mermaid,-,M +7/-8,-,M +61/-61 +docs/02-architecture/mmd-diagrams/views/05-layers-interaction-full.mermaid,-,M +15/-15,M +2/-13,M +68/-79 +docs/02-architecture/mmd-diagrams/views/05-layers-interaction-infra.mermaid,-,M +7/-8,-,M +61/-61 +docs/02-architecture/mmd-diagrams/views/05-layers-interaction-overview.mermaid,M +11/-10,M +6/-7,M +1/-1,M +51/-51 +docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-dataflow.mermaid,M +9/-8,M +13/-14,M +1/-1,M +40/-40 +docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-domain.mermaid,-,M +8/-9,-,M +60/-60 +docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-full.mermaid,-,M +2/-1,M +1/-1,M +174/-174 +docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-infra.mermaid,-,M +7/-5,-,M +58/-58 +docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-overview.mermaid,-,M +7/-5,-,M +46/-46 +docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-dataflow.mermaid,M +11/-10,M +14/-12,M +1/-1,M +40/-40 +docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-domain.mermaid,-,M +4/-2,-,M +50/-50 +docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-full.mermaid,-,M +2/-1,M +1/-1,M +361/-361 +docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-infra.mermaid,-,M +4/-2,-,M +48/-48 +docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-overview.mermaid,-,M +4/-5,-,M +38/-38 +docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-dataflow.mermaid,-,M +4/-2,-,M +28/-28 +docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-domain.mermaid,-,M +4/-5,-,M +49/-49 +docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-full.mermaid,-,M +2/-1,M +1/-1,M +64/-64 +docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-infra.mermaid,-,M +4/-5,-,M +49/-49 +docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-overview.mermaid,-,M +4/-5,-,M +42/-42 +docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-dataflow.mermaid,M +10/-9,M +11/-9,M +1/-1,M +30/-30 +docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-domain.mermaid,-,M +6/-4,-,M +47/-47 +docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-full.mermaid,-,M +59/-58,M +6/-59,M +103/-156 +docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-infra.mermaid,-,M +4/-2,-,M +39/-39 +docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-overview.mermaid,M +12/-11,M +15/-13,M +1/-1,M +45/-45 +docs/02-architecture/mmd-diagrams/views/08-domain-ddd-dataflow.mermaid,M +11/-10,M +15/-13,M +1/-1,M +44/-44 +docs/02-architecture/mmd-diagrams/views/08-domain-ddd-domain.mermaid,-,M +5/-3,M +2/-14,M +51/-63 +docs/02-architecture/mmd-diagrams/views/08-domain-ddd-full.mermaid,-,M +15/-13,M +3/-19,M +72/-88 +docs/02-architecture/mmd-diagrams/views/08-domain-ddd-infra.mermaid,-,M +5/-3,M +3/-16,M +52/-65 +docs/02-architecture/mmd-diagrams/views/08-domain-ddd-overview.mermaid,-,M +5/-6,M +2/-11,M +43/-52 +docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-dataflow.mermaid,M +12/-11,M +16/-17,M +1/-1,M +46/-46 +docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-domain.mermaid,-,M +5/-6,-,M +51/-51 +docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-full.mermaid,-,M +2/-1,M +1/-1,M +369/-369 +docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-infra.mermaid,-,M +5/-6,-,M +48/-48 +docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-overview.mermaid,-,M +5/-6,-,M +47/-47 +docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-dataflow.mermaid,M +12/-11,M +15/-16,M +1/-1,M +42/-42 +docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-domain.mermaid,-,M +5/-6,M +2/-18,M +55/-71 +docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-full.mermaid,-,M +11/-12,M +8/-27,M +76/-95 +docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-infra.mermaid,-,M +4/-5,-,M +49/-49 +docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-overview.mermaid,-,M +5/-6,-,M +44/-44 +docs/02-architecture/mmd-diagrams/views/14-provider-health-states-dataflow.mermaid,-,M +6/-4,-,M +39/-39 +docs/02-architecture/mmd-diagrams/views/14-provider-health-states-domain.mermaid,-,M +4/-5,-,M +52/-52 +docs/02-architecture/mmd-diagrams/views/14-provider-health-states-full.mermaid,-,M +2/-1,M +1/-1,M +98/-98 +docs/02-architecture/mmd-diagrams/views/14-provider-health-states-infra.mermaid,-,M +5/-6,-,M +56/-56 +docs/02-architecture/mmd-diagrams/views/14-provider-health-states-overview.mermaid,-,M +5/-6,M +3/-19,M +50/-66 +docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-dataflow.mermaid,-,M +6/-7,-,M +37/-37 +docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-domain.mermaid,-,M +4/-2,-,M +46/-46 +docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-full.mermaid,-,M +11/-12,M +7/-7,M +103/-103 +docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-infra.mermaid,-,M +6/-7,-,M +54/-54 +docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-overview.mermaid,-,M +6/-7,-,M +44/-44 +docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-dataflow.mermaid,-,M +4/-2,-,M +25/-25 +docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-domain.mermaid,-,M +2/-0,-,M +37/-37 +docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-full.mermaid,-,M +7/-10,M +5/-21,M +98/-114 +docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-infra.mermaid,-,M +2/-0,-,M +37/-37 +docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-overview.mermaid,-,M +2/-0,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-dataflow.mermaid,-,M +4/-2,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-domain.mermaid,-,M +4/-2,-,M +46/-46 +docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-full.mermaid,-,M +7/-6,M +4/-4,M +128/-128 +docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-infra.mermaid,-,M +4/-2,-,M +44/-44 +docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-overview.mermaid,-,M +4/-2,-,M +36/-36 +docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-dataflow.mermaid,M +14/-13,M +17/-18,M +2/-14,M +34/-46 +docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-domain.mermaid,M +20/-19,M +5/-6,M +2/-20,M +52/-70 +docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-full.mermaid,-,M +15/-34,M +3/-3,M +144/-144 +docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-infra.mermaid,M +20/-19,M +5/-9,M +2/-20,M +52/-70 +docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-overview.mermaid,-,M +6/-5,M +1/-1,M +43/-43 +docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-dataflow.mermaid,M +11/-10,M +15/-19,M +1/-1,M +44/-44 +docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-domain.mermaid,M +23/-22,M +24/-22,M +2/-23,M +43/-64 +docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-full.mermaid,-,M +11/-32,M +1/-1,M +150/-150 +docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-infra.mermaid,M +23/-22,M +26/-27,M +2/-23,M +51/-72 +docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-overview.mermaid,-,M +4/-3,-,M +19/-19 +docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-dataflow.mermaid,M +7/-6,M +4/-2,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-domain.mermaid,M +11/-10,M +4/-2,M +1/-1,M +48/-48 +docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-full.mermaid,-,M +8/-26,-,M +176/-176 +docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-infra.mermaid,M +11/-10,M +4/-2,M +1/-1,M +48/-48 +docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-overview.mermaid,-,M +5/-7,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-dataflow.mermaid,M +15/-14,M +19/-20,M +2/-15,M +39/-52 +docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-domain.mermaid,-,M +9/-8,M +1/-1,M +64/-64 +docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-full.mermaid,-,M +2/-1,M +1/-1,M +47/-47 +docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-infra.mermaid,-,M +9/-31,-,M +96/-96 +docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-overview.mermaid,-,M +9/-11,M +1/-1,M +53/-53 +docs/02-architecture/mmd-diagrams/views/32-single-record-journey-dataflow.mermaid,-,M +3/-2,-,M +25/-25 +docs/02-architecture/mmd-diagrams/views/32-single-record-journey-domain.mermaid,-,M +6/-5,-,M +49/-49 +docs/02-architecture/mmd-diagrams/views/32-single-record-journey-full.mermaid,-,M +18/-21,M +6/-16,M +60/-70 +docs/02-architecture/mmd-diagrams/views/32-single-record-journey-infra.mermaid,-,M +4/-3,-,M +41/-41 +docs/02-architecture/mmd-diagrams/views/32-single-record-journey-overview.mermaid,-,M +5/-4,-,M +39/-39 +docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-dataflow.mermaid,-,M +6/-8,-,M +48/-48 +docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-domain.mermaid,-,M +5/-7,-,M +64/-64 +docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-full.mermaid,-,M +2/-1,M +1/-1,M +61/-61 +docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-infra.mermaid,-,M +6/-8,-,M +68/-68 +docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-overview.mermaid,-,M +6/-5,-,M +53/-53 +docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-dataflow.mermaid,M +18/-17,M +22/-23,M +2/-18,M +42/-58 +docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-domain.mermaid,-,M +7/-6,-,M +59/-59 +docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-full.mermaid,-,M +2/-1,-,M +51/-51 +docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-infra.mermaid,-,M +7/-9,-,M +59/-59 +docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-overview.mermaid,M +21/-20,M +25/-26,M +2/-21,M +48/-67 +docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-dataflow.mermaid,M +12/-11,M +2/-0,M +1/-1,M +34/-34 +docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-domain.mermaid,M +22/-21,M +2/-0,M +2/-22,M +42/-62 +docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-full.mermaid,-,M +5/-4,-,M +82/-82 +docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-infra.mermaid,M +22/-21,M +2/-0,M +2/-22,M +42/-62 +docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-overview.mermaid,M +16/-15,M +2/-0,M +2/-16,M +31/-45 +docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-dataflow.mermaid,M +12/-11,M +17/-21,M +1/-1,M +50/-50 +docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-domain.mermaid,M +12/-11,M +5/-3,M +1/-1,M +54/-54 +docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-full.mermaid,-,M +2/-1,-,M +84/-84 +docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-infra.mermaid,M +6/-5,M +5/-3,-,M +42/-42 +docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-overview.mermaid,-,M +6/-7,M +3/-13,M +50/-60 +docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-dataflow.mermaid,M +10/-9,M +11/-9,M +1/-1,M +30/-30 +docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-domain.mermaid,M +15/-14,M +16/-14,M +2/-15,M +35/-48 +docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-full.mermaid,-,M +17/-25,M +3/-13,M +73/-83 +docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-infra.mermaid,M +15/-14,M +18/-19,M +2/-15,M +43/-56 +docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-overview.mermaid,M +12/-11,M +13/-11,M +1/-1,M +37/-37 +docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-dataflow.mermaid,M +10/-9,M +14/-15,M +1/-1,M +42/-42 +docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-domain.mermaid,M +17/-16,M +21/-22,M +2/-17,M +49/-64 +docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-full.mermaid,-,M +10/-29,-,M +131/-131 +docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-infra.mermaid,M +17/-16,M +20/-18,M +2/-17,M +45/-60 +docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-overview.mermaid,-,M +6/-5,-,M +38/-38 +docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-dataflow.mermaid,M +10/-9,M +13/-14,M +1/-1,M +38/-38 +docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-domain.mermaid,M +17/-16,M +4/-2,M +2/-17,M +45/-60 +docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-full.mermaid,-,M +5/-4,M +5/-16,M +54/-65 +docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-infra.mermaid,M +17/-16,M +4/-2,M +2/-17,M +45/-60 +docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-overview.mermaid,M +11/-10,M +4/-5,M +1/-1,M +43/-43 +docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-dataflow.mermaid,M +5/-4,M +9/-7,-,M +32/-32 +docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-domain.mermaid,M +5/-4,M +5/-6,-,M +40/-40 +docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-full.mermaid,-,M +8/-26,M +1/-1,M +116/-116 +docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-infra.mermaid,M +5/-4,M +6/-7,-,M +44/-44 +docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-overview.mermaid,M +5/-4,M +5/-3,-,M +35/-35 +docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-dataflow.mermaid,M +14/-13,M +18/-22,M +2/-14,M +38/-50 +docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-domain.mermaid,-,M +4/-6,-,M +55/-55 +docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-full.mermaid,-,M +2/-1,M +1/-1,M +112/-112 +docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-infra.mermaid,-,M +5/-10,-,M +59/-59 +docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-overview.mermaid,M +15/-14,M +4/-2,M +2/-15,M +38/-51 +docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-dataflow.mermaid,M +9/-8,M +13/-11,M +1/-1,M +40/-40 +docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-domain.mermaid,-,M +5/-6,M +2/-20,M +57/-75 +docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-full.mermaid,-,M +12/-11,M +7/-7,M +98/-98 +docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-infra.mermaid,M +23/-22,M +5/-6,M +2/-23,M +55/-76 +docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-overview.mermaid,-,M +5/-3,M +3/-17,M +48/-62 +docs/02-architecture/mmd-diagrams/views/png/INDEX.md,D +0/-940,-,D +0/-940,D +0/-940 +docs/02-architecture/mmd-diagrams/views/svg/INDEX.md,D +0/-940,-,D +0/-940,D +0/-940 +mkdocs.yml,M +18/-8,-,M +0/-8,M +0/-8 +scripts/add_svg_text_fallback.py,-,-,M +15/-9,- +scripts/check_diagram_quality_gates.py,-,-,M +9/-3,- +scripts/extract_diagram_params.py,-,A +2113/-0,-,- +scripts/fix_diagram_links.py,-,-,M +35/-19,- +scripts/lint_diagrams.py,M +27/-0,-,M +71/-12,M +71/-12 +scripts/reindex_linkstyles.py,-,-,-,A +180/-0 +scripts/uniform_diagram_sizes.py,-,-,M +1/-1,- diff --git a/docs/reports/branch-full-diff-matrix-diagram-scope-2026-03-01.md b/docs/reports/branch-full-diff-matrix-diagram-scope-2026-03-01.md new file mode 100644 index 0000000000..0ea9906876 --- /dev/null +++ b/docs/reports/branch-full-diff-matrix-diagram-scope-2026-03-01.md @@ -0,0 +1,323 @@ +# Branch Diff Matrix (Diagram Scope, vs local HEAD) — 2026-03-01 + +Baseline: local `TMP01-01` (`HEAD`).\ +Cell format: `STATUS +added/-deleted` from `git diff HEAD..origin/`. + +Total scoped files: **313**.\ +CSV: `docs/reports/branch-full-diff-matrix-diagram-scope-2026-03-01.csv`. + +| File | `bioetl-architecture-prompts-v3-lLJJu` | `audit-fix-diagrams-hZglG` | `audit-diagram-docs-scripts-fUJUM` | `improve-diagram-design-K2XMN` | +|---|---|---|---|---| +| `.github/workflows/docs.yml` | M +4/-0 | - | - | - | +| `assets/javascripts/MERMAID_VERSION` | - | - | M +1/-1 | - | +| `assets/javascripts/mermaid-loader.js` | - | - | M +1/-1 | - | +| `assets/stylesheets/mermaid.css` | - | - | - | M +34/-0 | +| `docs/02-architecture/06-diagram-policy.md` | - | - | M +4/-15 | - | +| `docs/02-architecture/architecture-diagrams.md` | - | - | M +15/-15 | - | +| `docs/02-architecture/decisions/ADR-040-diagram-governance.md` | - | M +24/-8 | M +2/-2 | - | +| `docs/02-architecture/mmd-diagrams/00-legend.mmd` | A +54/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/_template.mmd` | - | - | M +1/-0 | M +85/-79 | +| `docs/02-architecture/mmd-diagrams/architecture/01-high-level-hexagonal.mmd` | - | M +4/-4 | M +1/-0 | M +127/-122 | +| `docs/02-architecture/mmd-diagrams/architecture/01a-hexagonal-overview.mmd` | - | M +7/-13 | - | M +57/-54 | +| `docs/02-architecture/mmd-diagrams/architecture/01b-hexagonal-domain-app.mmd` | - | M +3/-3 | - | M +37/-34 | +| `docs/02-architecture/mmd-diagrams/architecture/01c-hexagonal-infra-comp.mmd` | - | M +3/-6 | M +1/-1 | M +48/-45 | +| `docs/02-architecture/mmd-diagrams/architecture/02-layer-dependency-matrix.mmd` | - | M +2/-1 | - | M +54/-51 | +| `docs/02-architecture/mmd-diagrams/architecture/03-medallion-data-flow.mmd` | - | M +8/-10 | M +7/-6 | M +125/-103 | +| `docs/02-architecture/mmd-diagrams/architecture/03a-medallion-layers-overview.mmd` | - | M +4/-3 | - | M +35/-32 | +| `docs/02-architecture/mmd-diagrams/architecture/04-pipeline-execution-flow.mmd` | - | M +1/-0 | M +1/-1 | M +101/-98 | +| `docs/02-architecture/mmd-diagrams/architecture/05-provider-adapter-hierarchy.mmd` | - | M +3/-14 | M +1/-0 | M +110/-106 | +| `docs/02-architecture/mmd-diagrams/architecture/05a-adapter-hierarchy-base.mmd` | - | M +3/-3 | - | M +33/-30 | +| `docs/02-architecture/mmd-diagrams/architecture/05b-adapter-hierarchy-providers.mmd` | - | M +2/-2 | M +1/-1 | M +40/-37 | +| `docs/02-architecture/mmd-diagrams/architecture/06-storage-layer.mmd` | - | M +4/-10 | M +1/-0 | M +100/-96 | +| `docs/02-architecture/mmd-diagrams/architecture/06a-storage-writers.mmd` | - | - | A +65/-0 | A +68/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/06b-storage-support.mmd` | - | - | A +45/-0 | A +48/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/07-dq-system.mmd` | - | M +4/-4 | M +1/-0 | M +107/-106 | +| `docs/02-architecture/mmd-diagrams/architecture/07a-dq-analysis.mmd` | - | - | A +60/-0 | A +63/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/07b-dq-pipeline.mmd` | - | - | A +47/-0 | A +50/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/08-composite-pipeline.mmd` | - | M +7/-13 | M +3/-2 | M +136/-124 | +| `docs/02-architecture/mmd-diagrams/architecture/08a-composite-config.mmd` | - | - | A +56/-0 | A +59/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/08b-composite-execution.mmd` | - | - | A +99/-0 | A +102/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/09-observability-stack.mmd` | - | M +6/-12 | M +2/-1 | M +85/-81 | +| `docs/02-architecture/mmd-diagrams/architecture/09a-observability-app.mmd` | - | - | A +44/-0 | A +47/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/09b-observability-infra.mmd` | - | - | A +62/-0 | A +65/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/10-resilience-patterns.mmd` | - | M +5/-9 | M +2/-2 | M +74/-71 | +| `docs/02-architecture/mmd-diagrams/architecture/11-configuration-system.mmd` | - | M +3/-6 | M +1/-0 | M +112/-108 | +| `docs/02-architecture/mmd-diagrams/architecture/11a-config-loading.mmd` | - | - | A +58/-0 | A +61/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/11b-config-domain.mmd` | - | - | A +63/-0 | A +66/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/12-bootstrap-di-container.mmd` | - | M +3/-5 | M +2/-1 | M +134/-121 | +| `docs/02-architecture/mmd-diagrams/architecture/12a-bootstrap-factories.mmd` | - | M +3/-2 | M +1/-1 | M +37/-34 | +| `docs/02-architecture/mmd-diagrams/architecture/12b-bootstrap-wiring.mmd` | - | M +4/-4 | M +1/-1 | M +58/-55 | +| `docs/02-architecture/mmd-diagrams/architecture/13-port-protocol-contracts.mmd` | - | M +4/-4 | M +1/-0 | M +136/-135 | +| `docs/02-architecture/mmd-diagrams/architecture/13a-data-storage-ports.mmd` | - | M +2/-16 | - | M +44/-44 | +| `docs/02-architecture/mmd-diagrams/architecture/13a-port-contracts-data-sources.mmd` | - | M +3/-4 | - | M +18/-18 | +| `docs/02-architecture/mmd-diagrams/architecture/13b-operational-ports.mmd` | - | M +2/-16 | M +1/-0 | M +48/-47 | +| `docs/02-architecture/mmd-diagrams/architecture/13b-port-contracts-storage.mmd` | - | M +3/-2 | - | M +23/-23 | +| `docs/02-architecture/mmd-diagrams/architecture/13c-port-contracts-observability.mmd` | - | M +3/-3 | - | M +29/-29 | +| `docs/02-architecture/mmd-diagrams/architecture/13c-validation-dq-ports.mmd` | - | M +2/-16 | - | M +50/-50 | +| `docs/02-architecture/mmd-diagrams/architecture/13d-port-contracts-services.mmd` | - | M +5/-5 | M +1/-1 | M +61/-61 | +| `docs/02-architecture/mmd-diagrams/architecture/13e-operational-ports-domain.mmd` | - | - | A +26/-0 | A +26/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/13f-operational-ports-infra.mmd` | - | - | A +25/-0 | A +25/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/14-cli-interface-layer.mmd` | - | M +3/-9 | M +1/-0 | M +91/-87 | +| `docs/02-architecture/mmd-diagrams/architecture/14a-cli-commands.mmd` | - | - | A +60/-0 | A +63/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/14b-cli-routing.mmd` | - | - | A +62/-0 | A +65/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/15-batch-executor-internals.mmd` | - | M +6/-12 | M +2/-2 | M +61/-61 | +| `docs/02-architecture/mmd-diagrams/architecture/16-transformer-hierarchy.mmd` | - | M +7/-9 | M +2/-1 | M +54/-50 | +| `docs/02-architecture/mmd-diagrams/architecture/16a-transformer-base.mmd` | - | - | A +50/-0 | A +50/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/16b-transformer-pub-other.mmd` | - | - | A +59/-0 | A +62/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/17-security-pii-audit.mmd` | - | M +5/-7 | M +1/-1 | M +74/-71 | +| `docs/02-architecture/mmd-diagrams/architecture/18-lock-checkpoint-shutdown.mmd` | - | M +3/-11 | M +2/-1 | M +88/-84 | +| `docs/02-architecture/mmd-diagrams/architecture/18a-lock-system.mmd` | - | - | A +57/-0 | A +60/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/18b-checkpoint-shutdown.mmd` | - | - | A +63/-0 | A +66/-0 | +| `docs/02-architecture/mmd-diagrams/architecture/png/INDEX.md` | D +0/-202 | - | D +0/-202 | D +0/-202 | +| `docs/02-architecture/mmd-diagrams/architecture/svg/INDEX.md` | D +0/-202 | - | D +0/-202 | D +0/-202 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/01-domain-ports.mmd` | M +1/-0 | M +2/-0 | - | M +252/-252 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/02-entities-aggregates.mmd` | M +1/-0 | M +2/-0 | - | M +237/-237 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/03-value-objects.mmd` | M +1/-0 | M +2/-0 | - | M +278/-278 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/04-types-enums.mmd` | M +1/-0 | M +2/-0 | - | M +231/-231 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/05-exceptions.mmd` | M +1/-0 | M +3/-1 | M +1/-1 | M +161/-161 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/06-config-classes.mmd` | M +1/-0 | M +16/-14 | M +14/-14 | M +177/-177 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/07-application-core-services.mmd` | M +1/-0 | M +2/-0 | - | M +229/-229 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/08-application-services.mmd` | M +1/-0 | M +2/-0 | - | M +198/-198 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/09-transformers.mmd` | M +1/-0 | M +2/-0 | - | M +152/-152 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/10-adapters.mmd` | M +1/-0 | M +2/-0 | - | M +225/-225 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/11-storage.mmd` | M +1/-0 | M +3/-1 | - | M +248/-248 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/12-composite-pipeline.mmd` | M +1/-0 | M +2/-0 | - | M +187/-187 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/13-domain-services.mmd` | M +1/-0 | M +2/-0 | - | M +57/-57 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/14-observability.mmd` | M +1/-0 | M +5/-3 | - | M +246/-246 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/15-extractors.mmd` | M +1/-0 | M +2/-0 | - | M +107/-107 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/16-factories-bootstrap.mmd` | M +1/-0 | M +2/-0 | M +1/-1 | M +136/-136 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/png/INDEX.md` | D +0/-100 | - | D +0/-100 | D +0/-100 | +| `docs/02-architecture/mmd-diagrams/class-diagrams/svg/INDEX.md` | D +0/-100 | - | D +0/-100 | D +0/-100 | +| `docs/02-architecture/mmd-diagrams/docs/00-diagramming-policy.md` | - | - | M +15/-274 | - | +| `docs/02-architecture/mmd-diagrams/foundation/01-full-system-component.mmd` | - | M +8/-32 | M +1/-1 | M +263/-260 | +| `docs/02-architecture/mmd-diagrams/foundation/01-high-level.mmd` | - | M +11/-12 | - | M +60/-57 | +| `docs/02-architecture/mmd-diagrams/foundation/01a-system-overview.mmd` | A +28/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/foundation/01b-system-data-pipeline.mmd` | A +33/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/foundation/01c-system-cross-cutting.mmd` | A +39/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/foundation/02-full-medallion-data-flow.mmd` | - | M +7/-11 | M +1/-1 | M +59/-56 | +| `docs/02-architecture/mmd-diagrams/foundation/03-pipeline-execution-happy-path.mmd` | - | M +2/-1 | M +1/-1 | M +87/-84 | +| `docs/02-architecture/mmd-diagrams/foundation/04-domain-layer-class-diagram.mmd` | - | M +2/-1 | - | M +344/-341 | +| `docs/02-architecture/mmd-diagrams/foundation/04-error-flow.mmd` | - | M +6/-5 | M +4/-4 | M +47/-44 | +| `docs/02-architecture/mmd-diagrams/foundation/05-layers-interaction.mmd` | - | M +7/-7 | - | M +63/-60 | +| `docs/02-architecture/mmd-diagrams/foundation/05-pipeline-lifecycle-states.mmd` | - | M +2/-1 | M +1/-1 | M +177/-174 | +| `docs/02-architecture/mmd-diagrams/foundation/06-application-layer-class-diagram.mmd` | - | M +2/-1 | M +1/-1 | M +364/-361 | +| `docs/02-architecture/mmd-diagrams/foundation/06-pipeline-execution.mmd` | - | M +2/-0 | M +3/-3 | M +64/-61 | +| `docs/02-architecture/mmd-diagrams/foundation/07-circuit-breaker-states.mmd` | - | M +2/-1 | M +1/-1 | M +67/-64 | +| `docs/02-architecture/mmd-diagrams/foundation/07-medallion-flow.mmd` | - | M +6/-4 | M +1/-1 | M +52/-49 | +| `docs/02-architecture/mmd-diagrams/foundation/08-complete-etl-workflow.mmd` | - | M +11/-10 | M +1/-1 | M +99/-99 | +| `docs/02-architecture/mmd-diagrams/foundation/08-domain-ddd.mmd` | - | M +2/-0 | M +1/-1 | M +70/-67 | +| `docs/02-architecture/mmd-diagrams/foundation/09-full-er-diagram.mmd` | - | M +2/-1 | - | M +234/-234 | +| `docs/02-architecture/mmd-diagrams/foundation/10-infrastructure-layer-class-diagram.mmd` | - | M +2/-1 | M +1/-1 | M +372/-369 | +| `docs/02-architecture/mmd-diagrams/foundation/11-lock-acquisition-sequence.mmd` | - | M +2/-1 | M +29/-29 | M +85/-82 | +| `docs/02-architecture/mmd-diagrams/foundation/12-local-deployment-architecture.mmd` | - | M +7/-9 | - | M +74/-71 | +| `docs/02-architecture/mmd-diagrams/foundation/13-domain-models-relationship.mmd` | - | M +2/-1 | - | M +399/-396 | +| `docs/02-architecture/mmd-diagrams/foundation/14-provider-health-states.mmd` | - | M +2/-1 | M +1/-1 | M +101/-98 | +| `docs/02-architecture/mmd-diagrams/foundation/15-dq-check-workflow.mmd` | - | M +11/-12 | - | M +100/-100 | +| `docs/02-architecture/mmd-diagrams/foundation/16-memory-lock-class.mmd` | - | M +2/-1 | - | M +136/-133 | +| `docs/02-architecture/mmd-diagrams/foundation/17-pipeline-hierarchy.mmd` | - | M +2/-1 | - | M +233/-233 | +| `docs/02-architecture/mmd-diagrams/foundation/18-bronze-write-sequence.mmd` | - | M +2/-1 | - | M +63/-60 | +| `docs/02-architecture/mmd-diagrams/foundation/19-delta-lake-write-sequence.mmd` | - | M +2/-1 | M +1/-1 | M +103/-100 | +| `docs/02-architecture/mmd-diagrams/foundation/20-quarantine-record-states.mmd` | - | M +2/-1 | M +1/-1 | M +122/-119 | +| `docs/02-architecture/mmd-diagrams/foundation/21-activity-entity-data-flow.mmd` | - | M +6/-13 | - | M +93/-90 | +| `docs/02-architecture/mmd-diagrams/foundation/22-client-api-request-sequence.mmd` | - | M +2/-1 | M +1/-1 | M +83/-80 | +| `docs/02-architecture/mmd-diagrams/foundation/23-silver-writer-class.mmd` | - | M +2/-1 | M +2/-68 | M +180/-243 | +| `docs/02-architecture/mmd-diagrams/foundation/24-hash-service-class.mmd` | - | M +2/-1 | - | M +70/-67 | +| `docs/02-architecture/mmd-diagrams/foundation/25-circuit-breaker-observer-class.mmd` | - | M +2/-1 | - | M +251/-248 | +| `docs/02-architecture/mmd-diagrams/foundation/26-hexagonal-ports-adapters.mmd` | - | M +8/-9 | M +5/-5 | M +115/-115 | +| `docs/02-architecture/mmd-diagrams/foundation/27-import-matrix-enforcement.mmd` | - | M +4/-3 | - | M +53/-50 | +| `docs/02-architecture/mmd-diagrams/foundation/28-composition-root-di-graph.mmd` | - | M +15/-34 | M +3/-3 | M +147/-144 | +| `docs/02-architecture/mmd-diagrams/foundation/29-composite-pipeline-workflow.mmd` | - | M +11/-32 | M +1/-1 | M +153/-150 | +| `docs/02-architecture/mmd-diagrams/foundation/30-port-adapter-mapping.mmd` | - | M +8/-26 | - | M +179/-176 | +| `docs/02-architecture/mmd-diagrams/foundation/31-pipeline-run-lifecycle.mmd` | - | M +2/-1 | M +1/-1 | M +50/-47 | +| `docs/02-architecture/mmd-diagrams/foundation/32-single-record-journey.mmd` | - | M +6/-9 | M +2/-2 | M +59/-56 | +| `docs/02-architecture/mmd-diagrams/foundation/33-cli-run-interaction.mmd` | - | M +2/-1 | M +1/-1 | M +58/-55 | +| `docs/02-architecture/mmd-diagrams/foundation/34-batch-processing-flow.mmd` | - | M +2/-1 | - | M +50/-47 | +| `docs/02-architecture/mmd-diagrams/foundation/36-architecture-principles-mindmap.mmd` | - | M +2/-1 | - | M +84/-84 | +| `docs/02-architecture/mmd-diagrams/foundation/37-cli-entry-full-chain.mmd` | - | M +6/-5 | M +2/-2 | M +57/-54 | +| `docs/02-architecture/mmd-diagrams/foundation/38-runtime-assembly-sequence.mmd` | - | M +2/-1 | M +1/-1 | M +66/-63 | +| `docs/02-architecture/mmd-diagrams/foundation/39-medallion-invariants.mmd` | - | M +7/-15 | M +1/-1 | M +73/-70 | +| `docs/02-architecture/mmd-diagrams/foundation/40-application-core-collaboration.mmd` | - | M +5/-10 | M +2/-2 | M +49/-46 | +| `docs/02-architecture/mmd-diagrams/foundation/41-error-classification-tree.mmd` | - | M +10/-29 | - | M +134/-131 | +| `docs/02-architecture/mmd-diagrams/foundation/42-pipeline-runner-class.mmd` | - | M +2/-1 | M +1/-1 | M +158/-155 | +| `docs/02-architecture/mmd-diagrams/foundation/43-fan-out-fan-in-pattern.mmd` | - | M +5/-6 | M +2/-2 | M +57/-54 | +| `docs/02-architecture/mmd-diagrams/foundation/44-cross-provider-enrichment.mmd` | - | M +5/-6 | M +5/-5 | M +55/-52 | +| `docs/02-architecture/mmd-diagrams/foundation/46-yaml-config-resolution.mmd` | - | M +8/-26 | M +4/-4 | M +128/-125 | +| `docs/02-architecture/mmd-diagrams/foundation/47-publication-merge-sources.mmd` | - | M +2/-1 | M +1/-1 | M +60/-57 | +| `docs/02-architecture/mmd-diagrams/foundation/48-composite-phase-lifecycle.mmd` | - | M +2/-1 | M +1/-1 | M +115/-112 | +| `docs/02-architecture/mmd-diagrams/foundation/49-composite-runner-class.mmd` | - | M +2/-1 | M +1/-1 | M +332/-329 | +| `docs/02-architecture/mmd-diagrams/foundation/50-exception-hierarchy.mmd` | - | M +10/-9 | M +5/-5 | M +95/-92 | +| `docs/02-architecture/mmd-diagrams/foundation/50a-exceptions-critical.mmd` | A +33/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/foundation/50b-exceptions-recoverable.mmd` | A +39/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/foundation/50c-exceptions-data-quality.mmd` | A +35/-0 | - | - | - | +| `docs/02-architecture/mmd-diagrams/foundation/png/INDEX.md` | D +0/-328 | - | D +0/-328 | D +0/-328 | +| `docs/02-architecture/mmd-diagrams/foundation/svg/INDEX.md` | D +0/-328 | - | D +0/-328 | D +0/-328 | +| `docs/02-architecture/mmd-diagrams/render.sh` | M +6/-0 | - | - | M +21/-0 | +| `docs/02-architecture/mmd-diagrams/theme/custom-dark.css` | - | - | - | A +260/-0 | +| `docs/02-architecture/mmd-diagrams/theme/custom.css` | - | - | M +9/-0 | M +66/-12 | +| `docs/02-architecture/mmd-diagrams/theme/mermaid-config.json` | - | - | M +1/-1 | M +7/-7 | +| `docs/02-architecture/mmd-diagrams/views/00-legend.mermaid` | - | M +3/-1 | - | M +61/-61 | +| `docs/02-architecture/mmd-diagrams/views/01-full-system-component-dataflow.mermaid` | M +9/-8 | M +13/-14 | M +1/-1 | M +40/-40 | +| `docs/02-architecture/mmd-diagrams/views/01-full-system-component-domain.mermaid` | M +11/-10 | M +4/-2 | M +1/-1 | M +48/-48 | +| `docs/02-architecture/mmd-diagrams/views/01-full-system-component-full.mermaid` | - | M +8/-32 | M +1/-1 | M +260/-260 | +| `docs/02-architecture/mmd-diagrams/views/01-full-system-component-infra.mermaid` | M +2/-1 | M +6/-10 | - | M +38/-38 | +| `docs/02-architecture/mmd-diagrams/views/01-full-system-component-overview.mermaid` | - | M +8/-13 | M +1/-1 | M +54/-54 | +| `docs/02-architecture/mmd-diagrams/views/01-high-level-dataflow.mermaid` | M +11/-10 | M +15/-16 | M +1/-1 | M +44/-44 | +| `docs/02-architecture/mmd-diagrams/views/01-high-level-domain.mermaid` | - | M +7/-11 | - | M +63/-63 | +| `docs/02-architecture/mmd-diagrams/views/01-high-level-full.mermaid` | - | M +19/-20 | M +6/-15 | M +72/-81 | +| `docs/02-architecture/mmd-diagrams/views/01-high-level-infra.mermaid` | M +12/-11 | M +6/-10 | M +1/-1 | M +58/-58 | +| `docs/02-architecture/mmd-diagrams/views/01-high-level-overview.mermaid` | - | M +6/-10 | - | M +54/-54 | +| `docs/02-architecture/mmd-diagrams/views/02-medallion-dataflow.mermaid` | M +3/-2 | M +4/-2 | - | M +16/-16 | +| `docs/02-architecture/mmd-diagrams/views/02-medallion-domain.mermaid` | M +3/-2 | M +6/-4 | - | M +32/-32 | +| `docs/02-architecture/mmd-diagrams/views/02-medallion-full.mermaid` | - | M +11/-10 | M +3/-3 | M +49/-49 | +| `docs/02-architecture/mmd-diagrams/views/02-medallion-infra.mermaid` | M +3/-2 | M +4/-2 | - | M +24/-24 | +| `docs/02-architecture/mmd-diagrams/views/02-medallion-overview.mermaid` | M +3/-2 | M +6/-4 | - | M +27/-27 | +| `docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-dataflow.mermaid` | M +9/-8 | M +12/-10 | M +1/-1 | M +36/-36 | +| `docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-domain.mermaid` | M +8/-7 | M +2/-0 | - | M +34/-34 | +| `docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-full.mermaid` | - | M +2/-1 | - | M +312/-312 | +| `docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-infra.mermaid` | M +11/-10 | M +4/-2 | M +1/-1 | M +48/-48 | +| `docs/02-architecture/mmd-diagrams/views/04-domain-layer-class-diagram-overview.mermaid` | - | M +5/-3 | - | M +50/-50 | +| `docs/02-architecture/mmd-diagrams/views/05-layers-interaction-dataflow.mermaid` | M +10/-9 | M +17/-21 | M +1/-1 | M +57/-57 | +| `docs/02-architecture/mmd-diagrams/views/05-layers-interaction-domain.mermaid` | - | M +7/-8 | - | M +61/-61 | +| `docs/02-architecture/mmd-diagrams/views/05-layers-interaction-full.mermaid` | - | M +15/-15 | M +2/-13 | M +68/-79 | +| `docs/02-architecture/mmd-diagrams/views/05-layers-interaction-infra.mermaid` | - | M +7/-8 | - | M +61/-61 | +| `docs/02-architecture/mmd-diagrams/views/05-layers-interaction-overview.mermaid` | M +11/-10 | M +6/-7 | M +1/-1 | M +51/-51 | +| `docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-dataflow.mermaid` | M +9/-8 | M +13/-14 | M +1/-1 | M +40/-40 | +| `docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-domain.mermaid` | - | M +8/-9 | - | M +60/-60 | +| `docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-full.mermaid` | - | M +2/-1 | M +1/-1 | M +174/-174 | +| `docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-infra.mermaid` | - | M +7/-5 | - | M +58/-58 | +| `docs/02-architecture/mmd-diagrams/views/05-pipeline-lifecycle-states-overview.mermaid` | - | M +7/-5 | - | M +46/-46 | +| `docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-dataflow.mermaid` | M +11/-10 | M +14/-12 | M +1/-1 | M +40/-40 | +| `docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-domain.mermaid` | - | M +4/-2 | - | M +50/-50 | +| `docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-full.mermaid` | - | M +2/-1 | M +1/-1 | M +361/-361 | +| `docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-infra.mermaid` | - | M +4/-2 | - | M +48/-48 | +| `docs/02-architecture/mmd-diagrams/views/06-application-layer-class-diagram-overview.mermaid` | - | M +4/-5 | - | M +38/-38 | +| `docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-dataflow.mermaid` | - | M +4/-2 | - | M +28/-28 | +| `docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-domain.mermaid` | - | M +4/-5 | - | M +49/-49 | +| `docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-full.mermaid` | - | M +2/-1 | M +1/-1 | M +64/-64 | +| `docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-infra.mermaid` | - | M +4/-5 | - | M +49/-49 | +| `docs/02-architecture/mmd-diagrams/views/07-circuit-breaker-states-overview.mermaid` | - | M +4/-5 | - | M +42/-42 | +| `docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-dataflow.mermaid` | M +10/-9 | M +11/-9 | M +1/-1 | M +30/-30 | +| `docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-domain.mermaid` | - | M +6/-4 | - | M +47/-47 | +| `docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-full.mermaid` | - | M +59/-58 | M +6/-59 | M +103/-156 | +| `docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-infra.mermaid` | - | M +4/-2 | - | M +39/-39 | +| `docs/02-architecture/mmd-diagrams/views/08-complete-etl-workflow-overview.mermaid` | M +12/-11 | M +15/-13 | M +1/-1 | M +45/-45 | +| `docs/02-architecture/mmd-diagrams/views/08-domain-ddd-dataflow.mermaid` | M +11/-10 | M +15/-13 | M +1/-1 | M +44/-44 | +| `docs/02-architecture/mmd-diagrams/views/08-domain-ddd-domain.mermaid` | - | M +5/-3 | M +2/-14 | M +51/-63 | +| `docs/02-architecture/mmd-diagrams/views/08-domain-ddd-full.mermaid` | - | M +15/-13 | M +3/-19 | M +72/-88 | +| `docs/02-architecture/mmd-diagrams/views/08-domain-ddd-infra.mermaid` | - | M +5/-3 | M +3/-16 | M +52/-65 | +| `docs/02-architecture/mmd-diagrams/views/08-domain-ddd-overview.mermaid` | - | M +5/-6 | M +2/-11 | M +43/-52 | +| `docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-dataflow.mermaid` | M +12/-11 | M +16/-17 | M +1/-1 | M +46/-46 | +| `docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-domain.mermaid` | - | M +5/-6 | - | M +51/-51 | +| `docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-full.mermaid` | - | M +2/-1 | M +1/-1 | M +369/-369 | +| `docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-infra.mermaid` | - | M +5/-6 | - | M +48/-48 | +| `docs/02-architecture/mmd-diagrams/views/10-infrastructure-layer-class-diagram-overview.mermaid` | - | M +5/-6 | - | M +47/-47 | +| `docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-dataflow.mermaid` | M +12/-11 | M +15/-16 | M +1/-1 | M +42/-42 | +| `docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-domain.mermaid` | - | M +5/-6 | M +2/-18 | M +55/-71 | +| `docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-full.mermaid` | - | M +11/-12 | M +8/-27 | M +76/-95 | +| `docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-infra.mermaid` | - | M +4/-5 | - | M +49/-49 | +| `docs/02-architecture/mmd-diagrams/views/12-local-deployment-architecture-overview.mermaid` | - | M +5/-6 | - | M +44/-44 | +| `docs/02-architecture/mmd-diagrams/views/14-provider-health-states-dataflow.mermaid` | - | M +6/-4 | - | M +39/-39 | +| `docs/02-architecture/mmd-diagrams/views/14-provider-health-states-domain.mermaid` | - | M +4/-5 | - | M +52/-52 | +| `docs/02-architecture/mmd-diagrams/views/14-provider-health-states-full.mermaid` | - | M +2/-1 | M +1/-1 | M +98/-98 | +| `docs/02-architecture/mmd-diagrams/views/14-provider-health-states-infra.mermaid` | - | M +5/-6 | - | M +56/-56 | +| `docs/02-architecture/mmd-diagrams/views/14-provider-health-states-overview.mermaid` | - | M +5/-6 | M +3/-19 | M +50/-66 | +| `docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-dataflow.mermaid` | - | M +6/-7 | - | M +37/-37 | +| `docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-domain.mermaid` | - | M +4/-2 | - | M +46/-46 | +| `docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-full.mermaid` | - | M +11/-12 | M +7/-7 | M +103/-103 | +| `docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-infra.mermaid` | - | M +6/-7 | - | M +54/-54 | +| `docs/02-architecture/mmd-diagrams/views/15-dq-check-workflow-overview.mermaid` | - | M +6/-7 | - | M +44/-44 | +| `docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-dataflow.mermaid` | - | M +4/-2 | - | M +25/-25 | +| `docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-domain.mermaid` | - | M +2/-0 | - | M +37/-37 | +| `docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-full.mermaid` | - | M +7/-10 | M +5/-21 | M +98/-114 | +| `docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-infra.mermaid` | - | M +2/-0 | - | M +37/-37 | +| `docs/02-architecture/mmd-diagrams/views/21-activity-entity-data-flow-overview.mermaid` | - | M +2/-0 | - | M +32/-32 | +| `docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-dataflow.mermaid` | - | M +4/-2 | - | M +32/-32 | +| `docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-domain.mermaid` | - | M +4/-2 | - | M +46/-46 | +| `docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-full.mermaid` | - | M +7/-6 | M +4/-4 | M +128/-128 | +| `docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-infra.mermaid` | - | M +4/-2 | - | M +44/-44 | +| `docs/02-architecture/mmd-diagrams/views/26-hexagonal-ports-adapters-overview.mermaid` | - | M +4/-2 | - | M +36/-36 | +| `docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-dataflow.mermaid` | M +14/-13 | M +17/-18 | M +2/-14 | M +34/-46 | +| `docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-domain.mermaid` | M +20/-19 | M +5/-6 | M +2/-20 | M +52/-70 | +| `docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-full.mermaid` | - | M +15/-34 | M +3/-3 | M +144/-144 | +| `docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-infra.mermaid` | M +20/-19 | M +5/-9 | M +2/-20 | M +52/-70 | +| `docs/02-architecture/mmd-diagrams/views/28-composition-root-di-graph-overview.mermaid` | - | M +6/-5 | M +1/-1 | M +43/-43 | +| `docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-dataflow.mermaid` | M +11/-10 | M +15/-19 | M +1/-1 | M +44/-44 | +| `docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-domain.mermaid` | M +23/-22 | M +24/-22 | M +2/-23 | M +43/-64 | +| `docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-full.mermaid` | - | M +11/-32 | M +1/-1 | M +150/-150 | +| `docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-infra.mermaid` | M +23/-22 | M +26/-27 | M +2/-23 | M +51/-72 | +| `docs/02-architecture/mmd-diagrams/views/29-composite-pipeline-workflow-overview.mermaid` | - | M +4/-3 | - | M +19/-19 | +| `docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-dataflow.mermaid` | M +7/-6 | M +4/-2 | - | M +32/-32 | +| `docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-domain.mermaid` | M +11/-10 | M +4/-2 | M +1/-1 | M +48/-48 | +| `docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-full.mermaid` | - | M +8/-26 | - | M +176/-176 | +| `docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-infra.mermaid` | M +11/-10 | M +4/-2 | M +1/-1 | M +48/-48 | +| `docs/02-architecture/mmd-diagrams/views/30-port-adapter-mapping-overview.mermaid` | - | M +5/-7 | - | M +32/-32 | +| `docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-dataflow.mermaid` | M +15/-14 | M +19/-20 | M +2/-15 | M +39/-52 | +| `docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-domain.mermaid` | - | M +9/-8 | M +1/-1 | M +64/-64 | +| `docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-full.mermaid` | - | M +2/-1 | M +1/-1 | M +47/-47 | +| `docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-infra.mermaid` | - | M +9/-31 | - | M +96/-96 | +| `docs/02-architecture/mmd-diagrams/views/31-pipeline-run-lifecycle-overview.mermaid` | - | M +9/-11 | M +1/-1 | M +53/-53 | +| `docs/02-architecture/mmd-diagrams/views/32-single-record-journey-dataflow.mermaid` | - | M +3/-2 | - | M +25/-25 | +| `docs/02-architecture/mmd-diagrams/views/32-single-record-journey-domain.mermaid` | - | M +6/-5 | - | M +49/-49 | +| `docs/02-architecture/mmd-diagrams/views/32-single-record-journey-full.mermaid` | - | M +18/-21 | M +6/-16 | M +60/-70 | +| `docs/02-architecture/mmd-diagrams/views/32-single-record-journey-infra.mermaid` | - | M +4/-3 | - | M +41/-41 | +| `docs/02-architecture/mmd-diagrams/views/32-single-record-journey-overview.mermaid` | - | M +5/-4 | - | M +39/-39 | +| `docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-dataflow.mermaid` | - | M +6/-8 | - | M +48/-48 | +| `docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-domain.mermaid` | - | M +5/-7 | - | M +64/-64 | +| `docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-full.mermaid` | - | M +2/-1 | M +1/-1 | M +61/-61 | +| `docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-infra.mermaid` | - | M +6/-8 | - | M +68/-68 | +| `docs/02-architecture/mmd-diagrams/views/33-cli-run-interaction-overview.mermaid` | - | M +6/-5 | - | M +53/-53 | +| `docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-dataflow.mermaid` | M +18/-17 | M +22/-23 | M +2/-18 | M +42/-58 | +| `docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-domain.mermaid` | - | M +7/-6 | - | M +59/-59 | +| `docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-full.mermaid` | - | M +2/-1 | - | M +51/-51 | +| `docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-infra.mermaid` | - | M +7/-9 | - | M +59/-59 | +| `docs/02-architecture/mmd-diagrams/views/34-batch-processing-flow-overview.mermaid` | M +21/-20 | M +25/-26 | M +2/-21 | M +48/-67 | +| `docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-dataflow.mermaid` | M +12/-11 | M +2/-0 | M +1/-1 | M +34/-34 | +| `docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-domain.mermaid` | M +22/-21 | M +2/-0 | M +2/-22 | M +42/-62 | +| `docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-full.mermaid` | - | M +5/-4 | - | M +82/-82 | +| `docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-infra.mermaid` | M +22/-21 | M +2/-0 | M +2/-22 | M +42/-62 | +| `docs/02-architecture/mmd-diagrams/views/35-bootstrap-sequence-overview.mermaid` | M +16/-15 | M +2/-0 | M +2/-16 | M +31/-45 | +| `docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-dataflow.mermaid` | M +12/-11 | M +17/-21 | M +1/-1 | M +50/-50 | +| `docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-domain.mermaid` | M +12/-11 | M +5/-3 | M +1/-1 | M +54/-54 | +| `docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-full.mermaid` | - | M +2/-1 | - | M +84/-84 | +| `docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-infra.mermaid` | M +6/-5 | M +5/-3 | - | M +42/-42 | +| `docs/02-architecture/mmd-diagrams/views/36-architecture-principles-mindmap-overview.mermaid` | - | M +6/-7 | M +3/-13 | M +50/-60 | +| `docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-dataflow.mermaid` | M +10/-9 | M +11/-9 | M +1/-1 | M +30/-30 | +| `docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-domain.mermaid` | M +15/-14 | M +16/-14 | M +2/-15 | M +35/-48 | +| `docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-full.mermaid` | - | M +17/-25 | M +3/-13 | M +73/-83 | +| `docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-infra.mermaid` | M +15/-14 | M +18/-19 | M +2/-15 | M +43/-56 | +| `docs/02-architecture/mmd-diagrams/views/39-medallion-invariants-overview.mermaid` | M +12/-11 | M +13/-11 | M +1/-1 | M +37/-37 | +| `docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-dataflow.mermaid` | M +10/-9 | M +14/-15 | M +1/-1 | M +42/-42 | +| `docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-domain.mermaid` | M +17/-16 | M +21/-22 | M +2/-17 | M +49/-64 | +| `docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-full.mermaid` | - | M +10/-29 | - | M +131/-131 | +| `docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-infra.mermaid` | M +17/-16 | M +20/-18 | M +2/-17 | M +45/-60 | +| `docs/02-architecture/mmd-diagrams/views/41-error-classification-tree-overview.mermaid` | - | M +6/-5 | - | M +38/-38 | +| `docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-dataflow.mermaid` | M +10/-9 | M +13/-14 | M +1/-1 | M +38/-38 | +| `docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-domain.mermaid` | M +17/-16 | M +4/-2 | M +2/-17 | M +45/-60 | +| `docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-full.mermaid` | - | M +5/-4 | M +5/-16 | M +54/-65 | +| `docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-infra.mermaid` | M +17/-16 | M +4/-2 | M +2/-17 | M +45/-60 | +| `docs/02-architecture/mmd-diagrams/views/44-cross-provider-enrichment-overview.mermaid` | M +11/-10 | M +4/-5 | M +1/-1 | M +43/-43 | +| `docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-dataflow.mermaid` | M +5/-4 | M +9/-7 | - | M +32/-32 | +| `docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-domain.mermaid` | M +5/-4 | M +5/-6 | - | M +40/-40 | +| `docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-full.mermaid` | - | M +8/-26 | M +1/-1 | M +116/-116 | +| `docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-infra.mermaid` | M +5/-4 | M +6/-7 | - | M +44/-44 | +| `docs/02-architecture/mmd-diagrams/views/46-yaml-config-resolution-overview.mermaid` | M +5/-4 | M +5/-3 | - | M +35/-35 | +| `docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-dataflow.mermaid` | M +14/-13 | M +18/-22 | M +2/-14 | M +38/-50 | +| `docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-domain.mermaid` | - | M +4/-6 | - | M +55/-55 | +| `docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-full.mermaid` | - | M +2/-1 | M +1/-1 | M +112/-112 | +| `docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-infra.mermaid` | - | M +5/-10 | - | M +59/-59 | +| `docs/02-architecture/mmd-diagrams/views/48-composite-phase-lifecycle-overview.mermaid` | M +15/-14 | M +4/-2 | M +2/-15 | M +38/-51 | +| `docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-dataflow.mermaid` | M +9/-8 | M +13/-11 | M +1/-1 | M +40/-40 | +| `docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-domain.mermaid` | - | M +5/-6 | M +2/-20 | M +57/-75 | +| `docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-full.mermaid` | - | M +12/-11 | M +7/-7 | M +98/-98 | +| `docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-infra.mermaid` | M +23/-22 | M +5/-6 | M +2/-23 | M +55/-76 | +| `docs/02-architecture/mmd-diagrams/views/50-exception-hierarchy-overview.mermaid` | - | M +5/-3 | M +3/-17 | M +48/-62 | +| `docs/02-architecture/mmd-diagrams/views/png/INDEX.md` | D +0/-940 | - | D +0/-940 | D +0/-940 | +| `docs/02-architecture/mmd-diagrams/views/svg/INDEX.md` | D +0/-940 | - | D +0/-940 | D +0/-940 | +| `mkdocs.yml` | M +18/-8 | - | M +0/-8 | M +0/-8 | +| `scripts/add_svg_text_fallback.py` | - | - | M +15/-9 | - | +| `scripts/check_diagram_quality_gates.py` | - | - | M +9/-3 | - | +| `scripts/extract_diagram_params.py` | - | A +2113/-0 | - | - | +| `scripts/fix_diagram_links.py` | - | - | M +35/-19 | - | +| `scripts/lint_diagrams.py` | M +27/-0 | - | M +71/-12 | M +71/-12 | +| `scripts/reindex_linkstyles.py` | - | - | - | A +180/-0 | +| `scripts/uniform_diagram_sizes.py` | - | - | M +1/-1 | - | diff --git a/docs/reports/branch-render-settings-diff-matrix-2026-03-01.md b/docs/reports/branch-render-settings-diff-matrix-2026-03-01.md new file mode 100644 index 0000000000..23f21dac61 --- /dev/null +++ b/docs/reports/branch-render-settings-diff-matrix-2026-03-01.md @@ -0,0 +1,50 @@ +# Branch Diff Matrix: Diagram Render Scripts & Settings (2026-03-01) + +Baseline: local branch `TMP01-01`. +Compared branches: +- `claude/bioetl-architecture-prompts-v3-lLJJu` +- `claude/audit-fix-diagrams-hZglG` +- `claude/audit-diagram-docs-scripts-fUJUM` +- `claude/improve-diagram-design-K2XMN` + +## Matrix (Render/Theme Scope) + +| File | claude/bioetl-architecture-prompts-v3-lLJJu | claude/audit-fix-diagrams-hZglG | claude/audit-diagram-docs-scripts-fUJUM | claude/improve-diagram-design-K2XMN | +|---|---|---|---|---| +| `docs/02-architecture/mmd-diagrams/render.sh` | Added skip for diagrams marked `%% @status superseded` (not rendered). | No changes. | No changes. | Added dark mode: `--dark`, `DARK_MODE`, `BG=#0f172a`, dark output dirs `svg-dark/png-dark`, optional dark config/css switch. | +| `docs/02-architecture/mmd-diagrams/theme/mermaid-config.json` | No changes. | No changes. | `flowchart.padding: 24 -> 32`. | `clusterBkg` and `fillType5` palette shift; `nodeSpacing 50 -> 55`, `rankSpacing 45 -> 50`; ELK spacing `40/30/20 -> 45/35/25`. | +| `docs/02-architecture/mmd-diagrams/theme/custom.css` | No changes. | No changes. | Added `.cluster-label` + `.cluster-label .nodeLabel` padding/line-height. | Large visual restyle: stronger stroke/shadow, edge label readability tweaks, hover/contrast/readability rules. | +| `docs/02-architecture/mmd-diagrams/_template.mmd` | No changes. | No changes. | Added generic linkStyle guideline (`stroke:#475569,...`). | Large template/style-guide rewrite (metadata formatting, palette tiers, naming/format rules, spacing guidance). | +| `assets/javascripts/mermaid-loader.js` | No changes. | No changes. | Default Mermaid version `10.4.0 -> 10.6.1`. | No changes. | +| `assets/javascripts/MERMAID_VERSION` | No changes. | No changes. | `10.4.0 -> 10.6.1`. | No changes. | +| `assets/stylesheets/mermaid.css` | No changes. | No changes. | No changes. | Added contrast enhancements for embedded Mermaid (cluster/node shadows, edgeLabel weight, hover feedback). | +| `docs/02-architecture/mmd-diagrams/theme/custom-dark.css` | No changes. | No changes. | No changes. | New file (dark theme CSS profile). | +| `docs/02-architecture/mmd-diagrams/theme/mermaid-config-dark.json` | No changes. | No changes. | No changes. | Not present (render dark-mode code expects it, but branch does not add it). | + + +## Continuation: Policy/Docs/Scripts Matrix + +| File | claude/bioetl-architecture-prompts-v3-lLJJu | claude/audit-fix-diagrams-hZglG | claude/audit-diagram-docs-scripts-fUJUM | claude/improve-diagram-design-K2XMN | +|---|---|---|---|---| +| `docs/02-architecture/decisions/ADR-040-diagram-governance.md` | No changes. | Rewrites D7/D8 thresholds (`<=10`, `11-30`, `>30`), adds sequence-diagram ELK exception note, updates LAYOUT-001/002 conditions. | Minor doc sync: source-line references and linkStyle count wording (`5 -> 6`). | No changes. | +| `docs/02-architecture/06-diagram-policy.md` | No changes. | No changes. | Replaces multiline ELK init example with one-line `%%{init:...}%%`; explicitly states init directive must be one line in `.mmd`. | No changes. | +| `docs/02-architecture/architecture-diagrams.md` | No changes. | No changes. | Bulk link hygiene: `.mermaid -> .mmd` in file references; fixes wrong target for `30-port-adapter-mapping`. | No changes. | +| `docs/02-architecture/mmd-diagrams/docs/00-diagramming-policy.md` | No changes. | No changes. | Large reduction/refactor: historical long policy replaced by compact canonical-pointer policy text. | No changes. | +| `docs/02-architecture/mmd-diagrams/00-legend.mmd` | **New file** (legend diagram, classes + linkStyle legend blocks). | No changes. | No changes. | No changes. | +| `scripts/lint_diagrams.py` | Adds skip logic for superseded/legend diagrams; introduces approved fill list checks integration. | No changes. | Includes same lint hardening (+ additional updates from newer line base): keeps skip logic and expands lint policy checks. | Same change profile as fUJUM in this file (+71/-12 vs local). | +| `scripts/check_diagram_quality_gates.py` | No changes. | No changes. | Hardens edge parser: detects more forbidden operators (`x--`, `<--`, `<==>`), strips quoted text before operator validation to reduce false positives. | No changes. | +| `scripts/fix_diagram_links.py` | No changes. | No changes. | Refactored to safer regex-only markdown link rewrites (`.mmd -> .mermaid` in links only), typed helpers, explicit return code. | No changes. | +| `scripts/uniform_diagram_sizes.py` | No changes. | No changes. | Regex bugfix for node label closing bracket pattern (`\"]\)` variant). | No changes. | +| `scripts/add_svg_text_fallback.py` | No changes. | No changes. | Refactor to in-memory processing (`_process_tree`), explicit `write` flag; check/dry-run paths no longer rely on restoring original text. | No changes. | +| `scripts/reindex_linkstyles.py` | No changes. | No changes. | No changes. | **New file**: audit/check tool for stale `linkStyle` indices (check/fix reporting mode). | +| `mkdocs.yml` | Adds `validation` + `not_in_nav`, removes index pages from nav, keeps docs strictness maintenance. | No changes. | Compared to local: branch is missing local `mkdocs.yml` updates (net `0/+8` from local perspective). | Same as fUJUM for `mkdocs.yml` delta vs local (missing local updates). | +| `.github/workflows/docs.yml` | Adds workflow `concurrency` block (`group`, `cancel-in-progress`). | No changes. | No changes. | No changes. | +| `assets/javascripts/MERMAID_VERSION` | No changes. | No changes. | `10.4.0 -> 10.6.1`. | No changes. | +| `assets/javascripts/mermaid-loader.js` | No changes. | No changes. | Embedded default Mermaid version `10.4.0 -> 10.6.1`. | No changes. | +| `assets/stylesheets/mermaid.css` | No changes. | No changes. | No changes. | Adds embedded-mermaid contrast/style layer (cluster/node shadowing, edge label weight, hover feedback). | + +## Notes + +- `claude/audit-fix-diagrams-hZglG` is mostly diagram-source normalization; render/theme/script layer impact is intentionally minimal. +- `claude/improve-diagram-design-K2XMN` introduces dark-mode rendering flow in `render.sh` and `custom-dark.css`, but does **not** include `mermaid-config-dark.json`, so dark-mode config switch is only partially wired. + diff --git a/docs/reports/scripts-inventory-2026-03-01.md b/docs/reports/scripts-inventory-2026-03-01.md new file mode 100644 index 0000000000..4276bee8e6 --- /dev/null +++ b/docs/reports/scripts-inventory-2026-03-01.md @@ -0,0 +1 @@ +# Scripts Inventory\n\nTotal scripts: **106**\n\n## By Folder\n\n| Folder | Count |\n|---|---:|\n| `.` | 2 |\n| `assets/javascripts` | 1 |\n| `docs/02-architecture/mmd-diagrams` | 1 |\n| `docs/skills/global/gh-address-comments/scripts` | 1 |\n| `docs/skills/global/gh-fix-ci/scripts` | 1 |\n| `scripts` | 59 |\n| `scripts/ci` | 1 |\n| `scripts/dev` | 4 |\n| `scripts/diagrams` | 20 |\n| `src/tools/scripts` | 14 |\n| `src/tools/scripts/migrations` | 2 |\n\n## Table\n\n| Script | Folder | Purpose |\n|---|---|---|\n| `.setup_wsl_codex.sh` | `.` | Run: bash /mnt/e/g-drive/05_AI/github/BioactivityDataAcquisition2/.setup_wsl_codex.sh |\n| `assets/javascripts/download_mermaid.ps1` | `assets/javascripts` | Download mermaid bundle and css into assets (PowerShell) |\n| `docs/02-architecture/mmd-diagrams/render.sh` | `docs/02-architecture/mmd-diagrams` | BioETL — Unified Diagram Renderer |\n| `docs/skills/global/gh-address-comments/scripts/fetch_comments.py` | `docs/skills/global/gh-address-comments/scripts` | Fetch all PR conversation comments + reviews + review threads (inline threads) |\n| `docs/skills/global/gh-fix-ci/scripts/inspect_pr_checks.py` | `docs/skills/global/gh-fix-ci/scripts` | Script: inspect pr checks |\n| `entrypoint.sh` | `.` | Start the WARP service daemon |\n| `scripts/add_svg_text_fallback.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/ast_inventory.py` | `scripts` | AST-based inventory of all Python files in the bioetl package. |\n| `scripts/audit_root_cleanliness.py` | `scripts` | Validate allowed files/directories in repository root. |\n| `scripts/audit_structure.py` | `scripts` | BioETL Structure Audit Tool. |\n| `scripts/check_config_invariants.py` | `scripts` | Pre-commit hook: validate CI invariants for configs/** directory. |\n| `scripts/check_delta_integrity.py` | `scripts` | Try reading it with polars |\n| `scripts/check_diagram_artifacts.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/check_diagram_quality_gates.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/check_diagram_visual_smoke.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/check_doc_links.py` | `scripts` | check_doc_links.py - Validate documentation links and spec file existence. |\n| `scripts/check_mcp.sh` | `scripts` | Script: check mcp |\n| `scripts/check_root_vcr_cassettes.py` | `scripts` | Block VCR cassette files from being committed in repository root. |\n| `scripts/check_svg_text_visibility.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/check_version_consistency.py` | `scripts` | Lightweight consistency check for project version metadata. |\n| `scripts/ci/run_pytest_resilient.py` | `scripts/ci` | Resilient pytest runner with xdist crash fallback for CI. |\n| `scripts/cleanup_consolidate.py` | `scripts` | cleanup_consolidate.py — Консолидированный аудит артефактов и кода проекта. |\n| `scripts/cleanup_project.py` | `scripts` | cleanup_project.py - Clean up caches, build artifacts, and temporary files. |\n| `scripts/config_gap_analysis.py` | `scripts` | Gap analysis for pipeline configs against ADR-014/025/027. |\n| `scripts/debug_pandera.py` | `scripts` | Monkeypatch FunctionDispatch |\n| `scripts/debug_storage_health.py` | `scripts` | Script: debug storage health |\n| `scripts/delete-stale-branches.sh` | `scripts` | Delete stale and duplicate remote branches |\n| `scripts/deploy-bioetl.sh` | `scripts` | BioETL Kubernetes Quick-Start Script |\n| `scripts/dev/dev_setup.sh` | `scripts/dev` | scripts/dev/dev_setup.sh — Скрипт настройки окружения разработки для BioETL |\n| `scripts/dev/metrics_mock_server.py` | `scripts/dev` | BioETL-compatible Prometheus metrics server with sample data. |\n| `scripts/dev/run_tests.ps1` | `scripts/dev` | BioETL Test Runner (PowerShell) |\n| `scripts/dev/run_tests.sh` | `scripts/dev` | BioETL Test Runner |\n| `scripts/diagrams/add_svg_text_fallback.py` | `scripts/diagrams` | Add plain SVG fallbacks for Mermaid labels. |\n| `scripts/diagrams/check_diagram_artifacts.py` | `scripts/diagrams` | Validate rendered diagram artifacts for smoke baseline set. |\n| `scripts/diagrams/check_diagram_quality_gates.py` | `scripts/diagrams` | Diagram regression quality gates for DIAG-T018..DIAG-T023. |\n| `scripts/diagrams/check_diagram_visual_smoke.py` | `scripts/diagrams` | Smoke visual regression check for selected diagram SVG baselines. |\n| `scripts/diagrams/check_svg_text_visibility.py` | `scripts/diagrams` | Validate rendered SVG text visibility for diagram smoke baselines. |\n| `scripts/diagrams/fix_diagram_links.py` | `scripts/diagrams` | 1. Remove 'mermaid/' from diagram paths |\n| `scripts/diagrams/fix_sequence_nbsp.py` | `scripts/diagrams` | Fix   in sequence diagram participant/actor lines. |\n| `scripts/diagrams/inject_svg_styles.py` | `scripts/diagrams` | inject_svg_styles.py — Inject CSS overrides into rendered Mermaid SVG files. |\n| `scripts/diagrams/lint_diagrams.py` | `scripts/diagrams` | lint_diagrams.py - Diagram policy linter for BioETL project. |\n| `scripts/diagrams/mermaid_prune_orphans.py` | `scripts/diagrams` | Prune orphan nodes from Mermaid sequence and flowchart diagrams. |\n| `scripts/diagrams/normalize_node_sizes.py` | `scripts/diagrams` | Normalize Mermaid node sizes for class/sequence diagrams. |\n| `scripts/diagrams/prune_orphan_nodes.py` | `scripts/diagrams` | prune_orphan_nodes.py — Detect and remove orphan nodes from Mermaid diagrams. |\n| `scripts/diagrams/render_diagrams.py` | `scripts/diagrams` | Render Mermaid diagrams to PNG. |\n| `scripts/diagrams/report_diagram_padding.py` | `scripts/diagrams` | Report   density in Mermaid source files. |\n| `scripts/diagrams/run_diagram_checks.sh` | `scripts/diagrams` | Unified runner for diagram validation suites. |\n| `scripts/diagrams/run_diagram_nightly_suite.py` | `scripts/diagrams` | Nightly regression suite for diagram Phase 2 checks (DIAG-T024..DIAG-T029). |\n| `scripts/diagrams/strip_svg_foreign_object.py` | `scripts/diagrams` | Strip Mermaid foreignObject labels from rendered SVG files. |\n| `scripts/diagrams/summarize_diagram_lint.py` | `scripts/diagrams` | Summarize diagram lint JSON report by severity and rule. |\n| `scripts/diagrams/uniform_diagram_sizes.py` | `scripts/diagrams` | uniform_diagram_sizes.py — Normalize object sizes in Mermaid diagrams. |\n| `scripts/diagrams/validate_mermaid_syntax.sh` | `scripts/diagrams` | Retry once to reduce flaky Puppeteer/mmdc startup failures. |\n| `scripts/dq_baseline_update.py` | `scripts` | dq_baseline_update.py - Update Data Quality baseline metrics. |\n| `scripts/extract_null_fields.py` | `scripts` | Поля для извлечения (всегда пустые/null) |\n| `scripts/fix_diagram_links.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/fix_doc_links_auto.py` | `scripts` | 1. Fix absolute-looking links like [text](docs/...) to be relative |\n| `scripts/fix_doc_links_explicit.py` | `scripts` | Mapping of incorrect paths to correct ones |\n| `scripts/fix_grafana_dashboards.py` | `scripts` | Script to inject Grafana variables and fix PromQL queries for BioETL pipelines. |\n| `scripts/fix_sequence_nbsp.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/generate_content_hash_comparison_report.py` | `scripts` | Generate comparison report for legacy vs current content hash algorithm. |\n| `scripts/generate_pipeline_schema.py` | `scripts` | Generate JSON Schema from Pydantic pipeline configuration models. |\n| `scripts/generate_schema_artifacts.py` | `scripts` | Generate schema artifacts from canonical unified entity schema sections. |\n| `scripts/inject_svg_styles.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/install_deps.py` | `scripts` | Script: install deps |\n| `scripts/lint_config_paths.py` | `scripts` | lint_config_paths.py - Validate canonical config path references. |\n| `scripts/lint_diagrams.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/lint_terminology.py` | `scripts` | Compatibility wrapper for the terminology linter. |\n| `scripts/mermaid_prune_orphans.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/naming_audit.py` | `scripts` | Naming Convention Audit Tool for BioETL. |\n| `scripts/normalize_node_sizes.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/preflight_cleanup.sh` | `scripts` | Add cache directories explicitly in case they were pruned |\n| `scripts/prune_orphan_nodes.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/render_diagrams.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/report_diagram_padding.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/run_diagram_checks.sh` | `scripts` | Script: run diagram checks |\n| `scripts/run_diagram_nightly_suite.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/run_pytest.sh` | `scripts` | Script: run pytest |\n| `scripts/salt_rotate.py` | `scripts` | salt_rotate.py - Rotate PII hashing salt for security compliance. |\n| `scripts/sentence_doc_audit.py` | `scripts` | Script: sentence doc audit |\n| `scripts/setup.sh` | `scripts` | setup.sh - Compatibility wrapper for environment setup. |\n| `scripts/setup_plugins.sh` | `scripts` | setup_plugins.sh - Configure development plugins for BioETL. |\n| `scripts/setup_skills.sh` | `scripts` | setup_skills.sh - Sync repository Codex skills into CODEX_HOME. |\n| `scripts/strip_svg_foreign_object.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/summarize_diagram_lint.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/uniform_diagram_sizes.py` | `scripts` | Deprecated wrapper; use scripts/diagrams counterpart. |\n| `scripts/vacuum_delta.py` | `scripts` | vacuum_delta.py - VACUUM operation for Delta Lake tables. |\n| `scripts/validate_data_dir.py` | `scripts` | Validate tracked data/ files against allowlist and size limits. |\n| `scripts/validate_mermaid_syntax.sh` | `scripts` | Script: validate mermaid syntax |\n| `scripts/validate_pipeline_configs.py` | `scripts` | Validate unified pipeline and composite configs against JSON schemas. |\n| `scripts/verify_checksums.py` | `scripts` | verify_checksums.py - Verify checksums of critical artifacts. |\n| `src/tools/scripts/check_application_deps.py` | `src/tools/scripts` | Check application layer dependencies. |\n| `src/tools/scripts/check_architecture.py` | `src/tools/scripts` | Check infrastructure layer architecture. |\n| `src/tools/scripts/check_constructor_args.py` | `src/tools/scripts` | Check constructor argument counts to enforce dependency limits. |\n| `src/tools/scripts/cleanup_cache.py` | `src/tools/scripts` | Clean pytest cache and duplicate test files. |\n| `src/tools/scripts/config_matrix_generator.py` | `src/tools/scripts` | Generate comparison matrix for unified entity/composite configs. |\n| `src/tools/scripts/duplicate_function_analyzer.py` | `src/tools/scripts` | AST-анализатор дубликатов функций в выбранной области проекта. |\n| `src/tools/scripts/generate_contracts.py` | `src/tools/scripts` | Generate Gold JSON contracts from Pandera DataFrameModel schemas. |\n| `src/tools/scripts/lint_terminology.py` | `src/tools/scripts` | Terminology linter for BioETL Ubiquitous Language. |\n| `src/tools/scripts/migrate_openalex_citation_count.py` | `src/tools/scripts` | Migration script: Rename cited_by_count to citation_count in OpenAlex tables. |\n| `src/tools/scripts/migrations/migrate_pmid_to_string.py` | `src/tools/scripts/migrations` | Migration script: Convert pubmed_id from int to string in Delta Lake tables. |\n| `src/tools/scripts/migrations/rename_structure_fields.py` | `src/tools/scripts/migrations` | Migration script to rename ChEMBL molecule structure field names. |\n| `src/tools/scripts/run-tests.sh` | `src/tools/scripts` | run-tests.sh - Test runner script for BioETL |\n| `src/tools/scripts/run_pytest.sh` | `src/tools/scripts` | Script: run pytest |\n| `src/tools/scripts/setup.sh` | `src/tools/scripts` | setup.sh - Compatibility wrapper for environment setup. |\n| `src/tools/scripts/test_changed.sh` | `src/tools/scripts` | test_changed.sh - Run tests for changed files only |\n| `src/tools/scripts/validate_unified_configs.py` | `src/tools/scripts` | Validate unified entity configs (`configs/entities/**/*.yaml`). |\n \ No newline at end of file diff --git a/docs/skills/local/technical-designer-mermaid/SKILL.md b/docs/skills/local/technical-designer-mermaid/SKILL.md index 73eb2f72c4..8c85235fa6 100644 --- a/docs/skills/local/technical-designer-mermaid/SKILL.md +++ b/docs/skills/local/technical-designer-mermaid/SKILL.md @@ -89,11 +89,11 @@ Otherwise use generic Mermaid mode. - Preserve or improve label readability and avoid unnecessary crossing. 7. Run project quality gate after edits. -- `python scripts/lint_diagrams.py docs` -- `bash scripts/validate_mermaid_syntax.sh` +- `python scripts/diagrams/lint_diagrams.py docs` +- `bash scripts/diagrams/validate_mermaid_syntax.sh` - `bash docs/02-architecture/mmd-diagrams/render.sh` (or targeted render command) - Optional smoke check: - - `python scripts/check_diagram_visual_smoke.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt` + - `python scripts/diagrams/check_diagram_visual_smoke.py --manifest docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt` 8. Respect repository delivery rules. - If source `.mmd/.mermaid` changed, ensure rendered `svg/png` outputs are updated in commit. diff --git a/plans/diagram-views-improvement-plan.md b/plans/diagram-views-improvement-plan.md new file mode 100644 index 0000000000..a65e45c35e --- /dev/null +++ b/plans/diagram-views-improvement-plan.md @@ -0,0 +1,169 @@ +# План улучшения диаграмм views (полный охват) + +- Дата аудита: 2026-03-01 +- Охват: `156` диаграмм из `docs/02-architecture/mmd-diagrams/views/*.mermaid` +- Источники: `scripts/diagrams/lint_diagrams.py`, `scripts/diagrams/check_diagram_quality_gates.py` +- Текущее состояние: `lint issues = 0`; quality warnings = 0. +- В этом цикле: выровнена семантика связей в flowchart, сокращены перегруженные подписи, удалены избыточные `
`. +- Последний подтверждённый прогон: `2026-03-01 17:49` (`render.sh --png-only --dir docs/02-architecture/mmd-diagrams/views` + targeted full-view rerender). + +## Таблица по каждой диаграмме + +| # | Диаграмма | Тип | Найдено проблем | План улучшения | Статус | +|---:|---|---|---|---|---| +| 1 | `00-legend.mermaid` | `flowchart` | — | плановых правок нет; периодический lint/render/smoke-контроль | без правок в этом цикле | +| 2 | `01-full-system-component-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 3 | `01-full-system-component-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 4 | `01-full-system-component-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 5 | `01-full-system-component-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 6 | `01-full-system-component-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 7 | `01-high-level-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 8 | `01-high-level-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 9 | `01-high-level-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 10 | `01-high-level-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 11 | `01-high-level-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 12 | `02-medallion-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 13 | `02-medallion-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 14 | `02-medallion-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 15 | `02-medallion-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 16 | `02-medallion-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 17 | `04-domain-layer-class-diagram-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 18 | `04-domain-layer-class-diagram-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 19 | `04-domain-layer-class-diagram-full.mermaid` | `classDiagram` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 20 | `04-domain-layer-class-diagram-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 21 | `04-domain-layer-class-diagram-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 22 | `05-layers-interaction-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 23 | `05-layers-interaction-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 24 | `05-layers-interaction-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 25 | `05-layers-interaction-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 26 | `05-layers-interaction-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 27 | `05-pipeline-lifecycle-states-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 28 | `05-pipeline-lifecycle-states-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 29 | `05-pipeline-lifecycle-states-full.mermaid` | `stateDiagram` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 30 | `05-pipeline-lifecycle-states-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 31 | `05-pipeline-lifecycle-states-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 32 | `06-application-layer-class-diagram-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 33 | `06-application-layer-class-diagram-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 34 | `06-application-layer-class-diagram-full.mermaid` | `classDiagram` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 35 | `06-application-layer-class-diagram-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 36 | `06-application-layer-class-diagram-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 37 | `07-circuit-breaker-states-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 38 | `07-circuit-breaker-states-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 39 | `07-circuit-breaker-states-full.mermaid` | `stateDiagram` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 40 | `07-circuit-breaker-states-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 41 | `07-circuit-breaker-states-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 42 | `08-complete-etl-workflow-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 43 | `08-complete-etl-workflow-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 44 | `08-complete-etl-workflow-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 45 | `08-complete-etl-workflow-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 46 | `08-complete-etl-workflow-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 47 | `08-domain-ddd-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 48 | `08-domain-ddd-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 49 | `08-domain-ddd-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | обновлено в этом цикле | +| 50 | `08-domain-ddd-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 51 | `08-domain-ddd-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 52 | `10-infrastructure-layer-class-diagram-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 53 | `10-infrastructure-layer-class-diagram-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 54 | `10-infrastructure-layer-class-diagram-full.mermaid` | `classDiagram` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 55 | `10-infrastructure-layer-class-diagram-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 56 | `10-infrastructure-layer-class-diagram-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 57 | `12-local-deployment-architecture-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 58 | `12-local-deployment-architecture-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 59 | `12-local-deployment-architecture-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 60 | `12-local-deployment-architecture-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 61 | `12-local-deployment-architecture-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 62 | `14-provider-health-states-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 63 | `14-provider-health-states-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 64 | `14-provider-health-states-full.mermaid` | `stateDiagram` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 65 | `14-provider-health-states-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 66 | `14-provider-health-states-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 67 | `15-dq-check-workflow-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 68 | `15-dq-check-workflow-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 69 | `15-dq-check-workflow-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 70 | `15-dq-check-workflow-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 71 | `15-dq-check-workflow-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 72 | `21-activity-entity-data-flow-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 73 | `21-activity-entity-data-flow-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 74 | `21-activity-entity-data-flow-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 75 | `21-activity-entity-data-flow-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 76 | `21-activity-entity-data-flow-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 77 | `26-hexagonal-ports-adapters-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 78 | `26-hexagonal-ports-adapters-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 79 | `26-hexagonal-ports-adapters-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 80 | `26-hexagonal-ports-adapters-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 81 | `26-hexagonal-ports-adapters-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 82 | `28-composition-root-di-graph-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 83 | `28-composition-root-di-graph-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 84 | `28-composition-root-di-graph-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 85 | `28-composition-root-di-graph-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 86 | `28-composition-root-di-graph-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 87 | `29-composite-pipeline-workflow-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 88 | `29-composite-pipeline-workflow-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 89 | `29-composite-pipeline-workflow-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 90 | `29-composite-pipeline-workflow-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 91 | `29-composite-pipeline-workflow-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 92 | `30-port-adapter-mapping-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 93 | `30-port-adapter-mapping-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 94 | `30-port-adapter-mapping-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 95 | `30-port-adapter-mapping-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 96 | `30-port-adapter-mapping-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 97 | `31-pipeline-run-lifecycle-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 98 | `31-pipeline-run-lifecycle-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 99 | `31-pipeline-run-lifecycle-full.mermaid` | `stateDiagram` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 100 | `31-pipeline-run-lifecycle-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 101 | `31-pipeline-run-lifecycle-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 102 | `32-single-record-journey-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 103 | `32-single-record-journey-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 104 | `32-single-record-journey-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | обновлено в этом цикле | +| 105 | `32-single-record-journey-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 106 | `32-single-record-journey-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 107 | `33-cli-run-interaction-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 108 | `33-cli-run-interaction-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 109 | `33-cli-run-interaction-full.mermaid` | `sequenceDiagram` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 110 | `33-cli-run-interaction-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 111 | `33-cli-run-interaction-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 112 | `34-batch-processing-flow-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 113 | `34-batch-processing-flow-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 114 | `34-batch-processing-flow-full.mermaid` | `sequenceDiagram` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 115 | `34-batch-processing-flow-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 116 | `34-batch-processing-flow-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 117 | `35-bootstrap-sequence-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 118 | `35-bootstrap-sequence-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 119 | `35-bootstrap-sequence-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 120 | `35-bootstrap-sequence-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 121 | `35-bootstrap-sequence-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 122 | `36-architecture-principles-mindmap-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 123 | `36-architecture-principles-mindmap-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 124 | `36-architecture-principles-mindmap-full.mermaid` | `mindmap` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 125 | `36-architecture-principles-mindmap-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 126 | `36-architecture-principles-mindmap-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 127 | `39-medallion-invariants-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 128 | `39-medallion-invariants-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 129 | `39-medallion-invariants-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | обновлено в этом цикле | +| 130 | `39-medallion-invariants-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 131 | `39-medallion-invariants-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 132 | `41-error-classification-tree-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 133 | `41-error-classification-tree-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 134 | `41-error-classification-tree-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 135 | `41-error-classification-tree-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 136 | `41-error-classification-tree-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 137 | `44-cross-provider-enrichment-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 138 | `44-cross-provider-enrichment-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 139 | `44-cross-provider-enrichment-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | обновлено в этом цикле | +| 140 | `44-cross-provider-enrichment-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 141 | `44-cross-provider-enrichment-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 142 | `46-yaml-config-resolution-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 143 | `46-yaml-config-resolution-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 144 | `46-yaml-config-resolution-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 145 | `46-yaml-config-resolution-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 146 | `46-yaml-config-resolution-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 147 | `48-composite-phase-lifecycle-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 148 | `48-composite-phase-lifecycle-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 149 | `48-composite-phase-lifecycle-full.mermaid` | `stateDiagram` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 150 | `48-composite-phase-lifecycle-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 151 | `48-composite-phase-lifecycle-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | +| 152 | `50-exception-hierarchy-dataflow.mermaid` | `flowchart` | — | поддерживать явный путь данных Bronze→Silver→Gold и маркировать ветки ошибок | без правок в этом цикле | +| 153 | `50-exception-hierarchy-domain.mermaid` | `flowchart` | — | поддерживать доменную фокусировку: исключать инфраструктурные детали и служебные узлы | без правок в этом цикле | +| 154 | `50-exception-hierarchy-full.mermaid` | `flowchart` | — | сохранять полноту, но выносить перегруженные детали в декомпозированные view | без правок в этом цикле | +| 155 | `50-exception-hierarchy-infra.mermaid` | `flowchart` | — | поддерживать инфраструктурный фокус: показывать адаптеры/хранилища и точки интеграции | без правок в этом цикле | +| 156 | `50-exception-hierarchy-overview.mermaid` | `flowchart` | — | держать L1-вид в пределах 5-9 блоков и проверять пересечения при добавлении узлов | без правок в этом цикле | diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000000..0660e8687d --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,40 @@ +# Scripts Layout + +This directory is being consolidated by function to reduce discovery time and +make CI entrypoints explicit. + +## Current Status + +| Area | Canonical Path | Status | +|---|---|---| +| Diagram tooling | `scripts/diagrams/` | Done (phase 1) | +| CI helpers | `scripts/ci/` | Existing | +| Dev helpers | `scripts/dev/` | Existing | +| Config tooling | `scripts/config/` | Planned | +| Docs tooling | `scripts/docs/` | Planned | +| Data tooling | `scripts/data/` | Planned | +| Quality/architecture tooling | `scripts/quality/` | Planned | +| Ops/security tooling | `scripts/ops/`, `scripts/security/` | Planned | + +## Diagram Scripts + +Canonical diagram scripts now live in: + +- `scripts/diagrams/` + +Compatibility wrappers remain in: + +- `scripts/*.py` +- `scripts/*.sh` + +Wrappers print a deprecation warning and forward to `scripts/diagrams/*`. + +## Migration Rule + +For new automation, use canonical paths only: + +- `scripts/diagrams/run_diagram_checks.sh` +- `scripts/diagrams/lint_diagrams.py` +- `scripts/diagrams/validate_mermaid_syntax.sh` + +Do not add new references to legacy wrapper paths under `scripts/`. diff --git a/scripts/add_svg_text_fallback.py b/scripts/add_svg_text_fallback.py index 386e3e9255..a357870a98 100644 --- a/scripts/add_svg_text_fallback.py +++ b/scripts/add_svg_text_fallback.py @@ -1,216 +1,14 @@ #!/usr/bin/env python3 -""" -Add plain SVG fallbacks for Mermaid labels. - -Why: - Some SVG/PNG renderers ignore foreignObject (HTML labels), which makes - node and edge text invisible. This script keeps foreignObject in place and - adds a fallback element underneath it. - -Behavior: - - Does not remove/alter foreignObject (safe for layout and arrows) - - Skips empty/zero-size labels - - Idempotent per file (avoids duplicate fallback text) -""" - +"""Deprecated wrapper; use scripts/diagrams counterpart.""" from __future__ import annotations -import argparse -import re -import sys -import xml.etree.ElementTree as ET from pathlib import Path +import runpy +import sys -SVG_NS = "http://www.w3.org/2000/svg" -ET.register_namespace("", SVG_NS) - -SVG_DIRS = [ - Path("docs/02-architecture/mmd-diagrams/architecture/svg"), - Path("docs/02-architecture/mmd-diagrams/class-diagrams/svg"), - Path("docs/02-architecture/mmd-diagrams/foundation/svg"), - Path("docs/02-architecture/mmd-diagrams/views/svg"), -] - - -def _local_name(tag: str) -> str: - return tag.split("}", 1)[1] if "}" in tag else tag - - -def _parse_float(raw: str | None, default: float = 0.0) -> float: - if raw is None: - return default - try: - return float(raw) - except ValueError: - return default - - -def _fmt_float(value: float) -> str: - return f"{value:.3f}".rstrip("0").rstrip(".") or "0" - - -def _normalize_text(text: str) -> str: - return re.sub(r"\s+", " ", text).strip() - - -def _extract_text(node: ET.Element) -> str: - return _normalize_text(" ".join(node.itertext())) - - -def _is_empty_edge_label_group(node: ET.Element) -> bool: - """Detect Mermaid-generated empty edgeLabel containers. - - Some Mermaid outputs include wrappers with a zero-sized - foreignObject and no text content. These render as white rectangles in certain - viewers and should be removed. - """ - if _local_name(node.tag) != "g": - return False - classes = node.attrib.get("class", "") - if "edgeLabel" not in classes.split(): - return False - if _extract_text(node): - return False - - # Keep group if any foreignObject is non-zero (potentially meaningful label). - for child in node.iter(): - if _local_name(child.tag) != "foreignObject": - continue - width = _parse_float(child.attrib.get("width")) - height = _parse_float(child.attrib.get("height")) - if width > 0.0 or height > 0.0: - return False - return True - - -def _is_fallback_text(node: ET.Element) -> bool: - if _local_name(node.tag) != "text": - return False - classes = node.attrib.get("class", "") - return "fo-fallback" in classes.split() - - -def _build_fallback_text(fo: ET.Element) -> ET.Element | None: - text_value = _extract_text(fo) - if not text_value: - return None - - width = _parse_float(fo.attrib.get("width")) - height = _parse_float(fo.attrib.get("height")) - if width <= 0.0 and height <= 0.0: - return None - - x = _parse_float(fo.attrib.get("x")) - y = _parse_float(fo.attrib.get("y")) - - text_elem = ET.Element(f"{{{SVG_NS}}}text") - text_elem.set("x", _fmt_float(x + width / 2.0)) - text_elem.set("y", _fmt_float(y + height / 2.0)) - text_elem.set("text-anchor", "middle") - text_elem.set("dominant-baseline", "middle") - text_elem.set("xml:space", "preserve") - - cls = fo.attrib.get("class", "").strip() - text_elem.set("class", f"{cls} fo-fallback".strip()) - - transform = fo.attrib.get("transform") - if transform: - text_elem.set("transform", transform) - - text_elem.text = text_value - return text_elem - - -def add_fallbacks(path: Path) -> int: - tree = ET.parse(path) - root = tree.getroot() - - inserted = 0 - removed_empty_edge_labels = 0 - for parent in root.iter(): - children = list(parent) - for child in children: - if not _is_empty_edge_label_group(child): - continue - parent.remove(child) - removed_empty_edge_labels += 1 - - for parent in root.iter(): - children = list(parent) - for idx, child in enumerate(children): - if _local_name(child.tag) != "foreignObject": - continue - - if idx > 0 and _is_fallback_text(children[idx - 1]): - continue - - fallback = _build_fallback_text(child) - if fallback is None: - continue - - parent.insert(idx, fallback) - inserted += 1 - - if inserted > 0 or removed_empty_edge_labels > 0: - tree.write(path, encoding="utf-8", xml_declaration=False) - - return inserted + removed_empty_edge_labels - - -def collect_svg_files(files: list[Path] | None, dirs: list[Path] | None) -> list[Path]: - if files: - return files - if dirs: - result: list[Path] = [] - for d in dirs: - if d.is_dir(): - result.extend(sorted(d.glob("*.svg"))) - return result - result: list[Path] = [] - for d in SVG_DIRS: - if d.is_dir(): - result.extend(sorted(d.glob("*.svg"))) - return result - - -def main() -> int: - parser = argparse.ArgumentParser( - description="Add fallback SVG text for Mermaid foreignObject labels.", - ) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument("--check", action="store_true", help="Exit 1 if fallback insertion needed") - group.add_argument("--fix", action="store_true", help="Write changes in place") - group.add_argument("--dry-run", action="store_true", help="Show what would change") - parser.add_argument("-f", "--file", type=Path, action="append", help="Specific SVG file(s)") - parser.add_argument("--dir", type=Path, action="append", help="Specific directory(ies)") - args = parser.parse_args() - - mode = "check" if args.check else ("dry-run" if args.dry_run else "fix") - files = collect_svg_files(args.file, args.dir) - if not files: - print("No SVG files found.") - return 0 - - changed = 0 - for path in files: - original = path.read_text(encoding="utf-8") - inserted = add_fallbacks(path) - if inserted == 0: - continue - changed += 1 - if mode == "check": - print(f"! {path} (needs fallback text, +{inserted})") - path.write_text(original, encoding="utf-8") - elif mode == "dry-run": - print(f"~ {path} (would add fallback text +{inserted})") - path.write_text(original, encoding="utf-8") - else: - print(f"+ {path} (added fallback text +{inserted})") - - if mode == "check" and changed > 0: - return 1 - return 0 - +_CURRENT = Path(__file__).resolve() +_TARGET = _CURRENT.parent / "diagrams" / _CURRENT.name if __name__ == "__main__": - sys.exit(main()) + print(f"[DEPRECATED] Use scripts/diagrams/{_CURRENT.name}", file=sys.stderr) + runpy.run_path(str(_TARGET), run_name="__main__") diff --git a/scripts/check_diagram_artifacts.py b/scripts/check_diagram_artifacts.py index a95ed52e16..a357870a98 100644 --- a/scripts/check_diagram_artifacts.py +++ b/scripts/check_diagram_artifacts.py @@ -1,169 +1,14 @@ #!/usr/bin/env python3 -"""Validate rendered diagram artifacts for smoke baseline set. - -Checks: -- DIAG-T010: SVG artifacts exist -- DIAG-T011: PNG artifacts exist -- DIAG-T012: SVG/PNG artifacts are non-empty -""" - +"""Deprecated wrapper; use scripts/diagrams counterpart.""" from __future__ import annotations -import argparse -import json -import sys -from dataclasses import asdict, dataclass from pathlib import Path +import runpy +import sys -DEFAULT_MANIFEST = Path("docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt") - - -@dataclass(frozen=True) -class ArtifactIssue: - file: str - kind: str - message: str - - -def _out(message: str) -> None: - sys.stdout.write(f"{message}\n") - - -def _err(message: str) -> None: - sys.stderr.write(f"{message}\n") - - -def load_manifest(manifest_path: Path) -> list[Path]: - if not manifest_path.exists(): - raise FileNotFoundError(f"Manifest not found: {manifest_path}") - - paths: list[Path] = [] - for raw in manifest_path.read_text(encoding="utf-8").splitlines(): - line = raw.strip() - if not line or line.startswith("#"): - continue - path = Path(line) - if path.suffix.lower() != ".svg": - raise ValueError(f"Manifest must contain SVG paths only: {line}") - paths.append(path) - - if not paths: - raise ValueError(f"Manifest is empty: {manifest_path}") - - return paths - - -def to_png_path(svg_path: Path) -> Path: - parts = list(svg_path.parts) - try: - svg_idx = parts.index("svg") - except ValueError: - raise ValueError(f"Cannot derive PNG path (missing '/svg/' segment): {svg_path}") from None - - parts[svg_idx] = "png" - png = Path(*parts).with_suffix(".png") - return png - - -def validate_artifacts(repo_root: Path, svg_rel_paths: list[Path]) -> list[ArtifactIssue]: - issues: list[ArtifactIssue] = [] - - for svg_rel in svg_rel_paths: - svg_abs = repo_root / svg_rel - png_rel = to_png_path(svg_rel) - png_abs = repo_root / png_rel - - if not svg_abs.exists(): - issues.append( - ArtifactIssue( - file=str(svg_rel), - kind="DIAG-T010", - message="SVG artifact is missing", - ) - ) - elif svg_abs.stat().st_size <= 0: - issues.append( - ArtifactIssue( - file=str(svg_rel), - kind="DIAG-T012", - message="SVG artifact is empty", - ) - ) - - if not png_abs.exists(): - issues.append( - ArtifactIssue( - file=str(png_rel), - kind="DIAG-T011", - message="PNG artifact is missing", - ) - ) - elif png_abs.stat().st_size <= 0: - issues.append( - ArtifactIssue( - file=str(png_rel), - kind="DIAG-T012", - message="PNG artifact is empty", - ) - ) - - return issues - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description="Validate diagram SVG/PNG artifact existence") - parser.add_argument( - "--manifest", - type=Path, - default=DEFAULT_MANIFEST, - help=f"Path to SVG manifest (default: {DEFAULT_MANIFEST})", - ) - parser.add_argument( - "--json", - action="store_true", - help="Emit JSON report", - ) - return parser.parse_args() - - -def main() -> int: - args = parse_args() - repo_root = Path.cwd() - manifest = args.manifest if args.manifest.is_absolute() else repo_root / args.manifest - - try: - svg_paths = load_manifest(manifest) - except (FileNotFoundError, ValueError) as exc: - _err(f"[ERROR] {exc}") - return 2 - - issues = validate_artifacts(repo_root, svg_paths) - - if args.json: - _out( - json.dumps( - { - "ok": not issues, - "checked": len(svg_paths), - "issues": [asdict(issue) for issue in issues], - }, - ensure_ascii=True, - indent=2, - ) - ) - else: - _out(f"[INFO] Checked artifact pairs: {len(svg_paths)}") - - if issues: - _err("[ERROR] Diagram artifact validation failed:") - for issue in issues: - _err(f" - {issue.kind} {issue.file}: {issue.message}") - return 1 - - if not args.json: - _out("[OK] Diagram artifact validation passed.") - return 0 - +_CURRENT = Path(__file__).resolve() +_TARGET = _CURRENT.parent / "diagrams" / _CURRENT.name if __name__ == "__main__": - raise SystemExit(main()) + print(f"[DEPRECATED] Use scripts/diagrams/{_CURRENT.name}", file=sys.stderr) + runpy.run_path(str(_TARGET), run_name="__main__") diff --git a/scripts/check_diagram_quality_gates.py b/scripts/check_diagram_quality_gates.py index f895002c02..a357870a98 100644 --- a/scripts/check_diagram_quality_gates.py +++ b/scripts/check_diagram_quality_gates.py @@ -1,552 +1,14 @@ #!/usr/bin/env python3 -"""Diagram regression quality gates for DIAG-T018..DIAG-T023. - -This script implements policy-aligned checks from -`diagram-regression-test-plan.md` and emits a machine-readable JSON report -plus a markdown summary. -""" - +"""Deprecated wrapper; use scripts/diagrams counterpart.""" from __future__ import annotations -import argparse -import json -import re -import sys -from dataclasses import asdict, dataclass from pathlib import Path +import runpy +import sys -REPO_ROOT = Path(__file__).resolve().parents[1] -DEFAULT_TARGET = Path("docs/02-architecture/mmd-diagrams") -DEFAULT_MANIFEST = Path("docs/02-architecture/mmd-diagrams/quality-gate-manifest.txt") -SUPPORTED_SUFFIXES = {".mmd", ".mermaid"} -EXPECTED_CLASSDEFS = {"port", "adapter", "service", "process", "storage"} -ALLOWED_EDGE_MARKERS = ("-->", "-.->", "==>") -FORBIDDEN_EDGE_TOKENS = ("---", "--x", "x--", "<--", "<==>") -NODES_RE = re.compile(r"%%\s*@nodes\s+(\d+)") -CLASSDEF_RE = re.compile(r"^\s*classDef\s+([A-Za-z0-9_-]+)") -QUOTED_RE = re.compile(r'"([^"\\]*(?:\\.[^"\\]*)*)"') -TAG_RE = re.compile(r"<[^>]+>") - - -@dataclass(frozen=True) -class Violation: - file: str - rule_id: str - severity: str - message: str - - -@dataclass(frozen=True) -class RuleSummary: - rule_id: str - hard_gate: bool - passed: bool - violations: int - - -@dataclass(frozen=True) -class Report: - checked_files: int - hard_failures: int - warning_failures: int - rules: list[RuleSummary] - violations: list[Violation] - - -def _out(message: str) -> None: - sys.stdout.write(f"{message}\n") - - -def _err(message: str) -> None: - sys.stderr.write(f"{message}\n") - - -def load_manifest(manifest_path: Path) -> list[Path]: - if not manifest_path.exists(): - raise FileNotFoundError(f"Manifest not found: {manifest_path}") - - files: list[Path] = [] - for raw in manifest_path.read_text(encoding="utf-8").splitlines(): - line = raw.strip() - if not line or line.startswith("#"): - continue - candidate = line if line.startswith("/") else (REPO_ROOT / line) - path = Path(candidate) - if path.suffix not in SUPPORTED_SUFFIXES: - raise ValueError(f"Manifest entry must be .mmd/.mermaid: {line}") - files.append(path) - - if not files: - raise ValueError(f"Manifest has no diagram entries: {manifest_path}") - return files - - -def discover_files(targets: list[Path]) -> list[Path]: - seen: set[Path] = set() - files: list[Path] = [] - - for target in targets: - resolved = target if target.is_absolute() else (REPO_ROOT / target) - if resolved.is_file(): - if resolved.suffix in SUPPORTED_SUFFIXES and resolved not in seen: - seen.add(resolved) - files.append(resolved) - continue - - if not resolved.exists(): - continue - - for pattern in ("*.mmd", "*.mermaid"): - for candidate in resolved.rglob(pattern): - if candidate.name.startswith("_"): - continue - if "99-archive" in candidate.parts: - continue - if candidate not in seen: - seen.add(candidate) - files.append(candidate) - - return sorted(files) - - -def parse_node_count(lines: list[str]) -> int | None: - for line in lines: - match = NODES_RE.search(line) - if match: - return int(match.group(1)) - return None - - -def is_flowchart(lines: list[str]) -> bool: - for line in lines: - stripped = line.strip() - if not stripped or stripped.startswith("%%"): - continue - lowered = stripped.lower() - return lowered.startswith("flowchart") or lowered.startswith("graph") - return False - - -def has_edge_syntax(line: str) -> bool: - if "linkStyle" in line or line.strip().startswith("classDef"): - return False - return "-->" in line or "-.->" in line or "==>" in line or "---" in line or "--x" in line - - -def normalize_label(raw: str) -> str: - no_br = raw.replace("
", " ").replace("
", " ") - no_tags = TAG_RE.sub("", no_br) - return " ".join(no_tags.split()) - - -def check_line_style_guide(path: Path, lines: list[str]) -> list[Violation]: - violations: list[Violation] = [] - if not is_flowchart(lines): - return violations - - for idx, line in enumerate(lines, start=1): - stripped = line.strip() - if not stripped or stripped.startswith("%%"): - continue - if not has_edge_syntax(stripped): - continue - - if any(token in stripped for token in FORBIDDEN_EDGE_TOKENS): - violations.append( - Violation( - file=str(path), - rule_id="DIAG-T018", - severity="ERROR", - message=( - f"line {idx}: forbidden edge operator token detected; " - "allowed semantic styles are -->, -.->, ==>" - ), - ) - ) - continue - - if "--" in stripped and not any(marker in stripped for marker in ALLOWED_EDGE_MARKERS): - violations.append( - Violation( - file=str(path), - rule_id="DIAG-T018", - severity="ERROR", - message=( - f"line {idx}: edge operator is outside style guide; " - "use -->, -.-> or ==>" - ), - ) - ) - - return violations - - -def check_classdef_coverage(path: Path, lines: list[str]) -> list[Violation]: - violations: list[Violation] = [] - if not is_flowchart(lines): - return violations - - classdefs = {match.group(1) for line in lines if (match := CLASSDEF_RE.match(line))} - - if not classdefs: - violations.append( - Violation( - file=str(path), - rule_id="DIAG-T019", - severity="WARNING", - message="no classDef declarations found; expected typed node classes", - ) - ) - return violations - - covered = classdefs & EXPECTED_CLASSDEFS - if len(covered) < 2: - violations.append( - Violation( - file=str(path), - rule_id="DIAG-T019", - severity="WARNING", - message=( - "classDef coverage is low " - f"(found={sorted(classdefs)}, expected_any_of={sorted(EXPECTED_CLASSDEFS)})" - ), - ) - ) - return violations - - -def sibling_views_for(path: Path) -> list[Path]: - parent = path.stem - views_dir = REPO_ROOT / "docs/02-architecture/mmd-diagrams/views" - if not views_dir.exists(): - return [] - - prefix = parent.split("-", maxsplit=1)[0] - candidates = sorted(views_dir.glob(f"{prefix}-*.mermaid")) - if candidates: - return candidates - return sorted(views_dir.glob(f"{parent}-*.mermaid")) - - -def check_large_diagram_decomposition(path: Path, lines: list[str], threshold: int) -> list[Violation]: - violations: list[Violation] = [] - nodes = parse_node_count(lines) - if nodes is None or nodes < threshold or path.suffix != ".mmd": - return violations - - views = sibling_views_for(path) - has_full = any(view.name.endswith("-full.mermaid") for view in views) - has_detail = any( - any(token in view.name for token in ("-overview", "-domain", "-infra", "-dataflow")) - for view in views - ) - - if not (has_full and has_detail): - violations.append( - Violation( - file=str(path), - rule_id="DIAG-T020", - severity="ERROR", - message=( - f"@nodes={nodes} requires decomposition; missing expected views in " - "docs/02-architecture/mmd-diagrams/views" - ), - ) - ) - return violations - - -def check_large_diagram_legend(path: Path, lines: list[str], threshold: int) -> list[Violation]: - violations: list[Violation] = [] - nodes = parse_node_count(lines) - if nodes is None or nodes < threshold: - return violations - - content = "\n".join(lines) - has_legend = ( - re.search(r"^\s*subgraph\s+Legend\b", content, flags=re.IGNORECASE | re.MULTILINE) - is not None - or "%% Legend:" in content - or "00-legend.mermaid" in content - ) - if not has_legend: - violations.append( - Violation( - file=str(path), - rule_id="DIAG-T021", - severity="ERROR", - message=f"@nodes={nodes} requires legend semantics on canvas or reference", - ) - ) - return violations - - -def check_label_quality(path: Path, lines: list[str], max_label_length: int, max_br: int) -> list[Violation]: - violations: list[Violation] = [] - - for idx, line in enumerate(lines, start=1): - stripped = line.strip() - if not stripped or stripped.startswith("%%"): - continue - - for match in QUOTED_RE.finditer(stripped): - raw = match.group(1) - normalized = normalize_label(raw) - if not normalized: - continue - - if len(normalized) > max_label_length: - violations.append( - Violation( - file=str(path), - rule_id="DIAG-T022", - severity="WARNING", - message=( - f"line {idx}: label length {len(normalized)} > {max_label_length}; " - "move verbose context to tooltip/click/docs" - ), - ) - ) - - br_count = raw.lower().count("
") + raw.lower().count("
") - if br_count > max_br: - violations.append( - Violation( - file=str(path), - rule_id="DIAG-T023", - severity="WARNING", - message=f"line {idx}: label has {br_count}
tags (max {max_br})", - ) - ) - - return violations - - -def evaluate_file(path: Path, *, large_threshold: int, max_label_length: int, max_br: int) -> list[Violation]: - try: - lines = path.read_text(encoding="utf-8").splitlines() - except OSError as exc: - return [ - Violation( - file=str(path), - rule_id="DIAG-T018", - severity="ERROR", - message=f"failed to read file: {exc}", - ) - ] - - violations: list[Violation] = [] - violations.extend(check_line_style_guide(path, lines)) - violations.extend(check_classdef_coverage(path, lines)) - violations.extend(check_large_diagram_decomposition(path, lines, threshold=large_threshold)) - violations.extend(check_large_diagram_legend(path, lines, threshold=large_threshold)) - violations.extend(check_label_quality(path, lines, max_label_length=max_label_length, max_br=max_br)) - return violations - - -def summarize(violations: list[Violation]) -> list[RuleSummary]: - hard_rules = {"DIAG-T018", "DIAG-T020", "DIAG-T021"} - all_rules = ["DIAG-T018", "DIAG-T019", "DIAG-T020", "DIAG-T021", "DIAG-T022", "DIAG-T023"] - by_rule: dict[str, list[Violation]] = {rule: [] for rule in all_rules} - - for violation in violations: - by_rule.setdefault(violation.rule_id, []).append(violation) - - summaries: list[RuleSummary] = [] - for rule in all_rules: - issues = by_rule.get(rule, []) - summaries.append( - RuleSummary( - rule_id=rule, - hard_gate=rule in hard_rules, - passed=not issues, - violations=len(issues), - ) - ) - return summaries - - -def render_markdown(report: Report) -> str: - lines: list[str] = [] - lines.append("# Diagram Regression Quality Report") - lines.append("") - lines.append("## Summary") - lines.append("") - lines.append(f"- Checked files: {report.checked_files}") - lines.append(f"- Hard failures: {report.hard_failures}") - lines.append(f"- Warning failures: {report.warning_failures}") - lines.append("") - lines.append("## Rule Status") - lines.append("") - lines.append("| Rule | Gate | Status | Violations |") - lines.append("|---|---|---|---:|") - for item in report.rules: - gate = "Hard" if item.hard_gate else "Soft" - status = "PASS" if item.passed else "FAIL" - lines.append(f"| {item.rule_id} | {gate} | {status} | {item.violations} |") - - if report.violations: - lines.append("") - lines.append("## Violations") - lines.append("") - for violation in report.violations: - lines.append( - f"- `{violation.rule_id}` [{violation.severity}] {violation.file}: {violation.message}" - ) - - return "\n".join(lines) + "\n" - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description="Run diagram regression quality gates") - parser.add_argument( - "paths", - nargs="*", - help="Diagram files/directories to check (ignored when --manifest is used)", - ) - parser.add_argument( - "--manifest", - type=Path, - default=DEFAULT_MANIFEST, - help=f"Path to source manifest (default: {DEFAULT_MANIFEST})", - ) - parser.add_argument( - "--no-manifest", - action="store_true", - help="Ignore manifest and evaluate paths/default target discovery", - ) - parser.add_argument( - "--large-threshold", - type=int, - default=30, - help="Node threshold for large-diagram checks (default: 30)", - ) - parser.add_argument( - "--max-label-length", - type=int, - default=90, - help="Max normalized label length before warning (default: 90)", - ) - parser.add_argument( - "--max-br", - type=int, - default=4, - help="Max
tags per label before warning (default: 4)", - ) - parser.add_argument( - "--json-out", - type=Path, - help="Write JSON report to file", - ) - parser.add_argument( - "--markdown-out", - type=Path, - help="Write markdown report to file", - ) - parser.add_argument( - "--json", - action="store_true", - help="Print JSON report to stdout", - ) - return parser.parse_args() - - -def main() -> int: - args = parse_args() - - try: - if not args.no_manifest: - manifest = args.manifest if args.manifest.is_absolute() else (REPO_ROOT / args.manifest) - files = load_manifest(manifest) - else: - targets = [Path(path) for path in args.paths] if args.paths else [DEFAULT_TARGET] - files = discover_files(targets) - except (FileNotFoundError, ValueError) as exc: - _err(f"[ERROR] {exc}") - return 2 - - if not files: - _err("[ERROR] No diagram files resolved for quality-gate check.") - return 2 - - violations: list[Violation] = [] - for file_path in files: - violations.extend( - evaluate_file( - file_path, - large_threshold=args.large_threshold, - max_label_length=args.max_label_length, - max_br=args.max_br, - ) - ) - - summaries = summarize(violations) - hard_failures = sum( - 1 - for violation in violations - if violation.rule_id in {"DIAG-T018", "DIAG-T020", "DIAG-T021"} - ) - warning_failures = len(violations) - hard_failures - - report = Report( - checked_files=len(files), - hard_failures=hard_failures, - warning_failures=warning_failures, - rules=summaries, - violations=violations, - ) - - if args.json_out is not None: - out = args.json_out if args.json_out.is_absolute() else (REPO_ROOT / args.json_out) - out.parent.mkdir(parents=True, exist_ok=True) - out.write_text( - json.dumps( - { - "checked_files": report.checked_files, - "hard_failures": report.hard_failures, - "warning_failures": report.warning_failures, - "rules": [asdict(item) for item in report.rules], - "violations": [asdict(item) for item in report.violations], - }, - indent=2, - ensure_ascii=True, - ) - + "\n", - encoding="utf-8", - ) - - if args.markdown_out is not None: - out = args.markdown_out if args.markdown_out.is_absolute() else (REPO_ROOT / args.markdown_out) - out.parent.mkdir(parents=True, exist_ok=True) - out.write_text(render_markdown(report), encoding="utf-8") - - if args.json: - _out( - json.dumps( - { - "checked_files": report.checked_files, - "hard_failures": report.hard_failures, - "warning_failures": report.warning_failures, - "rules": [asdict(item) for item in report.rules], - "violations": [asdict(item) for item in report.violations], - }, - indent=2, - ensure_ascii=True, - ) - ) - else: - _out( - "[INFO] Diagram quality gates: " - f"checked={report.checked_files}, hard_failures={report.hard_failures}, " - f"warnings={report.warning_failures}" - ) - for rule in report.rules: - gate = "HARD" if rule.hard_gate else "SOFT" - status = "PASS" if rule.passed else "FAIL" - _out(f"[INFO] {rule.rule_id} [{gate}] {status} ({rule.violations})") - - return 1 if report.hard_failures > 0 else 0 - +_CURRENT = Path(__file__).resolve() +_TARGET = _CURRENT.parent / "diagrams" / _CURRENT.name if __name__ == "__main__": - raise SystemExit(main()) + print(f"[DEPRECATED] Use scripts/diagrams/{_CURRENT.name}", file=sys.stderr) + runpy.run_path(str(_TARGET), run_name="__main__") diff --git a/scripts/check_diagram_visual_smoke.py b/scripts/check_diagram_visual_smoke.py index 596bfc1a9d..a357870a98 100644 --- a/scripts/check_diagram_visual_smoke.py +++ b/scripts/check_diagram_visual_smoke.py @@ -1,103 +1,14 @@ #!/usr/bin/env python3 -"""Smoke visual regression check for selected diagram SVG baselines. - -Intended usage: -1. Run diagram render pipeline (render.sh) in CI. -2. Run this script to ensure selected baseline SVGs were not modified by render. -""" - +"""Deprecated wrapper; use scripts/diagrams counterpart.""" from __future__ import annotations -import argparse -import subprocess -import sys from pathlib import Path +import runpy +import sys - -DEFAULT_MANIFEST = Path( - "docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt" -) - - -def load_manifest(manifest_path: Path) -> list[str]: - """Load relative paths from a manifest file.""" - if not manifest_path.exists(): - raise FileNotFoundError(f"Manifest not found: {manifest_path}") - - paths: list[str] = [] - for raw in manifest_path.read_text(encoding="utf-8").splitlines(): - line = raw.strip() - if not line or line.startswith("#"): - continue - paths.append(line) - - if not paths: - raise ValueError(f"Manifest is empty: {manifest_path}") - return paths - - -def ensure_paths_exist(repo_root: Path, rel_paths: list[str]) -> None: - """Validate that all manifest paths exist in working tree.""" - missing = [p for p in rel_paths if not (repo_root / p).exists()] - if missing: - msg = "\n".join(f" - {p}" for p in missing) - raise FileNotFoundError(f"Missing manifest path(s):\n{msg}") - - -def changed_paths(rel_paths: list[str]) -> list[str]: - """Return list of changed paths among provided manifest entries.""" - cmd = ["git", "diff", "--name-only", "--", *rel_paths] - completed = subprocess.run( - cmd, - check=False, - capture_output=True, - text=True, - ) - if completed.returncode != 0: - err = completed.stderr.strip() - raise RuntimeError(f"git diff failed: {err or 'unknown error'}") - return [line.strip() for line in completed.stdout.splitlines() if line.strip()] - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser( - description="Smoke-check selected SVG baselines for diagram render drift." - ) - parser.add_argument( - "--manifest", - type=Path, - default=DEFAULT_MANIFEST, - help=f"Path to manifest file (default: {DEFAULT_MANIFEST})", - ) - return parser.parse_args() - - -def main() -> int: - args = parse_args() - repo_root = Path.cwd() - manifest = args.manifest if args.manifest.is_absolute() else repo_root / args.manifest - - try: - rel_paths = load_manifest(manifest) - ensure_paths_exist(repo_root, rel_paths) - changed = changed_paths(rel_paths) - except (FileNotFoundError, ValueError, RuntimeError) as exc: - print(f"[ERROR] {exc}", file=sys.stderr) - return 2 - - if changed: - print("[ERROR] Visual smoke regression detected in baseline SVG(s):", file=sys.stderr) - for path in changed: - print(f" - {path}", file=sys.stderr) - print( - "[HINT] Re-run diagram render pipeline and commit updated baseline SVGs.", - file=sys.stderr, - ) - return 1 - - print(f"[OK] Visual smoke check passed ({len(rel_paths)} baseline SVGs unchanged).") - return 0 - +_CURRENT = Path(__file__).resolve() +_TARGET = _CURRENT.parent / "diagrams" / _CURRENT.name if __name__ == "__main__": - raise SystemExit(main()) + print(f"[DEPRECATED] Use scripts/diagrams/{_CURRENT.name}", file=sys.stderr) + runpy.run_path(str(_TARGET), run_name="__main__") diff --git a/scripts/check_svg_text_visibility.py b/scripts/check_svg_text_visibility.py index 181419bd2b..a357870a98 100644 --- a/scripts/check_svg_text_visibility.py +++ b/scripts/check_svg_text_visibility.py @@ -1,265 +1,14 @@ #!/usr/bin/env python3 -"""Validate rendered SVG text visibility for diagram smoke baselines. - -This guard focuses on failures where labels are rendered as white rectangles -without readable text in some viewers. -""" - +"""Deprecated wrapper; use scripts/diagrams counterpart.""" from __future__ import annotations -import argparse -import json -import sys -import xml.etree.ElementTree as ET -from dataclasses import asdict, dataclass from pathlib import Path +import runpy +import sys -SVG_NS = "http://www.w3.org/2000/svg" -NS = {"svg": SVG_NS} - -DEFAULT_MANIFEST = Path( - "docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt" -) - - -@dataclass(frozen=True) -class SvgMetrics: - file: str - edge_label_groups: int - edge_label_groups_with_text: int - foreign_objects: int - fallback_text_nodes: int - has_edge_label_color_css: bool - has_fallback_color_css: bool - - -def _normalize(text: str) -> str: - return " ".join(text.split()).strip() - - -def _local_name(tag: str) -> str: - return tag.split("}", 1)[1] if "}" in tag else tag - - -def _class_tokens(elem: ET.Element) -> set[str]: - raw = elem.attrib.get("class", "") - return {token for token in raw.split() if token} - - -def _has_nonempty_text(elem: ET.Element) -> bool: - text = _normalize(" ".join(elem.itertext())) - return bool(text) - - -def _collect_style_text(root: ET.Element) -> str: - parts: list[str] = [] - for style in root.findall(".//svg:style", NS): - parts.append(style.text or "") - return "\n".join(parts) - - -def analyze_svg(path: Path) -> tuple[SvgMetrics, list[str]]: - tree = ET.parse(path) - root = tree.getroot() - - edge_groups: list[ET.Element] = [] - fallback_text_nodes = 0 - foreign_objects = 0 - - for elem in root.iter(): - name = _local_name(elem.tag) - if name == "foreignObject": - foreign_objects += 1 - if name == "g" and "edgeLabel" in _class_tokens(elem): - edge_groups.append(elem) - if name == "text" and "fo-fallback" in _class_tokens(elem) and _has_nonempty_text(elem): - fallback_text_nodes += 1 - - edge_with_text = 0 - for group in edge_groups: - has_text = False - for child in group.iter(): - child_name = _local_name(child.tag) - if child_name == "foreignObject" and _has_nonempty_text(child): - has_text = True - break - if child_name == "text" and "fo-fallback" in _class_tokens(child) and _has_nonempty_text(child): - has_text = True - break - if has_text: - edge_with_text += 1 - - style_text = _collect_style_text(root) - has_edge_label_color_css = ".edgeLabel span" in style_text and "#111827" in style_text - has_fallback_color_css = "text.fo-fallback" in style_text and "#111827" in style_text - - metrics = SvgMetrics( - file=str(path), - edge_label_groups=len(edge_groups), - edge_label_groups_with_text=edge_with_text, - foreign_objects=foreign_objects, - fallback_text_nodes=fallback_text_nodes, - has_edge_label_color_css=has_edge_label_color_css, - has_fallback_color_css=has_fallback_color_css, - ) - - issues: list[str] = [] - if metrics.edge_label_groups > 0 and metrics.edge_label_groups_with_text == 0: - issues.append("edgeLabel groups exist but no readable label text was found") - if ( - metrics.edge_label_groups > 0 - and not metrics.has_edge_label_color_css - and metrics.fallback_text_nodes == 0 - ): - issues.append( - "missing edge-label text safeguards: no .edgeLabel color CSS and no fallback text" - ) - if metrics.fallback_text_nodes > 0 and not metrics.has_fallback_color_css: - issues.append("fallback text nodes exist but text.fo-fallback CSS color rule is missing") - - return metrics, issues - - -def load_manifest(manifest_path: Path) -> list[str]: - if not manifest_path.exists(): - raise FileNotFoundError(f"Manifest not found: {manifest_path}") - - paths: list[str] = [] - for raw in manifest_path.read_text(encoding="utf-8").splitlines(): - line = raw.strip() - if not line or line.startswith("#"): - continue - paths.append(line) - - if not paths: - raise ValueError(f"Manifest is empty: {manifest_path}") - return paths - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser( - description="Check SVG text visibility for diagram smoke set." - ) - parser.add_argument( - "--manifest", - type=Path, - default=DEFAULT_MANIFEST, - help=f"Path to manifest file (default: {DEFAULT_MANIFEST})", - ) - parser.add_argument( - "--json", - action="store_true", - help="Emit JSON report.", - ) - parser.add_argument( - "-f", - "--file", - type=Path, - action="append", - help="Check specific SVG file(s). If set, manifest is ignored.", - ) - parser.add_argument( - "--dir", - type=Path, - action="append", - help="Check all *.svg in specific directory(ies). If set, manifest is ignored.", - ) - return parser.parse_args() - - -def _out(message: str) -> None: - sys.stdout.write(f"{message}\n") - - -def _err(message: str) -> None: - sys.stderr.write(f"{message}\n") - - -def _collect_targets(args: argparse.Namespace, repo_root: Path) -> list[Path]: - if args.file or args.dir: - targets: list[Path] = [] - for file_path in args.file or []: - targets.append(file_path if file_path.is_absolute() else repo_root / file_path) - for directory in args.dir or []: - abs_dir = directory if directory.is_absolute() else repo_root / directory - if abs_dir.is_dir(): - targets.extend(sorted(abs_dir.glob("*.svg"))) - # Preserve order for files while deduplicating. - unique: list[Path] = [] - seen: set[str] = set() - for path in targets: - key = str(path.resolve()) if path.exists() else str(path) - if key not in seen: - unique.append(path) - seen.add(key) - return unique - - manifest = args.manifest if args.manifest.is_absolute() else repo_root / args.manifest - rel_paths = load_manifest(manifest) - return [repo_root / rel for rel in rel_paths] - - -def main() -> int: - args = parse_args() - repo_root = Path.cwd() - try: - targets = _collect_targets(args, repo_root) - except (FileNotFoundError, ValueError) as exc: - _err(f"[ERROR] {exc}") - return 2 - - if not targets: - _err("[ERROR] No SVG files to check.") - return 2 - - metrics_out: list[SvgMetrics] = [] - failures: list[tuple[str, list[str]]] = [] - - for path in targets: - rel = str(path.relative_to(repo_root)) if path.is_absolute() and str(path).startswith(str(repo_root)) else str(path) - if not path.exists(): - failures.append((rel, ["file not found"])) - continue - try: - metrics, issues = analyze_svg(path) - except ET.ParseError as exc: - failures.append((rel, [f"xml parse error: {exc}"])) - continue - metrics_out.append(metrics) - if issues: - failures.append((rel, issues)) - - if args.json: - payload = { - "ok": not failures, - "checked": len(targets), - "metrics": [asdict(m) for m in metrics_out], - "failures": [{"file": f, "issues": i} for f, i in failures], - } - _out(json.dumps(payload, ensure_ascii=True, indent=2)) - else: - _out(f"[INFO] Checked {len(targets)} SVG file(s).") - for m in metrics_out: - _out( - "[INFO] " - f"{Path(m.file).name}: edgeLabels={m.edge_label_groups}, " - f"withText={m.edge_label_groups_with_text}, " - f"foreignObject={m.foreign_objects}, " - f"foFallback={m.fallback_text_nodes}" - ) - - if failures: - _err("[ERROR] SVG text visibility check failed:") - for file_path, issues in failures: - _err(f" - {file_path}") - for issue in issues: - _err(f" * {issue}") - return 1 - - if not args.json: - _out("[OK] SVG text visibility check passed.") - return 0 - +_CURRENT = Path(__file__).resolve() +_TARGET = _CURRENT.parent / "diagrams" / _CURRENT.name if __name__ == "__main__": - raise SystemExit(main()) + print(f"[DEPRECATED] Use scripts/diagrams/{_CURRENT.name}", file=sys.stderr) + runpy.run_path(str(_TARGET), run_name="__main__") diff --git a/scripts/diagrams/add_svg_text_fallback.py b/scripts/diagrams/add_svg_text_fallback.py new file mode 100644 index 0000000000..8a6018318f --- /dev/null +++ b/scripts/diagrams/add_svg_text_fallback.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python3 +""" +Add plain SVG fallbacks for Mermaid labels. + +Why: + Some SVG/PNG renderers ignore foreignObject (HTML labels), which makes + node and edge text invisible. This script keeps foreignObject in place and + adds a fallback element underneath it. + +Behavior: + - Does not remove/alter foreignObject (safe for layout and arrows) + - Skips empty/zero-size labels + - Idempotent per file (avoids duplicate fallback text) +""" + +from __future__ import annotations + +import argparse +import re +import sys +import textwrap +import xml.etree.ElementTree as ET +from pathlib import Path + +SVG_NS = "http://www.w3.org/2000/svg" +ET.register_namespace("", SVG_NS) + +SVG_DIRS = [ + Path("docs/02-architecture/mmd-diagrams/architecture/svg"), + Path("docs/02-architecture/mmd-diagrams/class-diagrams/svg"), + Path("docs/02-architecture/mmd-diagrams/foundation/svg"), + Path("docs/02-architecture/mmd-diagrams/views/svg"), +] + + +def _local_name(tag: str) -> str: + return tag.split("}", 1)[1] if "}" in tag else tag + + +def _parse_float(raw: str | None, default: float = 0.0) -> float: + if raw is None: + return default + try: + return float(raw) + except ValueError: + return default + + +def _fmt_float(value: float) -> str: + return f"{value:.3f}".rstrip("0").rstrip(".") or "0" + + +def _normalize_text(text: str) -> str: + return re.sub(r"\s+", " ", text).strip() + + +def _extract_text(node: ET.Element) -> str: + """Extract collapsed single-line text from node tree.""" + return _normalize_text(" ".join(node.itertext())) + + +def _append_raw_text(parts: list[str], raw: str | None) -> None: + if raw is None: + return + if raw: + parts.append(raw) + + +def _extract_text_lines(node: ET.Element) -> list[str]: + """Extract semantic text lines from foreignObject HTML content. + + Mermaid labels are rendered through foreignObject HTML with explicit
+ markers. We preserve these line breaks and convert to compact plain-text + lines for SVG fallback text. + """ + + parts: list[str] = [] + + def visit(elem: ET.Element) -> None: + _append_raw_text(parts, elem.text) + for child in list(elem): + child_name = _local_name(child.tag).lower() + if child_name == "br": + parts.append("\n") + else: + visit(child) + if child_name in {"p", "div", "li"}: + parts.append("\n") + _append_raw_text(parts, child.tail) + + visit(node) + raw = "".join(parts) + if not raw: + return [] + + normalized: list[str] = [_normalize_text(line) for line in raw.split("\n")] + + # Collapse large blank gaps from Mermaid padding (

...). + compact: list[str] = [] + prev_blank = False + for line in normalized: + is_blank = not line + if is_blank and prev_blank: + continue + compact.append(line) + prev_blank = is_blank + + while compact and not compact[0]: + compact.pop(0) + while compact and not compact[-1]: + compact.pop() + + return compact + + +def _sanitize_label_line(line: str) -> str: + stripped = line.strip() + if not stripped: + return "" + + # Collapse decorative separators to a short neutral divider. + if len(stripped) >= 6 and not any(ch.isalnum() for ch in stripped): + glyphs = {ch for ch in stripped if not ch.isspace()} + if len(glyphs) <= 3: + return "--------" + + # Normalize slash separators for more readable fallback labels. + stripped = re.sub(r"\s*/\s*", " / ", stripped) + + # Improve wrapping for long PascalCase/camelCase identifiers. + # humanized = re.sub(r"(?<=[A-Z])(?=[A-Z][a-z])", " ", stripped) + # humanized = re.sub(r"(?<=[a-z0-9])(?=[A-Z])", " ", humanized) + humanized = stripped + return humanized + + +def _estimate_wrap_chars(width: float, font_size: float) -> int: + # Approximate average glyph width for sans-serif text. + avg_char_width = max(font_size * 0.56, 6.0) + usable_width = max(width * 0.88, 40.0) + estimate = int(usable_width / avg_char_width) + return max(18, min(64, estimate)) + + +def _wrap_label_lines(lines: list[str], max_chars: int) -> list[str]: + wrapped: list[str] = [] + for raw in lines: + line = _sanitize_label_line(raw) + if not line: + if wrapped and wrapped[-1]: + wrapped.append("") + continue + chunks = textwrap.wrap( + line, + width=max_chars, + break_long_words=False, + break_on_hyphens=False, + ) + if not chunks: + chunks = [line] + + # If a token still exceeds width (no spaces), hard-wrap it. + for chunk in chunks: + if len(chunk) <= max_chars: + wrapped.append(chunk) + continue + start = 0 + while start < len(chunk): + wrapped.append(chunk[start:start + max_chars]) + start += max_chars + + while wrapped and not wrapped[0]: + wrapped.pop(0) + while wrapped and not wrapped[-1]: + wrapped.pop() + return wrapped + + +def _is_empty_edge_label_group(node: ET.Element) -> bool: + """Detect Mermaid-generated empty edgeLabel containers. + + Some Mermaid outputs include wrappers with a zero-sized + foreignObject and no text content. These render as white rectangles in certain + viewers and should be removed. + """ + if _local_name(node.tag) != "g": + return False + classes = node.attrib.get("class", "") + if "edgeLabel" not in classes.split(): + return False + if _extract_text(node): + return False + + # Keep group if any foreignObject is non-zero (potentially meaningful label). + for child in node.iter(): + if _local_name(child.tag) != "foreignObject": + continue + width = _parse_float(child.attrib.get("width")) + height = _parse_float(child.attrib.get("height")) + if width > 0.0 or height > 0.0: + return False + return True + + +def _is_fallback_text(node: ET.Element) -> bool: + if _local_name(node.tag) != "text": + return False + classes = node.attrib.get("class", "") + return "fo-fallback" in classes.split() + + +def _build_fallback_text(fo: ET.Element) -> ET.Element | None: + text_lines = _extract_text_lines(fo) + if not text_lines: + return None + + width = _parse_float(fo.attrib.get("width")) + height = _parse_float(fo.attrib.get("height")) + if width <= 0.0 and height <= 0.0: + return None + + x = _parse_float(fo.attrib.get("x")) + y = _parse_float(fo.attrib.get("y")) + + center_x = x + width / 2.0 + font_size = 14.0 + max_chars = _estimate_wrap_chars(width=width, font_size=font_size) + wrapped_lines = _wrap_label_lines(text_lines, max_chars=max_chars) + if not wrapped_lines: + return None + + # Keep fallback labels compact even for oversized node descriptions. + max_lines = 12 + if len(wrapped_lines) > max_lines: + wrapped_lines = wrapped_lines[: max_lines - 1] + ["..."] + + line_height = max(font_size * 1.2, 10.0) + total_span = (len(wrapped_lines) - 1) * line_height + first_line_y = y + (height - total_span) / 2.0 + + text_elem = ET.Element(f"{{{SVG_NS}}}text") + text_elem.set("x", _fmt_float(center_x)) + text_elem.set("y", _fmt_float(first_line_y)) + text_elem.set("text-anchor", "middle") + text_elem.set("xml:space", "preserve") + + cls = fo.attrib.get("class", "").strip() + text_elem.set("class", f"{cls} fo-fallback".strip()) + + transform = fo.attrib.get("transform") + if transform: + text_elem.set("transform", transform) + + for idx, line in enumerate(wrapped_lines): + tspan = ET.Element(f"{{{SVG_NS}}}tspan") + tspan.set("x", _fmt_float(center_x)) + if idx > 0: + tspan.set("dy", _fmt_float(line_height)) + tspan.text = line + text_elem.append(tspan) + + return text_elem + + +def add_fallbacks(path: Path) -> int: + tree = ET.parse(path) + root = tree.getroot() + + inserted = 0 + removed_empty_edge_labels = 0 + for parent in root.iter(): + children = list(parent) + for child in children: + if not _is_empty_edge_label_group(child): + continue + parent.remove(child) + removed_empty_edge_labels += 1 + + for parent in root.iter(): + children = list(parent) + for idx, child in enumerate(children): + if _local_name(child.tag) != "foreignObject": + continue + + if idx > 0 and _is_fallback_text(children[idx - 1]): + parent.remove(children[idx - 1]) + + fallback = _build_fallback_text(child) + if fallback is None: + continue + + live_children = list(parent) + child_index = live_children.index(child) + parent.insert(child_index, fallback) + inserted += 1 + + if inserted > 0 or removed_empty_edge_labels > 0: + tree.write(path, encoding="utf-8", xml_declaration=False) + + return inserted + removed_empty_edge_labels + + +def collect_svg_files(files: list[Path] | None, dirs: list[Path] | None) -> list[Path]: + if files: + return files + if dirs: + selected: list[Path] = [] + for d in dirs: + if d.is_dir(): + selected.extend(sorted(d.glob("*.svg"))) + return selected + result: list[Path] = [] + for d in SVG_DIRS: + if d.is_dir(): + result.extend(sorted(d.glob("*.svg"))) + return result + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Add fallback SVG text for Mermaid foreignObject labels.", + ) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("--check", action="store_true", help="Exit 1 if fallback insertion needed") + group.add_argument("--fix", action="store_true", help="Write changes in place") + group.add_argument("--dry-run", action="store_true", help="Show what would change") + parser.add_argument("-f", "--file", type=Path, action="append", help="Specific SVG file(s)") + parser.add_argument("--dir", type=Path, action="append", help="Specific directory(ies)") + args = parser.parse_args() + + mode = "check" if args.check else ("dry-run" if args.dry_run else "fix") + files = collect_svg_files(args.file, args.dir) + if not files: + print("No SVG files found.") + return 0 + + changed = 0 + for path in files: + original = path.read_text(encoding="utf-8") + inserted = add_fallbacks(path) + if inserted == 0: + continue + changed += 1 + if mode == "check": + print(f"! {path} (needs fallback text, +{inserted})") + path.write_text(original, encoding="utf-8") + elif mode == "dry-run": + print(f"~ {path} (would add fallback text +{inserted})") + path.write_text(original, encoding="utf-8") + else: + print(f"+ {path} (added fallback text +{inserted})") + + if mode == "check" and changed > 0: + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/diagrams/check_diagram_artifacts.py b/scripts/diagrams/check_diagram_artifacts.py new file mode 100644 index 0000000000..a95ed52e16 --- /dev/null +++ b/scripts/diagrams/check_diagram_artifacts.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +"""Validate rendered diagram artifacts for smoke baseline set. + +Checks: +- DIAG-T010: SVG artifacts exist +- DIAG-T011: PNG artifacts exist +- DIAG-T012: SVG/PNG artifacts are non-empty +""" + +from __future__ import annotations + +import argparse +import json +import sys +from dataclasses import asdict, dataclass +from pathlib import Path + +DEFAULT_MANIFEST = Path("docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt") + + +@dataclass(frozen=True) +class ArtifactIssue: + file: str + kind: str + message: str + + +def _out(message: str) -> None: + sys.stdout.write(f"{message}\n") + + +def _err(message: str) -> None: + sys.stderr.write(f"{message}\n") + + +def load_manifest(manifest_path: Path) -> list[Path]: + if not manifest_path.exists(): + raise FileNotFoundError(f"Manifest not found: {manifest_path}") + + paths: list[Path] = [] + for raw in manifest_path.read_text(encoding="utf-8").splitlines(): + line = raw.strip() + if not line or line.startswith("#"): + continue + path = Path(line) + if path.suffix.lower() != ".svg": + raise ValueError(f"Manifest must contain SVG paths only: {line}") + paths.append(path) + + if not paths: + raise ValueError(f"Manifest is empty: {manifest_path}") + + return paths + + +def to_png_path(svg_path: Path) -> Path: + parts = list(svg_path.parts) + try: + svg_idx = parts.index("svg") + except ValueError: + raise ValueError(f"Cannot derive PNG path (missing '/svg/' segment): {svg_path}") from None + + parts[svg_idx] = "png" + png = Path(*parts).with_suffix(".png") + return png + + +def validate_artifacts(repo_root: Path, svg_rel_paths: list[Path]) -> list[ArtifactIssue]: + issues: list[ArtifactIssue] = [] + + for svg_rel in svg_rel_paths: + svg_abs = repo_root / svg_rel + png_rel = to_png_path(svg_rel) + png_abs = repo_root / png_rel + + if not svg_abs.exists(): + issues.append( + ArtifactIssue( + file=str(svg_rel), + kind="DIAG-T010", + message="SVG artifact is missing", + ) + ) + elif svg_abs.stat().st_size <= 0: + issues.append( + ArtifactIssue( + file=str(svg_rel), + kind="DIAG-T012", + message="SVG artifact is empty", + ) + ) + + if not png_abs.exists(): + issues.append( + ArtifactIssue( + file=str(png_rel), + kind="DIAG-T011", + message="PNG artifact is missing", + ) + ) + elif png_abs.stat().st_size <= 0: + issues.append( + ArtifactIssue( + file=str(png_rel), + kind="DIAG-T012", + message="PNG artifact is empty", + ) + ) + + return issues + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Validate diagram SVG/PNG artifact existence") + parser.add_argument( + "--manifest", + type=Path, + default=DEFAULT_MANIFEST, + help=f"Path to SVG manifest (default: {DEFAULT_MANIFEST})", + ) + parser.add_argument( + "--json", + action="store_true", + help="Emit JSON report", + ) + return parser.parse_args() + + +def main() -> int: + args = parse_args() + repo_root = Path.cwd() + manifest = args.manifest if args.manifest.is_absolute() else repo_root / args.manifest + + try: + svg_paths = load_manifest(manifest) + except (FileNotFoundError, ValueError) as exc: + _err(f"[ERROR] {exc}") + return 2 + + issues = validate_artifacts(repo_root, svg_paths) + + if args.json: + _out( + json.dumps( + { + "ok": not issues, + "checked": len(svg_paths), + "issues": [asdict(issue) for issue in issues], + }, + ensure_ascii=True, + indent=2, + ) + ) + else: + _out(f"[INFO] Checked artifact pairs: {len(svg_paths)}") + + if issues: + _err("[ERROR] Diagram artifact validation failed:") + for issue in issues: + _err(f" - {issue.kind} {issue.file}: {issue.message}") + return 1 + + if not args.json: + _out("[OK] Diagram artifact validation passed.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/diagrams/check_diagram_quality_gates.py b/scripts/diagrams/check_diagram_quality_gates.py new file mode 100644 index 0000000000..cca10b2569 --- /dev/null +++ b/scripts/diagrams/check_diagram_quality_gates.py @@ -0,0 +1,552 @@ +#!/usr/bin/env python3 +"""Diagram regression quality gates for DIAG-T018..DIAG-T023. + +This script implements policy-aligned checks from +`diagram-regression-test-plan.md` and emits a machine-readable JSON report +plus a markdown summary. +""" + +from __future__ import annotations + +import argparse +import json +import re +import sys +from dataclasses import asdict, dataclass +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[2] +DEFAULT_TARGET = Path("docs/02-architecture/mmd-diagrams") +DEFAULT_MANIFEST = Path("docs/02-architecture/mmd-diagrams/quality-gate-manifest.txt") +SUPPORTED_SUFFIXES = {".mmd", ".mermaid"} +EXPECTED_CLASSDEFS = {"port", "adapter", "service", "process", "storage"} +ALLOWED_EDGE_MARKERS = ("-->", "-.->", "==>") +FORBIDDEN_EDGE_TOKENS = ("---", "--x", "x--", "<--", "<==>") +NODES_RE = re.compile(r"%%\s*@nodes\s+(\d+)") +CLASSDEF_RE = re.compile(r"^\s*classDef\s+([A-Za-z0-9_-]+)") +QUOTED_RE = re.compile(r'"([^"\\]*(?:\\.[^"\\]*)*)"') +TAG_RE = re.compile(r"<[^>]+>") + + +@dataclass(frozen=True) +class Violation: + file: str + rule_id: str + severity: str + message: str + + +@dataclass(frozen=True) +class RuleSummary: + rule_id: str + hard_gate: bool + passed: bool + violations: int + + +@dataclass(frozen=True) +class Report: + checked_files: int + hard_failures: int + warning_failures: int + rules: list[RuleSummary] + violations: list[Violation] + + +def _out(message: str) -> None: + sys.stdout.write(f"{message}\n") + + +def _err(message: str) -> None: + sys.stderr.write(f"{message}\n") + + +def load_manifest(manifest_path: Path) -> list[Path]: + if not manifest_path.exists(): + raise FileNotFoundError(f"Manifest not found: {manifest_path}") + + files: list[Path] = [] + for raw in manifest_path.read_text(encoding="utf-8").splitlines(): + line = raw.strip() + if not line or line.startswith("#"): + continue + candidate = line if line.startswith("/") else (REPO_ROOT / line) + path = Path(candidate) + if path.suffix not in SUPPORTED_SUFFIXES: + raise ValueError(f"Manifest entry must be .mmd/.mermaid: {line}") + files.append(path) + + if not files: + raise ValueError(f"Manifest has no diagram entries: {manifest_path}") + return files + + +def discover_files(targets: list[Path]) -> list[Path]: + seen: set[Path] = set() + files: list[Path] = [] + + for target in targets: + resolved = target if target.is_absolute() else (REPO_ROOT / target) + if resolved.is_file(): + if resolved.suffix in SUPPORTED_SUFFIXES and resolved not in seen: + seen.add(resolved) + files.append(resolved) + continue + + if not resolved.exists(): + continue + + for pattern in ("*.mmd", "*.mermaid"): + for candidate in resolved.rglob(pattern): + if candidate.name.startswith("_"): + continue + if "99-archive" in candidate.parts: + continue + if candidate not in seen: + seen.add(candidate) + files.append(candidate) + + return sorted(files) + + +def parse_node_count(lines: list[str]) -> int | None: + for line in lines: + match = NODES_RE.search(line) + if match: + return int(match.group(1)) + return None + + +def is_flowchart(lines: list[str]) -> bool: + for line in lines: + stripped = line.strip() + if not stripped or stripped.startswith("%%"): + continue + lowered = stripped.lower() + return lowered.startswith("flowchart") or lowered.startswith("graph") + return False + + +def has_edge_syntax(line: str) -> bool: + if "linkStyle" in line or line.strip().startswith("classDef"): + return False + return "-->" in line or "-.->" in line or "==>" in line or "---" in line or "--x" in line + + +def normalize_label(raw: str) -> str: + no_br = raw.replace("
", " ").replace("
", " ") + no_tags = TAG_RE.sub("", no_br) + return " ".join(no_tags.split()) + + +def check_line_style_guide(path: Path, lines: list[str]) -> list[Violation]: + violations: list[Violation] = [] + if not is_flowchart(lines): + return violations + + for idx, line in enumerate(lines, start=1): + stripped = line.strip() + if not stripped or stripped.startswith("%%"): + continue + if not has_edge_syntax(stripped): + continue + + if any(token in stripped for token in FORBIDDEN_EDGE_TOKENS): + violations.append( + Violation( + file=str(path), + rule_id="DIAG-T018", + severity="ERROR", + message=( + f"line {idx}: forbidden edge operator token detected; " + "allowed semantic styles are -->, -.->, ==>" + ), + ) + ) + continue + + if "--" in stripped and not any(marker in stripped for marker in ALLOWED_EDGE_MARKERS): + violations.append( + Violation( + file=str(path), + rule_id="DIAG-T018", + severity="ERROR", + message=( + f"line {idx}: edge operator is outside style guide; " + "use -->, -.-> or ==>" + ), + ) + ) + + return violations + + +def check_classdef_coverage(path: Path, lines: list[str]) -> list[Violation]: + violations: list[Violation] = [] + if not is_flowchart(lines): + return violations + + classdefs = {match.group(1) for line in lines if (match := CLASSDEF_RE.match(line))} + + if not classdefs: + violations.append( + Violation( + file=str(path), + rule_id="DIAG-T019", + severity="WARNING", + message="no classDef declarations found; expected typed node classes", + ) + ) + return violations + + covered = classdefs & EXPECTED_CLASSDEFS + if len(covered) < 2: + violations.append( + Violation( + file=str(path), + rule_id="DIAG-T019", + severity="WARNING", + message=( + "classDef coverage is low " + f"(found={sorted(classdefs)}, expected_any_of={sorted(EXPECTED_CLASSDEFS)})" + ), + ) + ) + return violations + + +def sibling_views_for(path: Path) -> list[Path]: + parent = path.stem + views_dir = REPO_ROOT / "docs/02-architecture/mmd-diagrams/views" + if not views_dir.exists(): + return [] + + prefix = parent.split("-", maxsplit=1)[0] + candidates = sorted(views_dir.glob(f"{prefix}-*.mermaid")) + if candidates: + return candidates + return sorted(views_dir.glob(f"{parent}-*.mermaid")) + + +def check_large_diagram_decomposition(path: Path, lines: list[str], threshold: int) -> list[Violation]: + violations: list[Violation] = [] + nodes = parse_node_count(lines) + if nodes is None or nodes < threshold or path.suffix != ".mmd": + return violations + + views = sibling_views_for(path) + has_full = any(view.name.endswith("-full.mermaid") for view in views) + has_detail = any( + any(token in view.name for token in ("-overview", "-domain", "-infra", "-dataflow")) + for view in views + ) + + if not (has_full and has_detail): + violations.append( + Violation( + file=str(path), + rule_id="DIAG-T020", + severity="ERROR", + message=( + f"@nodes={nodes} requires decomposition; missing expected views in " + "docs/02-architecture/mmd-diagrams/views" + ), + ) + ) + return violations + + +def check_large_diagram_legend(path: Path, lines: list[str], threshold: int) -> list[Violation]: + violations: list[Violation] = [] + nodes = parse_node_count(lines) + if nodes is None or nodes < threshold: + return violations + + content = "\n".join(lines) + has_legend = ( + re.search(r"^\s*subgraph\s+Legend\b", content, flags=re.IGNORECASE | re.MULTILINE) + is not None + or "%% Legend:" in content + or "00-legend.mermaid" in content + ) + if not has_legend: + violations.append( + Violation( + file=str(path), + rule_id="DIAG-T021", + severity="ERROR", + message=f"@nodes={nodes} requires legend semantics on canvas or reference", + ) + ) + return violations + + +def check_label_quality(path: Path, lines: list[str], max_label_length: int, max_br: int) -> list[Violation]: + violations: list[Violation] = [] + + for idx, line in enumerate(lines, start=1): + stripped = line.strip() + if not stripped or stripped.startswith("%%"): + continue + + for match in QUOTED_RE.finditer(stripped): + raw = match.group(1) + normalized = normalize_label(raw) + if not normalized: + continue + + if len(normalized) > max_label_length: + violations.append( + Violation( + file=str(path), + rule_id="DIAG-T022", + severity="WARNING", + message=( + f"line {idx}: label length {len(normalized)} > {max_label_length}; " + "move verbose context to tooltip/click/docs" + ), + ) + ) + + br_count = raw.lower().count("
") + raw.lower().count("
") + if br_count > max_br: + violations.append( + Violation( + file=str(path), + rule_id="DIAG-T023", + severity="WARNING", + message=f"line {idx}: label has {br_count}
tags (max {max_br})", + ) + ) + + return violations + + +def evaluate_file(path: Path, *, large_threshold: int, max_label_length: int, max_br: int) -> list[Violation]: + try: + lines = path.read_text(encoding="utf-8").splitlines() + except OSError as exc: + return [ + Violation( + file=str(path), + rule_id="DIAG-T018", + severity="ERROR", + message=f"failed to read file: {exc}", + ) + ] + + violations: list[Violation] = [] + violations.extend(check_line_style_guide(path, lines)) + violations.extend(check_classdef_coverage(path, lines)) + violations.extend(check_large_diagram_decomposition(path, lines, threshold=large_threshold)) + violations.extend(check_large_diagram_legend(path, lines, threshold=large_threshold)) + violations.extend(check_label_quality(path, lines, max_label_length=max_label_length, max_br=max_br)) + return violations + + +def summarize(violations: list[Violation]) -> list[RuleSummary]: + hard_rules = {"DIAG-T018", "DIAG-T020", "DIAG-T021"} + all_rules = ["DIAG-T018", "DIAG-T019", "DIAG-T020", "DIAG-T021", "DIAG-T022", "DIAG-T023"] + by_rule: dict[str, list[Violation]] = {rule: [] for rule in all_rules} + + for violation in violations: + by_rule.setdefault(violation.rule_id, []).append(violation) + + summaries: list[RuleSummary] = [] + for rule in all_rules: + issues = by_rule.get(rule, []) + summaries.append( + RuleSummary( + rule_id=rule, + hard_gate=rule in hard_rules, + passed=not issues, + violations=len(issues), + ) + ) + return summaries + + +def render_markdown(report: Report) -> str: + lines: list[str] = [] + lines.append("# Diagram Regression Quality Report") + lines.append("") + lines.append("## Summary") + lines.append("") + lines.append(f"- Checked files: {report.checked_files}") + lines.append(f"- Hard failures: {report.hard_failures}") + lines.append(f"- Warning failures: {report.warning_failures}") + lines.append("") + lines.append("## Rule Status") + lines.append("") + lines.append("| Rule | Gate | Status | Violations |") + lines.append("|---|---|---|---:|") + for item in report.rules: + gate = "Hard" if item.hard_gate else "Soft" + status = "PASS" if item.passed else "FAIL" + lines.append(f"| {item.rule_id} | {gate} | {status} | {item.violations} |") + + if report.violations: + lines.append("") + lines.append("## Violations") + lines.append("") + for violation in report.violations: + lines.append( + f"- `{violation.rule_id}` [{violation.severity}] {violation.file}: {violation.message}" + ) + + return "\n".join(lines) + "\n" + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Run diagram regression quality gates") + parser.add_argument( + "paths", + nargs="*", + help="Diagram files/directories to check (ignored when --manifest is used)", + ) + parser.add_argument( + "--manifest", + type=Path, + default=DEFAULT_MANIFEST, + help=f"Path to source manifest (default: {DEFAULT_MANIFEST})", + ) + parser.add_argument( + "--no-manifest", + action="store_true", + help="Ignore manifest and evaluate paths/default target discovery", + ) + parser.add_argument( + "--large-threshold", + type=int, + default=30, + help="Node threshold for large-diagram checks (default: 30)", + ) + parser.add_argument( + "--max-label-length", + type=int, + default=90, + help="Max normalized label length before warning (default: 90)", + ) + parser.add_argument( + "--max-br", + type=int, + default=4, + help="Max
tags per label before warning (default: 4)", + ) + parser.add_argument( + "--json-out", + type=Path, + help="Write JSON report to file", + ) + parser.add_argument( + "--markdown-out", + type=Path, + help="Write markdown report to file", + ) + parser.add_argument( + "--json", + action="store_true", + help="Print JSON report to stdout", + ) + return parser.parse_args() + + +def main() -> int: + args = parse_args() + + try: + if not args.no_manifest: + manifest = args.manifest if args.manifest.is_absolute() else (REPO_ROOT / args.manifest) + files = load_manifest(manifest) + else: + targets = [Path(path) for path in args.paths] if args.paths else [DEFAULT_TARGET] + files = discover_files(targets) + except (FileNotFoundError, ValueError) as exc: + _err(f"[ERROR] {exc}") + return 2 + + if not files: + _err("[ERROR] No diagram files resolved for quality-gate check.") + return 2 + + violations: list[Violation] = [] + for file_path in files: + violations.extend( + evaluate_file( + file_path, + large_threshold=args.large_threshold, + max_label_length=args.max_label_length, + max_br=args.max_br, + ) + ) + + summaries = summarize(violations) + hard_failures = sum( + 1 + for violation in violations + if violation.rule_id in {"DIAG-T018", "DIAG-T020", "DIAG-T021"} + ) + warning_failures = len(violations) - hard_failures + + report = Report( + checked_files=len(files), + hard_failures=hard_failures, + warning_failures=warning_failures, + rules=summaries, + violations=violations, + ) + + if args.json_out is not None: + out = args.json_out if args.json_out.is_absolute() else (REPO_ROOT / args.json_out) + out.parent.mkdir(parents=True, exist_ok=True) + out.write_text( + json.dumps( + { + "checked_files": report.checked_files, + "hard_failures": report.hard_failures, + "warning_failures": report.warning_failures, + "rules": [asdict(item) for item in report.rules], + "violations": [asdict(item) for item in report.violations], + }, + indent=2, + ensure_ascii=True, + ) + + "\n", + encoding="utf-8", + ) + + if args.markdown_out is not None: + out = args.markdown_out if args.markdown_out.is_absolute() else (REPO_ROOT / args.markdown_out) + out.parent.mkdir(parents=True, exist_ok=True) + out.write_text(render_markdown(report), encoding="utf-8") + + if args.json: + _out( + json.dumps( + { + "checked_files": report.checked_files, + "hard_failures": report.hard_failures, + "warning_failures": report.warning_failures, + "rules": [asdict(item) for item in report.rules], + "violations": [asdict(item) for item in report.violations], + }, + indent=2, + ensure_ascii=True, + ) + ) + else: + _out( + "[INFO] Diagram quality gates: " + f"checked={report.checked_files}, hard_failures={report.hard_failures}, " + f"warnings={report.warning_failures}" + ) + for rule in report.rules: + gate = "HARD" if rule.hard_gate else "SOFT" + status = "PASS" if rule.passed else "FAIL" + _out(f"[INFO] {rule.rule_id} [{gate}] {status} ({rule.violations})") + + return 1 if report.hard_failures > 0 else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/diagrams/check_diagram_visual_smoke.py b/scripts/diagrams/check_diagram_visual_smoke.py new file mode 100644 index 0000000000..596bfc1a9d --- /dev/null +++ b/scripts/diagrams/check_diagram_visual_smoke.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +"""Smoke visual regression check for selected diagram SVG baselines. + +Intended usage: +1. Run diagram render pipeline (render.sh) in CI. +2. Run this script to ensure selected baseline SVGs were not modified by render. +""" + +from __future__ import annotations + +import argparse +import subprocess +import sys +from pathlib import Path + + +DEFAULT_MANIFEST = Path( + "docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt" +) + + +def load_manifest(manifest_path: Path) -> list[str]: + """Load relative paths from a manifest file.""" + if not manifest_path.exists(): + raise FileNotFoundError(f"Manifest not found: {manifest_path}") + + paths: list[str] = [] + for raw in manifest_path.read_text(encoding="utf-8").splitlines(): + line = raw.strip() + if not line or line.startswith("#"): + continue + paths.append(line) + + if not paths: + raise ValueError(f"Manifest is empty: {manifest_path}") + return paths + + +def ensure_paths_exist(repo_root: Path, rel_paths: list[str]) -> None: + """Validate that all manifest paths exist in working tree.""" + missing = [p for p in rel_paths if not (repo_root / p).exists()] + if missing: + msg = "\n".join(f" - {p}" for p in missing) + raise FileNotFoundError(f"Missing manifest path(s):\n{msg}") + + +def changed_paths(rel_paths: list[str]) -> list[str]: + """Return list of changed paths among provided manifest entries.""" + cmd = ["git", "diff", "--name-only", "--", *rel_paths] + completed = subprocess.run( + cmd, + check=False, + capture_output=True, + text=True, + ) + if completed.returncode != 0: + err = completed.stderr.strip() + raise RuntimeError(f"git diff failed: {err or 'unknown error'}") + return [line.strip() for line in completed.stdout.splitlines() if line.strip()] + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Smoke-check selected SVG baselines for diagram render drift." + ) + parser.add_argument( + "--manifest", + type=Path, + default=DEFAULT_MANIFEST, + help=f"Path to manifest file (default: {DEFAULT_MANIFEST})", + ) + return parser.parse_args() + + +def main() -> int: + args = parse_args() + repo_root = Path.cwd() + manifest = args.manifest if args.manifest.is_absolute() else repo_root / args.manifest + + try: + rel_paths = load_manifest(manifest) + ensure_paths_exist(repo_root, rel_paths) + changed = changed_paths(rel_paths) + except (FileNotFoundError, ValueError, RuntimeError) as exc: + print(f"[ERROR] {exc}", file=sys.stderr) + return 2 + + if changed: + print("[ERROR] Visual smoke regression detected in baseline SVG(s):", file=sys.stderr) + for path in changed: + print(f" - {path}", file=sys.stderr) + print( + "[HINT] Re-run diagram render pipeline and commit updated baseline SVGs.", + file=sys.stderr, + ) + return 1 + + print(f"[OK] Visual smoke check passed ({len(rel_paths)} baseline SVGs unchanged).") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/diagrams/check_svg_text_visibility.py b/scripts/diagrams/check_svg_text_visibility.py new file mode 100644 index 0000000000..181419bd2b --- /dev/null +++ b/scripts/diagrams/check_svg_text_visibility.py @@ -0,0 +1,265 @@ +#!/usr/bin/env python3 +"""Validate rendered SVG text visibility for diagram smoke baselines. + +This guard focuses on failures where labels are rendered as white rectangles +without readable text in some viewers. +""" + +from __future__ import annotations + +import argparse +import json +import sys +import xml.etree.ElementTree as ET +from dataclasses import asdict, dataclass +from pathlib import Path + +SVG_NS = "http://www.w3.org/2000/svg" +NS = {"svg": SVG_NS} + +DEFAULT_MANIFEST = Path( + "docs/02-architecture/mmd-diagrams/visual-smoke-manifest.txt" +) + + +@dataclass(frozen=True) +class SvgMetrics: + file: str + edge_label_groups: int + edge_label_groups_with_text: int + foreign_objects: int + fallback_text_nodes: int + has_edge_label_color_css: bool + has_fallback_color_css: bool + + +def _normalize(text: str) -> str: + return " ".join(text.split()).strip() + + +def _local_name(tag: str) -> str: + return tag.split("}", 1)[1] if "}" in tag else tag + + +def _class_tokens(elem: ET.Element) -> set[str]: + raw = elem.attrib.get("class", "") + return {token for token in raw.split() if token} + + +def _has_nonempty_text(elem: ET.Element) -> bool: + text = _normalize(" ".join(elem.itertext())) + return bool(text) + + +def _collect_style_text(root: ET.Element) -> str: + parts: list[str] = [] + for style in root.findall(".//svg:style", NS): + parts.append(style.text or "") + return "\n".join(parts) + + +def analyze_svg(path: Path) -> tuple[SvgMetrics, list[str]]: + tree = ET.parse(path) + root = tree.getroot() + + edge_groups: list[ET.Element] = [] + fallback_text_nodes = 0 + foreign_objects = 0 + + for elem in root.iter(): + name = _local_name(elem.tag) + if name == "foreignObject": + foreign_objects += 1 + if name == "g" and "edgeLabel" in _class_tokens(elem): + edge_groups.append(elem) + if name == "text" and "fo-fallback" in _class_tokens(elem) and _has_nonempty_text(elem): + fallback_text_nodes += 1 + + edge_with_text = 0 + for group in edge_groups: + has_text = False + for child in group.iter(): + child_name = _local_name(child.tag) + if child_name == "foreignObject" and _has_nonempty_text(child): + has_text = True + break + if child_name == "text" and "fo-fallback" in _class_tokens(child) and _has_nonempty_text(child): + has_text = True + break + if has_text: + edge_with_text += 1 + + style_text = _collect_style_text(root) + has_edge_label_color_css = ".edgeLabel span" in style_text and "#111827" in style_text + has_fallback_color_css = "text.fo-fallback" in style_text and "#111827" in style_text + + metrics = SvgMetrics( + file=str(path), + edge_label_groups=len(edge_groups), + edge_label_groups_with_text=edge_with_text, + foreign_objects=foreign_objects, + fallback_text_nodes=fallback_text_nodes, + has_edge_label_color_css=has_edge_label_color_css, + has_fallback_color_css=has_fallback_color_css, + ) + + issues: list[str] = [] + if metrics.edge_label_groups > 0 and metrics.edge_label_groups_with_text == 0: + issues.append("edgeLabel groups exist but no readable label text was found") + if ( + metrics.edge_label_groups > 0 + and not metrics.has_edge_label_color_css + and metrics.fallback_text_nodes == 0 + ): + issues.append( + "missing edge-label text safeguards: no .edgeLabel color CSS and no fallback text" + ) + if metrics.fallback_text_nodes > 0 and not metrics.has_fallback_color_css: + issues.append("fallback text nodes exist but text.fo-fallback CSS color rule is missing") + + return metrics, issues + + +def load_manifest(manifest_path: Path) -> list[str]: + if not manifest_path.exists(): + raise FileNotFoundError(f"Manifest not found: {manifest_path}") + + paths: list[str] = [] + for raw in manifest_path.read_text(encoding="utf-8").splitlines(): + line = raw.strip() + if not line or line.startswith("#"): + continue + paths.append(line) + + if not paths: + raise ValueError(f"Manifest is empty: {manifest_path}") + return paths + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Check SVG text visibility for diagram smoke set." + ) + parser.add_argument( + "--manifest", + type=Path, + default=DEFAULT_MANIFEST, + help=f"Path to manifest file (default: {DEFAULT_MANIFEST})", + ) + parser.add_argument( + "--json", + action="store_true", + help="Emit JSON report.", + ) + parser.add_argument( + "-f", + "--file", + type=Path, + action="append", + help="Check specific SVG file(s). If set, manifest is ignored.", + ) + parser.add_argument( + "--dir", + type=Path, + action="append", + help="Check all *.svg in specific directory(ies). If set, manifest is ignored.", + ) + return parser.parse_args() + + +def _out(message: str) -> None: + sys.stdout.write(f"{message}\n") + + +def _err(message: str) -> None: + sys.stderr.write(f"{message}\n") + + +def _collect_targets(args: argparse.Namespace, repo_root: Path) -> list[Path]: + if args.file or args.dir: + targets: list[Path] = [] + for file_path in args.file or []: + targets.append(file_path if file_path.is_absolute() else repo_root / file_path) + for directory in args.dir or []: + abs_dir = directory if directory.is_absolute() else repo_root / directory + if abs_dir.is_dir(): + targets.extend(sorted(abs_dir.glob("*.svg"))) + # Preserve order for files while deduplicating. + unique: list[Path] = [] + seen: set[str] = set() + for path in targets: + key = str(path.resolve()) if path.exists() else str(path) + if key not in seen: + unique.append(path) + seen.add(key) + return unique + + manifest = args.manifest if args.manifest.is_absolute() else repo_root / args.manifest + rel_paths = load_manifest(manifest) + return [repo_root / rel for rel in rel_paths] + + +def main() -> int: + args = parse_args() + repo_root = Path.cwd() + try: + targets = _collect_targets(args, repo_root) + except (FileNotFoundError, ValueError) as exc: + _err(f"[ERROR] {exc}") + return 2 + + if not targets: + _err("[ERROR] No SVG files to check.") + return 2 + + metrics_out: list[SvgMetrics] = [] + failures: list[tuple[str, list[str]]] = [] + + for path in targets: + rel = str(path.relative_to(repo_root)) if path.is_absolute() and str(path).startswith(str(repo_root)) else str(path) + if not path.exists(): + failures.append((rel, ["file not found"])) + continue + try: + metrics, issues = analyze_svg(path) + except ET.ParseError as exc: + failures.append((rel, [f"xml parse error: {exc}"])) + continue + metrics_out.append(metrics) + if issues: + failures.append((rel, issues)) + + if args.json: + payload = { + "ok": not failures, + "checked": len(targets), + "metrics": [asdict(m) for m in metrics_out], + "failures": [{"file": f, "issues": i} for f, i in failures], + } + _out(json.dumps(payload, ensure_ascii=True, indent=2)) + else: + _out(f"[INFO] Checked {len(targets)} SVG file(s).") + for m in metrics_out: + _out( + "[INFO] " + f"{Path(m.file).name}: edgeLabels={m.edge_label_groups}, " + f"withText={m.edge_label_groups_with_text}, " + f"foreignObject={m.foreign_objects}, " + f"foFallback={m.fallback_text_nodes}" + ) + + if failures: + _err("[ERROR] SVG text visibility check failed:") + for file_path, issues in failures: + _err(f" - {file_path}") + for issue in issues: + _err(f" * {issue}") + return 1 + + if not args.json: + _out("[OK] SVG text visibility check passed.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/diagrams/fix_diagram_links.py b/scripts/diagrams/fix_diagram_links.py new file mode 100644 index 0000000000..ec63e15600 --- /dev/null +++ b/scripts/diagrams/fix_diagram_links.py @@ -0,0 +1,50 @@ + +import re +import os +from pathlib import Path + +DOCS_DIR = Path("docs") + +def fix_links(): + md_files = list(DOCS_DIR.rglob("*.md")) + fixed_count = 0 + + for md_file in md_files: + content = md_file.read_text(encoding="utf-8") + original_content = content + + # 1. Remove 'mermaid/' from diagram paths + # [Text](diagrams/mermaid/file.mermaid) -> [Text](diagrams/file.mermaid) + content = content.replace("diagrams/mermaid/", "diagrams/") + + # 2. Fix .mmd extension to .mermaid + content = content.replace(".mmd", ".mermaid") + + # 3. Fix common diagram names that use underscores but should use dashes + # This is tricky, I'll only do it for known diagrams if they are still failing. + # Let's try to find all links to .mermaid files and normalize them. + + def mermaid_link_fix(match): + link_text = match.group(1) + path = match.group(2) + # Normalize path: underscores to dashes in the filename part + parts = path.split("/") + filename = parts[-1] + if ".mermaid" in filename: + filename = filename.replace("_", "-") + elif "v1.0.json" in filename: + filename = filename.replace("-", "_") + new_path = "/".join(parts[:-1] + [filename]) + return f"[{link_text}]({new_path})" + + content = re.sub(r"\[([^\]]*)\]\(([^)]+(?:\.mermaid|v1\.0\.json))\)", mermaid_link_fix, content) + + if content != original_content: + md_file.write_text(content, encoding="utf-8") + fixed_count += 1 + print(f"Fixed: {md_file}") + + print(f"Total files fixed: {fixed_count}") + +if __name__ == "__main__": + fix_links() diff --git a/scripts/diagrams/fix_sequence_nbsp.py b/scripts/diagrams/fix_sequence_nbsp.py new file mode 100644 index 0000000000..6680d972cb --- /dev/null +++ b/scripts/diagrams/fix_sequence_nbsp.py @@ -0,0 +1,44 @@ +"""Fix   in sequence diagram participant/actor lines.""" +import re +import glob + + +def fix_file(filepath: str) -> bool: + with open(filepath, "r", encoding="utf-8") as fh: + content = fh.read() + + if "sequenceDiagram" not in content: + return False + + lines = content.split("\n") + changed = False + new_lines = [] + + for line in lines: + stripped = line.lstrip() + if (stripped.startswith("participant ") or stripped.startswith("actor ")) and " " in line: + new_line = line.replace(" ", "").rstrip() + # Clean up redundant 'as SameName' (e.g., 'participant CLI as CLI' -> 'participant CLI') + m = re.match(r"^(\s*(?:participant|actor)\s+)(\w+)\s+as\s+\2\s*$", new_line) + if m: + new_line = m.group(1) + m.group(2) + new_lines.append(new_line) + if new_line != line: + changed = True + else: + new_lines.append(line) + + if changed: + with open(filepath, "w", encoding="utf-8", newline="\n") as fh: + fh.write("\n".join(new_lines)) + return changed + + +fixed = [] +for f in glob.glob("docs/02-architecture/mmd-diagrams/**/*.mmd", recursive=True): + if fix_file(f): + fixed.append(f) + +print(f"Fixed {len(fixed)} files:") +for f in sorted(fixed): + print(f" {f}") diff --git a/scripts/diagrams/inject_svg_styles.py b/scripts/diagrams/inject_svg_styles.py new file mode 100644 index 0000000000..39a8462012 --- /dev/null +++ b/scripts/diagrams/inject_svg_styles.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +""" +inject_svg_styles.py — Inject CSS overrides into rendered Mermaid SVG files. + +Mermaid generates ID-scoped CSS rules that make edge labels semi-transparent: + #my-svg .edgeLabel rect { opacity: .5 } + #my-svg .labelBkg { background-color: rgba(255,255,255,.5) } + +The custom.css !important overrides are stripped by mmdc during SVG extraction. +This post-processor re-injects those rules into the SVG |)") + + +# ── CSS rules to inject ──────────────────────────────────────────────────── + +def _build_css_rules(svg_id: str) -> str: + """Build ID-scoped CSS override rules for edge label readability.""" + return ( + f"{SENTINEL}" + f"#{svg_id} .edgeLabel rect{{opacity:1!important;fill:#ffffff!important}}" + f"#{svg_id} .labelBkg{{background-color:#ffffff!important;opacity:1!important}}" + f"#{svg_id} .edgeLabel .labelBkg{{background-color:#ffffff!important;opacity:1!important}}" + f"#{svg_id} .edgeLabel{{font-size:12px;line-height:1.1;padding:1px 3px}}" + f"#{svg_id} .edgeLabel span{{color:#111827!important;fill:#111827!important;opacity:1!important;line-height:1.1;margin:0;padding:0}}" + f"#{svg_id} .edgeLabel p{{color:#111827!important;fill:#111827!important;opacity:1!important;line-height:1.1;margin:0;padding:0}}" + f"#{svg_id} text.fo-fallback{{color:#111827!important;fill:#111827!important;opacity:1!important}}" + ) + + +# ── Core logic ────────────────────────────────────────────────────────────── + +def needs_injection(content: str) -> bool: + """Check if SVG content already has injected styles.""" + return SENTINEL not in content + + +def inject_styles(content: str) -> str | None: + """Inject CSS overrides into SVG |)") - - -# ── CSS rules to inject ──────────────────────────────────────────────────── - -def _build_css_rules(svg_id: str) -> str: - """Build ID-scoped CSS override rules for edge label readability.""" - return ( - f"{SENTINEL}" - f"#{svg_id} .edgeLabel rect{{opacity:1!important;fill:#ffffff!important}}" - f"#{svg_id} .labelBkg{{background-color:#ffffff!important;opacity:1!important}}" - f"#{svg_id} .edgeLabel .labelBkg{{background-color:#ffffff!important;opacity:1!important}}" - f"#{svg_id} .edgeLabel{{font-size:12px;line-height:1.1;padding:1px 3px}}" - f"#{svg_id} .edgeLabel span{{color:#111827!important;fill:#111827!important;opacity:1!important;line-height:1.1;margin:0;padding:0}}" - f"#{svg_id} .edgeLabel p{{color:#111827!important;fill:#111827!important;opacity:1!important;line-height:1.1;margin:0;padding:0}}" - f"#{svg_id} text.fo-fallback{{color:#111827!important;fill:#111827!important;opacity:1!important}}" - ) - - -# ── Core logic ────────────────────────────────────────────────────────────── - -def needs_injection(content: str) -> bool: - """Check if SVG content already has injected styles.""" - return SENTINEL not in content - - -def inject_styles(content: str) -> str | None: - """Inject CSS overrides into SVG