<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Wipe Platform Admin Documentation on Wipe Platform Admin Docs</title><link>/</link><description>Recent content in Wipe Platform Admin Documentation on Wipe Platform Admin Docs</description><generator>Hugo</generator><language>en-us</language><atom:link href="/index.xml" rel="self" type="application/rss+xml"/><item><title>Local Stack</title><link>/docs/cluster-bring-up/01-local-stack/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/cluster-bring-up/01-local-stack/</guid><description>&lt;h1 id="local-stack"&gt;Local Stack &lt;a href="#local-stack" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Run the full local stack from the repository root:&lt;/p&gt;



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="ef6156d" class="language-bash "&gt;
 &lt;code&gt;docker compose up --build&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;p&gt;The root compose file builds the backend and the SvelteKit portal, then starts
PostgreSQL with PGMQ, Keycloak, MinIO, Mailpit, OpenTelemetry Collector,
Prometheus, Loki, Tempo, Grafana, API, workers, and frontend.&lt;/p&gt;
&lt;h2 id="service-urls"&gt;Service URLs &lt;a href="#service-urls" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Service&lt;/th&gt;
					&lt;th&gt;URL&lt;/th&gt;
					&lt;th&gt;Notes&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;API&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:8080&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Backend API, &lt;code&gt;/healthz&lt;/code&gt;, &lt;code&gt;/readyz&lt;/code&gt;, Swagger.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Swagger UI&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:8080/swagger/index.html&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Generated from backend annotations.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Frontend BFF&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:5174&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The SvelteKit portal, and the only UI. &lt;code&gt;/&lt;/code&gt; for tenants, &lt;code&gt;/admin&lt;/code&gt; for platform administrators, &lt;code&gt;/verify&lt;/code&gt; for public certificate checks. OIDC tokens stay server-side.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Admin docs&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:5175&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Static Hugo/LotusDocs administrator handbook.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Keycloak&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:8081&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;admin&lt;/code&gt; / &lt;code&gt;admin&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;PostgreSQL&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;localhost:5432&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;wipe&lt;/code&gt; / &lt;code&gt;wipe&lt;/code&gt;, database &lt;code&gt;wipe&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;MinIO console&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:9001&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;minioadmin&lt;/code&gt; / &lt;code&gt;minioadmin&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Mailpit&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:8025&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Captured SMTP messages.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Grafana&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:3000&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;admin&lt;/code&gt; / &lt;code&gt;admin&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Prometheus&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:9090&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Scrapes OTel Collector exporter.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Loki&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:3100&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Logs.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Tempo&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:3200&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Traces.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;OTLP gRPC/HTTP&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;localhost:4317&lt;/code&gt;, &lt;code&gt;localhost:4318&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Telemetry ingest.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="seeded-accounts"&gt;Seeded Accounts &lt;a href="#seeded-accounts" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Realm&lt;/th&gt;
					&lt;th&gt;Username&lt;/th&gt;
					&lt;th&gt;Password&lt;/th&gt;
					&lt;th&gt;Role&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;master&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;platform-admin&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;admin&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;master&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;billing-operator&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;admin&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;BILLING_OPERATOR&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;exawipe&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;client-admin&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;admin&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;exawipe&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;client-tech&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;admin&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_TECH&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;exawipe&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;auditor&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;admin&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;AUDITOR&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The seeded direct-access clients are &lt;code&gt;wipe-admin-cli&lt;/code&gt; for the &lt;code&gt;master&lt;/code&gt; realm and
&lt;code&gt;wipe-dev-cli&lt;/code&gt; for the &lt;code&gt;exawipe&lt;/code&gt; realm. The newer frontend BFF requires
standard-flow web clients with PKCE: &lt;code&gt;wipe-portal-admin&lt;/code&gt; in &lt;code&gt;master&lt;/code&gt; and
&lt;code&gt;wipe-portal&lt;/code&gt; in &lt;code&gt;exawipe&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Tenants And Organizations</title><link>/docs/administration/01-tenants-organizations/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/administration/01-tenants-organizations/</guid><description>&lt;h1 id="tenants-and-organizations"&gt;Tenants And Organizations &lt;a href="#tenants-and-organizations" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Use these routes with a &lt;code&gt;PLATFORM_ADMIN&lt;/code&gt; token.&lt;/p&gt;
&lt;h2 id="tenant-lifecycle"&gt;Tenant Lifecycle &lt;a href="#tenant-lifecycle" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Action&lt;/th&gt;
					&lt;th&gt;Route&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;List tenants&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;GET /admin/api/v1/tenants&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Create tenant&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /admin/api/v1/tenants&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Read tenant&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;GET /admin/api/v1/tenants/{tenant_id}&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Update tenant&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;PATCH /admin/api/v1/tenants/{tenant_id}&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Delete tenant&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;DELETE /admin/api/v1/tenants/{tenant_id}&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Create tenants with a stable &lt;code&gt;slug&lt;/code&gt;, display &lt;code&gt;name&lt;/code&gt;, optional
