0.11.0: arc42 and ArchiMate examples; ref in every diagram kind
Six example models next to the three C4 ones: arc42 (Cinema Tickets, IoT Telemetry, Team Wiki) by section, ArchiMate (Insurance Claims, HR Onboarding, Logistics Tracking) by layer, each validated with 0 errors and 0 warnings. resolveRefs and the editor schemas now take ref: in workflow and dataflow nodes, sequence participants and lifecycle states, as the skill already did. Example tests check each framework's folders.
This commit is contained in:
1 parent
f4df6a0834
commit
0745de822a
85 files changed
+2945
-67
No files matched your search
@@ -0,0 +1,30 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Technical context
|
||||
output: technical-context.html
|
||||
components:
|
||||
- ref: customer
|
||||
pos: [40, 60]
|
||||
size: [130, 60]
|
||||
- ref: usher
|
||||
pos: [40, 260]
|
||||
size: [130, 60]
|
||||
- ref: tickets
|
||||
pos: [290, 160]
|
||||
size: [150, 60]
|
||||
- ref: psp
|
||||
pos: [560, 60]
|
||||
size: [150, 60]
|
||||
- ref: mail
|
||||
pos: [560, 160]
|
||||
size: [150, 60]
|
||||
- ref: pos
|
||||
pos: [560, 260]
|
||||
size: [150, 60]
|
||||
connections:
|
||||
- { from: customer, to: tickets, label: HTTPS JSON, variant: emphasis }
|
||||
- { from: usher, to: tickets, label: HTTPS app }
|
||||
- { from: tickets, to: psp, label: REST webhook, variant: security }
|
||||
- { from: tickets, to: mail, label: SMTP TLS }
|
||||
- { from: tickets, to: pos, label: REST VPN }
|
||||
@@ -0,0 +1,49 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Booking API - level 2
|
||||
output: booking.html
|
||||
decisions: [seat-holds-with-ttl]
|
||||
components:
|
||||
- ref: web
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- id: programme
|
||||
type: backend
|
||||
label: Programme
|
||||
sublabel: shows, halls
|
||||
pos: [250, 60]
|
||||
size: [130, 60]
|
||||
- id: seats
|
||||
type: backend
|
||||
label: Seat Holds
|
||||
sublabel: lock, release
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- id: checkout
|
||||
type: backend
|
||||
label: Checkout
|
||||
sublabel: orders, webhook
|
||||
pos: [250, 260]
|
||||
size: [130, 60]
|
||||
- ref: seatlock
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
decisions: [seat-holds-with-ttl]
|
||||
- ref: db
|
||||
pos: [460, 60]
|
||||
size: [130, 60]
|
||||
- ref: psp
|
||||
pos: [460, 360]
|
||||
size: [150, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Booking API
|
||||
wraps: [programme, seats, checkout]
|
||||
connections:
|
||||
- { from: web, to: programme, label: browse }
|
||||
- { from: web, to: seats, label: hold, variant: emphasis }
|
||||
- { from: web, to: checkout, label: pay }
|
||||
- { from: programme, to: db, label: SQL }
|
||||
- { from: seats, to: seatlock, label: SET NX, decisions: [seat-holds-with-ttl] }
|
||||
- { from: checkout, to: psp, label: session, variant: security }
|
||||
@@ -0,0 +1,64 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Building blocks - level 1
|
||||
output: level-1.html
|
||||
decisions: [booking-owns-seat-inventory]
|
||||
components:
|
||||
- ref: web
|
||||
pos: [40, 110]
|
||||
size: [130, 60]
|
||||
- ref: mobile
|
||||
pos: [40, 210]
|
||||
size: [130, 60]
|
||||
- ref: scanner
|
||||
pos: [40, 360]
|
||||
size: [130, 60]
|
||||
- ref: booking
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- ref: seatlock
|
||||
pos: [460, 60]
|
||||
size: [130, 60]
|
||||
- ref: db
|
||||
pos: [460, 260]
|
||||
size: [130, 60]
|
||||
- ref: ticketing
|
||||
pos: [250, 360]
|
||||
size: [130, 60]
|
||||
- ref: possync
|
||||
pos: [670, 260]
|
||||
size: [130, 60]
|
||||
- ref: psp
|
||||
pos: [900, 160]
|
||||
size: [150, 60]
|
||||
- ref: pos
|
||||
pos: [900, 260]
|
||||
size: [150, 60]
|
||||
- ref: mail
|
||||
pos: [900, 460]
|
||||
size: [150, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Cinema Tickets
|
||||
wraps: [web, mobile, scanner, booking, seatlock, db, ticketing, possync]
|
||||
connections:
|
||||
- { from: web, to: booking, label: JSON, variant: emphasis }
|
||||
- { from: mobile, to: booking, label: JSON }
|
||||
- { from: booking, to: seatlock, label: hold }
|
||||
- { from: booking, to: db, label: SQL }
|
||||
- { from: booking, to: psp, label: checkout, variant: security }
|
||||
- { from: booking, to: ticketing, label: issue, labelAt: [315, 234] }
|
||||
- { from: scanner, to: ticketing, label: check-in }
|
||||
- { from: ticketing, to: db, label: SQL }
|
||||
- { from: ticketing, to: mail, label: QR mail }
|
||||
- { from: possync, to: db, label: SQL }
|
||||
- { from: possync, to: pos, label: sales, decisions: [booking-owns-seat-inventory] }
|
||||
cards:
|
||||
- dot: amber
|
||||
title: 8 Crosscutting concepts
|
||||
items:
|
||||
- "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"
|
||||
@@ -0,0 +1,27 @@
|
||||
schema_version: 1
|
||||
diagram_type: sequence
|
||||
meta:
|
||||
title: Runtime - book seats
|
||||
output: book-seats.html
|
||||
viewBox: [1060, 680]
|
||||
column_fit: spread
|
||||
decisions: [seat-holds-with-ttl]
|
||||
participants:
|
||||
- { ref: customer }
|
||||
- { ref: web }
|
||||
- { ref: booking }
|
||||
- { ref: seatlock }
|
||||
- { ref: psp }
|
||||
- { ref: ticketing }
|
||||
- { ref: mail }
|
||||
messages:
|
||||
- { from: customer, to: web, y: 170, label: pick seats, variant: emphasis }
|
||||
- { from: web, to: booking, y: 214, label: POST /holds }
|
||||
- { from: booking, to: seatlock, y: 258, label: SET NX TTL 8m, decisions: [seat-holds-with-ttl] }
|
||||
- { from: seatlock, to: booking, y: 302, label: OK, variant: return }
|
||||
- { from: booking, to: web, y: 346, label: hold id, variant: return }
|
||||
- { from: web, to: psp, y: 390, label: hosted checkout, variant: security }
|
||||
- { from: psp, to: booking, y: 434, label: webhook paid, variant: security }
|
||||
- { from: booking, to: ticketing, y: 478, label: issue tickets }
|
||||
- { from: ticketing, to: mail, y: 522, label: QR e-mail }
|
||||
- { from: mail, to: customer, y: 566, label: tickets, variant: return }
|
||||
@@ -0,0 +1,19 @@
|
||||
schema_version: 1
|
||||
diagram_type: sequence
|
||||
meta:
|
||||
title: Runtime - check-in at the door
|
||||
output: check-in.html
|
||||
viewBox: [900, 480]
|
||||
column_fit: spread
|
||||
decisions: [signed-qr-codes]
|
||||
participants:
|
||||
- { ref: usher }
|
||||
- { ref: scanner }
|
||||
- { ref: ticketing }
|
||||
- { ref: db }
|
||||
messages:
|
||||
- { from: usher, to: scanner, y: 180, label: scan QR, variant: emphasis, note: signature checked offline, decisions: [signed-qr-codes] }
|
||||
- { from: scanner, to: ticketing, y: 230, label: POST /checkins }
|
||||
- { from: ticketing, to: db, y: 280, label: first scan wins }
|
||||
- { from: ticketing, to: scanner, y: 330, label: valid seat 7F, variant: return }
|
||||
- { from: scanner, to: usher, y: 380, label: green light, variant: return }
|
||||
@@ -0,0 +1,58 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Deployment - production
|
||||
output: production.html
|
||||
components:
|
||||
- ref: customer
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- id: ingress
|
||||
type: security
|
||||
label: Ingress
|
||||
sublabel: TLS, WAF
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- ref: web
|
||||
pos: [460, 60]
|
||||
size: [130, 60]
|
||||
- ref: booking
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- ref: ticketing
|
||||
pos: [460, 260]
|
||||
size: [130, 60]
|
||||
- ref: possync
|
||||
pos: [460, 360]
|
||||
size: [130, 60]
|
||||
- ref: seatlock
|
||||
pos: [710, 110]
|
||||
size: [130, 60]
|
||||
- ref: db
|
||||
pos: [710, 260]
|
||||
size: [130, 60]
|
||||
- ref: pos
|
||||
pos: [250, 460]
|
||||
size: [150, 60]
|
||||
- ref: scanner
|
||||
pos: [40, 460]
|
||||
size: [130, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: EU cloud - k8s cluster
|
||||
wraps: [ingress, web, booking, ticketing, possync]
|
||||
- kind: security-group
|
||||
label: Managed data zone
|
||||
wraps: [seatlock, db]
|
||||
- kind: region
|
||||
label: Cinema site
|
||||
wraps: [pos, scanner]
|
||||
connections:
|
||||
- { from: customer, to: ingress, label: HTTPS, variant: emphasis }
|
||||
- { from: ingress, to: web, label: route }
|
||||
- { from: ingress, to: booking, label: route }
|
||||
- { from: booking, to: seatlock, label: TLS }
|
||||
- { from: booking, to: db, label: TLS }
|
||||
- { from: ticketing, to: db, label: TLS }
|
||||
- { from: possync, to: pos, label: VPN, variant: security }
|
||||
- { from: scanner, to: ingress, label: HTTPS }
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: seat-holds-with-ttl
|
||||
title: Seat holds as Redis keys with a TTL
|
||||
status: accepted
|
||||
date: 2026-09-08
|
||||
elements: [booking, seatlock]
|
||||
diagrams: [0500-building-blocks/booking.archify, 0600-runtime/book-seats.archify]
|
||||
context: >
|
||||
A customer may spend minutes at the payment page. Holding seats
|
||||
as rows in the database left orphans when a browser closed, and
|
||||
a nightly job freed them far too late for Friday shows.
|
||||
decision: >
|
||||
A hold is one Redis key per seat, set with SET NX and an
|
||||
8-minute TTL. The payment webhook turns holds into an order in
|
||||
PostgreSQL; an expired key frees the seat without any job.
|
||||
consequences: >
|
||||
Holds survive no Redis restart; at worst a customer re-picks
|
||||
seats. The webhook must check the hold still exists before it
|
||||
confirms the order, otherwise it refunds.
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: booking-owns-seat-inventory
|
||||
title: The Booking API owns the seat inventory
|
||||
status: accepted
|
||||
date: 2026-09-22
|
||||
elements: [booking, db, possync, pos]
|
||||
diagrams: [0500-building-blocks/level-1.archify]
|
||||
context: >
|
||||
The box-office POS and the web shop both sold seats from their
|
||||
own copy of the seat map. Twice a month a seat was sold at the
|
||||
counter and online.
|
||||
decision: >
|
||||
The Tickets DB is the only seat inventory. The POS asks POS Sync
|
||||
for a seat before it prints a ticket; POS Sync writes the sale
|
||||
through the same rules as online orders.
|
||||
consequences: >
|
||||
The counter needs the network to sell; a fallback block of
|
||||
reserved seats per show covers outages. The POS vendor adapter
|
||||
is ours to maintain.
|
||||
@@ -0,0 +1,19 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: signed-qr-codes
|
||||
title: Signed QR codes checked offline at the door
|
||||
status: accepted
|
||||
date: 2026-10-06
|
||||
elements: [ticketing, scanner]
|
||||
diagrams: [0600-runtime/check-in.archify]
|
||||
context: >
|
||||
Cinema Wi-Fi drops when a full hall arrives. A scanner that
|
||||
needs the server for every ticket stops the queue.
|
||||
decision: >
|
||||
The Ticket Service signs each QR payload (ticket id, show,
|
||||
seat) with a private key. The scanner app verifies it with the
|
||||
public key and queues check-ins until it is online again.
|
||||
consequences: >
|
||||
A forwarded ticket scans twice while offline; the second scan
|
||||
is flagged when the queue syncs. Key rotation needs an app
|
||||
update window.
|
||||
@@ -0,0 +1,72 @@
|
||||
schema_version: 1
|
||||
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.
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Cinema Tickets - business context
|
||||
output: main.html
|
||||
components:
|
||||
- ref: customer
|
||||
pos: [40, 60]
|
||||
size: [130, 60]
|
||||
- ref: usher
|
||||
pos: [40, 260]
|
||||
size: [130, 60]
|
||||
- ref: tickets
|
||||
pos: [280, 160]
|
||||
size: [150, 60]
|
||||
- ref: psp
|
||||
pos: [540, 60]
|
||||
size: [150, 60]
|
||||
- ref: mail
|
||||
pos: [540, 160]
|
||||
size: [150, 60]
|
||||
- ref: pos
|
||||
pos: [540, 260]
|
||||
size: [150, 60]
|
||||
connections:
|
||||
- { from: customer, to: tickets, label: books seats, variant: emphasis }
|
||||
- { from: usher, to: tickets, label: checks in }
|
||||
- { from: tickets, to: psp, label: payments, variant: security }
|
||||
- { from: tickets, to: mail, label: tickets }
|
||||
- { from: tickets, to: pos, label: seat sales }
|
||||
cards:
|
||||
- dot: cyan
|
||||
title: 1 Quality goals
|
||||
items:
|
||||
- "No seat is ever sold twice"
|
||||
- "Checkout under 2 s at Friday peak"
|
||||
- "Door check-in works offline"
|
||||
- dot: slate
|
||||
title: 2 Constraints
|
||||
items:
|
||||
- "Existing box-office POS stays"
|
||||
- "Card data only at the provider"
|
||||
- "Team of four; hosted in the EU"
|
||||
- dot: emerald
|
||||
title: 10 Quality scenarios
|
||||
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"
|
||||
- dot: rose
|
||||
title: 11 Risks
|
||||
items:
|
||||
- "POS vendor API is slow and undocumented"
|
||||
- "Forwarded QR e-mails: first scan wins"
|
||||
- dot: violet
|
||||
title: 12 Glossary
|
||||
items:
|
||||
- "Show: one screening of a film in a hall"
|
||||
- "Hold: a seat locked for one customer"
|
||||
- "Check-in: first valid scan of a ticket"
|
||||
- "POS: point-of-sale till at the box office"
|
||||
@@ -0,0 +1,57 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
web:
|
||||
type: frontend
|
||||
label: Web Shop
|
||||
sublabel: React
|
||||
brand: react
|
||||
description: >
|
||||
Programme, seat map and checkout in the browser.
|
||||
mobile:
|
||||
type: frontend
|
||||
label: Mobile App
|
||||
sublabel: iOS and Android
|
||||
description: >
|
||||
The same booking flow as the web shop, plus a ticket wallet.
|
||||
scanner:
|
||||
type: frontend
|
||||
label: Scanner App
|
||||
sublabel: door phones
|
||||
description: >
|
||||
Reads QR codes at the door; checks signatures 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.
|
||||
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.
|
||||
possync:
|
||||
type: backend
|
||||
label: POS Sync
|
||||
sublabel: adapter
|
||||
description: >
|
||||
Exchanges seat sales with the box-office POS in both directions.
|
||||
seatlock:
|
||||
type: database
|
||||
label: Seat Locks
|
||||
sublabel: Redis
|
||||
brand: redis
|
||||
description: >
|
||||
Short-lived seat holds with a TTL while the customer pays.
|
||||
db:
|
||||
type: database
|
||||
label: Tickets DB
|
||||
sublabel: PostgreSQL
|
||||
brand: postgresql
|
||||
description: >
|
||||
Shows, seats, orders and tickets; the source of truth.
|
||||
@@ -0,0 +1,14 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
customer:
|
||||
type: external
|
||||
label: Moviegoer
|
||||
sublabel: web and mobile
|
||||
description: >
|
||||
Picks a show, holds seats and pays; gets the tickets by e-mail.
|
||||
usher:
|
||||
type: external
|
||||
label: Usher
|
||||
sublabel: door staff
|
||||
description: >
|
||||
Scans tickets at the auditorium door with the scanner app.
|
||||
@@ -0,0 +1,30 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
tickets:
|
||||
type: cloud
|
||||
label: Cinema Tickets
|
||||
sublabel: the system
|
||||
description: >
|
||||
Online booking, seat holds, e-mail tickets and door check-in
|
||||
for the five cinemas of the fictional Lantern Cinemas chain.
|
||||
diagram: 0500-building-blocks/level-1.archify
|
||||
psp:
|
||||
type: external
|
||||
label: Payment provider
|
||||
sublabel: hosted checkout
|
||||
description: >
|
||||
Takes card and wallet payments on its own page; we never see
|
||||
card numbers.
|
||||
pos:
|
||||
type: external
|
||||
label: Box-office POS
|
||||
sublabel: in each cinema
|
||||
description: >
|
||||
Till system at the counter; sells walk-in seats from the same
|
||||
seat map.
|
||||
mail:
|
||||
type: external
|
||||
label: E-mail service
|
||||
sublabel: transactional
|
||||
description: >
|
||||
Delivers ticket e-mails with QR codes and receipts.
|
||||
@@ -0,0 +1,35 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Technical context
|
||||
output: technical-context.html
|
||||
decisions: [mqtt-with-mutual-tls]
|
||||
components:
|
||||
- ref: homeowner
|
||||
pos: [40, 60]
|
||||
size: [130, 60]
|
||||
- ref: ops-engineer
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: installer
|
||||
pos: [40, 260]
|
||||
size: [130, 60]
|
||||
- ref: telemetry-platform
|
||||
pos: [280, 160]
|
||||
size: [150, 60]
|
||||
- ref: heat-pump
|
||||
pos: [540, 60]
|
||||
size: [130, 60]
|
||||
- ref: push-service
|
||||
pos: [540, 160]
|
||||
size: [130, 60]
|
||||
- ref: service-desk
|
||||
pos: [540, 260]
|
||||
size: [130, 60]
|
||||
connections:
|
||||
- { from: homeowner, to: telemetry-platform, label: HTTPS }
|
||||
- { from: ops-engineer, to: telemetry-platform, label: HTTPS, variant: security }
|
||||
- { from: installer, to: telemetry-platform, label: HTTPS }
|
||||
- { 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 }
|
||||
@@ -0,0 +1,50 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Ingest, level 2
|
||||
output: ingest.html
|
||||
components:
|
||||
- ref: mqtt-broker
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- id: decoder
|
||||
type: backend
|
||||
label: Decoder
|
||||
sublabel: payload v1, v2
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- id: validator
|
||||
type: backend
|
||||
label: Validator
|
||||
sublabel: ranges, clock
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- id: writer
|
||||
type: backend
|
||||
label: Batch writer
|
||||
sublabel: 500 rows
|
||||
pos: [670, 160]
|
||||
size: [130, 60]
|
||||
- id: dead-letter
|
||||
type: database
|
||||
label: Dead letters
|
||||
sublabel: rejected readings
|
||||
pos: [460, 310]
|
||||
size: [130, 60]
|
||||
- ref: tsdb
|
||||
pos: [880, 160]
|
||||
size: [130, 60]
|
||||
- ref: rules
|
||||
pos: [670, 310]
|
||||
size: [130, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Ingest
|
||||
wraps: [decoder, validator, writer, dead-letter]
|
||||
connections:
|
||||
- { from: mqtt-broker, to: decoder, label: messages, variant: emphasis }
|
||||
- { from: decoder, to: validator, label: readings, variant: emphasis }
|
||||
- { from: validator, to: writer, label: valid, variant: emphasis }
|
||||
- { from: validator, to: dead-letter, label: invalid, variant: dashed, labelAt: [525, 234] }
|
||||
- { from: writer, to: tsdb, label: COPY, variant: emphasis }
|
||||
- { from: writer, to: rules, label: stream, labelAt: [735, 234] }
|
||||
@@ -0,0 +1,77 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Building blocks, level 1
|
||||
output: level-1.html
|
||||
decisions: [timescaledb-for-telemetry]
|
||||
components:
|
||||
- ref: heat-pump
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: installer
|
||||
pos: [40, 360]
|
||||
size: [130, 60]
|
||||
- ref: mqtt-broker
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
decisions: [mqtt-with-mutual-tls]
|
||||
- ref: provisioning
|
||||
pos: [250, 360]
|
||||
size: [130, 60]
|
||||
- ref: rules
|
||||
pos: [460, 60]
|
||||
size: [130, 60]
|
||||
- ref: ingest
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- ref: device-registry
|
||||
pos: [460, 360]
|
||||
size: [130, 60]
|
||||
- ref: tsdb
|
||||
pos: [670, 160]
|
||||
size: [130, 60]
|
||||
- ref: device-api
|
||||
pos: [670, 360]
|
||||
size: [130, 60]
|
||||
- ref: ops-dashboard
|
||||
pos: [880, 160]
|
||||
size: [130, 60]
|
||||
- ref: customer-app
|
||||
pos: [880, 360]
|
||||
size: [130, 60]
|
||||
- ref: push-service
|
||||
pos: [1090, 60]
|
||||
size: [130, 60]
|
||||
- ref: ops-engineer
|
||||
pos: [1090, 160]
|
||||
size: [130, 60]
|
||||
- ref: homeowner
|
||||
pos: [1090, 360]
|
||||
size: [130, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: IoT Telemetry
|
||||
wraps: [mqtt-broker, provisioning, rules, ingest, device-registry, tsdb, device-api, ops-dashboard, customer-app]
|
||||
connections:
|
||||
- { from: heat-pump, to: mqtt-broker, label: publish, variant: emphasis, decisions: [mqtt-with-mutual-tls] }
|
||||
- { from: mqtt-broker, to: ingest, label: subscribe, variant: emphasis }
|
||||
- { from: ingest, to: tsdb, label: write, variant: emphasis }
|
||||
- { from: ingest, to: rules, label: stream }
|
||||
- { from: ingest, to: device-registry, label: lookup, labelAt: [525, 234] }
|
||||
- { from: rules, to: push-service, label: alert }
|
||||
- { from: installer, to: provisioning, label: register }
|
||||
- { from: provisioning, to: mqtt-broker, label: certs, variant: security }
|
||||
- { from: provisioning, to: device-registry, label: store }
|
||||
- { from: device-api, to: tsdb, label: read }
|
||||
- { from: device-api, to: device-registry, label: read }
|
||||
- { from: tsdb, to: ops-dashboard, label: query }
|
||||
- { from: customer-app, to: device-api, label: REST }
|
||||
- { from: ops-engineer, to: ops-dashboard, label: views }
|
||||
- { from: homeowner, to: customer-app, label: uses }
|
||||
cards:
|
||||
- dot: amber
|
||||
title: 8 Crosscutting concepts
|
||||
items:
|
||||
- Device identity, one X.509 certificate per device
|
||||
- Idempotent writes, keyed by device id and timestamp
|
||||
- Observability, metrics and traces on every service
|
||||
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
diagram_type: sequence
|
||||
meta:
|
||||
title: Device provisioning
|
||||
output: device-provisioning.html
|
||||
decisions: [mqtt-with-mutual-tls]
|
||||
participants:
|
||||
- { ref: installer }
|
||||
- { ref: provisioning }
|
||||
- { ref: device-registry, label: Devices }
|
||||
- { ref: heat-pump }
|
||||
- { ref: mqtt-broker }
|
||||
messages:
|
||||
- { from: installer, to: provisioning, y: 160, label: register serial, variant: emphasis }
|
||||
- { from: provisioning, to: device-registry, y: 210, label: store device }
|
||||
- { from: provisioning, to: installer, y: 260, label: certificate, variant: return }
|
||||
- { from: installer, to: heat-pump, y: 310, label: load certificate }
|
||||
- { from: heat-pump, to: mqtt-broker, y: 360, label: connect mTLS, variant: emphasis }
|
||||
- { from: mqtt-broker, to: provisioning, y: 410, label: check revocation }
|
||||
- { from: mqtt-broker, to: heat-pump, y: 460, label: CONNACK, variant: return }
|
||||
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
diagram_type: sequence
|
||||
meta:
|
||||
title: Fault reading to alert
|
||||
output: telemetry-to-alert.html
|
||||
participants:
|
||||
- { ref: heat-pump }
|
||||
- { ref: mqtt-broker }
|
||||
- { ref: ingest }
|
||||
- { ref: tsdb, label: TSDB }
|
||||
- { ref: rules }
|
||||
- { ref: push-service }
|
||||
messages:
|
||||
- { from: heat-pump, to: mqtt-broker, y: 160, label: publish fault, variant: emphasis }
|
||||
- { from: mqtt-broker, to: ingest, y: 210, label: deliver QoS 1 }
|
||||
- { from: ingest, to: tsdb, y: 260, label: write batch }
|
||||
- { from: tsdb, to: ingest, y: 310, label: committed, variant: return }
|
||||
- { from: ingest, to: mqtt-broker, y: 360, label: ack, variant: return }
|
||||
- { from: ingest, to: rules, y: 410, label: reading }
|
||||
- { from: rules, to: push-service, y: 460, label: send alert, variant: emphasis }
|
||||
@@ -0,0 +1,44 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Deployment, production
|
||||
output: production.html
|
||||
decisions: [timescaledb-for-telemetry]
|
||||
components:
|
||||
- ref: heat-pump
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: mqtt-broker
|
||||
pos: [280, 160]
|
||||
size: [130, 60]
|
||||
- ref: ingest
|
||||
pos: [490, 160]
|
||||
size: [130, 60]
|
||||
- ref: rules
|
||||
pos: [490, 60]
|
||||
size: [130, 60]
|
||||
- ref: provisioning
|
||||
pos: [280, 260]
|
||||
size: [130, 60]
|
||||
- ref: device-api
|
||||
pos: [490, 260]
|
||||
size: [130, 60]
|
||||
- ref: tsdb
|
||||
pos: [760, 160]
|
||||
size: [130, 60]
|
||||
- ref: device-registry
|
||||
pos: [760, 260]
|
||||
size: [130, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Kubernetes cluster, eu-central
|
||||
wraps: [mqtt-broker, ingest, rules, provisioning, device-api]
|
||||
- kind: security-group
|
||||
label: Managed DB zone
|
||||
wraps: [tsdb, device-registry]
|
||||
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" }
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: mqtt-with-mutual-tls
|
||||
title: MQTT with mutual TLS for device traffic
|
||||
status: accepted
|
||||
date: 2026-08-12
|
||||
elements: [heat-pump, mqtt-broker, provisioning]
|
||||
diagrams: [0300-context/technical-context.archify, 0500-building-blocks/level-1.archify]
|
||||
context: >
|
||||
Heat pumps sit behind home routers on slow and flaky links.
|
||||
The first prototype polled an HTTPS endpoint and drained
|
||||
mobile data plans; shared API keys leaked from one device.
|
||||
decision: >
|
||||
Devices publish over MQTT 3.1.1 on port 8883. Each device
|
||||
has its own client certificate issued by Provisioning;
|
||||
the broker rejects any connection without one.
|
||||
consequences: >
|
||||
Small messages and one long-lived connection per device.
|
||||
Certificates must be rotated and revoked, so Provisioning
|
||||
is a critical building block. Installers need a step to
|
||||
register the device before it can connect.
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: timescaledb-for-telemetry
|
||||
title: TimescaleDB for telemetry
|
||||
status: accepted
|
||||
date: 2026-09-03
|
||||
elements: [tsdb, ingest, ops-dashboard]
|
||||
diagrams: [0500-building-blocks/level-1.archify, 0700-deployment/production.archify]
|
||||
context: >
|
||||
The fleet sends about 4,000 readings a second. A plain
|
||||
PostgreSQL table grew too fast and dashboards slowed down
|
||||
after a few weeks of data.
|
||||
decision: >
|
||||
Store telemetry in TimescaleDB hypertables with hourly
|
||||
continuous aggregates. Raw data is kept 90 days, rollups
|
||||
10 years. The team already runs PostgreSQL.
|
||||
consequences: >
|
||||
SQL stays the query language for the API and the
|
||||
dashboard. Retention jobs must be monitored. Very high
|
||||
device counts may need sharding later (see risk R1).
|
||||
@@ -0,0 +1,76 @@
|
||||
schema_version: 1
|
||||
model:
|
||||
id: iot-telemetry
|
||||
name: IoT Telemetry
|
||||
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.
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Business context
|
||||
output: main.html
|
||||
components:
|
||||
- ref: homeowner
|
||||
pos: [40, 60]
|
||||
size: [130, 60]
|
||||
- ref: ops-engineer
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: installer
|
||||
pos: [40, 260]
|
||||
size: [130, 60]
|
||||
- ref: telemetry-platform
|
||||
pos: [280, 160]
|
||||
size: [150, 60]
|
||||
- ref: heat-pump
|
||||
pos: [540, 60]
|
||||
size: [130, 60]
|
||||
- ref: push-service
|
||||
pos: [540, 160]
|
||||
size: [130, 60]
|
||||
- ref: service-desk
|
||||
pos: [540, 260]
|
||||
size: [130, 60]
|
||||
connections:
|
||||
- { from: homeowner, to: telemetry-platform, label: checks }
|
||||
- { from: ops-engineer, to: telemetry-platform, label: monitors }
|
||||
- { from: installer, to: telemetry-platform, label: registers }
|
||||
- { from: heat-pump, to: telemetry-platform, label: telemetry, variant: emphasis }
|
||||
- { from: telemetry-platform, to: push-service, label: alerts }
|
||||
- { from: telemetry-platform, to: service-desk, label: tickets }
|
||||
cards:
|
||||
- dot: cyan
|
||||
title: 1 Quality goals
|
||||
items:
|
||||
- Reliability, no telemetry lost once accepted
|
||||
- Timeliness, alert within 60 s of a fault
|
||||
- Security, every device authenticated
|
||||
- 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
|
||||
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
|
||||
- dot: rose
|
||||
title: 11 Risks
|
||||
items:
|
||||
- R1 fleet growth beyond one TSDB node
|
||||
- R2 partner firmware delays certificate rotation
|
||||
- dot: violet
|
||||
title: 12 Glossary
|
||||
items:
|
||||
- Telemetry, readings a device sends
|
||||
- Rollup, hourly aggregate of telemetry
|
||||
- Provisioning, giving a device its identity
|
||||
- Fault code, error number from the device
|
||||
@@ -0,0 +1,61 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
mqtt-broker:
|
||||
type: messagebus
|
||||
label: MQTT broker
|
||||
sublabel: mutual TLS
|
||||
description: >
|
||||
Terminates device connections; one topic per device.
|
||||
ingest:
|
||||
type: backend
|
||||
label: Ingest
|
||||
sublabel: Go
|
||||
brand: go
|
||||
description: >
|
||||
Decodes, validates and stores telemetry; forwards it to the rules.
|
||||
diagram: 0500-building-blocks/ingest.archify
|
||||
tsdb:
|
||||
type: database
|
||||
label: Time series DB
|
||||
sublabel: TimescaleDB
|
||||
brand: postgresql
|
||||
description: >
|
||||
Raw telemetry for 90 days and hourly rollups for 10 years.
|
||||
rules:
|
||||
type: backend
|
||||
label: Rules engine
|
||||
sublabel: alerting
|
||||
description: >
|
||||
Evaluates thresholds and fault codes; raises alerts.
|
||||
provisioning:
|
||||
type: security
|
||||
label: Provisioning
|
||||
sublabel: device certs
|
||||
description: >
|
||||
Registers devices and issues their client certificates.
|
||||
device-registry:
|
||||
type: database
|
||||
label: Device registry
|
||||
sublabel: PostgreSQL
|
||||
brand: postgresql
|
||||
description: >
|
||||
Devices, owners, firmware versions and certificate state.
|
||||
device-api:
|
||||
type: backend
|
||||
label: Device API
|
||||
sublabel: REST
|
||||
description: >
|
||||
Serves telemetry and device data to the customer app.
|
||||
ops-dashboard:
|
||||
type: frontend
|
||||
label: Ops dashboard
|
||||
sublabel: Grafana
|
||||
brand: grafana
|
||||
description: >
|
||||
Fleet view for the operations team, read only on the TSDB.
|
||||
customer-app:
|
||||
type: frontend
|
||||
label: Customer app
|
||||
sublabel: mobile
|
||||
description: >
|
||||
Shows the homeowner their heat pump and its alerts.
|
||||
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
homeowner:
|
||||
type: external
|
||||
label: Homeowner
|
||||
sublabel: customer app
|
||||
description: >
|
||||
Owns a heat pump; checks temperatures and gets fault alerts.
|
||||
ops-engineer:
|
||||
type: external
|
||||
label: Ops engineer
|
||||
sublabel: operations team
|
||||
description: >
|
||||
Watches the fleet, handles alerts and plans service visits.
|
||||
installer:
|
||||
type: external
|
||||
label: Installer
|
||||
sublabel: field service
|
||||
description: >
|
||||
Mounts heat pumps on site and registers them with the platform.
|
||||
@@ -0,0 +1,27 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
telemetry-platform:
|
||||
type: cloud
|
||||
label: IoT Telemetry
|
||||
sublabel: the system
|
||||
description: >
|
||||
Everything we build and run; broker, ingest, stores, rules and apps.
|
||||
diagram: 0500-building-blocks/level-1.archify
|
||||
heat-pump:
|
||||
type: external
|
||||
label: Heat pump
|
||||
sublabel: field device
|
||||
description: >
|
||||
Sends telemetry every 30 seconds over MQTT; built by a partner.
|
||||
push-service:
|
||||
type: external
|
||||
label: Push service
|
||||
sublabel: mobile push
|
||||
description: >
|
||||
Delivers push notifications to the customer app.
|
||||
service-desk:
|
||||
type: external
|
||||
label: Service desk
|
||||
sublabel: ticketing
|
||||
description: >
|
||||
Opens service tickets for faults that need a visit.
|
||||
@@ -0,0 +1,26 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Technical context
|
||||
output: technical-context.html
|
||||
components:
|
||||
- ref: engineer
|
||||
pos: [40, 60]
|
||||
size: [130, 60]
|
||||
- ref: wiki-admin
|
||||
pos: [40, 260]
|
||||
size: [130, 60]
|
||||
- ref: wiki
|
||||
pos: [280, 160]
|
||||
size: [150, 60]
|
||||
- ref: idp
|
||||
pos: [520, 60]
|
||||
size: [150, 60]
|
||||
- ref: object-store
|
||||
pos: [520, 260]
|
||||
size: [150, 60]
|
||||
connections:
|
||||
- { from: engineer, to: wiki, label: HTTPS, variant: emphasis }
|
||||
- { from: wiki-admin, to: wiki, label: kubectl }
|
||||
- { from: wiki, to: idp, label: OIDC, variant: security }
|
||||
- { from: wiki, to: object-store, label: S3 API }
|
||||
@@ -0,0 +1,47 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Building blocks - level 1
|
||||
output: level-1.html
|
||||
decisions: [postgres-full-text-search]
|
||||
components:
|
||||
- ref: engineer
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: web
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- ref: api
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- ref: db
|
||||
pos: [460, 360]
|
||||
size: [130, 60]
|
||||
- ref: backup-job
|
||||
pos: [670, 360]
|
||||
size: [130, 60]
|
||||
- ref: idp
|
||||
pos: [670, 60]
|
||||
size: [130, 60]
|
||||
- ref: object-store
|
||||
pos: [880, 160]
|
||||
size: [130, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Team Wiki
|
||||
wraps: [web, api, db, backup-job]
|
||||
connections:
|
||||
- { from: engineer, to: web, label: HTTPS, variant: emphasis }
|
||||
- { from: web, to: api, label: JSON, variant: emphasis }
|
||||
- { from: api, to: db, label: SQL, labelAt: [525, 234], decisions: [postgres-full-text-search] }
|
||||
- { from: api, to: idp, label: OIDC, variant: security }
|
||||
- { from: api, to: object-store, label: files }
|
||||
- { from: backup-job, to: db, label: dump }
|
||||
- { from: backup-job, to: object-store, label: upload }
|
||||
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
|
||||
@@ -0,0 +1,55 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Building blocks - level 2, Wiki API
|
||||
output: wiki-api.html
|
||||
components:
|
||||
- ref: web
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- id: auth
|
||||
type: security
|
||||
label: Auth
|
||||
sublabel: OIDC session
|
||||
pos: [250, 60]
|
||||
size: [130, 60]
|
||||
- id: pages
|
||||
type: backend
|
||||
label: Pages
|
||||
sublabel: revisions
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- id: search
|
||||
type: backend
|
||||
label: Search
|
||||
sublabel: full-text
|
||||
pos: [250, 260]
|
||||
size: [130, 60]
|
||||
decisions: [postgres-full-text-search]
|
||||
- id: attachments
|
||||
type: backend
|
||||
label: Attachments
|
||||
pos: [250, 360]
|
||||
size: [130, 60]
|
||||
- ref: idp
|
||||
pos: [460, 60]
|
||||
size: [130, 60]
|
||||
- ref: db
|
||||
pos: [460, 210]
|
||||
size: [130, 60]
|
||||
- ref: object-store
|
||||
pos: [460, 360]
|
||||
size: [130, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Wiki API
|
||||
wraps: [auth, pages, search, attachments]
|
||||
connections:
|
||||
- { from: web, to: auth, label: sign in, variant: security }
|
||||
- { from: web, to: pages, label: edit, labelAt: [222, 182] }
|
||||
- { from: web, to: search, label: query }
|
||||
- { from: web, to: attachments, label: upload }
|
||||
- { from: auth, to: idp, label: OIDC, variant: security }
|
||||
- { from: pages, to: db, label: SQL }
|
||||
- { from: search, to: db, label: SQL }
|
||||
- { from: attachments, to: object-store, label: S3 }
|
||||
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
diagram_type: sequence
|
||||
meta:
|
||||
title: Runtime - search and open a page
|
||||
output: search-page.html
|
||||
participants:
|
||||
- ref: engineer
|
||||
- ref: web
|
||||
- ref: api
|
||||
- { ref: db, label: DB }
|
||||
- { ref: object-store, label: Object store }
|
||||
messages:
|
||||
- { from: engineer, to: web, y: 160, label: type query, variant: emphasis }
|
||||
- { from: web, to: api, y: 210, label: GET /search }
|
||||
- { from: api, to: db, y: 260, label: full-text query }
|
||||
- { from: db, to: api, y: 310, label: ranked pages, variant: return }
|
||||
- { from: api, to: web, y: 360, label: results, variant: return }
|
||||
- { from: web, to: api, y: 410, label: GET /pages/id }
|
||||
- { from: api, to: object-store, y: 460, label: signed URL }
|
||||
- { from: api, to: web, y: 510, label: page, variant: return }
|
||||
@@ -0,0 +1,19 @@
|
||||
schema_version: 1
|
||||
diagram_type: sequence
|
||||
meta:
|
||||
title: Runtime - sign in
|
||||
output: sign-in.html
|
||||
decisions: [sso-only-via-company-idp]
|
||||
participants:
|
||||
- ref: engineer
|
||||
- ref: web
|
||||
- ref: api
|
||||
- { ref: idp, label: Company IdP }
|
||||
messages:
|
||||
- { from: engineer, to: web, y: 160, label: open wiki, variant: emphasis }
|
||||
- { from: web, to: api, y: 210, label: GET /session }
|
||||
- { from: api, to: web, y: 260, label: redirect, variant: return }
|
||||
- { from: web, to: idp, y: 310, label: OIDC login, variant: security }
|
||||
- { from: idp, to: api, y: 360, label: code, variant: return }
|
||||
- { from: api, to: idp, y: 410, label: token exchange, variant: security }
|
||||
- { from: api, to: web, y: 460, label: session cookie, variant: return }
|
||||
@@ -0,0 +1,48 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Deployment - production
|
||||
output: production.html
|
||||
components:
|
||||
- ref: engineer
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- id: ingress
|
||||
type: security
|
||||
label: Ingress
|
||||
sublabel: TLS
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- ref: web
|
||||
pos: [460, 60]
|
||||
size: [130, 60]
|
||||
- ref: api
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- ref: db
|
||||
pos: [670, 160]
|
||||
size: [130, 60]
|
||||
- ref: backup-job
|
||||
pos: [670, 360]
|
||||
size: [130, 60]
|
||||
- ref: idp
|
||||
pos: [460, 460]
|
||||
size: [130, 60]
|
||||
- ref: object-store
|
||||
pos: [880, 460]
|
||||
size: [130, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Company cluster
|
||||
wraps: [ingress, web, api, db, backup-job]
|
||||
- kind: security-group
|
||||
label: Namespace team-wiki
|
||||
wraps: [web, api, db, backup-job]
|
||||
connections:
|
||||
- { from: engineer, to: ingress, label: HTTPS, variant: emphasis }
|
||||
- { from: ingress, to: web, label: static }
|
||||
- { from: ingress, to: api, label: /api, variant: emphasis }
|
||||
- { from: api, to: db, label: SQL }
|
||||
- { 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 }
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: postgres-full-text-search
|
||||
title: PostgreSQL full-text search, no search engine
|
||||
status: accepted
|
||||
date: 2026-10-05
|
||||
elements: [api, db]
|
||||
diagrams: [0500-building-blocks/level-1.archify, 0500-building-blocks/wiki-api.archify]
|
||||
context: >
|
||||
The wiki holds a few thousand pages for one team. A
|
||||
separate search engine would be one more service to run,
|
||||
back up and keep in sync.
|
||||
decision: >
|
||||
Search uses PostgreSQL full-text search on a generated
|
||||
column of each page. The API queries it in the same
|
||||
transaction as the page data.
|
||||
consequences: >
|
||||
Results are never stale and backups cover search too.
|
||||
Ranking is simpler than a search engine. Revisit when
|
||||
the wiki grows past 100000 pages.
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: sso-only-via-company-idp
|
||||
title: Sign-in only through the company identity provider
|
||||
status: accepted
|
||||
date: 2026-10-12
|
||||
elements: [idp, api, web]
|
||||
diagrams: [0300-context/technical-context.archify, 0600-runtime/sign-in.archify]
|
||||
context: >
|
||||
Leavers kept access to the old wiki because it had its
|
||||
own passwords. Nobody owned the user list.
|
||||
decision: >
|
||||
The wiki has no local accounts. Users sign in with OIDC
|
||||
at the company identity provider; team groups map to
|
||||
wiki spaces.
|
||||
consequences: >
|
||||
Offboarding removes wiki access at once. The wiki cannot
|
||||
be used when the identity provider is down. The admin
|
||||
needs a break-glass account kept in the vault.
|
||||
@@ -0,0 +1,66 @@
|
||||
schema_version: 1
|
||||
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.
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Team Wiki - business context
|
||||
output: main.html
|
||||
decisions: [sso-only-via-company-idp]
|
||||
components:
|
||||
- ref: engineer
|
||||
pos: [40, 60]
|
||||
size: [130, 60]
|
||||
- ref: wiki-admin
|
||||
pos: [40, 260]
|
||||
size: [130, 60]
|
||||
- ref: wiki
|
||||
pos: [280, 160]
|
||||
size: [150, 60]
|
||||
- ref: idp
|
||||
pos: [520, 60]
|
||||
size: [150, 60]
|
||||
- ref: object-store
|
||||
pos: [520, 260]
|
||||
size: [150, 60]
|
||||
connections:
|
||||
- { from: engineer, to: wiki, label: reads, variant: emphasis }
|
||||
- { from: wiki-admin, to: wiki, label: runs }
|
||||
- { from: wiki, to: idp, label: sign-in, variant: security }
|
||||
- { from: wiki, to: object-store, label: files }
|
||||
cards:
|
||||
- dot: cyan
|
||||
title: 1 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: slate
|
||||
title: 2 Constraints
|
||||
items:
|
||||
- Runs on the company Kubernetes cluster
|
||||
- Sign-in only via the company identity provider
|
||||
- dot: emerald
|
||||
title: 10 Quality scenarios
|
||||
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
|
||||
- dot: rose
|
||||
title: 11 Risks
|
||||
items:
|
||||
- Identity provider outage blocks all sign-ins
|
||||
- Backups untested until a restore drill is run
|
||||
- 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
|
||||
@@ -0,0 +1,33 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
web:
|
||||
type: frontend
|
||||
label: Web App
|
||||
sublabel: React
|
||||
brand: react
|
||||
description: >
|
||||
Page editor, viewer and search box in the browser; talks
|
||||
only to the API.
|
||||
api:
|
||||
type: backend
|
||||
label: Wiki API
|
||||
sublabel: REST
|
||||
description: >
|
||||
Pages, search, attachments and access checks; the only
|
||||
writer of the database.
|
||||
diagram: 0500-building-blocks/wiki-api.archify
|
||||
db:
|
||||
type: database
|
||||
label: Database
|
||||
sublabel: PostgreSQL
|
||||
brand: postgresql
|
||||
description: >
|
||||
Pages, revisions, users and the full-text index; the
|
||||
source of truth.
|
||||
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.
|
||||
@@ -0,0 +1,15 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
engineer:
|
||||
type: external
|
||||
label: Engineer
|
||||
sublabel: team member
|
||||
description: >
|
||||
Reads and edits pages, searches, attaches files; signs in
|
||||
with the company account.
|
||||
wiki-admin:
|
||||
type: external
|
||||
label: Wiki admin
|
||||
sublabel: platform team
|
||||
description: >
|
||||
Runs the wiki, restores backups and manages spaces.
|
||||
@@ -0,0 +1,24 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
wiki:
|
||||
type: cloud
|
||||
label: Team Wiki
|
||||
sublabel: the system
|
||||
description: >
|
||||
Everything we build and run; web app, API, database and
|
||||
the backup job.
|
||||
diagram: 0500-building-blocks/level-1.archify
|
||||
idp:
|
||||
type: security
|
||||
label: Identity provider
|
||||
sublabel: company SSO
|
||||
description: >
|
||||
The company identity provider; signs users in over OIDC
|
||||
and owns team membership.
|
||||
object-store:
|
||||
type: external
|
||||
label: Object storage
|
||||
sublabel: S3-compatible
|
||||
description: >
|
||||
Company object storage; holds attachments and nightly
|
||||
backups in separate buckets.
|
||||
@@ -0,0 +1,36 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Business actors and services
|
||||
output: business-services.html
|
||||
components:
|
||||
- ref: hr
|
||||
pos: [40, 60]
|
||||
size: [130, 60]
|
||||
- ref: manager
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: service-desk
|
||||
pos: [40, 260]
|
||||
size: [130, 60]
|
||||
- ref: onboard
|
||||
pos: [250, 160]
|
||||
size: [150, 60]
|
||||
diagram: 0100-business/onboard-employee.archify
|
||||
- ref: onboarding-svc
|
||||
pos: [480, 60]
|
||||
size: [130, 60]
|
||||
- ref: workplace-svc
|
||||
pos: [480, 260]
|
||||
size: [130, 60]
|
||||
- ref: new-hire
|
||||
pos: [690, 160]
|
||||
size: [130, 60]
|
||||
connections:
|
||||
- { from: hr, to: onboard, label: assigned }
|
||||
- { from: manager, to: onboard, label: assigned }
|
||||
- { from: service-desk, to: onboard, label: assigned }
|
||||
- { from: onboard, to: onboarding-svc, label: realizes }
|
||||
- { from: onboard, to: workplace-svc, label: realizes }
|
||||
- { from: onboarding-svc, to: new-hire, label: serves, variant: emphasis }
|
||||
- { from: workplace-svc, to: new-hire, label: serves }
|
||||
@@ -0,0 +1,25 @@
|
||||
schema_version: 2
|
||||
diagram_type: workflow
|
||||
meta:
|
||||
title: Onboard Employee
|
||||
output: onboard-employee.html
|
||||
viewBox: [1040, 660]
|
||||
lanes:
|
||||
- { id: hr-lane, label: HR }
|
||||
- { id: manager-lane, label: Hiring manager }
|
||||
- { id: desk-lane, label: IT service desk }
|
||||
- { id: hire-lane, label: New hire }
|
||||
mainPath: [contract-signed, record, request, create-accounts, issue-laptop, first-day]
|
||||
nodes:
|
||||
- { ref: contract-signed, lane: hr-lane, col: 0, width: 120 }
|
||||
- { id: record, lane: hr-lane, col: 1, type: backend, label: Create record, tag: Business Process }
|
||||
- { id: request, lane: manager-lane, col: 2, type: frontend, label: Request access, tag: Business Process }
|
||||
- { ref: create-accounts, lane: desk-lane, col: 3, width: 120, decisions: [hr-system-drives-identity] }
|
||||
- { ref: issue-laptop, lane: desk-lane, col: 4, decisions: [zero-touch-laptops] }
|
||||
- { ref: first-day, lane: hire-lane, col: 5 }
|
||||
edges:
|
||||
- { from: contract-signed, to: record, label: triggers }
|
||||
- { from: record, to: request, label: notifies }
|
||||
- { from: request, to: create-accounts, label: ticket }
|
||||
- { from: create-accounts, to: issue-laptop, label: then }
|
||||
- { from: issue-laptop, to: first-day, label: hand over }
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Application components, services and data
|
||||
output: application-components.html
|
||||
components:
|
||||
- ref: provisioning-svc
|
||||
pos: [250, 60]
|
||||
size: [130, 60]
|
||||
- ref: portal
|
||||
pos: [460, 60]
|
||||
size: [130, 60]
|
||||
- ref: device-svc
|
||||
pos: [670, 60]
|
||||
size: [130, 60]
|
||||
- ref: hr-system
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: iam
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- ref: itsm
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- ref: mdm-app
|
||||
pos: [670, 160]
|
||||
size: [130, 60]
|
||||
- ref: employee-record
|
||||
pos: [40, 260]
|
||||
size: [130, 60]
|
||||
- ref: account
|
||||
pos: [250, 260]
|
||||
size: [130, 60]
|
||||
- ref: asset
|
||||
pos: [460, 260]
|
||||
size: [130, 60]
|
||||
connections:
|
||||
- { from: iam, to: provisioning-svc, label: realizes }
|
||||
- { from: itsm, to: portal, label: realizes }
|
||||
- { from: mdm-app, to: device-svc, label: realizes }
|
||||
- { from: hr-system, to: employee-record, label: writes, labelAt: [105, 234] }
|
||||
- { from: iam, to: account, label: writes, labelAt: [315, 234] }
|
||||
- { from: itsm, to: asset, label: writes, labelAt: [525, 234] }
|
||||
- { from: mdm-app, to: asset, label: reads }
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Application cooperation
|
||||
output: application-cooperation.html
|
||||
decisions: [hr-system-drives-identity]
|
||||
components:
|
||||
- ref: hr-system
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: iam
|
||||
pos: [250, 60]
|
||||
size: [130, 60]
|
||||
diagram: 0200-application/application-components.archify
|
||||
- ref: itsm
|
||||
pos: [250, 260]
|
||||
size: [130, 60]
|
||||
- ref: collab
|
||||
pos: [460, 60]
|
||||
size: [130, 60]
|
||||
- ref: mdm-app
|
||||
pos: [460, 260]
|
||||
size: [130, 60]
|
||||
connections:
|
||||
- { from: hr-system, to: iam, label: joiner event, variant: emphasis, decisions: [hr-system-drives-identity] }
|
||||
- { from: hr-system, to: itsm, label: laptop request }
|
||||
- { from: iam, to: collab, label: provisions }
|
||||
- { from: iam, to: mdm-app, label: users }
|
||||
- { from: itsm, to: mdm-app, label: assigns }
|
||||
@@ -0,0 +1,42 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Technology layer
|
||||
output: infrastructure.html
|
||||
decisions: [zero-touch-laptops]
|
||||
components:
|
||||
- ref: hr-saas
|
||||
pos: [40, 60]
|
||||
size: [130, 60]
|
||||
- ref: sso
|
||||
pos: [250, 60]
|
||||
size: [130, 60]
|
||||
- ref: directory
|
||||
pos: [460, 60]
|
||||
size: [130, 60]
|
||||
- ref: itsm-saas
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: mdm-saas
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- ref: laptop
|
||||
pos: [460, 360]
|
||||
size: [130, 60]
|
||||
- ref: office-net
|
||||
pos: [250, 360]
|
||||
size: [130, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: SaaS tenants
|
||||
wraps: [hr-saas, sso, directory, itsm-saas, mdm-saas]
|
||||
- kind: security-group
|
||||
label: Office
|
||||
wraps: [laptop, office-net]
|
||||
connections:
|
||||
- { from: directory, to: sso, label: realizes }
|
||||
- { from: sso, to: hr-saas, label: serves }
|
||||
- { from: sso, to: itsm-saas, label: serves }
|
||||
- { from: directory, to: mdm-saas, label: devices, labelAt: [525, 134] }
|
||||
- { from: mdm-saas, to: laptop, label: manages, labelAt: [525, 234], variant: security, decisions: [zero-touch-laptops] }
|
||||
- { from: laptop, to: office-net, label: connects }
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: hr-system-drives-identity
|
||||
title: The HR system drives identity
|
||||
status: accepted
|
||||
date: 2026-09-08
|
||||
elements: [hr-system, iam, account, employee-record]
|
||||
diagrams: [0200-application/application-cooperation.archify, 0100-business/onboard-employee.archify]
|
||||
context: >
|
||||
Accounts were created by hand from emails sent by HR.
|
||||
New hires waited days for access, and leavers kept
|
||||
accounts for weeks after their last day.
|
||||
decision: >
|
||||
The HR system is the source of truth for joiners and
|
||||
leavers. Identity management reads its events and
|
||||
creates, changes and disables accounts automatically.
|
||||
consequences: >
|
||||
No account without an employee record. HR data quality
|
||||
now decides access, so start dates must be right. The
|
||||
service desk only handles exceptions.
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: zero-touch-laptops
|
||||
title: Zero-touch enrollment for laptops
|
||||
status: accepted
|
||||
date: 2026-10-05
|
||||
elements: [mdm-app, mdm-saas, laptop, device-svc, asset]
|
||||
diagrams: [0300-technology/infrastructure.archify, 0100-business/onboard-employee.archify]
|
||||
context: >
|
||||
Every laptop was imaged by hand at the service desk,
|
||||
which took half a day per device and left settings that
|
||||
differed from one laptop to the next.
|
||||
decision: >
|
||||
Laptops are registered in device management at purchase.
|
||||
They configure themselves at first sign-in over any
|
||||
internet connection; the office network needs no VPN.
|
||||
consequences: >
|
||||
Laptops can be shipped straight to the new hire. A lost
|
||||
laptop is wiped remotely. Setup depends on the MDM
|
||||
tenant being reachable on the first day.
|
||||
@@ -0,0 +1,59 @@
|
||||
schema_version: 1
|
||||
model:
|
||||
id: hr-onboarding
|
||||
name: HR Onboarding
|
||||
description: >
|
||||
An ArchiMate example: how a new employee is onboarded, from signed
|
||||
contract to first day. Business, application and technology layers
|
||||
map to folders; each element's ArchiMate type is shown as its tag.
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: HR Onboarding - layered view
|
||||
output: main.html
|
||||
components:
|
||||
- ref: new-hire
|
||||
pos: [40, 70]
|
||||
size: [170, 60]
|
||||
- ref: onboarding-svc
|
||||
pos: [270, 70]
|
||||
size: [170, 60]
|
||||
- ref: onboard
|
||||
pos: [500, 70]
|
||||
size: [170, 60]
|
||||
- ref: portal
|
||||
pos: [40, 270]
|
||||
size: [170, 60]
|
||||
- ref: iam
|
||||
pos: [270, 270]
|
||||
size: [170, 60]
|
||||
- ref: provisioning-svc
|
||||
pos: [500, 270]
|
||||
size: [170, 60]
|
||||
- ref: office-net
|
||||
pos: [40, 470]
|
||||
size: [170, 60]
|
||||
- ref: sso
|
||||
pos: [270, 470]
|
||||
size: [170, 60]
|
||||
- ref: directory
|
||||
pos: [500, 470]
|
||||
size: [170, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Business layer
|
||||
wraps: [new-hire, onboarding-svc, onboard]
|
||||
- kind: region
|
||||
label: Application layer
|
||||
wraps: [portal, iam, provisioning-svc]
|
||||
- kind: region
|
||||
label: Technology layer
|
||||
wraps: [office-net, sso, directory]
|
||||
connections:
|
||||
- { from: onboarding-svc, to: new-hire, label: serves, variant: emphasis }
|
||||
- { from: onboard, to: onboarding-svc, label: realizes }
|
||||
- { from: portal, to: new-hire, label: serves }
|
||||
- { from: provisioning-svc, to: onboard, label: serves }
|
||||
- { from: iam, to: provisioning-svc, label: realizes }
|
||||
- { from: office-net, to: portal, label: serves }
|
||||
- { from: sso, to: iam, label: serves }
|
||||
- { from: directory, to: sso, label: realizes }
|
||||
@@ -0,0 +1,81 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
hr-system:
|
||||
type: backend
|
||||
label: HR system
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Holds employee records and contracts; the source of truth for joiners.
|
||||
diagram: 0200-application/application-cooperation.archify
|
||||
iam:
|
||||
type: security
|
||||
label: Identity mgmt
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Creates and removes accounts from HR events; single sign-on for all apps.
|
||||
diagram: 0200-application/application-components.archify
|
||||
itsm:
|
||||
type: backend
|
||||
label: IT service mgmt
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Tickets, requests and the asset inventory of the IT service desk.
|
||||
mdm-app:
|
||||
type: backend
|
||||
label: Device mgmt
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Enrolls laptops, pushes policies and apps, wipes lost devices.
|
||||
collab:
|
||||
type: backend
|
||||
label: Mail and chat
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Mailbox, calendar and chat; accounts provisioned by identity management.
|
||||
provisioning-svc:
|
||||
type: cloud
|
||||
label: Provisioning
|
||||
sublabel: App Service
|
||||
tag: App Service
|
||||
description: >
|
||||
Account create, change and disable, triggered by the HR system.
|
||||
device-svc:
|
||||
type: cloud
|
||||
label: Enrollment
|
||||
sublabel: App Service
|
||||
tag: App Service
|
||||
description: >
|
||||
Zero-touch enrollment; the laptop configures itself at first sign-in.
|
||||
portal:
|
||||
type: frontend
|
||||
label: Service portal
|
||||
sublabel: App Interface
|
||||
tag: App Interface
|
||||
description: >
|
||||
Where managers request equipment and access for a new hire.
|
||||
employee-record:
|
||||
type: database
|
||||
label: Employee record
|
||||
sublabel: Data Object
|
||||
tag: Data Object
|
||||
description: >
|
||||
Name, role, department, manager and start date of an employee.
|
||||
account:
|
||||
type: database
|
||||
label: Account
|
||||
sublabel: Data Object
|
||||
tag: Data Object
|
||||
description: >
|
||||
User id, groups and licences of one person.
|
||||
asset:
|
||||
type: database
|
||||
label: Asset
|
||||
sublabel: Data Object
|
||||
tag: Data Object
|
||||
description: >
|
||||
A laptop with serial number, owner and enrollment state.
|
||||
@@ -0,0 +1,81 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
new-hire:
|
||||
type: external
|
||||
label: New hire
|
||||
sublabel: Business Actor
|
||||
tag: Business Actor
|
||||
description: >
|
||||
The person joining the company; signs the contract and starts on day one.
|
||||
hr:
|
||||
type: external
|
||||
label: HR officer
|
||||
sublabel: Business Role
|
||||
tag: Business Role
|
||||
description: >
|
||||
Prepares the contract and the employee record; owns the onboarding process.
|
||||
manager:
|
||||
type: external
|
||||
label: Hiring manager
|
||||
sublabel: Business Role
|
||||
tag: Business Role
|
||||
description: >
|
||||
Requests access and equipment for the new hire and plans the first day.
|
||||
service-desk:
|
||||
type: external
|
||||
label: IT service desk
|
||||
sublabel: Business Role
|
||||
tag: Business Role
|
||||
description: >
|
||||
Creates accounts, prepares the laptop and hands it over.
|
||||
onboard:
|
||||
type: backend
|
||||
label: Onboard Employee
|
||||
sublabel: Business Process
|
||||
tag: Business Process
|
||||
description: >
|
||||
From signed contract to a productive first day.
|
||||
diagram: 0100-business/onboard-employee.archify
|
||||
onboarding-svc:
|
||||
type: cloud
|
||||
label: Onboarding
|
||||
sublabel: Business Service
|
||||
tag: Business Service
|
||||
description: >
|
||||
What the new hire gets from HR; contract, record, welcome and first day plan.
|
||||
diagram: 0100-business/business-services.archify
|
||||
workplace-svc:
|
||||
type: cloud
|
||||
label: Workplace setup
|
||||
sublabel: Business Service
|
||||
tag: Business Service
|
||||
description: >
|
||||
Accounts and a ready laptop, delivered by the IT service desk.
|
||||
contract-signed:
|
||||
type: messagebus
|
||||
label: Contract signed
|
||||
sublabel: Business Event
|
||||
tag: Business Event
|
||||
description: >
|
||||
Starts the process; HR records the start date.
|
||||
create-accounts:
|
||||
type: backend
|
||||
label: Create accounts
|
||||
sublabel: Business Process
|
||||
tag: Business Process
|
||||
description: >
|
||||
Service desk confirms the accounts the identity system provisioned.
|
||||
issue-laptop:
|
||||
type: backend
|
||||
label: Issue laptop
|
||||
sublabel: Business Process
|
||||
tag: Business Process
|
||||
description: >
|
||||
An enrolled laptop is assigned and handed over.
|
||||
first-day:
|
||||
type: messagebus
|
||||
label: First day
|
||||
sublabel: Business Event
|
||||
tag: Business Event
|
||||
description: >
|
||||
The new hire signs in for the first time; the process ends.
|
||||
@@ -0,0 +1,53 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
hr-saas:
|
||||
type: cloud
|
||||
label: HR tenant
|
||||
sublabel: Node
|
||||
tag: Node
|
||||
description: >
|
||||
The SaaS tenant that runs the HR system.
|
||||
diagram: 0300-technology/infrastructure.archify
|
||||
itsm-saas:
|
||||
type: cloud
|
||||
label: ITSM tenant
|
||||
sublabel: Node
|
||||
tag: Node
|
||||
description: >
|
||||
The SaaS tenant that runs IT service management.
|
||||
mdm-saas:
|
||||
type: cloud
|
||||
label: MDM tenant
|
||||
sublabel: Node
|
||||
tag: Node
|
||||
description: >
|
||||
The SaaS tenant that runs device management.
|
||||
directory:
|
||||
type: backend
|
||||
label: Directory
|
||||
sublabel: System Software
|
||||
tag: System Software
|
||||
description: >
|
||||
Cloud directory service; users, groups and devices.
|
||||
diagram: 0300-technology/infrastructure.archify
|
||||
sso:
|
||||
type: security
|
||||
label: Single sign-on
|
||||
sublabel: Tech Service
|
||||
tag: Tech Service
|
||||
description: >
|
||||
SAML and OIDC sign-in for every SaaS tenant, backed by the directory.
|
||||
laptop:
|
||||
type: frontend
|
||||
label: Laptop
|
||||
sublabel: Device
|
||||
tag: Device
|
||||
description: >
|
||||
Company laptop, enrolled before it is handed over.
|
||||
office-net:
|
||||
type: messagebus
|
||||
label: Office network
|
||||
sublabel: Network
|
||||
tag: Network
|
||||
description: >
|
||||
Wired and wireless network of the office; internet only, no VPN.
|
||||
@@ -0,0 +1,31 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Business layer
|
||||
output: business-layer.html
|
||||
components:
|
||||
- ref: customer
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: insurant
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- ref: claim-registration
|
||||
pos: [460, 60]
|
||||
size: [150, 60]
|
||||
- ref: claim-payment
|
||||
pos: [460, 260]
|
||||
size: [150, 60]
|
||||
- ref: handle-claim
|
||||
pos: [690, 160]
|
||||
size: [150, 60]
|
||||
- ref: claims-handler
|
||||
pos: [920, 160]
|
||||
size: [130, 60]
|
||||
connections:
|
||||
- { from: customer, to: insurant, label: assigned to }
|
||||
- { from: claim-registration, to: insurant, label: serves, variant: emphasis }
|
||||
- { from: claim-payment, to: insurant, label: serves }
|
||||
- { from: handle-claim, to: claim-registration, label: realizes }
|
||||
- { from: handle-claim, to: claim-payment, label: realizes }
|
||||
- { from: claims-handler, to: handle-claim, label: assigned to }
|
||||
@@ -0,0 +1,29 @@
|
||||
schema_version: 2
|
||||
diagram_type: workflow
|
||||
meta:
|
||||
title: Handle Claim
|
||||
output: handle-claim.html
|
||||
viewBox: [840, 534]
|
||||
lanes:
|
||||
- { id: insurant-lane, label: Insurant }
|
||||
- { id: handler-lane, label: Claims handler }
|
||||
- { id: systems-lane, label: Applications }
|
||||
mainPath: [damage, register, accept, valuate, pay]
|
||||
nodes:
|
||||
- { id: damage, lane: insurant-lane, col: 0, type: external, label: Damage occurs, tag: Business Event }
|
||||
- { ref: insurant, lane: insurant-lane, col: 5 }
|
||||
- { id: register, lane: handler-lane, col: 1, type: backend, label: Register, tag: Business Process }
|
||||
- { id: accept, lane: handler-lane, col: 2, type: security, label: Accept, sublabel: check coverage, tag: Business Process }
|
||||
- { id: valuate, lane: handler-lane, col: 3, type: backend, label: Valuate, tag: Business Process }
|
||||
- { id: pay, lane: handler-lane, col: 4, type: backend, label: Pay, tag: Business Process }
|
||||
- { ref: claims-app, lane: systems-lane, col: 2 }
|
||||
- { ref: payment, lane: systems-lane, col: 4 }
|
||||
edges:
|
||||
- { from: damage, to: register, label: report }
|
||||
- { from: register, to: accept }
|
||||
- { from: accept, to: valuate, label: covered }
|
||||
- { from: valuate, to: pay, label: approved }
|
||||
- { from: pay, to: insurant, label: paid }
|
||||
- { from: accept, to: insurant, label: rejected, role: branch, variant: dashed }
|
||||
- { from: claims-app, to: accept, label: serves, role: async }
|
||||
- { from: payment, to: pay, label: serves, role: async }
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Application cooperation
|
||||
output: application-cooperation.html
|
||||
components:
|
||||
- ref: portal
|
||||
pos: [40, 260]
|
||||
size: [130, 60]
|
||||
- ref: claims-app
|
||||
pos: [250, 260]
|
||||
size: [130, 60]
|
||||
- ref: crm
|
||||
pos: [250, 60]
|
||||
size: [130, 60]
|
||||
- ref: policy-admin
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
decisions: [policies-stay-on-mainframe]
|
||||
- ref: doc-mgmt
|
||||
pos: [460, 360]
|
||||
size: [130, 60]
|
||||
decisions: [documents-in-object-storage]
|
||||
- ref: payment
|
||||
pos: [250, 460]
|
||||
size: [130, 60]
|
||||
connections:
|
||||
- { from: portal, to: claims-app, label: claims, variant: emphasis }
|
||||
- { from: crm, to: claims-app, label: customer, labelAt: [315, 134] }
|
||||
- { from: policy-admin, to: claims-app, label: coverage, decisions: [policies-stay-on-mainframe] }
|
||||
- { from: claims-app, to: doc-mgmt, label: documents }
|
||||
- { from: claims-app, to: payment, label: payments, labelAt: [315, 334] }
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Application structure
|
||||
output: application-structure.html
|
||||
components:
|
||||
- ref: portal
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: claims-admin
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- ref: claims-app
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- ref: claim
|
||||
pos: [460, 360]
|
||||
size: [130, 60]
|
||||
- ref: crm
|
||||
pos: [670, 60]
|
||||
size: [130, 60]
|
||||
- ref: customer-file
|
||||
pos: [880, 60]
|
||||
size: [130, 60]
|
||||
- ref: policy-admin
|
||||
pos: [670, 260]
|
||||
size: [130, 60]
|
||||
- ref: policy
|
||||
pos: [880, 260]
|
||||
size: [130, 60]
|
||||
connections:
|
||||
- { from: claims-admin, to: portal, label: serves, variant: emphasis }
|
||||
- { from: claims-app, to: claims-admin, label: realizes }
|
||||
- { from: claims-app, to: claim, label: accesses, labelAt: [525, 234] }
|
||||
- { from: crm, to: customer-file, label: accesses }
|
||||
- { from: policy-admin, to: policy, label: accesses }
|
||||
@@ -0,0 +1,45 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Technology layer
|
||||
output: infrastructure.html
|
||||
components:
|
||||
- ref: dmz
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: doc-store
|
||||
pos: [250, 60]
|
||||
size: [130, 60]
|
||||
decisions: [documents-in-object-storage]
|
||||
- ref: app-servers
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- ref: db-service
|
||||
pos: [250, 260]
|
||||
size: [130, 60]
|
||||
- ref: db-cluster
|
||||
pos: [250, 360]
|
||||
size: [130, 60]
|
||||
- ref: mq
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- ref: mainframe
|
||||
pos: [670, 160]
|
||||
size: [130, 60]
|
||||
decisions: [policies-stay-on-mainframe]
|
||||
- ref: dc-lan
|
||||
pos: [670, 360]
|
||||
size: [130, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Data centre
|
||||
wraps: [doc-store, app-servers, db-service, db-cluster, mq, mainframe, dc-lan]
|
||||
connections:
|
||||
- { from: dmz, to: app-servers, label: HTTPS, variant: security }
|
||||
- { from: app-servers, to: doc-store, label: S3 API }
|
||||
- { from: db-service, to: app-servers, label: serves }
|
||||
- { from: db-cluster, to: db-service, label: realizes }
|
||||
- { from: app-servers, to: mq, label: MQ }
|
||||
- { from: mq, to: mainframe, label: bridge }
|
||||
- { from: db-cluster, to: dc-lan, label: LAN }
|
||||
- { from: mainframe, to: dc-lan, label: LAN, labelAt: [735, 234] }
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: policies-stay-on-mainframe
|
||||
title: Policies stay on the mainframe
|
||||
status: accepted
|
||||
date: 2026-09-08
|
||||
elements: [policy-admin, mainframe, mq, claims-app]
|
||||
diagrams: [0200-application/application-cooperation.archify, 0300-technology/infrastructure.archify]
|
||||
context: >
|
||||
The new claims application needs coverage data for every
|
||||
claim. Policy administration has run on the mainframe for
|
||||
twenty years and a migration was estimated at three years.
|
||||
decision: >
|
||||
Policy administration stays on the mainframe. The claims
|
||||
application reads coverage through the message queue bridge
|
||||
and never copies policies into its own database.
|
||||
consequences: >
|
||||
Accepting a claim depends on the mainframe being up during
|
||||
office hours. The queue bridge must be kept and tested.
|
||||
A later migration needs its own decision.
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: documents-in-object-storage
|
||||
title: Claim documents in object storage
|
||||
status: accepted
|
||||
date: 2026-10-14
|
||||
elements: [doc-mgmt, doc-store, claims-app]
|
||||
diagrams: [0200-application/application-cooperation.archify, 0300-technology/infrastructure.archify]
|
||||
context: >
|
||||
Photos and expert reports were stored as blobs in the claims
|
||||
database. The database grew by forty gigabytes a month and
|
||||
backups no longer fitted the nightly window.
|
||||
decision: >
|
||||
Document management stores every file in the document store
|
||||
and keeps only a reference in the claim. The claims
|
||||
application never writes files itself.
|
||||
consequences: >
|
||||
Database backups shrink and stay fast. Documents get their own
|
||||
retention rules. A claim and its files are restored from two
|
||||
places after an incident.
|
||||
@@ -0,0 +1,59 @@
|
||||
schema_version: 1
|
||||
model:
|
||||
id: insurance-claims
|
||||
name: Insurance Claims
|
||||
description: >
|
||||
ArchiMate example: how Halbrook Mutual handles claims. The business,
|
||||
application and technology layers are mapped to folders, and each
|
||||
element's ArchiMate type is shown as its tag.
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Insurance Claims - layered view
|
||||
output: main.html
|
||||
components:
|
||||
- ref: insurant
|
||||
pos: [40, 70]
|
||||
size: [170, 60]
|
||||
- ref: claim-registration
|
||||
pos: [270, 70]
|
||||
size: [170, 60]
|
||||
- ref: handle-claim
|
||||
pos: [500, 70]
|
||||
size: [170, 60]
|
||||
- ref: portal
|
||||
pos: [40, 270]
|
||||
size: [170, 60]
|
||||
- ref: claims-app
|
||||
pos: [270, 270]
|
||||
size: [170, 60]
|
||||
- ref: claims-admin
|
||||
pos: [500, 270]
|
||||
size: [170, 60]
|
||||
- ref: dmz
|
||||
pos: [40, 470]
|
||||
size: [170, 60]
|
||||
- ref: app-servers
|
||||
pos: [270, 470]
|
||||
size: [170, 60]
|
||||
- ref: db-cluster
|
||||
pos: [500, 470]
|
||||
size: [170, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Business layer
|
||||
wraps: [insurant, claim-registration, handle-claim]
|
||||
- kind: region
|
||||
label: Application layer
|
||||
wraps: [portal, claims-app, claims-admin]
|
||||
- kind: region
|
||||
label: Technology layer
|
||||
wraps: [dmz, app-servers, db-cluster]
|
||||
connections:
|
||||
- { from: claim-registration, to: insurant, label: serves, variant: emphasis }
|
||||
- { from: handle-claim, to: claim-registration, label: realizes }
|
||||
- { from: portal, to: insurant, label: serves }
|
||||
- { from: claims-admin, to: handle-claim, label: serves }
|
||||
- { from: claims-app, to: claims-admin, label: realizes }
|
||||
- { from: dmz, to: portal, label: serves }
|
||||
- { from: app-servers, to: claims-app, label: serves }
|
||||
- { from: db-cluster, to: app-servers, label: serves }
|
||||
@@ -0,0 +1,76 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
portal:
|
||||
type: frontend
|
||||
label: Customer Portal
|
||||
sublabel: App Interface
|
||||
tag: App Interface
|
||||
description: >
|
||||
Web and mobile front end where customers report claims and
|
||||
follow their status.
|
||||
claims-admin:
|
||||
type: cloud
|
||||
label: Claims Admin
|
||||
sublabel: App Service
|
||||
tag: App Service
|
||||
description: >
|
||||
Register, look up and update claims; used by the portal and
|
||||
by claims handlers.
|
||||
claims-app:
|
||||
type: backend
|
||||
label: Claims App
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Owns claims from registration to payment; the system of
|
||||
record for claims.
|
||||
diagram: 0200-application/application-structure.archify
|
||||
crm:
|
||||
type: backend
|
||||
label: CRM
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Customer contacts, addresses and the customer file.
|
||||
policy-admin:
|
||||
type: backend
|
||||
label: Policy Admin
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Policies, coverage and premiums; runs on the mainframe.
|
||||
doc-mgmt:
|
||||
type: backend
|
||||
label: Document Mgmt
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Scanned letters, photos and expert reports attached to claims.
|
||||
payment:
|
||||
type: backend
|
||||
label: Payment
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Sends approved claim payments to the bank in daily batches.
|
||||
claim:
|
||||
type: database
|
||||
label: Claim
|
||||
sublabel: Data Object
|
||||
tag: Data Object
|
||||
description: >
|
||||
One reported damage, its valuation and its payment status.
|
||||
policy:
|
||||
type: database
|
||||
label: Policy
|
||||
sublabel: Data Object
|
||||
tag: Data Object
|
||||
description: >
|
||||
Coverage, deductible and term of an insurance contract.
|
||||
customer-file:
|
||||
type: database
|
||||
label: Customer File
|
||||
sublabel: Data Object
|
||||
tag: Data Object
|
||||
description: >
|
||||
Everything known about a customer; contacts, policies, claims.
|
||||
@@ -0,0 +1,50 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
customer:
|
||||
type: external
|
||||
label: Customer
|
||||
sublabel: Business Actor
|
||||
tag: Business Actor
|
||||
description: >
|
||||
A person or small business holding one or more policies
|
||||
with Halbrook Mutual.
|
||||
insurant:
|
||||
type: external
|
||||
label: Insurant
|
||||
sublabel: Business Role
|
||||
tag: Business Role
|
||||
description: >
|
||||
The role a customer plays while a claim is open; reports
|
||||
damage and receives the payment.
|
||||
claims-handler:
|
||||
type: external
|
||||
label: Claims handler
|
||||
sublabel: Business Role
|
||||
tag: Business Role
|
||||
description: >
|
||||
Employee of the claims department who accepts, valuates
|
||||
and approves claims.
|
||||
handle-claim:
|
||||
type: backend
|
||||
label: Handle Claim
|
||||
sublabel: Business Process
|
||||
tag: Business Process
|
||||
description: >
|
||||
Register, accept, valuate and pay a claim; the core process
|
||||
of the claims department.
|
||||
diagram: 0100-business/handle-claim.archify
|
||||
claim-registration:
|
||||
type: frontend
|
||||
label: Claim Registration
|
||||
sublabel: Business Service
|
||||
tag: Business Service
|
||||
description: >
|
||||
Lets an insurant report damage by phone, mail or the
|
||||
customer portal.
|
||||
claim-payment:
|
||||
type: frontend
|
||||
label: Claim Payment
|
||||
sublabel: Business Service
|
||||
tag: Business Service
|
||||
description: >
|
||||
Pays the valuated amount to the insurant or a repairer.
|
||||
@@ -0,0 +1,62 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
app-servers:
|
||||
type: backend
|
||||
label: App Servers
|
||||
sublabel: Node
|
||||
tag: Node
|
||||
description: >
|
||||
Two virtual machine hosts running the claims app, CRM and the
|
||||
portal back end.
|
||||
diagram: 0300-technology/infrastructure.archify
|
||||
db-cluster:
|
||||
type: database
|
||||
label: DB Cluster
|
||||
sublabel: Node
|
||||
brand: postgresql
|
||||
tag: Node
|
||||
description: >
|
||||
Primary and standby database servers for claims and CRM data.
|
||||
doc-store:
|
||||
type: database
|
||||
label: Document Store
|
||||
sublabel: System Software
|
||||
tag: System Software
|
||||
description: >
|
||||
Object storage for scans and photos; written by document
|
||||
management only.
|
||||
mainframe:
|
||||
type: backend
|
||||
label: Mainframe
|
||||
sublabel: Node
|
||||
tag: Node
|
||||
description: >
|
||||
Hosts policy administration and the nightly payment batch.
|
||||
mq:
|
||||
type: messagebus
|
||||
label: Message Queue
|
||||
sublabel: System Software
|
||||
tag: System Software
|
||||
description: >
|
||||
Queue manager between the app servers and the mainframe.
|
||||
db-service:
|
||||
type: cloud
|
||||
label: DB Service
|
||||
sublabel: Tech Service
|
||||
tag: Tech Service
|
||||
description: >
|
||||
Managed SQL access with backups, offered to all applications.
|
||||
dc-lan:
|
||||
type: messagebus
|
||||
label: Data Centre LAN
|
||||
sublabel: Network
|
||||
tag: Network
|
||||
description: >
|
||||
Internal network linking app servers, databases and mainframe.
|
||||
dmz:
|
||||
type: security
|
||||
label: DMZ Gateway
|
||||
sublabel: Network
|
||||
tag: Network
|
||||
description: >
|
||||
Reverse proxy and firewall between the internet and the LAN.
|
||||
@@ -0,0 +1,34 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Business actors and services
|
||||
output: business-services.html
|
||||
components:
|
||||
- ref: shipper
|
||||
pos: [40, 60]
|
||||
size: [130, 60]
|
||||
- ref: recipient
|
||||
pos: [40, 260]
|
||||
size: [130, 60]
|
||||
- ref: delivery-service
|
||||
pos: [250, 60]
|
||||
size: [130, 60]
|
||||
- ref: tracking-service
|
||||
pos: [250, 260]
|
||||
size: [130, 60]
|
||||
- ref: deliver-shipment
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- ref: driver
|
||||
pos: [670, 60]
|
||||
size: [130, 60]
|
||||
- ref: customer-service
|
||||
pos: [670, 260]
|
||||
size: [130, 60]
|
||||
connections:
|
||||
- { from: delivery-service, to: shipper, label: serves, variant: emphasis }
|
||||
- { from: tracking-service, to: recipient, label: serves }
|
||||
- { from: deliver-shipment, to: delivery-service, label: realizes }
|
||||
- { from: deliver-shipment, to: tracking-service, label: realizes }
|
||||
- { from: driver, to: deliver-shipment, label: assigned to }
|
||||
- { from: customer-service, to: tracking-service, label: assigned to }
|
||||
@@ -0,0 +1,25 @@
|
||||
schema_version: 2
|
||||
diagram_type: workflow
|
||||
meta:
|
||||
title: Deliver Shipment
|
||||
output: deliver-shipment.html
|
||||
viewBox: [840, 534]
|
||||
lanes:
|
||||
- { id: customer-lane, label: Shipper and recipient }
|
||||
- { id: driver-lane, label: Driver }
|
||||
- { id: hub-lane, label: Hub }
|
||||
mainPath: [book, pick-up, sort, line-haul, last-mile, pod-step]
|
||||
nodes:
|
||||
- { id: book, lane: customer-lane, col: 0, type: external, label: Book shipment, tag: Business Event }
|
||||
- { id: pick-up, lane: driver-lane, col: 1, type: backend, label: Pick up, tag: Business Process }
|
||||
- { id: sort, lane: hub-lane, col: 2, type: backend, label: Sort at hub, tag: Business Process }
|
||||
- { id: line-haul, lane: hub-lane, col: 3, type: backend, label: Line haul, tag: Business Process }
|
||||
- { id: last-mile, lane: driver-lane, col: 4, type: backend, label: Last mile, tag: Business Process }
|
||||
- { id: pod-step, lane: customer-lane, col: 5, type: security, label: Delivered, sublabel: proof of delivery, tag: Business Process }
|
||||
edges:
|
||||
- { from: book, to: pick-up, label: triggers }
|
||||
- { from: pick-up, to: sort, label: parcel }
|
||||
- { from: sort, to: line-haul, label: trailer }
|
||||
- { from: line-haul, to: last-mile, label: route }
|
||||
- { from: last-mile, to: pod-step, label: hand over }
|
||||
- { from: last-mile, to: sort, label: not home, role: return, variant: dashed }
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Application cooperation
|
||||
output: application-cooperation.html
|
||||
decisions: [edi-gateway-in-front-of-tms]
|
||||
components:
|
||||
- ref: shipper
|
||||
pos: [40, 260]
|
||||
size: [130, 60]
|
||||
- ref: edi-gateway
|
||||
pos: [250, 260]
|
||||
size: [130, 60]
|
||||
decisions: [edi-gateway-in-front-of-tms]
|
||||
- ref: tms
|
||||
pos: [460, 260]
|
||||
size: [130, 60]
|
||||
- ref: driver-app
|
||||
pos: [460, 60]
|
||||
size: [130, 60]
|
||||
- ref: telematics
|
||||
pos: [460, 460]
|
||||
size: [130, 60]
|
||||
- ref: tracking-portal
|
||||
pos: [670, 260]
|
||||
size: [130, 60]
|
||||
connections:
|
||||
- { from: shipper, to: edi-gateway, label: bookings, variant: emphasis }
|
||||
- { from: edi-gateway, to: tms, label: shipments, variant: emphasis }
|
||||
- { from: driver-app, to: tms, label: scans, labelAt: [525, 134], decisions: [broker-for-tracking-events] }
|
||||
- { from: telematics, to: tms, label: positions, decisions: [broker-for-tracking-events] }
|
||||
- { from: tms, to: tracking-portal, label: status }
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Application services and data
|
||||
output: application-services.html
|
||||
components:
|
||||
- ref: tracking-portal
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: tracking-svc
|
||||
pos: [250, 160]
|
||||
size: [130, 60]
|
||||
- ref: tms
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- ref: driver-app
|
||||
pos: [670, 160]
|
||||
size: [130, 60]
|
||||
- ref: shipment
|
||||
pos: [250, 360]
|
||||
size: [130, 60]
|
||||
- ref: tracking-event
|
||||
pos: [460, 360]
|
||||
size: [130, 60]
|
||||
- ref: pod
|
||||
pos: [670, 360]
|
||||
size: [130, 60]
|
||||
connections:
|
||||
- { from: tracking-svc, to: tracking-portal, label: serves, variant: emphasis }
|
||||
- { from: tms, to: tracking-svc, label: realizes }
|
||||
- { from: driver-app, to: tms, label: uses }
|
||||
- { from: tms, to: shipment, label: accesses }
|
||||
- { from: tms, to: tracking-event, label: accesses, labelAt: [525, 234] }
|
||||
- { from: driver-app, to: pod, label: accesses, labelAt: [735, 234] }
|
||||
@@ -0,0 +1,44 @@
|
||||
schema_version: 1
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Technology infrastructure
|
||||
output: infrastructure.html
|
||||
decisions: [broker-for-tracking-events]
|
||||
components:
|
||||
- ref: handhelds
|
||||
pos: [40, 160]
|
||||
size: [130, 60]
|
||||
- ref: telematics-units
|
||||
pos: [40, 360]
|
||||
size: [130, 60]
|
||||
- ref: mobile-network
|
||||
pos: [250, 260]
|
||||
size: [130, 60]
|
||||
- ref: cloud-cluster
|
||||
pos: [460, 160]
|
||||
size: [130, 60]
|
||||
- ref: message-broker
|
||||
pos: [460, 360]
|
||||
size: [130, 60]
|
||||
decisions: [broker-for-tracking-events]
|
||||
- ref: db-server
|
||||
pos: [670, 160]
|
||||
size: [130, 60]
|
||||
- ref: event-streaming
|
||||
pos: [670, 360]
|
||||
size: [130, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Field devices
|
||||
wraps: [handhelds, telematics-units]
|
||||
- kind: security-group
|
||||
label: Cloud platform
|
||||
wraps: [cloud-cluster, message-broker, db-server, event-streaming]
|
||||
connections:
|
||||
- { from: handhelds, to: mobile-network, label: LTE }
|
||||
- { from: telematics-units, to: mobile-network, label: LTE }
|
||||
- { from: mobile-network, to: cloud-cluster, label: HTTPS, variant: security }
|
||||
- { from: mobile-network, to: message-broker, label: MQTT, variant: security }
|
||||
- { from: cloud-cluster, to: message-broker, label: hosts, labelAt: [525, 234] }
|
||||
- { from: cloud-cluster, to: db-server, label: SQL }
|
||||
- { from: message-broker, to: event-streaming, label: realizes }
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: broker-for-tracking-events
|
||||
title: A message broker for tracking events
|
||||
status: accepted
|
||||
date: 2026-09-08
|
||||
elements: [message-broker, telematics, driver-app, tms, tracking-event]
|
||||
diagrams: [0300-technology/infrastructure.archify, 0200-application/application-cooperation.archify]
|
||||
context: >
|
||||
Handhelds and telematics units posted every scan and position
|
||||
straight to the TMS. At evening peaks the TMS fell behind and
|
||||
dropped events when a device retried over a weak signal.
|
||||
decision: >
|
||||
Devices publish tracking events to a Kafka message broker on
|
||||
the cloud cluster. The TMS and telematics read the topics at
|
||||
their own pace; events are kept for seven days for replay.
|
||||
consequences: >
|
||||
Spikes no longer reach the TMS. Status on the tracking portal
|
||||
can lag by seconds. Consumers must handle duplicate events,
|
||||
and the broker is one more platform service to run.
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: edi-gateway-in-front-of-tms
|
||||
title: An EDI gateway in front of the TMS
|
||||
status: accepted
|
||||
date: 2026-09-22
|
||||
elements: [edi-gateway, tms, shipper, shipment]
|
||||
diagrams: [0200-application/application-cooperation.archify]
|
||||
context: >
|
||||
Large shippers send bookings as EDI files in three dialects.
|
||||
Each dialect was parsed inside the TMS, so a new shipper meant
|
||||
a TMS release.
|
||||
decision: >
|
||||
A separate EDI gateway receives, validates and translates
|
||||
every booking into one shipment message for the TMS. It also
|
||||
sends status messages back in the shipper's dialect.
|
||||
consequences: >
|
||||
New shippers are onboarded in the gateway alone. The TMS has
|
||||
one booking interface. A rejected booking now fails at the
|
||||
gateway, which customer service must be able to see.
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
schema_version: 1
|
||||
decision:
|
||||
id: photo-proof-of-delivery
|
||||
title: Photo as proof of delivery
|
||||
status: proposed
|
||||
date: 2026-10-27
|
||||
elements: [pod, driver-app, handhelds]
|
||||
diagrams: [0200-application/application-services.archify, 0100-business/deliver-shipment.archify]
|
||||
context: >
|
||||
Most parcels are left at the door when nobody signs. Disputes
|
||||
about such parcels take customer service days to settle.
|
||||
decision: >
|
||||
The driver app takes a photo of every parcel left without a
|
||||
signature and stores it with the proof of delivery.
|
||||
consequences: >
|
||||
Disputes are settled from the photo. Photos are personal data
|
||||
and are deleted after 90 days. Uploads add mobile data cost.
|
||||
@@ -0,0 +1,59 @@
|
||||
schema_version: 1
|
||||
model:
|
||||
id: logistics-tracking
|
||||
name: Logistics Tracking
|
||||
description: >
|
||||
An ArchiMate example: a parcel carrier lets shippers and recipients
|
||||
track shipments. Business, application and technology layers are
|
||||
mapped to folders; each element's ArchiMate type is shown as its tag.
|
||||
diagram_type: architecture
|
||||
meta:
|
||||
title: Logistics Tracking - layered view
|
||||
output: main.html
|
||||
components:
|
||||
- ref: recipient
|
||||
pos: [40, 70]
|
||||
size: [170, 60]
|
||||
- ref: tracking-service
|
||||
pos: [270, 70]
|
||||
size: [170, 60]
|
||||
- ref: deliver-shipment
|
||||
pos: [500, 70]
|
||||
size: [170, 60]
|
||||
- ref: tracking-portal
|
||||
pos: [40, 270]
|
||||
size: [170, 60]
|
||||
- ref: tms
|
||||
pos: [270, 270]
|
||||
size: [170, 60]
|
||||
- ref: tracking-svc
|
||||
pos: [500, 270]
|
||||
size: [170, 60]
|
||||
- ref: mobile-network
|
||||
pos: [40, 470]
|
||||
size: [170, 60]
|
||||
- ref: cloud-cluster
|
||||
pos: [270, 470]
|
||||
size: [170, 60]
|
||||
- ref: event-streaming
|
||||
pos: [500, 470]
|
||||
size: [170, 60]
|
||||
boundaries:
|
||||
- kind: region
|
||||
label: Business layer
|
||||
wraps: [recipient, tracking-service, deliver-shipment]
|
||||
- kind: region
|
||||
label: Application layer
|
||||
wraps: [tracking-portal, tms, tracking-svc]
|
||||
- kind: region
|
||||
label: Technology layer
|
||||
wraps: [mobile-network, cloud-cluster, event-streaming]
|
||||
connections:
|
||||
- { from: tracking-service, to: recipient, label: serves, variant: emphasis }
|
||||
- { from: deliver-shipment, to: tracking-service, label: realizes }
|
||||
- { from: tracking-portal, to: recipient, label: serves }
|
||||
- { from: tracking-svc, to: deliver-shipment, label: serves }
|
||||
- { from: tms, to: tracking-svc, label: realizes }
|
||||
- { from: mobile-network, to: tracking-portal, label: serves }
|
||||
- { from: cloud-cluster, to: tms, label: serves }
|
||||
- { from: event-streaming, to: tracking-svc, label: serves }
|
||||
@@ -0,0 +1,67 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
tms:
|
||||
type: backend
|
||||
label: TMS
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Owns shipments, routes and hub plans; the source of truth for status.
|
||||
diagram: 0200-application/application-cooperation.archify
|
||||
tracking-portal:
|
||||
type: frontend
|
||||
label: Tracking portal
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Public site where shippers and recipients follow a shipment.
|
||||
edi-gateway:
|
||||
type: security
|
||||
label: EDI gateway
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Receives booking messages from large shippers and returns status.
|
||||
driver-app:
|
||||
type: frontend
|
||||
label: Driver app
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Scans parcels at every hand-over and captures proof of delivery.
|
||||
telematics:
|
||||
type: backend
|
||||
label: Telematics
|
||||
sublabel: App Component
|
||||
tag: App Component
|
||||
description: >
|
||||
Collects vehicle positions and turns them into arrival estimates.
|
||||
tracking-svc:
|
||||
type: backend
|
||||
label: Tracking service
|
||||
sublabel: App Service
|
||||
tag: App Service
|
||||
description: >
|
||||
Status and arrival estimate of one shipment, offered by the TMS.
|
||||
diagram: 0200-application/application-services.archify
|
||||
shipment:
|
||||
type: database
|
||||
label: Shipment
|
||||
sublabel: Data Object
|
||||
tag: Data Object
|
||||
description: >
|
||||
One booked parcel with sender, recipient, route and status.
|
||||
tracking-event:
|
||||
type: database
|
||||
label: Tracking event
|
||||
sublabel: Data Object
|
||||
tag: Data Object
|
||||
description: >
|
||||
A scan or position report; the history of a shipment.
|
||||
pod:
|
||||
type: database
|
||||
label: Proof of delivery
|
||||
sublabel: Data Object
|
||||
tag: Data Object
|
||||
description: >
|
||||
Signature or photo taken at the door; closes the shipment.
|
||||
@@ -0,0 +1,54 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
shipper:
|
||||
type: external
|
||||
label: Shipper
|
||||
sublabel: Business Actor
|
||||
tag: Business Actor
|
||||
description: >
|
||||
Books shipments, hands parcels over at pick-up and follows
|
||||
them until delivery.
|
||||
recipient:
|
||||
type: external
|
||||
label: Recipient
|
||||
sublabel: Business Actor
|
||||
tag: Business Actor
|
||||
description: >
|
||||
Receives the parcel; tracks it and may reschedule delivery.
|
||||
driver:
|
||||
type: external
|
||||
label: Driver
|
||||
sublabel: Business Role
|
||||
tag: Business Role
|
||||
description: >
|
||||
Collects parcels, drives the routes and captures proof of delivery.
|
||||
customer-service:
|
||||
type: external
|
||||
label: Customer service
|
||||
sublabel: Business Role
|
||||
tag: Business Role
|
||||
description: >
|
||||
Answers shipper and recipient questions about late or lost parcels.
|
||||
deliver-shipment:
|
||||
type: backend
|
||||
label: Deliver Shipment
|
||||
sublabel: Business Process
|
||||
tag: Business Process
|
||||
description: >
|
||||
Pick up, sort at hub, line haul, last mile and proof of delivery.
|
||||
diagram: 0100-business/deliver-shipment.archify
|
||||
delivery-service:
|
||||
type: backend
|
||||
label: Parcel delivery
|
||||
sublabel: Business Service
|
||||
tag: Business Service
|
||||
description: >
|
||||
What the carrier sells; a parcel collected and delivered on time.
|
||||
diagram: 0100-business/business-services.archify
|
||||
tracking-service:
|
||||
type: backend
|
||||
label: Shipment tracking
|
||||
sublabel: Business Service
|
||||
tag: Business Service
|
||||
description: >
|
||||
Where a parcel is and when it arrives, for shippers and recipients.
|
||||
@@ -0,0 +1,55 @@
|
||||
schema_version: 1
|
||||
elements:
|
||||
cloud-cluster:
|
||||
type: cloud
|
||||
label: Cloud cluster
|
||||
sublabel: Node
|
||||
brand: kubernetes
|
||||
tag: Node
|
||||
description: >
|
||||
Container cluster that runs the TMS, portal, EDI gateway and telematics.
|
||||
diagram: 0300-technology/infrastructure.archify
|
||||
message-broker:
|
||||
type: messagebus
|
||||
label: Message broker
|
||||
sublabel: System Software
|
||||
brand: apache-kafka
|
||||
tag: System Software
|
||||
description: >
|
||||
Carries tracking events from devices and vehicles to the applications.
|
||||
db-server:
|
||||
type: database
|
||||
label: Database server
|
||||
sublabel: System Software
|
||||
brand: postgresql
|
||||
tag: System Software
|
||||
description: >
|
||||
Stores shipments, tracking events and proofs of delivery.
|
||||
event-streaming:
|
||||
type: backend
|
||||
label: Event streaming
|
||||
sublabel: Tech Service
|
||||
tag: Tech Service
|
||||
description: >
|
||||
Durable, ordered topics that applications publish to and read from.
|
||||
handhelds:
|
||||
type: external
|
||||
label: Handhelds
|
||||
sublabel: Device
|
||||
tag: Device
|
||||
description: >
|
||||
Scanners carried by drivers and hub staff; run the driver app.
|
||||
telematics-units:
|
||||
type: external
|
||||
label: Telematics units
|
||||
sublabel: Device
|
||||
tag: Device
|
||||
description: >
|
||||
GPS boxes in vans and trucks; report position every minute.
|
||||
mobile-network:
|
||||
type: security
|
||||
label: Mobile network
|
||||
sublabel: Network
|
||||
tag: Network
|
||||
description: >
|
||||
Carrier-grade mobile network that links devices to the cluster.
|
||||
Reference in new issue
Block a user