<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Platform Services on Deevnet IoTaaS</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/</link><description>Recent content in Platform Services on Deevnet IoTaaS</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/index.xml" rel="self" type="application/rss+xml"/><item><title>ADR-0036: A Service Proxy on Each Service VM</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0036-service-proxy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0036-service-proxy/</guid><description>&lt;h1 id="adr-0036-tenant-facing-services-answer-on-443-through-a-proxy-on-each-service-vm">
 ADR-0036: Tenant-Facing Services Answer on 443, Through a Proxy on Each Service VM
 &lt;a class="anchor" href="#adr-0036-tenant-facing-services-answer-on-443-through-a-proxy-on-each-service-vm">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Accepted (2026-10-10): built and deployed by 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0046-service-proxy/">CHG-0046&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-10-10&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>Where a tenant-facing HTTPS service listens, what name and port a tenant dials, and which process holds the certificate. Not who may call a service, which each service still decides (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/edge-devices/0020-direct-device-access-to-tenant-services/">ADR-0020&lt;/a> §5), and not the broker, which is not HTTP.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0013-management-services-domain-vms/">ADR-0013&lt;/a>: a service VM gains one more container, and a new service on it no longer opens a port to its segment.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Amends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0024-dashboards/">ADR-0024&lt;/a> As built §1 (&amp;ldquo;port 3000&amp;rdquo;), 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0022-central-logging/">ADR-0022&lt;/a> §3 (&amp;ldquo;vmauth is the only listener tenants can reach&amp;rdquo;) and 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0026-object-storage/">ADR-0026&lt;/a> §5 (&amp;ldquo;the store serves TLS&amp;rdquo;): each service is on loopback, and the proxy is the listener. What each decided about authentication stands.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0031-deevnet-pki/">ADR-0031&lt;/a> (the Substrate CA issues the proxy&amp;rsquo;s certificate), 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/naming-and-dns/0008-host-naming-site-codes/">ADR-0008&lt;/a> (service names are aliases of a host), 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0023-metrics-and-alerting/">ADR-0023&lt;/a> and 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0025-identity-directory/">ADR-0025&lt;/a> (the services that arrive next)&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;p>&lt;strong>Every tenant-facing service has its own port.&lt;/strong> Grafana is on 3000, the tenant downloads on 8443
and the log store on 8427, all on the observability store VM. The Deevnet API is on 8080 and the
state store on 9000, both on the provisioning VM. A tenant has to know five port numbers, and each
is written into tenant code, scripts and bookmarks.&lt;/p></description></item><item><title>ADR-0027: Tenant Log Store</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0027-tenant-log-store/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0027-tenant-log-store/</guid><description>&lt;h1 id="adr-0027-the-log-store-is-for-tenants-only-and-device-logs-arrive-over-mqtt">
 ADR-0027: The Log Store Is for Tenants Only, and Device Logs Arrive Over MQTT
 &lt;a class="anchor" href="#adr-0027-the-log-store-is-for-tenants-only-and-device-logs-arrive-over-mqtt">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Proposed&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-22&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>Who the central log store is for, what writes into each tenant&amp;rsquo;s partitions, how edge devices&amp;rsquo; logs reach it over MQTT, and what would justify moving it.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Supersedes, in part&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0022-central-logging/">ADR-0022: Central Logging&lt;/a>. Its &lt;strong>scope&lt;/strong>, which included substrate logs, and its §5 shipping of substrate hosts and network devices, including the syslog listener, are replaced. ADR-0022&amp;rsquo;s store, proxy, partition scheme, tokens and &amp;ldquo;publish, don&amp;rsquo;t filter&amp;rdquo; rule stand.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/">ADR-0012: IoT Platform Services Through a Deevnet API and Terraform Provider&lt;/a> §8, §10, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0013-management-services-domain-vms/">ADR-0013: Management-Hypervisor Services Run as Containers on Domain VMs&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0018-operator-access-to-tenants/">ADR-0018: Operator Access to Tenant Workloads&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0018-central-log-store/">CHG-0018: The Central Log Store&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/incidents/2026/0004-core-router-lost/">INC-0004&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;h3 id="what-exists">
 What exists
 &lt;a class="anchor" href="#what-exists">#&lt;/a>