&lt;code&gt;instance_fingerprint&lt;/code&gt;, and optional &lt;code&gt;branding&lt;/code&gt;.&lt;/p&gt;



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="68dbe78" class="language-json "&gt;
 &lt;code&gt;{
 &amp;#34;name&amp;#34;: &amp;#34;Example Tenant&amp;#34;,
 &amp;#34;slug&amp;#34;: &amp;#34;example-tenant&amp;#34;,
 &amp;#34;instance_fingerprint&amp;#34;: &amp;#34;sha256:example&amp;#34;
}&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;p&gt;Tenant deletion is a backend soft delete. Treat it as an operationally sensitive
action and keep the audit record attached to the change.&lt;/p&gt;</description></item><item><title>Host Deployment</title><link>/docs/cluster-bring-up/02-host-deployment/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/cluster-bring-up/02-host-deployment/</guid><description>&lt;h1 id="host-deployment"&gt;Host Deployment &lt;a href="#host-deployment" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The repository includes host deployment notes for &lt;code&gt;wipe.stack-plane.com&lt;/code&gt;. The
same pattern applies to a single VM or bare-metal host that runs Docker Compose
behind host Nginx.&lt;/p&gt;
&lt;h2 id="prepare-environment"&gt;Prepare Environment &lt;a href="#prepare-environment" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Copy the host environment template and replace every placeholder:&lt;/p&gt;



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="7e569da" class="language-bash "&gt;
 &lt;code&gt;cp deploy/host/wipe.stack-plane.com.env.example .env&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;p&gt;Review at minimum:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Group&lt;/th&gt;
					&lt;th&gt;Required values&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Public URLs&lt;/td&gt;
					&lt;td&gt;API, frontend, Keycloak, verification, invitation, callback URLs.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Secrets&lt;/td&gt;
					&lt;td&gt;PostgreSQL, Keycloak, S3, SMTP, frontend session secret, OIDC client secrets.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Admin access&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;ADMIN_API_ALLOWED_CIDRS&lt;/code&gt;, &lt;code&gt;ADMIN_API_ALLOW_INTERNAL_NETWORKS&lt;/code&gt;, MFA window.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Storage&lt;/td&gt;
					&lt;td&gt;S3 endpoint, bucket names, credentials, optional filesystem fallback.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Signer&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;SIGNER_MODE&lt;/code&gt;, endpoint, bearer or mTLS material, key IDs, TSA settings.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Observability&lt;/td&gt;
					&lt;td&gt;OTel endpoint, environment name, logs/metrics/traces routing.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Do not reuse local default passwords or seeded API keys outside local
development.&lt;/p&gt;</description></item><item><title>Users And Invitations</title><link>/docs/administration/02-users-invitations/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/administration/02-users-invitations/</guid><description>&lt;h1 id="users-and-invitations"&gt;Users And Invitations &lt;a href="#users-and-invitations" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Platform admins can create and maintain tenant users through the tenant API when
the target tenant and organization are supplied. Client admins can perform the
same workflow inside their own organization scope.&lt;/p&gt;
&lt;h2 id="routes"&gt;Routes &lt;a href="#routes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Action&lt;/th&gt;
					&lt;th&gt;Route&lt;/th&gt;
					&lt;th&gt;Roles&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;List users&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;GET /api/v1/users&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;, &lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Create user and invitation&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /api/v1/users&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;, &lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Update user profile&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;PUT /api/v1/users/{id}&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;, &lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Delete user by body alias&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;DELETE /api/v1/users&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;, &lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Delete user by path&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;DELETE /api/v1/users/{id}&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;, &lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Accept invitation&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /api/v1/invitations/accept&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Public token route&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="create-user"&gt;Create User &lt;a href="#create-user" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Example request:&lt;/p&gt;</description></item><item><title>IdP Federation</title><link>/docs/administration/03-idp-federation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/administration/03-idp-federation/</guid><description>&lt;h1 id="idp-federation"&gt;IdP Federation &lt;a href="#idp-federation" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Identity provider federation is configured by a &lt;code&gt;PLATFORM_ADMIN&lt;/code&gt; and must be
approved by a second &lt;code&gt;PLATFORM_ADMIN&lt;/code&gt; before it becomes public discovery
metadata.&lt;/p&gt;
&lt;h2 id="routes"&gt;Routes &lt;a href="#routes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Action&lt;/th&gt;
					&lt;th&gt;Route&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Read organization IdP metadata&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;GET /admin/api/v1/organizations/{id}/idp&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Configure IdP metadata&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /admin/api/v1/organizations/{id}/idp&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Approve IdP metadata&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /admin/api/v1/organizations/{id}/idp/approve&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Home realm discovery&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /api/v1/auth/discover&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="configure-idp"&gt;Configure IdP &lt;a href="#configure-idp" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Example request:&lt;/p&gt;



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="b3893a8" class="language-json "&gt;
 &lt;code&gt;{
 &amp;#34;tenant_id&amp;#34;: &amp;#34;11111111-1111-4111-8111-111111111111&amp;#34;,
 &amp;#34;provider&amp;#34;: &amp;#34;saml&amp;#34;,
 &amp;#34;metadata_url&amp;#34;: &amp;#34;https://idp.example/metadata&amp;#34;,
 &amp;#34;idp_url&amp;#34;: &amp;#34;https://idp.example/login&amp;#34;,
 &amp;#34;entity_id&amp;#34;: &amp;#34;https://idp.example/entity&amp;#34;,
 &amp;#34;display_name&amp;#34;: &amp;#34;Example IdP&amp;#34;
}&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;p&gt;The backend stores the metadata with &lt;code&gt;status=PENDING_APPROVAL&lt;/code&gt;, &lt;code&gt;requested_by&lt;/code&gt;,
and &lt;code&gt;requested_at&lt;/code&gt;. Pending metadata is not exposed by auth discovery.&lt;/p&gt;</description></item><item><title>Runtime Services</title><link>/docs/cluster-bring-up/03-runtime-services/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/cluster-bring-up/03-runtime-services/</guid><description>&lt;h1 id="runtime-services"&gt;Runtime Services &lt;a href="#runtime-services" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The platform is a modular Go backend plus SvelteKit frontends. Runtime state is
externalized to PostgreSQL and object storage.&lt;/p&gt;
&lt;h2 id="backend-binaries"&gt;Backend Binaries &lt;a href="#backend-binaries" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Binary&lt;/th&gt;
					&lt;th&gt;Compose service&lt;/th&gt;
					&lt;th&gt;Command&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;api&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;api&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/api&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Main HTTP API, admin API, public verification, embedded ingest in dev.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ingest&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Optional standalone&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/ingest&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Agent-only &lt;code&gt;/ingest/v1&lt;/code&gt; gateway with dedicated least-privilege DB role.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;worker-proof&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;proof-worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/worker-proof&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Consumes &lt;code&gt;proofs.validated&lt;/code&gt;; validates &lt;code&gt;.der&lt;/code&gt;, decrypts, signs, creates certificates.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;anchor-worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/worker anchor&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Consumes &lt;code&gt;certificates.to_anchor&lt;/code&gt;; submits/updates anchors and regenerates PDFs after anchoring.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;notification-worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/worker notifications&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Consumes &lt;code&gt;notifications.to_send&lt;/code&gt;; sends SMTP/webhook deliveries and records retries/DLQ.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;report-worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/worker reports&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Schedules and creates monthly billing reports and billing export artifacts.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;retry-worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/worker retry&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Enqueues due proof retries and re-tests recoverable proof states.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;maintenance-worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/worker maintenance&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Applies retention/anonymization and verifies audit/receipt chains.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;migrator&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;db-migrate&lt;/code&gt; profile&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/migrator&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Runs embedded SQL migrations.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;verifier&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;CLI image target&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/verifier&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Offline verification CLI foundation.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;worker&lt;/code&gt; binary chooses its kind from the first argument or &lt;code&gt;WORKER_KIND&lt;/code&gt;.
