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.
This commit is contained in:
root-at-skic committed 2026-11-08 23:11:46 +02:00
1 parent d9777fb90e
commit 900e0986e6
20 files changed
+554 -89

No files matched your search

+4 -3
View File
@@ -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: [<id>]` 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:<id>` for neighbours, `from:<a> to:<b>` for the route, `decision:<id>` 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).
@@ -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"
@@ -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"
@@ -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"
@@ -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"
+34 -15
View File
@@ -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:
@@ -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.
@@ -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"
@@ -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
@@ -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"
@@ -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"
+35 -14
View File
@@ -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:
@@ -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.
@@ -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"
@@ -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"
@@ -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"
@@ -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"
+42 -23
View File
@@ -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"
@@ -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.
+59
View File
@@ -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.