&lt;/h3>
&lt;p>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0018-central-log-store/">CHG-0018&lt;/a> built ADR-0022&amp;rsquo;s store on &lt;code>dv02obs001v01&lt;/code>, a
Platform VM on the management hypervisor: VictoriaLogs behind vmauth, with tenants partitioned by
index. It was verified, and it was completed with nothing shipping to it. ADR-0022 stayed Proposed
until a real writer exists.&lt;/p></description></item><item><title>ADR-0026: Object Storage</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0026-object-storage/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0026-object-storage/</guid><description>&lt;h1 id="adr-0026-the-state-store-becomes-object-storage-defined-by-a-contract-with-state-and-tenant-buckets-as-two-classes">
 ADR-0026: The State Store Becomes Object Storage, Defined by a Contract, With State and Tenant Buckets as Two Classes
 &lt;a class="anchor" href="#adr-0026-the-state-store-becomes-object-storage-defined-by-a-contract-with-state-and-tenant-buckets-as-two-classes">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Proposed&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Amended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0036-service-proxy/">ADR-0036: A Service Proxy on Each Service VM&lt;/a>: the store serves plain HTTP on loopback, and the service proxy holds the certificate (§5)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-21&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>What the substrate&amp;rsquo;s S3 service must guarantee, which engine provides it, and how it serves both Terraform state and tenants&amp;rsquo; own buckets. Covers isolation, quotas, locking, versioning, transport and replication.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0007-terraform-state-custody/">ADR-0007: Terraform State Custody&lt;/a>, which offered a state store and chose MinIO as a detail; 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0014-tenant-state-durability/">ADR-0014: Tenant State Durability&lt;/a>, whose data disk and replica this store needs before it holds anything more&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Amended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0033-code-is-the-state/">ADR-0033: Code Is the State&lt;/a> &lt;em>(Proposed)&lt;/em>: no replica. State is re-derivable, and tenant buckets are the tenant&amp;rsquo;s to copy; the &lt;code>replicated&lt;/code> option is withdrawn (§3, §4)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a> §4, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0013-management-services-domain-vms/">ADR-0013: Management-Hypervisor Services Run as Containers on Domain VMs&lt;/a> §6, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015: Tenants Are Built Through the Deevnet API&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0016-substrate-secrets-openbao/">ADR-0016: Substrate Secrets in OpenBao&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;h3 id="the-engine-under-the-state-store-is-abandoned">
 The engine under the state store is abandoned
 &lt;a class="anchor" href="#the-engine-under-the-state-store-is-abandoned">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>The state store is MinIO&amp;rsquo;s community edition, &lt;code>RELEASE.2025-09-07&lt;/code>&lt;/strong>, on &lt;code>dv02prv001v01&lt;/code>.&lt;/li>