&lt;code&gt;WORKER_ONCE=true&lt;/code&gt; runs one claim pass and exits, which is useful for controlled
maintenance or release validation.&lt;/p&gt;</description></item><item><title>Branding And Email Templates</title><link>/docs/administration/04-branding-email/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/administration/04-branding-email/</guid><description>&lt;h1 id="branding-and-email-templates"&gt;Branding And Email Templates &lt;a href="#branding-and-email-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Branding is organization-scoped JSON. It controls organization display metadata
and the invitation email template used for new users.&lt;/p&gt;
&lt;h2 id="routes"&gt;Routes &lt;a href="#routes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Action&lt;/th&gt;
					&lt;th&gt;Route&lt;/th&gt;
					&lt;th&gt;Roles&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Read branding&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;GET /api/v1/organizations/{id}/branding&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;, &lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Update branding&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;PUT /api/v1/organizations/{id}/branding&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;, &lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Platform admins must pass the target organization ID and tenant scope because a
master realm token is not naturally tenant-scoped.&lt;/p&gt;
&lt;h2 id="branding-payload"&gt;Branding Payload &lt;a href="#branding-payload" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Example:&lt;/p&gt;



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="5f727b3" class="language-json "&gt;
 &lt;code&gt;{
 &amp;#34;branding&amp;#34;: {
 &amp;#34;app_name&amp;#34;: &amp;#34;Example Wipe&amp;#34;,
 &amp;#34;logo_url&amp;#34;: &amp;#34;https://static.example.com/logo.png&amp;#34;,
 &amp;#34;email_templates&amp;#34;: {
 &amp;#34;user_invited_subject&amp;#34;: &amp;#34;Welcome to {{app_name}}&amp;#34;,
 &amp;#34;user_invited_text&amp;#34;: &amp;#34;You have been invited to {{organization_name}} as {{role}}. Accept: {{accept_url}}&amp;#34;,
 &amp;#34;user_invited_html&amp;#34;: &amp;#34;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;img src=\&amp;#34;{{logo_url}}\&amp;#34; alt=\&amp;#34;{{app_name}} logo\&amp;#34;&amp;gt;&amp;lt;p&amp;gt;You have been invited to {{organization_name}} as &amp;lt;strong&amp;gt;{{role}}&amp;lt;/strong&amp;gt;.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;lt;a href=\&amp;#34;{{accept_url}}\&amp;#34;&amp;gt;Accept invitation&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#34;
 }
 }
}&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;p&gt;The admin platform can edit &lt;code&gt;logo_url&lt;/code&gt;, &lt;code&gt;app_name&lt;/code&gt;, and the
&lt;code&gt;email_templates.*&lt;/code&gt; fields. The backend renders the email body from these
templates rather than sending raw JSON.&lt;/p&gt;</description></item><item><title>Configuration Reference</title><link>/docs/cluster-bring-up/04-configuration-reference/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/cluster-bring-up/04-configuration-reference/</guid><description>&lt;h1 id="configuration-reference"&gt;Configuration Reference &lt;a href="#configuration-reference" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The backend is configured from environment variables. The canonical local list
is &lt;code&gt;backend/.env.example&lt;/code&gt;; the root compose file supplies defaults for the
reference stack.&lt;/p&gt;
&lt;h2 id="core-http-and-public-urls"&gt;Core HTTP And Public URLs &lt;a href="#core-http-and-public-urls" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Variable&lt;/th&gt;
					&lt;th&gt;Use&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DEPLOYMENT_MODE&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;cloud&lt;/code&gt;, &lt;code&gt;onprem&lt;/code&gt;, or &lt;code&gt;airgapped&lt;/code&gt;; do not rely on it alone for network policy.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;HTTP_ADDRESS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;API bind address, usually &lt;code&gt;:8080&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;HTTP_SHUTDOWN_TIMEOUT&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Graceful shutdown window.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;HTTP_CORS_ALLOW_ORIGINS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Browser origins allowed to call the API directly.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;HTTP_HSTS_ENABLED&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Enables HSTS when TLS terminates at the API or trusted proxy chain.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;PUBLIC_VERIFY_BASE_URL&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Base URL used in certificate QR and public verification links.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;PUBLIC_INVITATION_BASE_URL&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Base URL used in invitation acceptance links.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="security-controls"&gt;Security Controls &lt;a href="#security-controls" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Variable&lt;/th&gt;
					&lt;th&gt;Use&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ADMIN_API_ALLOWED_CIDRS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Explicit IP/CIDR allowlist for &lt;code&gt;/admin/api/v1&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ADMIN_API_ALLOW_INTERNAL_NETWORKS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Allows loopback/private/link-local admin clients for internal deployments.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SENSITIVE_ACTION_MFA_MAX_AGE&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Recent-MFA window for sensitive writes; &lt;code&gt;0&lt;/code&gt; disables local-only checks.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SECURITY_OUTBOUND_ALLOWED_HOSTS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Host allowlist for IdP metadata, branding URLs, and webhooks.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SECURITY_OUTBOUND_ALLOWED_CIDRS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Explicit IP ranges allowed by outbound URL policy.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SECURITY_OUTBOUND_ALLOW_PRIVATE_NETWORKS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Only enable for controlled internal deployments.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;VERIFY_RATE_LIMIT_PER_MINUTE&lt;/code&gt; / &lt;code&gt;VERIFY_RATE_LIMIT_PER_HOUR&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Public verification rate limits.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;VERIFY_CAPTCHA_SECRET&lt;/code&gt; / &lt;code&gt;VERIFY_CAPTCHA_VERIFY_URL&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Optional Turnstile/hCaptcha-style siteverify integration.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="identity-and-keycloak"&gt;Identity And Keycloak &lt;a href="#identity-and-keycloak" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Variable&lt;/th&gt;
					&lt;th&gt;Use&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;KEYCLOAK_MASTER_ISSUER&lt;/code&gt; / &lt;code&gt;KEYCLOAK_EXAWIPE_ISSUER&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Public issuer URLs that must match JWT &lt;code&gt;iss&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;KEYCLOAK_MASTER_AUDIENCE&lt;/code&gt; / &lt;code&gt;KEYCLOAK_EXAWIPE_AUDIENCE&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Expected JWT audiences.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;KEYCLOAK_MASTER_JWKS_URL&lt;/code&gt; / &lt;code&gt;KEYCLOAK_EXAWIPE_JWKS_URL&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;JWKS endpoints used by the API.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;KEYCLOAK_JWKS_CACHE_TTL&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;JWKS cache duration.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;KEYCLOAK_ADMIN_*&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Optional Admin API service-account configuration for provisioning users and IdPs.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For the new frontend BFF, configure &lt;code&gt;APP_BASE_URL&lt;/code&gt;, &lt;code&gt;API_INTERNAL_URL&lt;/code&gt;,
