From 900e0986e66bbb1dd51bc599822ebd95c7a1ad8b Mon Sep 17 00:00:00 2001 From: Root At Skic Date: Sun, 8 Nov 2026 23:11:46 +0200 Subject: [PATCH] arc42 and ArchiMate layouts in the folder guide; arc42 examples cover all sections; 1.3 references/folders.md gains arc42 (sections as numbered folders and cards, black boxes, quality tree) and ArchiMate (layers, type in tag and sublabel, element mapping). Gotchas: ref in every kind needs extension 0.11.0; tags are not drawn on the box. --- SKILL.md | 7 +- .../0300-context/technical-context.archify | 9 +++ .../0500-building-blocks/level-1.archify | 4 +- .../0700-deployment/production.archify | 18 ++++- .../1000-quality/quality-tree.archify | 75 ++++++++++++++++++ examples/arc42-cinema-tickets/main.archify | 49 ++++++++---- .../registry/building-blocks.archify-registry | 35 ++++++--- .../0300-context/technical-context.archify | 10 +++ .../0500-building-blocks/level-1.archify | 3 + .../0700-deployment/production.archify | 23 ++++++ .../1000-quality/quality-tree.archify | 75 ++++++++++++++++++ examples/arc42-iot-telemetry/main.archify | 49 ++++++++---- .../registry/building-blocks.archify-registry | 32 +++++--- .../0300-context/technical-context.archify | 8 ++ .../0500-building-blocks/level-1.archify | 9 ++- .../0700-deployment/production.archify | 16 +++- .../1000-quality/quality-tree.archify | 77 +++++++++++++++++++ examples/arc42-team-wiki/main.archify | 65 ++++++++++------ .../registry/building-blocks.archify-registry | 20 +++-- references/folders.md | 59 ++++++++++++++ 20 files changed, 554 insertions(+), 89 deletions(-) create mode 100644 examples/arc42-cinema-tickets/1000-quality/quality-tree.archify create mode 100644 examples/arc42-iot-telemetry/1000-quality/quality-tree.archify create mode 100644 examples/arc42-team-wiki/1000-quality/quality-tree.archify diff --git a/SKILL.md b/SKILL.md index 3953349..c382843 100644 --- a/SKILL.md +++ b/SKILL.md @@ -15,7 +15,7 @@ license: MIT compatibility: Requires Node.js 18+, bash and go-task (task). No network access; Archify is bundled under scripts/vendor. metadata: author: root-at-skic - version: "1.2" + version: "1.3" origin-repository: https://gitea.lego-cloud.eu/vscode-extensions-skills/archify-vscode-ext.git targets: Archify Diagram Viewer (root-at-skic.archify-vscode-ext) --- @@ -175,7 +175,8 @@ Diagrams next to `main.archify` are listed first, ungrouped; deeper ones by fold - **Boxes need clear gaps.** Components closer than 8px fail; labels wider than the box fail (`6.5px` per character plus 13). The grid in `references/authoring.md` keeps a standard layout clear. - **Links are relative to the model root**, never to the file, and must end in `.archify` and exist. `..` is refused. - **A second `main.archify` deeper down** is reported, not nested. One model per tree. -- **Diagram kinds other than architecture** take `ref` too (workflow and dataflow `nodes`, sequence `participants`, lifecycle `states`), but the registry `type` must fit that kind: lifecycle states use their own type enum, and sequence participants have no `tag`. +- **Diagram kinds other than architecture** take `ref` too (workflow and dataflow `nodes`, sequence `participants`, lifecycle `states`), but the registry `type` must fit that kind: lifecycle states use their own type enum, and sequence participants have no `tag`. The extension resolves these since 0.11.0; older versions showed such a diagram with schema errors. +- **Tags are not drawn on the box.** Archify shows `tag` only in the focus panel and search. When a type must be visible (an ArchiMate element type, a C4 level), put it in `sublabel` too. - **Decisions are files, ids are words.** One `*.archify-decision` per decision (`decision:` block with id, title, status, date, elements, diagrams, supersedes; prose in context, decision, consequences). Diagrams point at them with `decisions: []` on the diagram, a node or an edge; the resolver strips the key. An unquoted numeric id (`0001`) is refused because YAML reads it as 1. When an agent changes the shape of a model (a new store, a new queue, a new boundary), it writes a decision and links the elements it touched. - **The graph answers structure questions.** Before guessing from file contents, run `task model:graph` with a query: `uses:` for neighbours, `from: to:` for the route, `decision:` for what a decision touches, `unused` for registry elements no diagram draws. Walks follow the diagrams' connections only; decision and registry nodes follow the elements they link to. The extension's Graph page (the **Model | Graph | Source** switch on `main.archify`) shows the same graph with the same queries. - **The extension checks keys the skill does not.** Since extension 0.9.2 every Archify page has a **Source** view (Diagram | Graph | Source, View | Source on registries and decisions) that checks the YAML against the bundled JSON schemas without a YAML extension: an unknown key in a registry element (`lable:`) or a diagram is an error there. `task model:validate` does not check registry keys yet and passes such a file, so read registry edits back for typos. When a user says "the Source view shows an error", the message names the key and path (`Unknown key "lable" in elements.api.`). @@ -186,5 +187,5 @@ Diagrams next to `main.archify` are listed first, ungrouped; deeper ones by fold - Read `references/authoring.md` when writing or repairing a diagram: kinds, fields, grid, labels, boundaries, brands, validator codes and fixes. - Read `references/formats.md` when writing `main.archify`, a registry, a `ref` or a link, or when unsure what the tasks strip before Archify runs. -- Read `references/folders.md` when laying out a model folder or explaining how the extension finds the root and groups diagrams. +- Read `references/folders.md` when laying out a model folder or explaining how the extension finds the root and groups diagrams; it has the C4, arc42 and ArchiMate layouts. - `examples/` holds nine complete models that validate with 0 problems; copy their shape, or copy one with `model:scaffold --example`. Three C4 (`c4-*`: context, containers, components). Three arc42 (`arc42-*`: the overview is section 3 business context with goals, constraints, quality, risks and glossary as `cards`; `0300-context`, `0500-building-blocks`, `0600-runtime` sequence diagrams, `0700-deployment`; decisions are section 9). Three ArchiMate (`archimate-*`: the overview is a layered view in three region boundaries; `0100-business`, `0200-application`, `0300-technology`; one registry file per layer; each element's ArchiMate type as its `tag` and `sublabel`, since Archify shows tags only in the focus panel). diff --git a/examples/arc42-cinema-tickets/0300-context/technical-context.archify b/examples/arc42-cinema-tickets/0300-context/technical-context.archify index 8a4f92e..f95b7dc 100644 --- a/examples/arc42-cinema-tickets/0300-context/technical-context.archify +++ b/examples/arc42-cinema-tickets/0300-context/technical-context.archify @@ -28,3 +28,12 @@ connections: - { from: tickets, to: psp, label: REST webhook, variant: security } - { from: tickets, to: mail, label: SMTP TLS } - { from: tickets, to: pos, label: REST VPN } +cards: + - dot: cyan + title: 3 Domain interfaces + items: + - "Moviegoer: in shows, seats, payment start; out seat map, QR tickets" + - "Usher: in scanned QR codes; out valid or invalid, seat" + - "Payment provider: out checkout session; in paid or failed webhook" + - "E-mail service: out ticket e-mails with QR and receipt" + - "Box-office POS: in counter sales; out seat availability" diff --git a/examples/arc42-cinema-tickets/0500-building-blocks/level-1.archify b/examples/arc42-cinema-tickets/0500-building-blocks/level-1.archify index 03b2a5e..d4f15b8 100644 --- a/examples/arc42-cinema-tickets/0500-building-blocks/level-1.archify +++ b/examples/arc42-cinema-tickets/0500-building-blocks/level-1.archify @@ -58,7 +58,9 @@ cards: - dot: amber title: 8 Crosscutting concepts items: + - "Persistence: PostgreSQL is the truth; Redis only for holds" + - "Security: OIDC for staff apps; card data never stored" + - "Errors: idempotency keys; failed webhooks are retried" - "Times in UTC; shown in cinema local time" - - "Every write carries an idempotency key" - "QR payload signed with an Ed25519 key" - "Structured logs with order id as trace key" diff --git a/examples/arc42-cinema-tickets/0700-deployment/production.archify b/examples/arc42-cinema-tickets/0700-deployment/production.archify index 878745d..23788d4 100644 --- a/examples/arc42-cinema-tickets/0700-deployment/production.archify +++ b/examples/arc42-cinema-tickets/0700-deployment/production.archify @@ -5,7 +5,10 @@ meta: output: production.html components: - ref: customer - pos: [40, 160] + pos: [40, 260] + size: [130, 60] + - ref: mobile + pos: [40, 60] size: [130, 60] - id: ingress type: security @@ -44,6 +47,9 @@ boundaries: - kind: security-group label: Managed data zone wraps: [seatlock, db] + - kind: region + label: Customer phones + wraps: [mobile] - kind: region label: Cinema site wraps: [pos, scanner] @@ -56,3 +62,13 @@ connections: - { from: ticketing, to: db, label: TLS } - { from: possync, to: pos, label: VPN, variant: security } - { from: scanner, to: ingress, label: HTTPS } + - { from: mobile, to: ingress, label: HTTPS } +cards: + - dot: slate + title: 7 Mapping + items: + - "Web Shop, Booking API, Ticket Service, POS Sync -> EU k8s cluster" + - "Seat Locks -> managed Redis; Tickets DB -> managed PostgreSQL" + - "Mobile App -> customer phones" + - "Scanner App -> door phones at the cinema site" + - "Box-office POS -> cinema site, VPN to POS Sync" diff --git a/examples/arc42-cinema-tickets/1000-quality/quality-tree.archify b/examples/arc42-cinema-tickets/1000-quality/quality-tree.archify new file mode 100644 index 0000000..1250a7b --- /dev/null +++ b/examples/arc42-cinema-tickets/1000-quality/quality-tree.archify @@ -0,0 +1,75 @@ +schema_version: 1 +diagram_type: architecture +meta: + title: Quality tree + output: quality-tree.html +components: + - id: quality + type: cloud + label: Quality + pos: [40, 260] + size: [130, 60] + - id: reliability + type: backend + label: Reliability + pos: [250, 60] + size: [130, 60] + - id: performance + type: backend + label: Performance + pos: [250, 210] + size: [130, 60] + - id: availability + type: backend + label: Availability + pos: [250, 360] + size: [130, 60] + - id: security + type: security + label: Security + pos: [250, 460] + size: [130, 60] + - id: s-nodouble + type: external + label: No double sale + pos: [460, 10] + size: [150, 60] + - id: s-payfail + type: external + label: Failed pay frees seats + pos: [460, 110] + size: [170, 60] + - id: s-peak + type: external + label: Checkout < 2 s at peak + pos: [460, 210] + size: [170, 60] + - id: s-offline + type: external + label: Offline door scans + pos: [460, 360] + size: [170, 60] + - id: s-forged + type: external + label: Forged QR rejected + pos: [460, 460] + size: [170, 60] +connections: + - { from: quality, to: reliability } + - { from: quality, to: performance } + - { from: quality, to: availability } + - { from: quality, to: security } + - { from: reliability, to: s-nodouble } + - { from: reliability, to: s-payfail } + - { from: performance, to: s-peak } + - { from: availability, to: s-offline } + - { from: security, to: s-forged } +cards: + - dot: emerald + title: 10 Quality scenarios + items: + - "500 holds on one show in 1 min: no seat sold twice" + - "Payment fails or is abandoned: seats free again within 8 min" + - "Friday 19:00 peak, 300 checkouts/min: p95 under 2 s" + - "Wi-Fi down at the door: scans go on, check-ins sync later" + - "Edited or forged QR code scanned: rejected at once" diff --git a/examples/arc42-cinema-tickets/main.archify b/examples/arc42-cinema-tickets/main.archify index 7a6a2ab..0914b96 100644 --- a/examples/arc42-cinema-tickets/main.archify +++ b/examples/arc42-cinema-tickets/main.archify @@ -3,13 +3,14 @@ model: id: cinema-tickets name: Cinema Tickets description: > - An arc42 example: online and mobile seat booking for a small - cinema chain. This overview is section 3 (business context) with - cards for sections 1, 2, 10, 11 and 12. 0300-context holds the - technical context (3), 0500-building-blocks the building block - view (5), 0600-runtime the runtime view (6), 0700-deployment the - deployment view (7), decisions/ the architecture decisions (9). - Crosscutting concepts (8) are a card on the level-1 diagram. + An arc42 example: seat booking for the fictional Lantern Cinemas. + 1 Requirements, quality goals, stakeholders; 2 Constraints; + 4 Solution strategy; 11 Risks; 12 Glossary: cards on this overview. + 3 Context: this overview (business) and 0300-context (technical). + 5 Building blocks: 0500-building-blocks, black boxes in registry/. + 6 Runtime: 0600-runtime. 7 Deployment: 0700-deployment. + 8 Crosscutting concepts: card on 0500-building-blocks/level-1. + 9 Decisions: decisions/. 10 Quality: 1000-quality. diagram_type: architecture meta: title: Cinema Tickets - business context @@ -40,12 +41,26 @@ connections: - { from: tickets, to: mail, label: tickets } - { from: tickets, to: pos, label: seat sales } cards: + - dot: orange + title: 1.1 Requirements + items: + - "Browse shows and pick seats on a seat map" + - "Hold seats, pay online, get QR tickets by e-mail" + - "Ushers check tickets in at the door" + - "Box-office POS sells from the same seats" - dot: cyan - title: 1 Quality goals + title: 1.2 Quality goals items: - "No seat is ever sold twice" - "Checkout under 2 s at Friday peak" - "Door check-in works offline" + - dot: amber + title: 1.3 Stakeholders + items: + - "Moviegoer: quick booking, tickets on the phone" + - "Usher: fast scans even without Wi-Fi" + - "Box-office staff: one seat map with online sales" + - "Lantern Cinemas management: fewer refunds, low cost" - dot: slate title: 2 Constraints items: @@ -53,16 +68,20 @@ cards: - "Card data only at the provider" - "Team of four; hosted in the EU" - dot: emerald - title: 10 Quality scenarios + title: 4 Solution strategy items: - - "500 holds on one show in 1 min: no double sale" - - "Wi-Fi down at the door: scans go on, sync later" - - "Payment fails: seats free again within 8 min" + - "Node.js, PostgreSQL, Redis on managed EU k8s: fits a team of four" + - "Three services by job: booking, tickets, POS sync" + - "No double sale: Booking API sole seat owner (booking-owns-seat-inventory)" + - "Checkout speed: Redis holds with TTL (seat-holds-with-ttl)" + - "Offline check-in: signed QR codes (signed-qr-codes)" - dot: rose - title: 11 Risks + title: 11 Risks and technical debt items: - - "POS vendor API is slow and undocumented" - - "Forwarded QR e-mails: first scan wins" + - "Risk: POS vendor API is slow and undocumented" + - "Risk: forwarded QR e-mails, first scan wins" + - "Debt: POS Sync adapter has no automated tests" + - "Debt: QR key rotation needs an app release" - dot: violet title: 12 Glossary items: diff --git a/examples/arc42-cinema-tickets/registry/building-blocks.archify-registry b/examples/arc42-cinema-tickets/registry/building-blocks.archify-registry index f35e243..2f659c0 100644 --- a/examples/arc42-cinema-tickets/registry/building-blocks.archify-registry +++ b/examples/arc42-cinema-tickets/registry/building-blocks.archify-registry @@ -6,52 +6,67 @@ elements: sublabel: React brand: react description: > - Programme, seat map and checkout in the browser. + Responsibility: programme, seat map and checkout in the browser. + Interfaces: provides the web UI; requires Booking API (JSON) + and the provider's hosted checkout page. mobile: type: frontend label: Mobile App sublabel: iOS and Android description: > - The same booking flow as the web shop, plus a ticket wallet. + Responsibility: the web shop's booking flow plus a ticket wallet. + Interfaces: provides the iOS/Android UI; requires Booking API + (JSON). scanner: type: frontend label: Scanner App sublabel: door phones description: > - Reads QR codes at the door; checks signatures offline. + Responsibility: reads QR codes at the door, checks signatures + offline. Interfaces: provides the usher UI; requires Ticket + Service (POST /checkins), queued while offline. booking: type: backend label: Booking API sublabel: Node.js brand: node-js description: > - Shows, seat maps, seat holds and orders; the only writer of - the seat inventory. + Responsibility: shows, seat maps, holds and orders; the only + writer of the seat inventory. Interfaces: provides REST JSON to + the apps and the payment webhook; requires Seat Locks, Tickets + DB, payment provider, Ticket Service. diagram: 0500-building-blocks/booking.archify ticketing: type: backend label: Ticket Service sublabel: QR, check-in description: > - Issues signed QR tickets, sends them by e-mail and records - check-ins at the door. + Responsibility: issues signed QR tickets, mails them and records + check-ins. Interfaces: provides issue and POST /checkins; + requires Tickets DB and the e-mail service (SMTP). possync: type: backend label: POS Sync sublabel: adapter description: > - Exchanges seat sales with the box-office POS in both directions. + Responsibility: exchanges seat sales with the box-office POS. + Interfaces: provides a REST adapter to the POS over VPN; + requires Tickets DB (SQL). seatlock: type: database label: Seat Locks sublabel: Redis brand: redis description: > - Short-lived seat holds with a TTL while the customer pays. + Responsibility: short-lived seat holds with a TTL while the + customer pays. Interfaces: provides Redis SET NX/GET/DEL to the + Booking API; requires nothing. db: type: database label: Tickets DB sublabel: PostgreSQL brand: postgresql description: > - Shows, seats, orders and tickets; the source of truth. + Responsibility: shows, seats, orders and tickets; the source of + truth. Interfaces: provides SQL to Booking API, Ticket Service + and POS Sync; requires nothing. diff --git a/examples/arc42-iot-telemetry/0300-context/technical-context.archify b/examples/arc42-iot-telemetry/0300-context/technical-context.archify index 7437a09..9fa4421 100644 --- a/examples/arc42-iot-telemetry/0300-context/technical-context.archify +++ b/examples/arc42-iot-telemetry/0300-context/technical-context.archify @@ -33,3 +33,13 @@ connections: - { from: heat-pump, to: telemetry-platform, label: MQTT 8883, variant: emphasis, decisions: [mqtt-with-mutual-tls] } - { from: telemetry-platform, to: push-service, label: HTTP/2 } - { from: telemetry-platform, to: service-desk, label: webhook } +cards: + - dot: cyan + title: 3 Domain interfaces + items: + - "Heat pump: in telemetry and fault codes; out none" + - "Homeowner: in app requests; out status, history, alerts" + - "Ops engineer: in queries; out fleet dashboards" + - "Installer: in device serial; out device certificate" + - "Push service: out alert notifications" + - "Service desk: out tickets for faults needing a visit" diff --git a/examples/arc42-iot-telemetry/0500-building-blocks/level-1.archify b/examples/arc42-iot-telemetry/0500-building-blocks/level-1.archify index 84490cf..fcff0f5 100644 --- a/examples/arc42-iot-telemetry/0500-building-blocks/level-1.archify +++ b/examples/arc42-iot-telemetry/0500-building-blocks/level-1.archify @@ -73,5 +73,8 @@ cards: title: 8 Crosscutting concepts items: - Device identity, one X.509 certificate per device + - Security, OIDC login for people, mTLS for devices + - Persistence, PostgreSQL dialect for all stores - Idempotent writes, keyed by device id and timestamp + - Error handling, invalid readings to dead letters - Observability, metrics and traces on every service diff --git a/examples/arc42-iot-telemetry/0700-deployment/production.archify b/examples/arc42-iot-telemetry/0700-deployment/production.archify index c74de51..cef9e32 100644 --- a/examples/arc42-iot-telemetry/0700-deployment/production.archify +++ b/examples/arc42-iot-telemetry/0700-deployment/production.archify @@ -29,6 +29,12 @@ components: - ref: device-registry pos: [760, 260] size: [130, 60] + - ref: ops-dashboard + pos: [1030, 160] + size: [130, 60] + - ref: customer-app + pos: [490, 440] + size: [130, 60] boundaries: - kind: region label: Kubernetes cluster, eu-central @@ -36,9 +42,26 @@ boundaries: - kind: security-group label: Managed DB zone wraps: [tsdb, device-registry] + - kind: region + label: Ops network, managed Grafana + wraps: [ops-dashboard] + - kind: region + label: Homeowner phones + wraps: [customer-app] connections: - { from: heat-pump, to: mqtt-broker, label: "8883", variant: emphasis } - { from: mqtt-broker, to: ingest, label: in-cluster } - { from: ingest, to: tsdb, label: "5432", variant: emphasis } - { from: ingest, to: rules, label: gRPC } - { from: device-api, to: device-registry, label: "5432" } + - { from: tsdb, to: ops-dashboard, label: read-only } + - { from: customer-app, to: device-api, label: HTTPS } +cards: + - dot: slate + title: 7 Mapping + items: + - "mqtt-broker, ingest, rules -> Kubernetes cluster, eu-central" + - "provisioning, device-api -> Kubernetes cluster, eu-central" + - "tsdb, device-registry -> managed DB zone, eu-central" + - "ops-dashboard -> ops network, managed Grafana" + - "customer-app -> homeowner phones, app stores" diff --git a/examples/arc42-iot-telemetry/1000-quality/quality-tree.archify b/examples/arc42-iot-telemetry/1000-quality/quality-tree.archify new file mode 100644 index 0000000..65da488 --- /dev/null +++ b/examples/arc42-iot-telemetry/1000-quality/quality-tree.archify @@ -0,0 +1,75 @@ +schema_version: 1 +diagram_type: architecture +meta: + title: Quality tree + output: quality-tree.html +components: + - id: quality + type: cloud + label: Quality + pos: [40, 240] + size: [130, 100] + - id: reliability + type: backend + label: Reliability + pos: [250, 60] + size: [130, 60] + - id: performance + type: backend + label: Performance + pos: [250, 210] + size: [130, 60] + - id: security + type: security + label: Security + pos: [250, 360] + size: [130, 60] + - id: operability + type: backend + label: Operability + pos: [250, 460] + size: [130, 60] + - id: q-no-loss + type: frontend + label: Broker restart, no loss + pos: [460, 60] + size: [180, 60] + - id: q-alert-60s + type: frontend + label: Fault alert in 60 s + pos: [460, 160] + size: [180, 60] + - id: q-peak-load + type: frontend + label: 4,000 readings/s + pos: [460, 260] + size: [180, 60] + - id: q-revoke + type: frontend + label: Revoke cert in 15 min + pos: [460, 360] + size: [180, 60] + - id: q-new-device + type: frontend + label: New device in 10 min + pos: [460, 460] + size: [180, 60] +connections: + - { from: quality, to: reliability } + - { from: quality, to: performance } + - { from: quality, to: security } + - { from: quality, to: operability } + - { from: reliability, to: q-no-loss } + - { from: performance, to: q-alert-60s } + - { from: performance, to: q-peak-load } + - { from: security, to: q-revoke } + - { from: operability, to: q-new-device } +cards: + - dot: emerald + title: 10 Quality scenarios + items: + - "Broker restarts under load: devices reconnect, no accepted reading lost" + - "Heat pump sends a fault code: homeowner gets a push within 60 s" + - "Fleet peaks at 4,000 readings/s: p95 ingest lag stays under 5 s" + - "A device certificate is stolen: ops revoke it, broker refuses it within 15 min" + - "Installer registers a new heat pump: data visible in the app within 10 min" diff --git a/examples/arc42-iot-telemetry/main.archify b/examples/arc42-iot-telemetry/main.archify index c0533f7..8b642fc 100644 --- a/examples/arc42-iot-telemetry/main.archify +++ b/examples/arc42-iot-telemetry/main.archify @@ -5,11 +5,14 @@ model: description: > An arc42 example: a fictional heat pump maker collects device telemetry over MQTT, stores it, raises alerts and shows it to operations and customers. - main.archify holds section 3 business context with cards for sections - 1 goals, 2 constraints, 10 quality, 11 risks and 12 glossary; - 0300-context the technical context; 0500-building-blocks section 5; - 0600-runtime section 6; 0700-deployment section 7; decisions/ section 9; - the crosscutting concepts of section 8 are a card on level-1. + Where the 12 arc42 sections live: + 1 introduction and goals, 2 constraints, 4 solution strategy, + 11 risks and 12 glossary are cards on this overview; + 3 business context is this overview, technical context in 0300-context; + 5 building blocks in 0500-building-blocks (black boxes in the registry); + 6 runtime in 0600-runtime; 7 deployment in 0700-deployment; + 8 crosscutting concepts a card on 0500-building-blocks/level-1; + 9 decisions in decisions/; 10 quality tree in 1000-quality. diagram_type: architecture meta: title: Business context @@ -44,29 +47,47 @@ connections: - { from: telemetry-platform, to: push-service, label: alerts } - { from: telemetry-platform, to: service-desk, label: tickets } cards: + - dot: orange + title: 1.1 Requirements + items: + - Collect telemetry from every heat pump every 30 s + - Alert homeowner and ops on fault codes + - Show live and historic data in app and dashboard + - Register and provision new devices on site - dot: cyan - title: 1 Quality goals + title: 1.2 Quality goals items: - Reliability, no telemetry lost once accepted - Timeliness, alert within 60 s of a fault - Security, every device authenticated + - dot: emerald + title: 1.3 Stakeholders + items: + - "Homeowner: sees status, gets alerts quickly" + - "Ops engineer: fleet view, few false alarms" + - "Installer: register a device in minutes" + - "Firmware partner: stable MQTT contract" - dot: slate title: 2 Constraints items: - Devices speak MQTT only; firmware by a partner - Data stays in one EU region - Team of six; PostgreSQL skills in house - - dot: emerald - title: 10 Quality scenarios + - dot: amber + title: 4 Solution strategy items: - - A fault code reaches the homeowner within 60 s - - Broker restart, devices reconnect, no data lost - - A stolen certificate is revoked within 15 min + - MQTT with mutual TLS for devices (security, ADR 0001) + - TimescaleDB for telemetry, SQL everywhere (ADR 0002) + - Ingest acks only after commit (reliability) + - Rules engine on the ingest stream (timeliness) + - Split by flow, ingest vs read vs provisioning - dot: rose - title: 11 Risks + title: 11 Risks and technical debt items: - - R1 fleet growth beyond one TSDB node - - R2 partner firmware delays certificate rotation + - "Risk: fleet growth beyond one TSDB node" + - "Risk: partner firmware delays cert rotation" + - "Debt: payload v1 decoder kept for old firmware" + - "Debt: rules configured in code, no UI" - dot: violet title: 12 Glossary items: diff --git a/examples/arc42-iot-telemetry/registry/building-blocks.archify-registry b/examples/arc42-iot-telemetry/registry/building-blocks.archify-registry index 55631d1..eecf44a 100644 --- a/examples/arc42-iot-telemetry/registry/building-blocks.archify-registry +++ b/examples/arc42-iot-telemetry/registry/building-blocks.archify-registry @@ -5,14 +5,18 @@ elements: label: MQTT broker sublabel: mutual TLS description: > - Terminates device connections; one topic per device. + Responsibility: terminates device connections, one topic per device. + Interfaces: provides MQTT 8883 with mTLS; requires certs and + revocation checks from Provisioning. ingest: type: backend label: Ingest sublabel: Go brand: go description: > - Decodes, validates and stores telemetry; forwards it to the rules. + Responsibility: decodes, validates and stores telemetry. + Interfaces: requires MQTT subscription, TSDB, device registry; + provides the reading stream to the rules engine. diagram: 0500-building-blocks/ingest.archify tsdb: type: database @@ -20,42 +24,52 @@ elements: sublabel: TimescaleDB brand: postgresql description: > - Raw telemetry for 90 days and hourly rollups for 10 years. + Responsibility: raw telemetry 90 days, hourly rollups 10 years. + Interfaces: provides SQL on 5432 to Device API and dashboard; + requires batched writes from Ingest. rules: type: backend label: Rules engine sublabel: alerting description: > - Evaluates thresholds and fault codes; raises alerts. + Responsibility: evaluates thresholds and fault codes, raises alerts. + Interfaces: requires the reading stream from Ingest; + provides alerts to the push service and service desk. provisioning: type: security label: Provisioning sublabel: device certs description: > - Registers devices and issues their client certificates. + Responsibility: registers devices and issues client certificates. + Interfaces: provides a REST register call for installers and + revocation checks for the broker; requires the device registry. device-registry: type: database label: Device registry sublabel: PostgreSQL brand: postgresql description: > - Devices, owners, firmware versions and certificate state. + Responsibility: devices, owners, firmware and certificate state. + Interfaces: provides SQL on 5432 to Ingest, Provisioning, Device API. device-api: type: backend label: Device API sublabel: REST description: > - Serves telemetry and device data to the customer app. + Responsibility: serves telemetry and device data to the customer app. + Interfaces: provides REST over HTTPS; requires TSDB and device registry. ops-dashboard: type: frontend label: Ops dashboard sublabel: Grafana brand: grafana description: > - Fleet view for the operations team, read only on the TSDB. + Responsibility: fleet view for the operations team. + Interfaces: provides web UI over HTTPS; requires read-only SQL on TSDB. customer-app: type: frontend label: Customer app sublabel: mobile description: > - Shows the homeowner their heat pump and its alerts. + Responsibility: shows the homeowner their heat pump and alerts. + Interfaces: provides the mobile UI; requires Device API and push. diff --git a/examples/arc42-team-wiki/0300-context/technical-context.archify b/examples/arc42-team-wiki/0300-context/technical-context.archify index 2d0f65b..d507575 100644 --- a/examples/arc42-team-wiki/0300-context/technical-context.archify +++ b/examples/arc42-team-wiki/0300-context/technical-context.archify @@ -24,3 +24,11 @@ connections: - { from: wiki-admin, to: wiki, label: kubectl } - { from: wiki, to: idp, label: OIDC, variant: security } - { from: wiki, to: object-store, label: S3 API } +cards: + - dot: cyan + title: 3 Domain interfaces + items: + - "Engineer: in edits, queries, files; out pages, results" + - "Wiki admin: in deploys, restore commands; out status, logs" + - "Identity provider: out sign-in code, groups; in token requests" + - "Object storage: out attachments, backups; in signed URL reads" diff --git a/examples/arc42-team-wiki/0500-building-blocks/level-1.archify b/examples/arc42-team-wiki/0500-building-blocks/level-1.archify index 20b2a3d..46fd461 100644 --- a/examples/arc42-team-wiki/0500-building-blocks/level-1.archify +++ b/examples/arc42-team-wiki/0500-building-blocks/level-1.archify @@ -42,6 +42,9 @@ cards: - dot: amber title: 8 Crosscutting concepts items: - - Access - every request checked against space groups - - Logs - JSON to stdout, collected by the cluster - - Config - environment variables, secrets from the vault + - "Security: OIDC session, every request checked against space groups" + - "Persistence: PostgreSQL is the only source of truth" + - "Errors: API returns problem JSON; the web app shows a retry" + - "Logging: JSON to stdout, collected by the cluster" + - "Backups: nightly dump to object storage, 30 days" + - "Config: environment variables, secrets from the vault" diff --git a/examples/arc42-team-wiki/0700-deployment/production.archify b/examples/arc42-team-wiki/0700-deployment/production.archify index f03255b..cf2f4f0 100644 --- a/examples/arc42-team-wiki/0700-deployment/production.archify +++ b/examples/arc42-team-wiki/0700-deployment/production.archify @@ -36,8 +36,11 @@ boundaries: label: Company cluster wraps: [ingress, web, api, db, backup-job] - kind: security-group - label: Namespace team-wiki - wraps: [web, api, db, backup-job] + label: App node pool + wraps: [web, api] + - kind: security-group + label: Data node + wraps: [db, backup-job] connections: - { from: engineer, to: ingress, label: HTTPS, variant: emphasis } - { from: ingress, to: web, label: static } @@ -46,3 +49,12 @@ connections: - { from: api, to: idp, label: OIDC, variant: security, labelAt: [525, 234] } - { from: backup-job, to: db, label: dump } - { from: backup-job, to: object-store, label: S3 } +cards: + - dot: slate + title: 7 Mapping + items: + - "Web App -> app node pool, nginx pod, namespace team-wiki" + - "Wiki API -> app node pool, 2 pods behind the ingress" + - "Database -> data node, PostgreSQL stateful set with volume" + - "Backup job -> data node, Kubernetes CronJob" + - "Attachments, backups -> company object storage buckets" diff --git a/examples/arc42-team-wiki/1000-quality/quality-tree.archify b/examples/arc42-team-wiki/1000-quality/quality-tree.archify new file mode 100644 index 0000000..b136291 --- /dev/null +++ b/examples/arc42-team-wiki/1000-quality/quality-tree.archify @@ -0,0 +1,77 @@ +schema_version: 1 +diagram_type: architecture +meta: + title: Quality tree + output: quality-tree.html + legend: + mode: hidden +components: + - id: quality + type: cloud + label: Quality + pos: [40, 200] + size: [130, 120] + - id: usability + type: frontend + label: Usability + pos: [250, 60] + size: [130, 60] + - id: security + type: security + label: Security + pos: [250, 160] + size: [130, 60] + - id: reliability + type: backend + label: Reliability + pos: [250, 310] + size: [130, 60] + - id: maintainability + type: backend + label: Maintainability + pos: [250, 460] + size: [130, 60] + - id: q-search + type: external + label: Search under 1 s + pos: [460, 60] + size: [170, 60] + - id: q-leaver + type: external + label: Leaver out in 5 min + pos: [460, 160] + size: [170, 60] + - id: q-restore + type: external + label: Restore in 30 min + pos: [460, 260] + size: [170, 60] + - id: q-pod + type: external + label: Pod back in 1 min + pos: [460, 360] + size: [170, 60] + - id: q-upgrade + type: external + label: Upgrade in 1 hour + pos: [460, 460] + size: [170, 60] +connections: + - { from: quality, to: usability } + - { from: quality, to: security } + - { from: quality, to: reliability } + - { from: quality, to: maintainability } + - { from: usability, to: q-search } + - { from: security, to: q-leaver } + - { from: reliability, to: q-restore } + - { from: reliability, to: q-pod } + - { from: maintainability, to: q-upgrade } +cards: + - dot: emerald + title: 10 Quality scenarios + items: + - "Search: an engineer searches 5000 pages; results in under 1 s" + - "Leaver: HR disables an account; wiki access ends within 5 minutes" + - "Restore: the database is lost; the admin restores last night in 30 minutes" + - "Crash: an API pod dies; the cluster restarts it, no data lost, back in 1 minute" + - "Upgrade: a new wiki version ships; one admin rolls it out in 1 hour" diff --git a/examples/arc42-team-wiki/main.archify b/examples/arc42-team-wiki/main.archify index 021886d..ebc0e8b 100644 --- a/examples/arc42-team-wiki/main.archify +++ b/examples/arc42-team-wiki/main.archify @@ -3,12 +3,14 @@ model: id: team-wiki name: Team Wiki description: > - An arc42 example: a small self-hosted wiki for an engineering - team. Sections 1 goals, 2 constraints, 3 business context, - 10 quality, 11 risks and 12 glossary are on this overview; - 0300-context holds 3 technical context, 0500-building-blocks - 5 building blocks, 0600-runtime 6 runtime, 0700-deployment - 7 deployment and decisions 9 architecture decisions. + An arc42 example: a small self-hosted wiki for an engineering team. + 1 Requirements, quality goals, stakeholders; 2 Constraints; + 4 Solution strategy; 11 Risks; 12 Glossary: cards on this overview. + 3 Context: this overview (business) and 0300-context (technical). + 5 Building blocks: 0500-building-blocks, black boxes in registry/. + 6 Runtime: 0600-runtime. 7 Deployment: 0700-deployment. + 8 Crosscutting concepts: card on 0500-building-blocks/level-1. + 9 Decisions: decisions/. 10 Quality: 1000-quality. diagram_type: architecture meta: title: Team Wiki - business context @@ -36,31 +38,48 @@ connections: - { from: wiki, to: idp, label: sign-in, variant: security } - { from: wiki, to: object-store, label: files } cards: - - dot: cyan - title: 1 Quality goals + - dot: orange + title: 1.1 Requirements items: - - Findability - any page found in two searches - - Security - only current staff can read - - Operability - one person runs it in an hour a week + - "Create, edit and version pages in team spaces" + - "Full-text search over every page a user may read" + - "Attach files to pages" + - "Admin restores the wiki from a nightly backup" + - dot: cyan + title: 1.2 Quality goals + items: + - "Findability: any page found in two searches" + - "Security: only current staff can read" + - "Operability: one person runs it in an hour a week" + - dot: amber + title: 1.3 Stakeholders + items: + - "Engineer: fast search, simple editor" + - "Wiki admin: little routine work, easy restore" + - "Security officer: no access after leaving" + - "Team lead: one place for team knowledge" - dot: slate title: 2 Constraints items: - - Runs on the company Kubernetes cluster - - Sign-in only via the company identity provider + - "Runs on the company Kubernetes cluster" + - "Sign-in only via the company identity provider" - dot: emerald - title: 10 Quality scenarios + title: 4 Solution strategy items: - - A search over 5000 pages answers in under 1 s - - A leaver loses access within 5 minutes - - The admin restores last night's state in 30 minutes + - "React, Node.js API, PostgreSQL: one stack the team knows" + - "Three blocks plus a backup job: operability" + - "Findability: PostgreSQL full-text search (postgres-full-text-search)" + - "Security: OIDC at the company IdP only (sso-only-via-company-idp)" + - "Operability: files and backups in company object storage" - dot: rose - title: 11 Risks + title: 11 Risks and technical debt items: - - Identity provider outage blocks all sign-ins - - Backups untested until a restore drill is run + - "Risk: identity provider outage blocks all sign-ins" + - "Risk: backups untested until a restore drill is run" + - "Debt: attachments are not virus-scanned yet" - dot: violet title: 12 Glossary items: - - Space - pages of one team, mapped to a group - - Revision - one saved version of a page - - Attachment - a file stored beside a page + - "Space: pages of one team, mapped to a group" + - "Revision: one saved version of a page" + - "Attachment: a file stored beside a page" diff --git a/examples/arc42-team-wiki/registry/building-blocks.archify-registry b/examples/arc42-team-wiki/registry/building-blocks.archify-registry index db8fbd7..65791b7 100644 --- a/examples/arc42-team-wiki/registry/building-blocks.archify-registry +++ b/examples/arc42-team-wiki/registry/building-blocks.archify-registry @@ -6,15 +6,17 @@ elements: sublabel: React brand: react description: > - Page editor, viewer and search box in the browser; talks - only to the API. + Responsibility: page editor, viewer and search box in the + browser. Interfaces: provides the UI over HTTPS; requires + the Wiki API (JSON). api: type: backend label: Wiki API sublabel: REST description: > - Pages, search, attachments and access checks; the only - writer of the database. + Responsibility: pages, search, attachments and access checks; + the only writer of the database. Interfaces: provides REST + JSON; requires the IdP (OIDC), the database (SQL), object storage (S3). diagram: 0500-building-blocks/wiki-api.archify db: type: database @@ -22,12 +24,14 @@ elements: sublabel: PostgreSQL brand: postgresql description: > - Pages, revisions, users and the full-text index; the - source of truth. + Responsibility: pages, revisions, users and the full-text + index; the source of truth. Interfaces: provides SQL to the + API and dumps to the backup job. backup-job: type: backend label: Backup job sublabel: nightly description: > - Dumps the database at 02:00 and writes it to the backup - bucket; keeps 30 days. + Responsibility: dumps the database at 02:00, keeps 30 days. + Interfaces: requires the database (pg_dump) and the backup + bucket (S3); provides none. diff --git a/references/folders.md b/references/folders.md index 106b41a..79ede40 100644 --- a/references/folders.md +++ b/references/folders.md @@ -77,6 +77,65 @@ The numbered folders are only for sorting; nothing depends on the names. A team Component types that fit C4: people are `external`; the system itself and other systems are `cloud` (own) or `external` (others); containers are `frontend`, `backend`, `database`, `messagebus`, `security`; components inside a container use the same set, wrapped in a `region` boundary named after the container. +## arc42 + +[arc42](https://arc42.org) is a documentation template with twelve sections; four of them are views (diagrams), the rest are text. In a model, the views are folders numbered like their section, the decisions are section 9, and the text sections are `cards` (title plus short items) on the diagram they belong to. Card titles carry the section number so a reader finds each section. + +``` +cinema-tickets/ + main.archify section 3 business context (the system and its neighbours); + cards 1.1 Requirements, 1.2 Quality goals, 1.3 Stakeholders, + 2 Constraints, 4 Solution strategy, 11 Risks and technical debt, + 12 Glossary + registry/ + people.archify-registry users and operators + systems.archify-registry neighbouring systems + building-blocks.archify-registry each block's description in black-box form: + "Responsibility: ... Interfaces: ..." (section 5) + 0300-context/ + technical-context.archify channels and protocols; card 3 Domain interfaces + 0500-building-blocks/ + level-1.archify the system's white box; card 8 Crosscutting concepts + booking.archify level 2 of one block, linked from its registry entry + 0600-runtime/ + book-seats.archify key scenarios as sequence diagrams + 0700-deployment/ + production.archify building blocks inside boundaries for nodes and zones; + card 7 Mapping (block -> node) + 1000-quality/ + quality-tree.archify Quality -> characteristics -> scenarios; + card 10 Quality scenarios (stimulus and response) + decisions/ section 9, one *.archify-decision per decision +``` + +Say where each section lives in `model.description`. Cards hold short lines, not prose: an arc42 document with long text belongs next to the model, not in it. `examples/arc42-cinema-tickets/`, `arc42-iot-telemetry/` and `arc42-team-wiki/` (the smallest) are complete. + +## ArchiMate + +[ArchiMate](https://www.opengroup.org/archimate-forum) models an enterprise in layers. Archify has no ArchiMate notation, so each element is an Archify component type with its ArchiMate type written out: in `tag` (searchable, shown in the focus panel) and in `sublabel` (shown on the box; Archify draws tags only in the focus panel). + +``` +insurance-claims/ + main.archify layered view: Business, Application, Technology as three + region boundaries, top to bottom, three elements each in the + same columns, serves/realizes arrows between layers + registry/ + business.archify-registry actors, roles, processes, services, events + application.archify-registry components, services, interfaces, data objects + technology.archify-registry nodes, system software, technology services, networks + 0100-business/ + business-layer.archify actors, roles and services + handle-claim.archify the business process as a workflow (lanes per role) + 0200-application/ + application-structure.archify components, services, interfaces, data objects + application-cooperation.archify how the components talk + 0300-technology/ + infrastructure.archify nodes and networks inside boundaries + decisions/ +``` + +A mapping that reads well: actors and roles `external`; processes `backend`; business and application services `cloud` or `frontend`; application components `backend` or `frontend`; data objects `database`; nodes `backend`, `cloud` or `database`; networks `messagebus` or `security`. Name relationships in connection labels: serves, realizes, uses, accesses, assigned to, triggers. Keep type names short enough for the box (`App Component`, `Tech Service`). `examples/archimate-insurance-claims/`, `archimate-hr-onboarding/` and `archimate-logistics-tracking/` are complete. + ## How the extension knows it is in a model The nearest folder above a file that contains `main.archify` is the root. Under that root, at any depth: `*.archify` are member diagrams, `*.archify-registry` make up the registry, subfolders are groups. `node_modules` and `.git` are skipped.