&lt;li>&lt;strong>The API confines each tenant through MinIO&amp;rsquo;s own admin API.&lt;/strong> It creates a user per tenant with a
canned policy limiting it to that tenant&amp;rsquo;s prefix of one bucket, &lt;code>tf-state&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Tenants lock state with &lt;code>use_lockfile = true&lt;/code>.&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>MinIO&amp;rsquo;s community repository was archived on 2026-04-25:&lt;/p></description></item><item><title>ADR-0025: Identity Directory</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0025-identity-directory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0025-identity-directory/</guid><description>&lt;h1 id="adr-0025-keycloak-is-the-identity-provider-with-a-realm-per-tenant-and-the-rebuild-path-kept-clear-of-it">
 ADR-0025: Keycloak Is the Identity Provider, With a Realm per Tenant and the Rebuild Path Kept Clear of It
 &lt;a class="anchor" href="#adr-0025-keycloak-is-the-identity-provider-with-a-realm-per-tenant-and-the-rebuild-path-kept-clear-of-it">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Proposed&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-21&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>Who can sign in to what, and how. This covers the operator on substrate UIs and hosts, each tenant&amp;rsquo;s people on the UIs the substrate offers them, and a tenant application&amp;rsquo;s own end users. It also covers how tenants are separated and what stays reachable when the directory is down. Not machine credentials, which the API and OpenBao issue.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0013-management-services-domain-vms/">ADR-0013: Management-Hypervisor Services Run as Containers on Domain VMs&lt;/a>, which placed &lt;em>&amp;ldquo;later an LDAP or Active Directory–compatible directory&amp;rdquo;&lt;/em> in the identity VM without choosing one; 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0024-dashboards/">ADR-0024: Dashboards&lt;/a>, whose local Grafana logins it replaces for people&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>In conflict with&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0033-code-is-the-state/">ADR-0033: Code Is the State&lt;/a> &lt;em>(Proposed)&lt;/em>: §7 makes the directory&amp;rsquo;s database kept data, which that record&amp;rsquo;s principle forbids. To be revisited before Keycloak is built&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a> §4, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0014-tenant-state-durability/">ADR-0014: Tenant State Durability&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015: Tenants Are Built Through the Deevnet API&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0016-substrate-secrets-openbao/">ADR-0016: Substrate Secrets in OpenBao&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0022-central-logging/">ADR-0022: Central Logging&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0023-metrics-and-alerting/">ADR-0023: Metrics and Alerting&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;h3 id="every-system-has-its-own-accounts">
 Every system has its own accounts
 &lt;a class="anchor" href="#every-system-has-its-own-accounts">#&lt;/a>
&lt;/h3>
&lt;p>Today, each system keeps its own accounts:&lt;/p></description></item><item><title>ADR-0024: Dashboards</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0024-dashboards/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0024-dashboards/</guid><description>&lt;h1 id="adr-0024-dashboards-are-grafana-one-organization-per-tenant-declared-as-code">
 ADR-0024: Dashboards Are Grafana, One Organization per Tenant, Declared as Code
 &lt;a class="anchor" href="#adr-0024-dashboards-are-grafana-one-organization-per-tenant-declared-as-code">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Accepted (2026-10-05): built and deployed by 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0024-tenant-dashboards/">CHG-0024&lt;/a>, which amends it (see 
 &lt;a href="#as-built-chg-0024">As built&lt;/a>)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Amended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0036-service-proxy/">ADR-0036: A Service Proxy on Each Service VM&lt;/a>: Grafana listens on loopback over plain HTTP, and the service proxy serves it at &lt;code>grafana&lt;/code> on 443 (As built §1)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-21&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>How the operator and each tenant view their metrics and logs as dashboards, how people log in to do it, how dashboards are declared as code, and what a tenant may and may not configure. Not alerting, which ADR-0023 decides.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0023-metrics-and-alerting/">ADR-0023: Metrics and Alerting&lt;/a>, whose §5 deferred saved dashboards and named Grafana with one organization per tenant as the likely shape&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0025-identity-directory/">ADR-0025: Identity Directory&lt;/a>: people sign in to Grafana through the directory, and the per-tenant login becomes machine-only &lt;em>(Proposed)&lt;/em>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a> §4, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/">ADR-0012: IoT Platform Services Through a Deevnet API and Terraform Provider&lt;/a> §4, §7, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015: Tenants Are Built Through the Deevnet API&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0016-substrate-secrets-openbao/">ADR-0016: Substrate Secrets in OpenBao&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0022-central-logging/">ADR-0022: Central Logging&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;h3 id="what-exists-to-read-data">
 What exists to read data
 &lt;a class="anchor" href="#what-exists-to-read-data">#&lt;/a>