&lt;code&gt;KEYCLOAK_ISSUER_MASTER&lt;/code&gt;, &lt;code&gt;KEYCLOAK_ISSUER_EXAWIPE&lt;/code&gt;, &lt;code&gt;KEYCLOAK_INTERNAL_URL&lt;/code&gt;,
web client IDs/secrets, and a 32-byte or longer &lt;code&gt;SESSION_SECRET&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>API Keys And Agents</title><link>/docs/administration/05-api-keys-agents/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/administration/05-api-keys-agents/</guid><description>&lt;h1 id="api-keys-and-agents"&gt;API Keys And Agents &lt;a href="#api-keys-and-agents" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;API keys are organization-scoped automation credentials. They are managed by
&lt;code&gt;CLIENT_ADMIN&lt;/code&gt; today, not by &lt;code&gt;PLATFORM_ADMIN&lt;/code&gt; admin routes.&lt;/p&gt;
&lt;h2 id="api-key-routes"&gt;API Key Routes &lt;a href="#api-key-routes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Action&lt;/th&gt;
					&lt;th&gt;Route&lt;/th&gt;
					&lt;th&gt;Role&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;List keys&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;GET /api/v1/api-keys&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Create key&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /api/v1/api-keys&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Rotate key&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /api/v1/api-keys/{id}/rotate&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Revoke key&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /api/v1/api-keys/{id}/revoke&lt;/code&gt; or &lt;code&gt;DELETE /api/v1/api-keys/{id}&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Create request:&lt;/p&gt;



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="a9d3786" class="language-json "&gt;
 &lt;code&gt;{
 &amp;#34;name&amp;#34;: &amp;#34;CI proof uploader&amp;#34;,
 &amp;#34;organization_id&amp;#34;: &amp;#34;22222222-2222-4222-8222-222222222222&amp;#34;,
 &amp;#34;scopes&amp;#34;: [&amp;#34;proofs:write&amp;#34;, &amp;#34;proofs:read&amp;#34;]
}&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;p&gt;The generated secret is returned once. Store it immediately. Later list calls
show metadata and prefix only.&lt;/p&gt;</description></item><item><title>Migrations And Release</title><link>/docs/cluster-bring-up/05-migrations-release/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/cluster-bring-up/05-migrations-release/</guid><description>&lt;h1 id="migrations-and-release"&gt;Migrations And Release &lt;a href="#migrations-and-release" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Use migrations and generated-contract checks as release gates. Do not depend on
runtime AutoMigrate outside local development.&lt;/p&gt;
&lt;h2 id="image-build-matrix"&gt;Image Build Matrix &lt;a href="#image-build-matrix" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The backend Dockerfile ships one Go build stage and exposes several runtime
targets. CI publishes each as a separate image; the default &lt;code&gt;runtime&lt;/code&gt; target
remains a combined image for local compatibility.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Image&lt;/th&gt;
					&lt;th&gt;Docker target&lt;/th&gt;
					&lt;th&gt;Entrypoint&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;wipe-api&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;api-runtime&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/api&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;wipe-proof-worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;proof-worker-runtime&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/worker-proof&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;wipe-worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;worker-runtime&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/worker&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;wipe-verifier-cli&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;verifier-cli-runtime&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/verifier&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;wipe-migrator&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;migrator-runtime&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/app/migrator&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Build an individual image locally from the repository root (requires &lt;code&gt;EXAWIPE_PROOF_READ_TOKEN&lt;/code&gt; in the environment; see &lt;a href="/docs/cluster-bring-up/05-migrations-release/#repository-secrets"&gt;Repository Secrets&lt;/a&gt;):&lt;/p&gt;</description></item><item><title>Kubernetes With Helm And Argo CD</title><link>/docs/cluster-bring-up/06-kubernetes-helm-argocd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/cluster-bring-up/06-kubernetes-helm-argocd/</guid><description>&lt;h1 id="kubernetes-with-helm-and-argo-cd"&gt;Kubernetes With Helm And Argo CD &lt;a href="#kubernetes-with-helm-and-argo-cd" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The compose stack in &lt;a href="/docs/cluster-bring-up/02-host-deployment/"&gt;Host deployment&lt;/a&gt;
