Story view and lanes
The story is the version of a scenario to put in front of someone who has not seen the system before. It reads as swimlanes: one column per actor, the steps running down the page in order, and the phases as horizontal bands.
The whole platform. Hover a box or a line to follow it, click a box for details, or pick a scenario to watch a job travel.
An operator opens a list. The management backend works out who they are, which device they mean and whether they may see it. Then it forwards the same call through the hub and the tunnel to the device, which checks again, asks the service, and sends the answer back along the same road.
| Key | From → To | Kind | Auth | What travels |
|---|---|---|---|---|
| A | Operator browser → nginx · mgmt-proxy | http | Identity session (OIDC) | management UI and API calls |
| B | nginx · mgmt-proxy → identity | http | none (public login pages) | OIDC redirects and token endpoint |
| C | nginx · mgmt-proxy → control-api | http | agent API key | agent websocket upgrade |
| D | nginx · mgmt-proxy → management-backend | http | bearer JWT | UI host and REST API |
| E | management-backend → control-api | http | service token | jobs, tunnels, policies |
| F | management-backend → vision-api | http | — | inference requests |
| G | management-backend → management-iot | http | — | device telemetry queries |
| H | management-backend → Hub · gateway | http | mTLS | calls forwarded to a device |
| I | Hub · gateway → nginx · mgmt-proxy | channel | agent API key | control websocket |
| J | management-backend ↔ Hub · gateway | channel | mTLS | config and state sync |
| K | Hub · gateway ↔ Gateway VM · spoke | tunnel | IPsec / WireGuard / OpenVPN | all management traffic |
| L | Hub · gateway ↔ More spokes × N | tunnel | — | — |
| M | Gateway VM · spoke → nginx (device) | http | — | forwarded management calls |
| N | Local operator → nginx (device) | http | device realm session | device UI |
| O | nginx (device) → dx-backend | http | — | device app and API |
| P | dx-backend ↔ Gateway VM · spoke | channel | — | job relay |
| Q | dx-backend → VMS | http | — | container lifecycle |
You do not write a second file. The story is drawn from the same steps as the packets and the sequence diagram. Use the Flow, Sequence and Story buttons beside the player to switch.
How steps become boxes
Section titled “How steps become boxes”Every step becomes a box in the lane where it happens.
| Step | In the story |
|---|---|
at a: ... |
A box in a’s lane. |
a -> b: ... |
A box in b’s lane, joined to the box before it by an arrow. If the story is not already at a, a small box shows where it starts. |
a -> b: { kind: lookup } |
A dashed box beside the step that asked, in b’s lane, with a double-headed dotted arrow. The answer that follows (b -> a: ...) is folded into the same box. |
Boxes are numbered 1, 2, 3 along the story. Lookups are not numbered. Click a box to play that step. The numbers match the step list under the player.
Shaping the lanes
Section titled “Shaping the lanes”With no extra YAML you get a lane per node, in the order the nodes first appear in the scenario. To shape it, add up to three optional things.
scenarios: request-story: title: One read request, end to end mode: story # open as a story; flow and sequence stay one click away lanes: # columns, left to right - { title: Operator browser, nodes: [operator] } - { title: Management stores, sub: Redis · Postgres, nodes: [redis, postgres] } - { title: Network, sub: hub ⇒ tunnel ⇒ spoke, nodes: [hub, spoke] } phases: - title: Who, where, may they? caption: on the management side # shown under the title in the gutter steps: - proxy -> backend: title: Who are you? # the box heading (defaults to the label) detail: | # one to three short lines under it session cookie → session tokens read from Redis - backend -> redis: { label: session + tokens, kind: lookup } - redis -> backend: foundmode: story opens the scenario as a story. Without it, a scenario opens as packets over the diagram (flow). Set mode: sequence for a sequence diagram. The reader can always switch.
To show a story on a page without the scenario picker, pass mode to the component:
<Diagram name="platform" scenario="request-story" mode="story" />A lane has a title, an optional sub (which defaults to the node’s sub, or the node titles joined) and the nodes it holds. A lane can hold several nodes, which is how you show “the data stores” or “the network” as one column.
List the lanes in the order you want. Nodes you leave out get a lane of their own at the end, and docspp check tells you which, so a forgotten node is never silent. A node can be in only one lane.
title and detail
Section titled “title and detail”On a step, title is the heading of the box and detail is one to three short lines under it. Write them for a person who does not know the system:
| Without | With |
|---|---|
management-backend -> redis |
Who are you? session cookie → session |
Hub-gateway -> nginx (device) |
Cross the tunnel same call, same token |
A step without a title uses its label, and without a detail shows from → to.
Writing a good story
Section titled “Writing a good story”- Phases carry the narrative. Name them as questions or stages: “Who, where, may they?”, “Across the tunnel”, “The answer”.
- Use lookups for reads of stores. They fold into side boxes, so the main line stays about what the request does, not about every query.
- Write a
summary. In the story view it appears as “The story in one breath” above the lanes. - Keep lanes to about eight. More than that and the story scrolls sideways.
Stripe refuses the card. The payment stays pending and the shopper is told why.
The body carries the decline code so the UI can say something useful.