&lt;/h3>
&lt;p>ADR-0022 and ADR-0023 store logs and metrics, partitioned per tenant behind vmauth. The only reading
surfaces they give are the store&amp;rsquo;s own UIs:&lt;/p></description></item><item><title>ADR-0023: Metrics and Alerting</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0023-metrics-and-alerting/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0023-metrics-and-alerting/</guid><description>&lt;h1 id="adr-0023-metrics-are-pulled-from-management-stored-beside-the-logs-and-alerted-on-per-tenant">
 ADR-0023: Metrics Are Pulled From Management, Stored Beside the Logs, and Alerted On Per Tenant
 &lt;a class="anchor" href="#adr-0023-metrics-are-pulled-from-management-stored-beside-the-logs-and-alerted-on-per-tenant">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Proposed&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-21&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>How substrate and tenant metrics are collected and stored, who may read them, how alert rules are declared and evaluated for the substrate and for each tenant, and where notifications go. Dashboards only as far as needed to read what is stored.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0022-central-logging/">ADR-0022: Central Logging&lt;/a>. Metrics use its store host, its authenticating proxy, its partition scheme and its tenant credentials.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0024-dashboards/">ADR-0024: Dashboards&lt;/a>: saved dashboards in Grafana, one organization per tenant &lt;em>(Accepted)&lt;/em>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0013-management-services-domain-vms/">ADR-0013: Management-Hypervisor Services Run as Containers on Domain VMs&lt;/a> §5, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015: Tenants Are Built Through the Deevnet API&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0016-substrate-secrets-openbao/">ADR-0016: Substrate Secrets in OpenBao&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0018-operator-access-to-tenants/">ADR-0018: Operator Access to Tenant Workloads&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;h3 id="nothing-is-measured-and-nothing-alerts">
 Nothing is measured and nothing alerts
 &lt;a class="anchor" href="#nothing-is-measured-and-nothing-alerts">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>The substrate has no metrics and no alerts.&lt;/strong> The operator learns about a fault when a tenant&amp;rsquo;s
apply times out or a page stops loading.&lt;/li>
&lt;li>&lt;strong>Both observability VMs are still empty.&lt;/strong> &lt;code>dv02sob001v01&lt;/code> is on management and
&lt;code>dv02tob001v01&lt;/code> is on Platform. Both are being replaced: &lt;code>tob&lt;/code> by the store &lt;code>dv02obs001v01&lt;/code>, and &lt;code>sob&lt;/code>
by the collector &lt;code>dv02col001v01&lt;/code> (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0018-central-log-store/">CHG-0018&lt;/a>, naming
§3.4). The rest of this record uses the new names.&lt;/li>
&lt;li>&lt;strong>Tenants were promised more than they have.&lt;/strong> The tenant pages promise &lt;em>&amp;ldquo;VM resource
utilization&amp;rdquo;&lt;/em>, &lt;em>&amp;ldquo;Per-tenant thresholds&amp;rdquo;&lt;/em> and &lt;em>&amp;ldquo;Tenant-specific notification channels&amp;rdquo;&lt;/em>. None of
it exists.&lt;/li>
&lt;/ul>
&lt;h3 id="what-is-wanted">
 What is wanted
 &lt;a class="anchor" href="#what-is-wanted">#&lt;/a>
&lt;/h3>
&lt;ol>
&lt;li>&lt;strong>Substrate metrics&lt;/strong>: every host, hypervisor and service, plus the router, switch and access
point.&lt;/li>
&lt;li>&lt;strong>Tenant metrics&lt;/strong>: what a tenant&amp;rsquo;s workloads emit, and the resource use of those workloads as
the hypervisor sees it.&lt;/li>
&lt;li>&lt;strong>Operator alerts&lt;/strong> on the substrate.&lt;/li>
&lt;li>&lt;strong>Tenant alerts&lt;/strong>: a tenant declares its own rules and where they notify, and nobody edits
substrate code for it.&lt;/li>
&lt;li>&lt;strong>The same partitioning as the logs.&lt;/strong> A tenant reads and alerts on its own data only.&lt;/li>
&lt;/ol>
&lt;h3 id="where-adr-0022-left-collection">
 Where ADR-0022 left collection
 &lt;a class="anchor" href="#where-adr-0022-left-collection">#&lt;/a>