is a single-host reference shape. For a regulated environment the same services
run on Kubernetes from the &lt;code&gt;wipe&lt;/code&gt; Helm chart in &lt;code&gt;deploy/helm/wipe&lt;/code&gt;, synced by
Argo CD from &lt;code&gt;deploy/argocd&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="what-the-chart-deploys"&gt;What The Chart Deploys &lt;a href="#what-the-chart-deploys" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Workload&lt;/th&gt;
					&lt;th&gt;Image&lt;/th&gt;
					&lt;th&gt;Shape&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;API&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;wipe-api&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Deployment plus Service on 8080. Serves &lt;code&gt;/ingest/v1&lt;/code&gt; on the same port while &lt;code&gt;INGEST_EMBEDDED=true&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Ingest gateway&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;wipe-ingest&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Disabled by default. Enable only with &lt;code&gt;INGEST_EMBEDDED=false&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Proof worker&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;wipe-proof-worker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Deployment, scaled horizontally.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Anchor worker&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;wipe-worker-anchor&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Single replica with the &lt;code&gt;Recreate&lt;/code&gt; strategy; anchoring submits ordered messages.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Notification, report, retry workers&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;wipe-worker-notifications&lt;/code&gt;, &lt;code&gt;wipe-worker-reports&lt;/code&gt;, &lt;code&gt;wipe-worker-retry&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Deployments.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Maintenance worker&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;wipe-worker-maintenance&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Single replica with the &lt;code&gt;Recreate&lt;/code&gt; strategy.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Migrations&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;wipe-migrator&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Hook Job, not a Deployment.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Portal&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;wipe-frontend&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;SvelteKit BFF on the main hostname, and the only UI: &lt;code&gt;/&lt;/code&gt; for tenants, &lt;code&gt;/admin&lt;/code&gt; for platform administrators, &lt;code&gt;/verify&lt;/code&gt; for public certificate checks.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Operator docs&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;wipe-admin-docs&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;This site, static Hugo behind nginx.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Workers expose no HTTP surface, so they carry no probes. The Go images are
distroless and have no shell, which rules out exec probes everywhere. The portal
does have health routes: the SvelteKit frontend answers &lt;code&gt;/healthz&lt;/code&gt; once its
server loop runs and &lt;code&gt;/readyz&lt;/code&gt; once the API dependency responds, which is what
its probes use.&lt;/p&gt;</description></item><item><title>Licenses And Billing</title><link>/docs/administration/06-licenses-billing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/administration/06-licenses-billing/</guid><description>&lt;h1 id="licenses-and-billing"&gt;Licenses And Billing &lt;a href="#licenses-and-billing" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;License grants are platform-admin managed. Tenant billing exports are available
to tenant admins, and restricted tenant-selected billing views are available to
platform admins and billing operators.&lt;/p&gt;
&lt;h2 id="license-grants"&gt;License Grants &lt;a href="#license-grants" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Action&lt;/th&gt;
					&lt;th&gt;Route&lt;/th&gt;
					&lt;th&gt;Roles&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;List license grants&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;GET /admin/api/v1/license-grants&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;, &lt;code&gt;BILLING_OPERATOR&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Import license grant&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /admin/api/v1/license-grants&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Import license grant alias&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /admin/api/v1/license-grants/import&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Example import:&lt;/p&gt;



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="7af702e" class="language-json "&gt;
 &lt;code&gt;{
 &amp;#34;tenant_id&amp;#34;: &amp;#34;11111111-1111-4111-8111-111111111111&amp;#34;,
 &amp;#34;grant_id&amp;#34;: &amp;#34;55555555-5555-4555-8555-555555555555&amp;#34;,
 &amp;#34;grant_type&amp;#34;: &amp;#34;QUANTITY&amp;#34;,
 &amp;#34;instance_fingerprint&amp;#34;: &amp;#34;sha256:example&amp;#34;,
 &amp;#34;license_type&amp;#34;: &amp;#34;desktop&amp;#34;,
 &amp;#34;quantity&amp;#34;: 100,
 &amp;#34;valid_from&amp;#34;: &amp;#34;2026-01-01&amp;#34;,
 &amp;#34;valid_until&amp;#34;: &amp;#34;2026-12-31&amp;#34;,
 &amp;#34;commercial_chain&amp;#34;: [&amp;#34;Exaion&amp;#34;, &amp;#34;Example Operator&amp;#34;],
 &amp;#34;signature&amp;#34;: &amp;#34;dev-signature&amp;#34;
}&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;p&gt;Imports validate the signed instance fingerprint against the tenant, reject
duplicate grants globally, validate addendum and revocation chains, and require
the commercial chain to start with Exaion and end with the current operator.
The final production Exaion keyring/rotation policy remains part of the signer
readiness backlog.&lt;/p&gt;</description></item><item><title>Proofs And Certificates</title><link>/docs/administration/07-proofs-certificates/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/administration/07-proofs-certificates/</guid><description>&lt;h1 id="proofs-and-certificates"&gt;Proofs And Certificates &lt;a href="#proofs-and-certificates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Proofs are &lt;code&gt;.der&lt;/code&gt; files produced by the wipe agent. The backend stores the raw
proof object before processing and uses asynchronous workers to validate,
decrypt, sign, certify, and optionally anchor the result.&lt;/p&gt;
&lt;h2 id="submission-routes"&gt;Submission Routes &lt;a href="#submission-routes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Route&lt;/th&gt;
					&lt;th&gt;Auth&lt;/th&gt;
					&lt;th&gt;Use&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;POST /api/v1/proofs&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;, &lt;code&gt;CLIENT_TECH&lt;/code&gt;, or generic &lt;code&gt;proofs:write&lt;/code&gt; API key&lt;/td&gt;
					&lt;td&gt;Submit one multipart &lt;code&gt;.der&lt;/code&gt; proof.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;POST /api/v1/proofs/bulk&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;, &lt;code&gt;CLIENT_TECH&lt;/code&gt;, or generic &lt;code&gt;proofs:write&lt;/code&gt; API key&lt;/td&gt;
					&lt;td&gt;Submit up to 100 files or a ZIP archive, max 500 MB.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;POST /ingest/v1/proofs&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Enrolled-agent API key with &lt;code&gt;proofs:write&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Submit one raw &lt;code&gt;.der&lt;/code&gt; body from an enrolled agent.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;GET /ingest/v1/proofs/{id}&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Enrolled-agent API key with &lt;code&gt;proofs:read&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Poll the status of an agent-owned proof.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Protected writes require &lt;code&gt;Idempotency-Key&lt;/code&gt;. The unit proof size limit is 5 MB.
