Compare commits
2
Commits
2ab4287f02
...
7fd34fcce0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fd34fcce0 | ||
|
|
f4663c089d |
No files matched your search
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## 0.11.1 — 2026-11-08
|
||||
|
||||
- **The arc42 examples cover all twelve sections.** Each overview carries cards for 1.1 Requirements, 1.2 Quality goals, 1.3 Stakeholders, 2 Constraints, 4 Solution strategy, 11 Risks and technical debt and 12 Glossary; the technical context lists the domain interfaces (3); every building block has a black-box description, responsibility and interfaces (5); the deployment view places the building blocks on their nodes with a mapping (7); level 1 carries the crosscutting concepts (8); a new `1000-quality` folder draws the quality tree with its scenarios (10). Each model's description says where each section lives.
|
||||
|
||||
## 0.11.0 — 2026-11-08
|
||||
|
||||
- **arc42 and ArchiMate examples.** *Archify | New Model…* now offers nine examples, three per framework. **arc42** (Cinema Tickets, IoT Telemetry, Team Wiki): the overview is the business context with quality goals, constraints, quality scenarios, risks and a glossary as cards; then `0300-context`, `0500-building-blocks` (levels 1 and 2), `0600-runtime` (sequence diagrams), `0700-deployment`, and the decisions as section 9. **ArchiMate** (Insurance Claims, HR Onboarding, Logistics Tracking): the overview is a layered view of the business, application and technology layers; then `0100-business` (with the business process as a workflow), `0200-application` and `0300-technology`, one registry file per layer, each element's ArchiMate type under its name.
|
||||
|
||||
@@ -126,7 +126,7 @@ online-shop/
|
||||
- **Decisions.** One `*.archify-decision` file per architecture decision: id, title, status, date, the registry elements and diagrams it is about, and prose for context, decision and consequences. Diagrams point at decisions with `decisions: [<id>]` on the diagram, a component or a connection. They show as a **Decisions** panel on the `main.archify` page, a **Decisions** rail panel under each diagram (hover lights up what the decision is attached to), on element cards and in the element dialog, and a decision opens as its own page. *Archify | New Decision…* creates one; links are checked in Problems.
|
||||
- **Registry view.** A `.archify-registry` file opens as its elements, as cards. Click one and a dialog shows its description, where it is defined and the diagrams that use it; click a diagram to open it. **View | Source** at the top right switches to the YAML, checked against the registry schema as you type.
|
||||
- **Elements and Connectors.** Under every diagram, Archify's node index is titled **Elements**, and a **Connectors** panel next to it lists every connection as "from → to" with its label. Hovering highlights the connector in the diagram; clicking keeps it highlighted and scrolls to it.
|
||||
- **Starting one.** *Archify | New Model…* (right-click a folder) copies one of the shipped examples into a new folder, named as you choose: **C4 - Standard Web App** (single-page app, API, database, cache, storage, identity provider), **C4 - E-Shop** (web shop, API, worker, queue, payment and email providers) or **C4 - Event-Based Integration** (event bus, router, dead-letter queue, event store, consumers), each with context, container and component diagrams. **arc42 - Cinema Tickets**, **arc42 - IoT Telemetry** and **arc42 - Team Wiki** follow arc42's sections: the overview is the business context with goals, constraints, quality scenarios, risks and a glossary as cards, then `0300-context`, `0500-building-blocks`, `0600-runtime` (sequence diagrams) and `0700-deployment`, with section 9 as decisions. **ArchiMate - Insurance Claims**, **ArchiMate - HR Onboarding** and **ArchiMate - Logistics Tracking** are layered: the overview is a layered view, then `0100-business`, `0200-application` and `0300-technology`, one registry file per layer, each element's ArchiMate type as its tag. Every example has a registry and decisions. For an empty model, *Archify | New Diagram… → Model* creates just a `main.archify`.
|
||||
- **Starting one.** *Archify | New Model…* (right-click a folder) copies one of the shipped examples into a new folder, named as you choose: **C4 - Standard Web App** (single-page app, API, database, cache, storage, identity provider), **C4 - E-Shop** (web shop, API, worker, queue, payment and email providers) or **C4 - Event-Based Integration** (event bus, router, dead-letter queue, event store, consumers), each with context, container and component diagrams. **arc42 - Cinema Tickets**, **arc42 - IoT Telemetry** and **arc42 - Team Wiki** cover all twelve arc42 sections: the overview is the business context (3) with requirements, quality goals, stakeholders, constraints, solution strategy, risks and technical debt, and a glossary as numbered cards; then `0300-context` (domain interfaces), `0500-building-blocks` (black boxes, crosscutting concepts), `0600-runtime` (sequence diagrams), `0700-deployment` (blocks mapped to nodes) and `1000-quality` (quality tree), with section 9 as decisions. **ArchiMate - Insurance Claims**, **ArchiMate - HR Onboarding** and **ArchiMate - Logistics Tracking** are layered: the overview is a layered view, then `0100-business`, `0200-application` and `0300-technology`, one registry file per layer, each element's ArchiMate type as its tag. Every example has a registry and decisions. For an empty model, *Archify | New Diagram… → Model* creates just a `main.archify`.
|
||||
- **The graph.** The **Model | Graph | Source** switch at the top of the `main.archify` page (next to **Export** when the file has a diagram) replaces the page with the whole model as one graph: every element any diagram draws plus every registry element, every connection between them, each once. Registry elements have a solid border, inline ones a dashed border; colours are Archify's type colours and the legend chips at the bottom hide or show a type. **Decisions** are nodes too (tags coloured by status, dotted links to the elements they are about, dashed links to what they supersede), and so are **registries** (one node per file, dotted links to the elements it defines); their chips hide them when the picture gets busy. The layout is **Layered** by default, like Archify's stack: clients on the left, data on the right, registries in a row above, decisions in a row below, connections drawn orthogonally; click the button for a **Force** layout instead. Drag nodes, scroll to zoom, **Fit** (or <kbd>0</kbd>) frames what matches, **Labels** toggles connection labels, the dotted **Links** from decisions and registries to their elements are on by default and can be switched off, in which case only the selected element's show (hovering an element lights up its connections), the sun/moon button switches the page between its dark and light theme (remembered, shared with the diagram pages' theme choice), **Export PNG** saves the picture. On a diagram page the switch reads **Diagram | Graph | Source** and Graph opens the graph already narrowed to that diagram; **Source** on the graph page goes back to `main.archify` in its Source view. *Archify | Open Model Graph* does the same from the Command Palette or Explorer.
|
||||
- **Queries.** Type a few words in the box (<kbd>/</kbd> focuses it); matches stay bright, the rest dims, the count shows "9 of 14 elements". Terms combine with AND and a leading `-` excludes: `database` (id, label, sublabel, brand or type contain it), `type:backend`, `diagram:0200-*` (what those diagrams draw), `decision:<id>` (what a decision is about or is attached to), `uses:api` (an element and its neighbours), `near:api,2` (within two steps), `from:web to:db` (the shortest path, following the arrows first), `unused` (registry elements no diagram draws), `shared` and `-shared` (registry or inline elements only), `type:decision` and `type:registry` for the decision and registry nodes. Decisions and registries follow the elements they are attached to into a result; `-type:decision` or `-type:registry` leaves them out. Walks and paths follow the diagrams' connections only, so a registry is never a shortcut between its elements. The **?** button lists them; clicking an example runs it.
|
||||
- **Side panel.** Click an element for its description, type, where it is defined (**Registry** opens the file at the line), the diagrams that draw it (click to open), its connections and its decisions (click to open). **Neighbours** runs `uses:` for it. Click a connection for its labels, the diagrams that draw it and its decisions. Click a decision node for its status, context and decision text, the elements and connections it is about, and **Open decision**; a registry node for the elements it defines, the ones no diagram draws yet, and **Open registry**.
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "archify-vscode-ext",
|
||||
"version": "0.11.0",
|
||||
"version": "0.11.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "archify-vscode-ext",
|
||||
"version": "0.11.0",
|
||||
"version": "0.11.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.20.4",
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"name": "archify-vscode-ext",
|
||||
"displayName": "Archify Diagram Viewer",
|
||||
"description": "Archify diagrams in VS Code. Write diagrams as .archify files in YAML: they open as the interactive diagram, with live updates, validation, templates and completion. Also previews Archify's own JSON files (*.architecture.json, …) and opens rendered Archify HTML.",
|
||||
"version": "0.11.0",
|
||||
"version": "0.11.1",
|
||||
"publisher": "root-at-skic",
|
||||
"license": "MIT",
|
||||
"sponsor": {
|
||||
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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.
|
||||
+12
-1
@@ -29,7 +29,7 @@ function walk(dir: string, rel = ''): string[] {
|
||||
// The folders each framework's examples must have, besides main.archify, registry/ and decisions/.
|
||||
const FRAMEWORK_FOLDERS: Record<string, string[]> = {
|
||||
c4: ['0100-context', '0200-containers', '0300-components'],
|
||||
arc42: ['0300-context', '0500-building-blocks', '0600-runtime', '0700-deployment'],
|
||||
arc42: ['0300-context', '0500-building-blocks', '0600-runtime', '0700-deployment', '1000-quality'],
|
||||
archimate: ['0100-business', '0200-application', '0300-technology'],
|
||||
};
|
||||
|
||||
@@ -95,6 +95,17 @@ for (const example of MODEL_EXAMPLES) {
|
||||
}
|
||||
// Every registry element is used by some diagram.
|
||||
for (const id of registry.elements.keys()) assert.ok(used.has(id), `element ${id} is never used`);
|
||||
|
||||
// arc42: every text section has a card somewhere, titled with its number.
|
||||
if (example.folder.startsWith('arc42-')) {
|
||||
const titles = diagrams.flatMap((file) => {
|
||||
const cards = parse(read(file))?.cards;
|
||||
return Array.isArray(cards) ? cards.map((card: { title?: string }) => String(card?.title ?? '')) : [];
|
||||
});
|
||||
for (const section of ['1.1', '1.2', '1.3', '2', '3', '4', '7', '8', '10', '11', '12']) {
|
||||
assert.ok(titles.some((title) => title.startsWith(`${section} `)), `${example.folder}: no card for arc42 section ${section}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user