TheYard infrastructure
Pinch or Ctrl+scroll to zoom; the text is selectable.
Source
·
TheYard
TheYard infrastructure: what runs today, how a merge becomes a roll, and the one piece of the production design still refused
TheYard on Azure, as it runs on 2026-10-19
Everything in the solid boxes is live and measured, the rendering service included; the dashed group is the one piece of the production design the subscription still refuses.
A request, left to right
HOSTING.md and ADR-004, ADR-007 record the chain; ADR-010 the Admin tab; ADR-015 the cache rules.
Visitor's browser
theyard
theyard-cosmos
.stevenstout.biz
Two sites, a store each
by name. Bundles
cached a year; the page,
API and docs say no-cache.
ADR-015, ADR-069
DNS at Wix
theyard CNAME
theyard-cosmos CNAME
theyard-edge.netlify.app
bare A, www, theshed CNAME
Registrar-locked to Wix; the
Cloudflare zone is staged for
the transfer around Oct 30.
HTTPS edge: Netlify (free)
One Let's Encrypt cert, four names.
_redirects, then netlify.toml
bare and www: 301 to theyard
a page, / with its query: to the
rendering service as that site
the rest: the web app, X-Yard-Host
netlify.toml
rebuilds only when edge/ changes
ADR-007, ADR-069, ADR-096
Origin: App Service plan PLAN-THEYARD-SS, Linux B2, westus3
APP-THEYARD-ONE-SS-ZMNETJ67BN5H2 2 vCPU and 3.5 GB, shared by two web apps
https://app-theyard-one-ss-zmnetj67bn5h2.azurewebsites.net
Runs image theyard:vN from the registry, pulled with the
user-assigned identity id-theyard-ss (AcrPull; Reader on the resource group).
Inside: one ASP.NET Core 10 process (Dockerfile, ADR-002)
Serves both sites by the name typed and The Shed as its own app inside it; the SPA,
/api/*, the docs with live code (ADR-014), /healthz and /readyz, and the Admin tab,
which trades the identity for a token and reads its site, the plan and six more
resources from Azure, kept a minute at a time in Cosmos DB (ADR-101, ADR-102).
Beside it: the rendering service, the second web app (render/, ADR-096)
APP-THEYARD-RENDER-SS on the same plan, its own 62 MB image: Node and the site's
build, no framework. For a page it reads what the view needs from the web app
under a 2.5 s deadline, draws the site with React's server renderer and streams
the HTML with the data in it; React takes it over. It draws only for its own build.
resolve
TLS
HTTPS
Store: Azure SQL Database, RG-THEYARD-SS, westus3
sqldb-theyard-ss-basic Basic 5 DTU 2 GB $4.90 a month
The server is Entra-only: it has no SQL login and therefore no password. The
site authenticates as id-theyard-ss, which holds db_datareader and
db_datawriter and cannot create or alter a table.
The schema is api/TheYard.Database, hand-written DDL published by SqlPackage.
Entity Framework maps to it; a conformance test fails the build if they differ.
West US 3 because West US 2 refused; the plan is here for the same reason.
When the database is not there
A container that cannot reach the store serves the catalogue from the
JSON files instead and says so on /api/health. Bids stop outliving the
process; nothing else changes for a visitor.
Built in ADR-033 for a serverless database that auto-pauses. The first
thing it actually caught was a deploy whose connection string never got
substituted, and nobody using the site could tell.
The deploy warns when a roll lands here (ADR-039 addendum).
Store: Azure Cosmos DB, RG-THEYARD-SS, westus2
cosmos-theyard-ss free tier 1000 RU/s shared session consistency no keys
Local authentication is disabled on the account, so there is no key to leak; the
container authenticates as id-theyard-ss with a data-plane role that can read and
write documents and cannot create a container (ADR-059, ADR-061).
Four containers hold the catalogue, photos, accounts and bids as documents,
partitioned on the make, the style, the account and the bidder (ADR-058).
Nothing indexed; the definitions are infra/cosmos/*.json (ADR-040 addendum).
Both stores and both sites in one process since 19 October
A request gets the store its name picks: sql on theyard, cosmos on
theyard-cosmos, both answered by this web app behind the same edge, which
says which name was typed (ADR-105). The Store bar links each site to the
other at the same page (no cookie); a measurement names a store for one request
with a header. The peer read retired with the second web app, and the
proof card sends a visitor's requests to the container itself on both stores and
says, per path, whether the two answer in the same time and why they differ.
ADR-066 the bar, ADR-069 the address, ADR-067 the proof, ADR-105 one web app.
the other store, per request
read once at startup, written on every bid
pulled by id-theyard-ss
az webapp config set (roll)
A merge becomes a roll, no hands on it
ADR-009 records the pipeline, ADR-005 the version, ADR-012 the changelog line each version writes.
The gate, on the laptop
Every check once a version:
build, format, SQL project,
xUnit on both stores, live,
vitest and Playwright.
Red commits nothing.
ADR-068, ADR-075
GitHub: push to main
The commit carries its
own changelog line, one
past the footer's number.
SteveStout/TheYard
Deploy and Deploy Render
Both fire on the push: deploy.yml rolls
the API's image onto the one web app;
deploy-render.yml builds render/Dockerfile
as the same version and rolls the service. OIDC;
the version is the changelog's top line (ADR-031);
each verifies its origin; the edge moves after.
roles: AcrPush, Website Contributor, two web apps
Registry (ACR)
crtheyardsszmnetj67bn5h2
.azurecr.io
One tag per version, two
images: theyard and
theyard-render. Basic tier.
CI (ci.yml)
On every push to main
and on a pull request:
style, then the three
suites and the SQL
project. Read-only
token.
ADR-068, the 5 October addendum
green
push
image
The one piece still refused: Azure Front Door
infra/main.bicep with enableFrontDoor=true; ADR-001 the decision, ADR-004 and ADR-079 why it waits.
Azure Front Door
Global entry, TLS, the custom domain
on Azure instead of the Netlify edge.
fdProfile, fdEndpoint,
fdOriginGroup, fdOrigin, fdRoute
The web app, as a locked origin
It answers only Azure Front Door's backend
range, and only with this profile's ID in
the X-Azure-FDID header (siteLock).
siteLock, one per web app
The same image
Nothing about the sites changes. Front
Door goes in front of the web app, which
answers only to it, and the Netlify
edge retires.
Why it waits
The free trial forbids Front Door
(measured 2026-08-31). App Service was
refused too, until 2026-09-20 found the
region that allows it. One parameter.
ADR-004, ADR-079
locked
runs
Source: docs/images/infrastructure.svg in the repository. Names, sizes and roles are the ones the records and the pipeline logs carry; the picture is redrawn when they change.