The local rate limits are per authenticated principal or agent key: 100 unit
submissions per hour and 500 batch submissions per hour. Each quota is a
separate counter, shared across all API and ingest replicas through the
database (&lt;code&gt;rate_limit_windows&lt;/code&gt;, migration 0025); a 429 carries &lt;code&gt;Retry-After&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Webhooks And Notifications</title><link>/docs/administration/08-webhooks-notifications/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/administration/08-webhooks-notifications/</guid><description>&lt;h1 id="webhooks-and-notifications"&gt;Webhooks And Notifications &lt;a href="#webhooks-and-notifications" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The backend has a notification worker that sends SMTP messages and signed
webhook deliveries from the &lt;code&gt;notifications.to_send&lt;/code&gt; queue. Invitations and
billing export delivery metadata are currently the most visible email flows;
certificate webhooks are emitted for &lt;code&gt;certificate.issued&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="webhook-routes"&gt;Webhook Routes &lt;a href="#webhook-routes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Action&lt;/th&gt;
					&lt;th&gt;Route&lt;/th&gt;
					&lt;th&gt;Role&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;List subscriptions&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;GET /api/v1/webhooks&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Create subscription&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /api/v1/webhooks&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Delete subscription&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;DELETE /api/v1/webhooks/{id}&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Example:&lt;/p&gt;



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="a8ad382" class="language-json "&gt;
 &lt;code&gt;{
 &amp;#34;url&amp;#34;: &amp;#34;https://hooks.example.com/wipe&amp;#34;,
 &amp;#34;events&amp;#34;: [&amp;#34;certificate.issued&amp;#34;]
}&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;p&gt;The subscription secret is returned once on creation. Store it in the receiving
system immediately.&lt;/p&gt;</description></item><item><title>Common Pitfalls</title><link>/docs/prerequisites/02-common-pitfalls/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/prerequisites/02-common-pitfalls/</guid><description>&lt;h1 id="common-pitfalls"&gt;Common Pitfalls &lt;a href="#common-pitfalls" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;A short list of mistakes that have either happened already or are easy to make
on first contact with the platform. Read this before operating a non-local
instance.&lt;/p&gt;
&lt;h2 id="dev-secrets-outside-local"&gt;Dev Secrets Outside Local &lt;a href="#dev-secrets-outside-local" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Secret&lt;/th&gt;
					&lt;th&gt;Why it bites you&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;wipe_dev_agent.0123456789abcdef0123456789abcdef&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Seeded proof-automation API key with &lt;code&gt;proofs:write&lt;/code&gt; and &lt;code&gt;proofs:read&lt;/code&gt;. If accepted by a non-local instance, anyone holding the seed can submit proofs.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;wipe_dev_enroll.0123456789abcdef0123456789abcdef&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Seeded one-time enrollment code. If enrollment is enabled in a shared environment, an attacker can enroll a rogue agent.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;KEYCLOAK_MASTER_SEED_USER_PASSWORD&lt;/code&gt; / &lt;code&gt;admin&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Default passwords for seeded users. Never reuse outside &lt;code&gt;DATABASE_SEED_DEV=true&lt;/code&gt; local stacks.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;TEST_SIGNER_SEED&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Test signer HMAC seed. Production must use a remote signer with real custody; the test signer is not a custody boundary.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Rule of thumb: if &lt;code&gt;DATABASE_SEED_DEV=true&lt;/code&gt;, &lt;code&gt;AGENT_DEV_ENROLLMENT_ENABLED=true&lt;/code&gt;,
