System context (C4 L1)¶
The level-1 view: Tend, the people who use it, and the systems around it. The defining feature of this diagram is the customer boundary — everything lives inside it, and the only things outside it are paths that are refused by design (Principle I).
C4Context
title System context — Tend, inside the customer boundary
Enterprise_Boundary(cb, "Customer-controlled boundary (tenancy + region)") {
Person(user, "Business power user", "Describes an app in natural language; owns it: renews expiry, requests promotion, answers for cost")
Person(approver, "Platform approver", "Reviews the platform-raised promotion PR; the merge is the approval")
Person(auditor, "Auditor / compliance", "Asks 'who built this, from what, and what does it touch' — at any time")
System(tend, "Tend", "Governed application lifecycle plane: contract enforcement, evidence chain, lifecycle, cost — the product")
System_Ext(builder, "AI builder", "Replaceable component behind a narrow contract: talk to the inference gateway, commit to the app repo, never deploy")
System_Ext(model, "Private model endpoint", "Tier 1 (the only tier ever run): managed endpoint in the customer's own cloud tenancy, reached over public-internet TLS not private interconnect; provider training and response caching disabled, abuse-logging retention exemption not yet requested. Tier 2 (reserved, not exercised): in-cluster vLLM-class serving")
SystemDb_Ext(data, "Customer data sources", "Postgres, S3-compatible object storage, internal REST, identity-governed warehouse — reached only through Tend's data gateway")
}
System_Ext(pub, "Public model APIs / public registries", "docker.io, api.openai.com, …")
Rel(user, builder, "describes and iterates on an app")
Rel(user, tend, "owns Apps: renew, promote, respond to warnings")
Rel(approver, tend, "approves promotion by merging the PR")
Rel(auditor, tend, "queries evidence and the estate view")
Rel(builder, tend, "inference via gateway; code via app repo")
Rel(tend, model, "routes all inference (gateway only)")
Rel(tend, data, "brokers all data access (gateway only)")
Rel(tend, pub, "no route — refused by design")
UpdateRelStyle(tend, pub, $lineColor="red", $textColor="red")
UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")
The actors¶
Business power user (app owner). The person Tend exists for: they can describe an app but not (safely) operate one. They talk to the builder, own exactly one App CR per app, and carry the lifecycle duties the platform enforces — renewal, promotion requests, cost accountability. They never touch git, kubectl, or Argo CD.
Platform approver. A member of the platform team (a Keycloak group). Their entire promotion workflow is reviewing a pull request that Tend raised, with the evidence record attached. Merging it is the approval — captured in git history and the attestation chain (Principle VI).
Auditor / compliance. Not a daily user, but the reason much of the system exists. Their question — "who built this, from what, and what does it touch?" — must be answerable per app, in one query, for the app's whole life (and after retirement). See the evidence chain.
The neighboring systems¶
AI builder — deliberately outside the product. The builder writes the
application code, and Tend treats it as untrusted and replaceable
(Principle VII, ADR-0013).
Its contract has exactly three clauses: inference only via the inference
gateway, code only via commits to the app's sandbox branch (with Prompt-Hash
and Model trailers), and never deploy. Everything Tend guarantees holds
for any builder honoring that contract — which is the point.
Private model endpoint. Which side of the cluster this sits on is the tier choice: Tier 1 uses a private managed endpoint in the customer's cloud tenancy. Tier 2 would serve models in-cluster, but it is reserved and has never been exercised — no installation has selected it and no in-cluster serving exists. Apps and builders are not intended to be able to tell the difference, because the inference gateway is the only model path either way; under Tier 1 that is enforced today.
Customer data sources. Real data never meets an app directly. The data gateway is the sole path, enforcing each app's declared scopes per request and logging every decision. An app is defaulted at admission to a single synthetic scope; reaching anything else takes a deliberately declared scope on the App CR.
Public APIs and registries. Present in the diagram only to be absent
from the system: no app namespace has a network route off-cluster, builds pull
images only from Harbor and language packages only from the in-boundary package
mirror (whose single upstream is registry.npmjs.org), and the attestation stack
runs with external transparency logs disabled. The red arrow is load-bearing, and CI
keeps it red: an isolation probe asserts the route stays unreachable. That
probe runs on pull requests touching the paths its workflow filters on rather
than on every pull request.
Reading on¶
- Zoom in one level: Containers (C4 L2)
- Why the boundary is the product: Boundary tiers
- What "governed" means concretely: Governance model