&lt;/h3>
&lt;p>ADR-0022 moved log &lt;em>storage&lt;/em> to Platform because every zone with something to log can push there.
For metrics, pull is the norm: the collector scrapes each target. ADR-0013 §5&amp;rsquo;s reasoning applies
to that directly. &lt;strong>Management reaches every zone, so a scraper on management reaches every
target.&lt;/strong> A scraper on Platform would need new rules into management and IoT Backend.&lt;/p></description></item><item><title>ADR-0022: Central Logging</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0022-central-logging/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/platform-services/0022-central-logging/</guid><description>&lt;h1 id="adr-0022-one-central-log-store-on-platform-partitioned-by-tenant">
 ADR-0022: One Central Log Store on Platform, Partitioned by Tenant
 &lt;a class="anchor" href="#adr-0022-one-central-log-store-on-platform-partitioned-by-tenant">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Accepted, as narrowed by ADR-0027&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Amended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0036-service-proxy/">ADR-0036: A Service Proxy on Each Service VM&lt;/a>: vmauth listens on loopback, and the service proxy is the listener tenants reach, at &lt;code>logs&lt;/code> on 443 (§3)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Accepted&lt;/strong>&lt;/td>
 &lt;td>2026-09-26, by the operator. What stands after 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0027-tenant-log-store/">ADR-0027&lt;/a> is built and in use: the store, vmauth, the partitions and the API-issued tenant tokens (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0018-central-log-store/">CHG-0018&lt;/a> to 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0021-mqtt-log-bridge/">CHG-0021&lt;/a>). Tenants read it through Grafana since 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0024-tenant-dashboards/">CHG-0024&lt;/a>. The v1 deferrals are on the 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/roadmap/infrastructure/mobile/management-plane/">Extended Management Plane&lt;/a> roadmap.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-21&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>Where substrate and tenant logs are sent and kept, how they are partitioned, who may read which partition, and which substrate events a tenant sees. Logs only: metrics and alerting are left for their own records.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Supersedes, in part&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0013-management-services-domain-vms/">ADR-0013: Management-Hypervisor Services Run as Containers on Domain VMs&lt;/a> §5, &lt;strong>for logs only&lt;/strong>. That section splits observability into a substrate store on management and a tenant store on Platform. For logs there is now one store, on Platform. Everything else in ADR-0013 stands, including both VMs.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0023-metrics-and-alerting/">ADR-0023: Metrics and Alerting&lt;/a>: metrics use the same store host, proxy, partitions and tenant tokens &lt;em>(Proposed)&lt;/em>. 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0024-dashboards/">ADR-0024: Dashboards&lt;/a>: tenants read their logs in Grafana, one organization per tenant &lt;em>(Accepted)&lt;/em>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Superseded in part by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0027-tenant-log-store/">ADR-0027: Tenant Log Store&lt;/a>: &lt;strong>the scope and §5.&lt;/strong> The store is for tenants only, the substrate and network devices don&amp;rsquo;t ship to it, and the syslog listener goes. Device logs arrive over MQTT into a new &lt;code>(index, 2)&lt;/code>. The store, proxy, partitions, tokens and §4 stand. &lt;em>(Proposed)&lt;/em>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Built by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0018-central-log-store/">CHG-0018: The Central Log Store&lt;/a>: the store, &lt;em>Complete 2026-09-22&lt;/em>. 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0020-tenant-log-tokens/">CHG-0020&lt;/a>: tenant tokens. 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0021-mqtt-log-bridge/">CHG-0021&lt;/a>: device logs over MQTT. Substrate shipping was withdrawn by ADR-0027.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0002-tenant-fabric-numbering/">ADR-0002: Tenant Fabric Numbering&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/">ADR-0012: IoT Platform Services Through a Deevnet API and Terraform Provider&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015: Tenants Are Built Through the Deevnet API&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0016-substrate-secrets-openbao/">ADR-0016: Substrate Secrets in OpenBao&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0021-tenant-secrets/">ADR-0021: Tenant Secrets&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;h3 id="nothing-collects-logs-today">
 Nothing collects logs today
 &lt;a class="anchor" href="#nothing-collects-logs-today">#&lt;/a>