&lt;code&gt;LICENSE_DEV_MODE=true&lt;/code&gt;, or &lt;code&gt;SIGNER_MODE=test&lt;/code&gt; is set, the environment is not
production-safe.&lt;/p&gt;</description></item><item><title>Workers And Queues</title><link>/docs/operations/02-workers-queues/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/operations/02-workers-queues/</guid><description>&lt;h1 id="workers-and-queues"&gt;Workers And Queues &lt;a href="#workers-and-queues" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The backend uses a PostgreSQL table-backed queue. Jobs are claimed with locking
semantics and dead-lettered after retry exhaustion. The operator source of truth
is the database plus structured worker logs and OpenTelemetry metrics.&lt;/p&gt;
&lt;h2 id="queues"&gt;Queues &lt;a href="#queues" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Queue&lt;/th&gt;
					&lt;th&gt;Producer&lt;/th&gt;
					&lt;th&gt;Consumer&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;proofs.validated&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Proof submit routes&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;worker-proof&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Validate proof, decrypt payload, create certificate, consume license, sign PDF/receipt.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;certificates.to_anchor&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Certificate service&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;worker anchor&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Submit or update blockchain anchor metadata and regenerate certificate PDF.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;notifications.to_send&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;User, billing, webhook flows&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;worker notifications&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Send SMTP/webhook notifications, retry failures, write delivery metadata.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;billing.exports&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Billing export routes&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;worker reports&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Generate requested export artifacts.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;reports.monthly&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Report scheduler&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;worker reports&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Generate monthly billing report artifacts.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;proofs.retry&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Retry routes/scheduler&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;worker retry&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Re-enqueue due failed or awaiting-license proofs.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The local PostgreSQL/PGMQ setup also seeds underscore queue aliases that
resolve to the same jobs table: &lt;code&gt;proofs_validated&lt;/code&gt;,
&lt;code&gt;certificates_to_anchor&lt;/code&gt;, &lt;code&gt;notifications_to_send&lt;/code&gt;, &lt;code&gt;billing_exports&lt;/code&gt;,
&lt;code&gt;reports_monthly&lt;/code&gt;, and &lt;code&gt;proofs_retry&lt;/code&gt;. The &lt;strong&gt;dot-notation form above is
canonical&lt;/strong&gt;; treat the underscore form as a Compose/PGMQ compatibility alias
only.&lt;/p&gt;</description></item><item><title>Observability And Alerts</title><link>/docs/operations/03-observability-alerts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/operations/03-observability-alerts/</guid><description>&lt;h1 id="observability-and-alerts"&gt;Observability And Alerts &lt;a href="#observability-and-alerts" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The current implementation emits OpenTelemetry signals to the collector. The
reference stack routes metrics to Prometheus, logs to Loki, traces to Tempo, and
dashboards/alerts to Grafana.&lt;/p&gt;
&lt;p&gt;The backend does not expose a Prometheus &lt;code&gt;/metrics&lt;/code&gt; endpoint by default.
Prometheus scrapes the OpenTelemetry Collector Prometheus exporter.&lt;/p&gt;
&lt;h2 id="local-urls"&gt;Local URLs &lt;a href="#local-urls" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Component&lt;/th&gt;
					&lt;th&gt;URL&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Grafana&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:3000&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Prometheus&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:9090&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Loki&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:3100&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Tempo&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;http://localhost:3200&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;OTLP gRPC&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;localhost:4317&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;OTLP HTTP&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;localhost:4318&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="signal-fields"&gt;Signal Fields &lt;a href="#signal-fields" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;HTTP logs include:&lt;/p&gt;</description></item><item><title>Audit, Verification, And Retention</title><link>/docs/operations/04-audit-verification-retention/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/operations/04-audit-verification-retention/</guid><description>&lt;h1 id="audit-verification-and-retention"&gt;Audit, Verification, And Retention &lt;a href="#audit-verification-and-retention" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The backend records admin/sensitive actions in the audit log and public
verification attempts in &lt;code&gt;verification_log&lt;/code&gt;. The maintenance worker handles
retention, verification metadata anonymization, and tamper-evident chain checks.&lt;/p&gt;
&lt;h2 id="audit-routes"&gt;Audit Routes &lt;a href="#audit-routes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Route&lt;/th&gt;
					&lt;th&gt;Role&lt;/th&gt;
					&lt;th&gt;Scope&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;GET /admin/api/v1/audit&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;PLATFORM_ADMIN&lt;/code&gt;, &lt;code&gt;BILLING_OPERATOR&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Recent audit rows across the instance.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;GET /api/v1/audit&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLIENT_ADMIN&lt;/code&gt;, &lt;code&gt;AUDITOR&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Tenant-scoped audit rows.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Audit entries are append-oriented and include hash-chain fields. The maintenance
