Architecture
Field contracts and worked examples for the 7 architecture blocks.
Field contracts and worked examples for the architecture blocks — converted at build time from the repo's authoring-skill reference. Every example body is YAML; in a real doc the fence language is the block type (for example sequence … ). Schemas are strict — unknown fields are rejected. See the field contract for the at-a-glance shape of all 77 blocks, or the block catalog for live previews.
Architecture diagrams
c4 — context / container / component
avo checkkind is person | system | external | store | container | component.
family (for container/component): client | service | data | store | controller | repo | external. Edge kind is solid | dashed | forbidden | error; edge tech renders as label [tech] (the C4 protocol convention).
col/row are optional — omit them everywhere for auto-layout (quick mode).
Optional boundary draws one dashed box auto-fitted around the internal nodes;
boundaries[] draws several named boxes, each around an explicit id list:
boundaries:
- { label: ClipShare platform, nodes: [api, worker, media], color: "#0e54a1" }
- { label: Partner estate, nodes: [cdn], color: "#991b1b" }kind: store draws as a true database cylinder; kind: external draws with a
dashed border (outside your control); the frame tag shows the level
(C4 · CONTAINER); the legend derives from the kinds you actually used.
Optional groups draw dashed zone wrappers around cell ranges (same shape as
on flow/block); prefer boundary/boundaries[] for system boundaries —
groups are for free-form zones anchored to the grid.
C4 done right — the rules that make it professional. A C4 diagram answers exactly ONE question per level. Never mix levels in one diagram.
- Context (
level: context) answers "who uses it and what does it talk to?" Allowed nodes:person,system(yours — usually exactly ONE),external. NO containers, NO stores. Persons in the top row; your system in the middle; externals in the outer rows/columns. 4-8 nodes total. - Container (
level: container) answers "what are the deployable pieces inside the system?" Oneboundary:(orboundaries[]) = the system;containernodes inside it (every container carriestech:— a container without a technology is a smell);storenodes inside;person+externalOUTSIDE the boundary. 5-9 nodes; if you need more, you're drawing two systems — split the diagram. - Component (
level: component) answers "what's inside ONE container?"componentnodes (usefamily:controller/service/repo to color-code the layering) + the stores/externals that container touches. Name the container in thetitle. - Every edge is a sentence.
label= an active verb phrase from the reader's perspective ("places order", "publishes events", "reads sessions");tech= the protocol/format (JSON/HTTPS,gRPC,SQL,SQS). An unlabeled C4 edge is unfinished. Async/eventual edges getkind: dashed; edges that must never exist getkind: forbidden. - Externals are things you don't deploy — SaaS, partner APIs, another
team's system. If your team owns it, it's a
container, not anexternal. Externals never sit inside a boundary. - Direction = dependency, not data. Draw the arrow from the thing that initiates toward the thing it calls; responses are implied. One arrow per relationship (don't draw the reply).
- Descriptions earn their space:
descis one clause stating responsibility ("Validates carts and takes payment"), not a repeat of the name. - Zooming: one level per section —
contextfirst, thencontainerfor the system the doc is about; deep-dive a single container withcomponentor hand off tobelogic. Cross-reference instead of redrawing.
A context-level example done to these rules:
title: ClipShare — system context
level: context
nodes:
- { id: creator, kind: person, name: Creator, desc: Uploads and shares clips. }
- { id: viewer, kind: person, name: Viewer, desc: Watches published clips. }
- { id: sys, kind: system, name: ClipShare, desc: "Ingests, transcodes, serves video." }
- { id: pay, kind: external, name: Billing partner, desc: Subscriptions + invoicing. }
- { id: idp, kind: external, name: Identity provider, desc: SSO for creators. }
edges:
- { from: creator, to: sys, label: uploads clips, tech: HTTPS }
- { from: viewer, to: sys, label: watches, tech: HLS }
- { from: sys, to: pay, label: reports usage, tech: REST }
- { from: creator, to: idp, label: signs in via, tech: OIDC }block — grid architecture with optional groups
avo checkEdges use the terse from -> to: label form by default (--> dashed,
-x-> error); switch an edge to the object form
({ from, to, label, kind }) only when the grammar can't say it.
Node kind is one of: client · service · microservice · compute · container · worker · etl · data · store · db · database · bucket · blob · object · queue · mq · broker · stream · cache · gateway · lb · proxy · function · lambda · cdn · dns · waf · firewall · shield · auth · idp · iam · oauth · sso · secrets · vault · kms · monitor · metrics · logs · tracing · scheduler · cron · job · warehouse · lake · analytics · bi · search · index · ml · model · llm · agent · vm · server · host · user · person · browser · mobile · device · iot · notification · webhook · email · sms · ci · cicd · pipeline · git · repo · registry · config · external · producer · topic · consumer · context — plus
vendor aliases (postgres/mysql/mongo → db, s3 → bucket,
sqs/rabbitmq → queue, kafka/kinesis → stream, redis/memcached →
cache, elasticsearch → search). Known kinds get coloured + glyphed
automatically and pick the canonical shape — db kinds draw as cylinders,
queue/stream kinds as horizontal-cylinder pipes, cdn/external as clouds,
gateway/lb/proxy as hexagons, cache/redis as an instance stack. Unknown kinds
render as a neutral box.
Quick mode. Omit col/row on every node and the layout is computed from
the edges (left → right). The example above needs no coordinates at all:
title: Search platform — quick mode
nodes:
- { id: crawler, kind: service, name: Crawler }
- { id: indexer, kind: service, name: Indexer }
- { id: idx, kind: search, name: Inverted index }
- { id: qapi, kind: gateway, name: Query API }
edges:
- crawler -> indexer
- indexer -> idx
- qapi --> idx: readsUse coordinates when you want a deliberate shape — and always with groups.
Nested zones (AWS-style VPC / subnets). groups can overlap to nest: draw
the outer zone (e.g. a VPC) as one big group, then inner zones (public / private
subnets) as smaller groups inside its cell range. The renderer paints larger
groups first, so smaller ones layer on top. Nodes still sit in grid col/row
cells; the groups just frame them.
preset: infra
title: VPC topology
groups:
- { col: 2, row: 1, cols: 3, rows: 3, label: "VPC 10.0.0.0/16", color: "#0e54a1" }
- { col: 2, row: 1, cols: 3, rows: 1, label: Public subnet, color: "#1f9747" }
- { col: 2, row: 2, cols: 3, rows: 1, label: "Private subnet · app", color: "#1a6dbe" }
nodes:
- { id: cf, col: 1, row: 1, kind: cdn, name: CloudFront }
- { id: alb, col: 2, row: 1, kind: gateway, name: ALB }
- { id: svc, col: 2, row: 2, kind: microservice, name: orders, tech: ECS }
edges:
- cf -> alb
- alb -> svcLayered layout. Presence of layers switches block to horizontal-band
layout — nodes use layer: <index> instead of col/row. A layer may carry
color: (hex) to tint its band + kicker, e.g.
- { label: Edge, color: "#1f9747" }.
preset: infra
title: AWS topology
systemLabel: ShopCo · us-east-1
layers:
- { label: Edge }
- { label: Compute }
- { label: Data }
nodes:
- { id: cf, layer: 0, kind: cdn, name: CloudFront }
- { id: api, layer: 1, kind: service, name: API }
- { id: pg, layer: 2, kind: store, name: orders-db }Presets. preset: infra | event | ddd | network keeps the exact same YAML
and only changes the domain framing — the colored frame tag and the section
eyebrow. Pick the preset that signals intent to a reader: infra for cloud
topology (CDN / gateway / compute / DB, as above), event for pub/sub
choreography, ddd for a bounded-context map, network for security zones
(the firewall glyph, a red zone tag, and kind: forbidden red edges). The
old block types infra / event / ddd / network live on as permanent
aliases that parse to block with the matching preset.
preset: event
title: Device telemetry
nodes:
- { id: fleet, col: 1, row: 1, kind: producer, name: device fleet }
- { id: bus, col: 2, row: 1, kind: topic, name: telemetry.raw }
- { id: alerts, col: 3, row: 1, kind: consumer, name: alerting }
- { id: lake, col: 3, row: 2, kind: consumer, name: lake sink }
edges:
- fleet -> bus
- bus -> alerts
- bus -> lakepreset: ddd
title: Bounded contexts
nodes:
- { id: idn, col: 1, row: 1, kind: context, name: Identity }
- { id: bill, col: 2, row: 1, kind: context, name: Billing }
- { id: sup, col: 3, row: 1, kind: context, name: Support }
edges:
- bill --> idn: customer ids
- sup --> bill: reads invoicescluster — k8s-style nested boxes with services
avo checkreplicas renders as small bars (capped at 5 + ×N label).
archmap — target-architecture capability map
avo checkThe classic EA one-pager: a square mosaic of tinted domain areas, each packed
with small capability/system tiles. A plain-string item is a current
capability; status codes the rest — target (dashed blue, to be built) ·
new (green, just added) · gap (dashed red, missing) · deprecated (gray,
retiring). A legend below the mosaic shows only the statuses actually used.
cols sets areas per row (2-4, default 3). Use archmap for a capability /
landscape view — what lives in each domain; use block/infra when the
arrows between systems matter.
Code-flavoured architecture
felogic — frontend / backend module graph
avo checkvariant: be is the same engine framed for the backend — use it to draw the
controller → service → repository chain (with a UML feel). The old belogic
type is its permanent alias:
variant: be
title: Orders API — the request chain
groups:
- { id: api, label: "orders/api", col: 1, row: 1, cols: 2, rows: 2, color: "#0e54a1" }
- { id: io, label: Egress, col: 3, row: 1, cols: 1, rows: 2, color: "#6b7280" }
nodes:
- { id: ctl, col: 1, row: 1, kind: controller, name: createOrder, note: "POST /orders" }
- { id: svc, col: 2, row: 1, kind: service, name: OrderService, note: "validate + place" }
- { id: repo, col: 1, row: 2, kind: repository, name: OrderRepo, note: persist }
- { id: gw, col: 2, row: 2, kind: gateway, name: PaymentGateway, note: charge }
- { id: db, col: 3, row: 1, kind: db, name: orders-db, note: Postgres }
edges:
- { from: ctl, to: svc, kind: uses }
- { from: svc, to: repo, kind: uses }
- { from: svc, to: gw, kind: uses }
- { from: repo, to: db, kind: egress }Node kind is one of: engine | core · interface · strategy · adapter · controller | handler | route · gateway · service | usecase · apiclient | client · repository | repo | dao · worker | consumer · middleware · model | entity · db | store | database · cache · queue | bus | broker · state | store_state · hook · external | backend | api | thirdparty. Edge kind is
uses | implements | egress | https | api | reads | dashed | async. These kinds
render with a UML «stereotype» banner: interface · controller · service · repository · adapter · gateway · strategy — so a backend graph reads like a
stereotyped component diagram. Labels wrap to fit, so they never overflow.
col/row are optional here too — omit them everywhere (and skip groups)
for an auto-laid-out module graph (quick mode). variant: be only changes
the framing (tag + eyebrow); the YAML is identical either way.
frontend — top-down component tree
avo checkkind is root | layout | page | component | leaf | provider | context | hook | store | state. Parents render above children with link paths.
uml — class diagram
avo checkRelation kind is inheritance | extends | implementation | implements | composition | aggregation | dependency | association (drives the marker
shape).
Field semantics — clarifications
A few fields are easy to misuse. Lock these in.
blockuses identical YAML across everypreset— the preset only changes the colored tag pill and section eyebrow. Pick the preset that best signals intent to a reader, not for any structural reason.- Diagram blocks with
layers:set go into horizontal-band layout. Withoutlayers:they use grid layout withcol/row. Don't mix — the renderer uses the presence oflayersto switch modes. - A CI/CD pipeline / DAG is
flowwithvariant: dag— seeflows.md.