&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>CHG-0008 built both observability VMs empty.&lt;/strong> &lt;code>dv02sob001v01&lt;/code>, on management, is for the
substrate. &lt;code>dv02tob001v01&lt;/code>, on Platform, is for tenants. Each runs only sshd, and CHG-0008&amp;rsquo;s
follow-up &lt;em>&amp;ldquo;Observability tooling for &lt;code>dv02sob001v01&lt;/code> and &lt;code>dv02tob001v01&lt;/code>&amp;rdquo;&lt;/em> is still open.&lt;/li>
&lt;li>&lt;strong>Both are replaced, not reused.&lt;/strong> This record puts every log in one store, so the audience split
their names describe no longer exists. 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0018-central-log-store/">CHG-0018&lt;/a>
replaces &lt;code>tob&lt;/code> with &lt;strong>&lt;code>dv02obs001v01&lt;/code>&lt;/strong>, the observability store, and &lt;code>sob&lt;/code> with
&lt;strong>&lt;code>dv02col001v01&lt;/code>&lt;/strong>, the collector (naming §3.4). Both are still empty, so replacing them costs
nothing. The rest of this record uses the new names.&lt;/li>
&lt;li>&lt;strong>Every host keeps its own journal.&lt;/strong> Reading across the site means an SSH session per host, and
the core router&amp;rsquo;s log buffer holds about fifty seconds.&lt;/li>
&lt;li>&lt;strong>Tenants have nothing at all.&lt;/strong> The tenant pages promise logs &lt;em>&amp;ldquo;Tagged with tenant identifier&amp;rdquo;&lt;/em>,
&lt;em>&amp;ldquo;Queryable by tenant scope&amp;rdquo;&lt;/em> and &lt;em>&amp;ldquo;Retained per tenant policy&amp;rdquo;&lt;/em>, and the shared-services table
lists tenant observability as &lt;em>&amp;ldquo;To be defined&amp;rdquo;&lt;/em>.&lt;/li>
&lt;/ul>
&lt;h3 id="what-is-wanted">
 What is wanted
 &lt;a class="anchor" href="#what-is-wanted">#&lt;/a>
&lt;/h3>
&lt;ol>
&lt;li>&lt;strong>One place for all logs.&lt;/strong> Tenants ship their workloads&amp;rsquo; logs there, and so do substrate
hosts and services.&lt;/li>
&lt;li>&lt;strong>Partitioned by tenant.&lt;/strong> Each tenant reads its own logs and never another tenant&amp;rsquo;s.&lt;/li>
&lt;li>&lt;strong>A tenant also sees the substrate events that concern it.&lt;/strong> Examples: the API creating its
workload, a DNS update to its zone, a broker refusing one of its accounts. It should not have to
ask the operator.&lt;/li>
&lt;li>&lt;strong>The operator reads everything.&lt;/strong>&lt;/li>
&lt;/ol>
&lt;h3 id="what-the-zone-policy-allows">
 What the zone policy allows
 &lt;a class="anchor" href="#what-the-zone-policy-allows">#&lt;/a>
&lt;/h3>
&lt;p>ADR-0013 §5 put substrate observability on management. That followed from the zone policy: IoT
Backend and Platform can&amp;rsquo;t reach management, so a store there has to &lt;em>pull&lt;/em>. That is still true.
What ADR-0013 didn&amp;rsquo;t weigh is the reverse.&lt;/p></description></item></channel></rss>