worker verifies audit-chain continuity and records metrics/alerts on breaks.&lt;/p&gt;</description></item><item><title>Incident Response</title><link>/docs/operations/05-incident-response/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/operations/05-incident-response/</guid><description>&lt;h1 id="incident-response"&gt;Incident Response &lt;a href="#incident-response" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Use this page for first response. Record the incident, capture request IDs,
trace IDs, affected tenant/organization IDs where permitted, and the exact time
window before replaying or deleting anything.&lt;/p&gt;
&lt;h2 id="keycloak-outage"&gt;Keycloak Outage &lt;a href="#keycloak-outage" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Impact:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New login/token requests fail.&lt;/li&gt;
&lt;li&gt;Existing API calls may continue briefly while tokens and JWKS cache remain valid.&lt;/li&gt;
&lt;li&gt;User, invitation, IdP, and provisioning operations should pause.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Triage:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check &lt;code&gt;keycloak&lt;/code&gt; and &lt;code&gt;keycloak-postgres&lt;/code&gt; container health.&lt;/li&gt;
&lt;li&gt;Query the realm metadata endpoint from the API network (not the browser):
&lt;code&gt;curl -fsS &amp;lt;issuer&amp;gt;/realms/&amp;lt;realm&amp;gt;/.well-known/openid-configuration&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Check API logs for JWT/JWKS fetch errors and elevated &lt;code&gt;401&lt;/code&gt; responses.&lt;/li&gt;
&lt;li&gt;Confirm public issuer URLs still match the configured JWT &lt;code&gt;iss&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Recovery:&lt;/p&gt;</description></item><item><title>Backup And Restore</title><link>/docs/operations/06-backup-restore/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/operations/06-backup-restore/</guid><description>&lt;h1 id="backup-and-restore"&gt;Backup And Restore &lt;a href="#backup-and-restore" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Backups are an operations responsibility. The repository provides the data
layout and runtime services, but the final backup tooling depends on the target
host or Kubernetes platform.&lt;/p&gt;
&lt;h2 id="what-to-back-up"&gt;What To Back Up &lt;a href="#what-to-back-up" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Asset&lt;/th&gt;
					&lt;th&gt;Why it matters&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;PostgreSQL application database&lt;/td&gt;
					&lt;td&gt;Tenants, organizations, users, proofs, certificates, jobs, DLQ, audit, receipts, licenses, idempotency, verification logs.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Keycloak database/config&lt;/td&gt;
					&lt;td&gt;Realms, clients, users, roles, federation, credentials metadata.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Object storage buckets&lt;/td&gt;
					&lt;td&gt;Raw &lt;code&gt;.der&lt;/code&gt; proofs, PDFs, canonical JSON, binaries, exports, monthly reports.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Environment and secrets&lt;/td&gt;
					&lt;td&gt;Runtime config, DB/S3/SMTP/Keycloak credentials, signer mTLS material, frontend session secret.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Signer key custody records&lt;/td&gt;
					&lt;td&gt;Production signer owns cryptographic keys; back up according to signer/HSM policy, not application DB policy.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Nginx/TLS config&lt;/td&gt;
					&lt;td&gt;Public routing, certificates, redirects, callback behavior.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Generated release artifacts&lt;/td&gt;
					&lt;td&gt;Image tags/digests, SBOM/provenance, Swagger/client versions.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Do not place API key raw secrets, JWTs, signer private keys, or production
license signing material in application backups.&lt;/p&gt;</description></item><item><title>API Contract And Release Checks</title><link>/docs/operations/07-api-contract-release/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/operations/07-api-contract-release/</guid><description>&lt;h1 id="api-contract-and-release-checks"&gt;API Contract And Release Checks &lt;a href="#api-contract-and-release-checks" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The backend owns the API contract. Swagger is generated from Go annotations, and
the route-contract tool compares generated Swagger paths with the cahier-derived
route backlog.&lt;/p&gt;
&lt;h2 id="contract-files"&gt;Contract Files &lt;a href="#contract-files" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;File&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;backend/docs/api-routes.md&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Product route backlog extracted from the backend cahier.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;backend/docs/swagger/swagger.json&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Generated OpenAPI JSON.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;backend/docs/api-contract-status.md&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Human-readable implemented/missing route comparison.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;backend/docs/api-contract-status.json&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Machine-readable route comparison.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;frontend/src/lib/api/client&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Generated HeyAPI client for the portal.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Current status: all 54 expected cahier backlog operations are represented in
Swagger. Additional implemented routes include tenant admin CRUD, API keys,
webhooks, audit, public verification aliases, agent campaign revocation, and
ingest proof polling.&lt;/p&gt;</description></item><item><title>Signer Boundary</title><link>/docs/operations/08-signer-boundary/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/operations/08-signer-boundary/</guid><description>&lt;h1 id="signer-boundary"&gt;Signer Boundary &lt;a href="#signer-boundary" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The signer is the only component allowed to perform private-key operations:
certificate PDF signatures, blockchain transaction signatures, defensive
certificate HMACs, and decryption of agent proof envelopes. Everything else in
the platform consumes the signer as a service.&lt;/p&gt;
&lt;h2 id="current-state-in-process-test-signer"&gt;Current State: In-Process Test Signer &lt;a href="#current-state-in-process-test-signer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Local and CI stacks use the in-process test signer. It is &lt;strong&gt;not a custody
boundary&lt;/strong&gt;.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Attribute&lt;/th&gt;
					&lt;th&gt;Value&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Mode&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;SIGNER_MODE=test&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Package&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;internal/adapters/signer/testsigner&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Seed&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;TEST_SIGNER_SEED&lt;/code&gt; (shared by API and proof worker so HMAC verification is stable)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Capabilities&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;proof-envelope:v1&lt;/code&gt; decryption, deterministic HMACs, RSA-backed PAdES signing, placeholder blockchain transaction signing&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Trust&lt;/td&gt;
					&lt;td&gt;None — no remote custody, no durable key store, no approval workflow, no hardware backing&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Both &lt;code&gt;SIGNER_MODE=test&lt;/code&gt; and &lt;code&gt;AGENT_TRUST_MODE=dev&lt;/code&gt; are refused at startup when &lt;code&gt;ENVIRONMENT&lt;/code&gt;, &lt;code&gt;APP_ENV&lt;/code&gt;, or &lt;code&gt;OBSERVABILITY_ENVIRONMENT&lt;/code&gt; is set to &lt;code&gt;prod&lt;/code&gt; or &lt;code&gt;production&lt;/code&gt;. Do not run production load against &lt;code&gt;SIGNER_MODE=test&lt;/code&gt;. A dedicated signer
service is the production boundary.&lt;/p&gt;</description></item></channel></rss>