TLSStress.Art — Desenho de Alto Nível do Sistema (HLD)¶
Público-alvo: arquitetos, operadores, revisores de segurança e investidores que precisam da visão do sistema inteiro em um único documento. Este HLD fica acima da visão geral de Arquitetura (tour de componentes) e dos Registros de Decisão de Arquitetura (racional por decisão). Onde este documento resume, aqueles documentos são autoritativos no detalhe.
Aprofundamentos companheiros: F2 — arquitetura do Cell-0 (Hetzner), postura de segurança ZTP-prem, ADR-0053 (hyperscale por cells).
1. Propósito & escopo¶
TLSStress.Art é um test-bed para medir performance de decriptografia TLS em Next-Generation Firewalls (NGFWs) atuando como Device Under Test (DUT). O alvo primário é HTTP/3 (QUIC sobre UDP/443) — todo NGFW moderno reivindica inspeção QUIC — com HTTP/2 (TCP/443) medido secundariamente para comparação.
O produto tem duas faces:
| Face | O que é | Onde roda |
|---|---|---|
| Plano de controle SaaS | Signup, billing, ledger de tokens (TSU), auto-provisionamento, enrollment central | AWS (App Runner + RDS) · Cloudflare (borda/DNS) · cell-0 Hetzner (K3s) |
| Appliance on-prem (TBI) | A bancada em si — agentes, personas, dashboard, observabilidade — instalada ao lado do NGFW do cliente | Datacenter/lab do cliente (K3s/RKE2 ou Docker Desktop dev) |
A bancada gera carga a partir de agentes (Playwright + k6) através do NGFW, que decripta/inspeciona/re-assina TLS, e segue até os webservers (as Personas). Comparando o tempo de handshake e o throughput com decriptografia ON vs BYPASS, o operador quantifica o custo de inspeção TLS do NGFW.
2. Contexto do sistema — atores¶
| Ator | Papel | Ponto de contato |
|---|---|---|
| Cliente | Compra um pacote no SaaS, recebe um tenant provisionado + um appliance on-prem (TBI) para download | app.tlsstress.art (signup/pagamento), download do TBI (S3/F1) |
| Operador | Roda a bancada contra um NGFW real. O Dashboard é a ÚNICA interface do operador — toda mudança de config passa pela UI (nunca kubectl edit / curl admin/ / exec) |
Dashboard on-prem (Next.js) |
| NGFW DUT | O dispositivo sob medição. Gateway L3 padrão das VLANs de test-plane; executa a decriptografia TLS | Firewall físico/virtual em trunks 802.1q |
flowchart LR
CUST(["Cliente"])
OPER(["Operador"])
subgraph SAAS["Plano de controle SaaS (sempre-online)"]
APP["customer-app<br/>App Runner · Next.js<br/>signup · Stripe · mint TSU"]
CELL["cell-0 (Hetzner K3s)<br/>Provisioning Orchestrator<br/>saga Temporal · RLS de tenant"]
TBI[("Artefatos TBI<br/>S3 · img/qcow2/oci")]
end
subgraph PREM["Appliance on-prem (datacenter do cliente)"]
DASH["Dashboard (Next.js)<br/>a ÚNICA UI do operador"]
AGENTS["Agentes<br/>Playwright + k6"]
PERS["Personas<br/>100 webservers (Caddy)"]
OBS["Observabilidade<br/>Prometheus + Grafana"]
end
DUT{{"NGFW DUT<br/>decripta · inspeciona · re-assina TLS"}}
CUST -->|"signup / pagamento"| APP
APP -->|"applyTier (mint de quota)"| APP
APP -->|"enqueueOnboarding (HMAC)"| CELL
CUST -->|"download do appliance"| TBI
TBI -.->|"dd para USB / KVM / boot"| PREM
OPER -->|"login · configurar"| DASH
DASH --> AGENTS
DASH --> PERS
DASH --> OBS
AGENTS ==>|"leg TLS 1"| DUT
DUT ==>|"leg TLS 2"| PERS
AGENTS -.->|"eventos de spend TSU"| DASH
DASH -.->|"reporte de uso (horário)"| APP
classDef saas fill:#0F1A2E,stroke:#00D8FC,color:#FCFCFC,stroke-width:2px
classDef prem fill:#f0fdf4,stroke:#16a34a,stroke-width:1px
classDef dut fill:#fef9c3,stroke:#b45309,stroke-width:2px
class APP,CELL,TBI saas
class DASH,AGENTS,PERS,OBS prem
class DUT dut
3. Visão de containers (C4-ish)¶
O próximo nível aproxima dos containers implantáveis e seus protocolos. O plano de controle fica on-prem (Dashboard ↔ agentes pela bridge OOBI) enquanto o plano de controle de billing/provisionamento vive na cloud (customer-app ↔ cell-0). O único canal on-prem→cloud é o reporte horário de uso TSU.
graph TB
CUST(["Cliente<br/>navegador"])
OPER(["Operador<br/>navegador"])
subgraph CLOUD["Plano de controle SaaS na cloud"]
direction TB
APP["customer-app<br/>(App Runner, Next.js)"]
RDS[("RDS · ledger UTXO<br/>mint @ checkout")]
STRIPE{{"Stripe"}}
PROV["Provisioning Orchestrator<br/>(cell-0, Go + Temporal)"]
CELLDB[("Cell control DB<br/>tenants · slots (RLS)")]
end
subgraph ONPREM["Appliance on-prem"]
direction TB
DASH["Dashboard<br/>(Next.js · Drizzle)<br/>gate license authorize()"]
PG[("Postgres 16<br/>runs · agents · audit_log<br/>notas UTXO · idempotency")]
PWA["Agentes Playwright<br/>(1..80, HPA)"]
K6A["Agentes k6<br/>(1..200, HPA)"]
PERS["Personas (Caddy)<br/>100 / 20 países"]
VYOS["MÓDULO ISP/BGP<br/>(VyOS + FRR)"]
PROM["Prometheus + Grafana"]
BOOT["bootstrap-controller<br/>(drain de spend TSU)"]
end
DUT{{"NGFW DUT"}}
CUST -->|"HTTPS"| APP
STRIPE -->|"checkout.session.completed"| APP
APP -->|"applyTier mint"| RDS
APP -->|"HMAC POST /trigger"| PROV
PROV -->|"saga"| CELLDB
OPER -->|"cookie HMAC / Basic"| DASH
DASH -->|"SQL"| PG
DASH <-->|"Bearer + Idempotency-Key"| PWA
DASH <-->|"Bearer"| K6A
DASH -->|"spend de nota de licença"| PG
PWA ==>|"leg TLS 1 · h2/h3"| DUT
K6A ==>|"leg TLS 1 · h2/h3"| DUT
DUT ==>|"leg TLS 2 (re-assinado)"| VYOS --> PERS
PROM -->|"scrape /api/metrics · SNMP"| DASH
BOOT -.->|"POST horário /api/usage/report"| APP
classDef cloud fill:#0F1A2E,stroke:#00D8FC,color:#FCFCFC,stroke-width:2px
classDef prem fill:#f0fdf4,stroke:#16a34a,stroke-width:1px
classDef dut fill:#fef9c3,stroke:#b45309,stroke-width:2px
class APP,RDS,STRIPE,PROV,CELLDB cloud
class DASH,PG,PWA,K6A,PERS,VYOS,PROM,BOOT prem
class DUT dut
4. Componentes principais & responsabilidades¶
4.1 Appliance on-prem (a bancada)¶
| Componente | Código | Responsabilidade |
|---|---|---|
| Dashboard | dashboard/ |
Next.js 15 App Router. A única UI do operador. Auth por cookie HMAC, audit_log de toda mutação, stream SSE ao vivo, /api/metrics Prometheus, o gate license authorize() (dashboard/src/lib/license/). |
| Agentes Playwright | agent/ |
Workers Chromium headless. BrowserContext novo por ciclo, captura protocolo / tcp_sockets_open / web-vitals. Circuit breaker por alvo, idempotency keys. HPA min=1, max=80. |
| Agentes k6 | k6-agent/ |
Wrapper Node.js do binário grafana/k6. Emite p50/p95/p99, error_rate, rps, data_received. readOnlyRootFilesystem, /tmp em memória. HPA min=1, max=200. |
| Personas | personas/, webserver/ |
100 webservers Caddy em 20 países (5 cada). H2 + H3, TLS 1.2 mín, session tickets desabilitados. Certs emitidos pelo persona-ca-issuer. Os endpoints do leg TLS 2. |
| MÓDULO ISP / BGP | bgp-router-peer/, ospf-router-peer/, vpn-remote/ |
VyOS + FRR. Rota padrão do NGFW; roteia adiante para cada /24 de país. Também stress de control-plane (injeção de LSA BGP/OSPF). |
| Postgres 16 | k8s/40-postgres.yaml |
runs, agents, k6_*, metrics_buckets, audit_log, idempotency, notas UTXO, envelopes de licença. CronJob diário de pg_dump. |
| Observabilidade | observability/, grafana/ |
Prometheus + Grafana, SNMP exporter para NGFW/Nexus, node_exporter. Dashboards DUT (NGFW, Nexus, probe de decrypt-mode). |
| DUT API engine | dashboard/src/lib/dut-api/ |
Adapters de vendor (Cisco FTD/Nexus/UCS-CIMC, FortiGate). Captura config + identidade sanitizadas, AES-GCM em repouso, hashes SHA-256 de snapshot embarcados no Test Run Report. |
| bootstrap-controller | pkg/bootstrap-controller/ |
Drena arquivos de spend TSU e faz POST para o /api/usage/report da cloud, de hora em hora. |
4.2 Plano de controle SaaS na cloud¶
| Componente | Código | Responsabilidade |
|---|---|---|
| customer-app | pkg/octopus/customer-app/ |
Next.js no AWS App Runner. Signup, checkout Stripe, minta a quota TSU no ledger UTXO do RDS no checkout (applyTier), e (fail-safe) enfileira o onboarding ao cell-0. |
| Provisioning Orchestrator | pkg/octopus/provisioning-orchestrator/ |
Worker Go + Temporal no cell-0. Roda o OnboardingWorkflow — saga de 12 atividades com compensação LIFO. Ver F2 HLD. |
| Cell control DB | internal/cell/migrations/ |
Database Postgres cell: tenants, slots, tenant_data com RLS Postgres para isolamento por tenant (ADR-0053). |
| Admin console | pkg/octopus/admin-console/ |
Console interno de operador/billing (separado do Dashboard on-prem). |
| TBI builder | build/tbi/, pkg/tbi-agent/ |
Constrói a imagem do appliance on-prem (mkosi → img/qcow2/oci). Embarca tbi-agent, k3s, gVisor, probes de hardware. |
5. Os dois legs TLS¶
O produto inteiro existe para medir o custo da decriptografia entre dois legs TLS.
flowchart TB
A["Pod de agente<br/>(Playwright / k6)<br/>VLAN 20 / 30 — TRUST/INSIDE"]
DUT{{"NGFW DUT<br/>decripta · inspeciona · re-assina TLS"}}
VYOS["MÓDULO ISP (VyOS + FRR)<br/>VLAN 2001 — UNTRUST/OUTSIDE<br/>rota padrão 200.130.0.2"]
PERS["Pod Persona Caddy<br/>ex.: shop.us.persona.tlsstress.art<br/>= 198.32.10.10 · H2 + H3"]
A ==>|"leg TLS 1<br/>agente confia na CA do NGFW"| DUT
DUT ==>|"leg TLS 2<br/>NGFW confia no persona-ca-issuer"| VYOS
VYOS -->|"uma saída por LAN de país"| PERS
note1["Confiança leg 1: agentes carregam NODE_EXTRA_CA_CERTS /<br/>SSL_CERT_FILE = CA do NGFW (ConfigMap 10-ngfw-ca)"]
note2["Confiança leg 2: NGFW confia no cert-manager<br/>persona-ca-issuer (platform/pki/)"]
note1 -.-> DUT
note2 -.-> VYOS
classDef agent fill:#dbeafe,stroke:#2563eb,stroke-width:1px
classDef dut fill:#fef9c3,stroke:#b45309,stroke-width:2px
classDef rtr fill:#fff7ed,stroke:#c2410c,stroke-width:1px
classDef pers fill:#f0fdf4,stroke:#16a34a,stroke-width:1px
classDef noted fill:#f5f5f7,stroke:#999,stroke-width:1px,color:#333
class A agent
class DUT dut
class VYOS rtr
class PERS pers
class note1,note2 noted
| Leg | De → Para | Âncora de confiança | Notas |
|---|---|---|---|
| Leg 1 | Agentes → NGFW | Agentes confiam na CA do NGFW (k8s/dut/10-ngfw-ca.yaml, injetada via NODE_EXTRA_CA_CERTS / SSL_CERT_FILE) |
O NGFW intercepta e re-assina com sua própria CA. Os agentes precisam aceitá-la para medir o caminho inspecionado. |
| Leg 2 | NGFW → Personas | NGFW confia no persona-ca-issuer (PKI cert-manager, platform/pki/) |
Personas apresentam certs com IP SANs (IP público real) + DNS <persona>.<country>.persona.tlsstress.art. |
O NGFW só vê o único edge link (VLAN 2001); o pod VyOS-ISP roteia adiante
para cada /24 de país. O inventário de interfaces do NGFW é, portanto, 8
interfaces (3 INSIDE + 4 OUTSIDE + 1 MGMT), não uma por persona.
6. Planos de dados — eth0 / net1 / VLANs¶
Cada pod é dual-homed. O eth0 carrega controle + observabilidade e nunca sai do host (bridge OOBI); o net1 é uma macvlan que bypassa iptables/NetworkPolicy e carrega o tráfego de teste de fato para o trunk VLAN. Essa separação é o que permite à bancada dirigir tráfego em line-rate por um NGFW físico mantendo a orquestração em um canal de controle limpo.
flowchart TB
subgraph POD["Cada pod de plano de dados"]
ETH0(["eth0<br/>net padrão K8s"])
NET1(["net1<br/>macvlan (Multus)"])
end
subgraph CTRL["Plano de controle + observabilidade (eth0)"]
DASH["Dashboard :3000"]
PG["Postgres :5432"]
PROM["Prometheus :9090"]
end
subgraph DATA["Plano de dados (net1 → trunk 802.1q)"]
V20["VLAN 20 · 172.16.0.0/16<br/>Agentes Playwright (TRUST)"]
V30["VLAN 30 · 172.17.0.0/16<br/>Agentes k6 (TRUST)"]
V99["VLAN 99 · 10.254.254.0/24<br/>OOBI / SNMP mgmt"]
V40["VLAN 40 · DHCP<br/>Cloner ISP (SEM NGFW)"]
VCO["VLANs 101-120<br/>Personas — 1 VLAN/país<br/>/24 público real"]
end
DUT{{"NGFW DUT"}}
NET2["VyOS-ISP → LANs de país"]
INET(["Internet pública"])
ETH0 --> CTRL
NET1 --> V20 --> DUT
NET1 --> V30 --> DUT
NET1 --> V99
NET1 --> V40 --> INET
DUT --> NET2 --> VCO
classDef ctrl fill:#fce7f3,stroke:#db2777,stroke-width:1px
classDef data fill:#dbeafe,stroke:#2563eb,stroke-width:1px
classDef dut fill:#fef9c3,stroke:#b45309,stroke-width:2px
classDef ext fill:#f5f5f7,stroke:#000,stroke-width:1px
class DASH,PG,PROM ctrl
class V20,V30,V99,V40,VCO data
class DUT dut
class INET,NET2 ext
| Plano | Interface | Segmento(s) | Propósito |
|---|---|---|---|
| Controle / mgmt | eth0 | net padrão K8s | API do Dashboard, heartbeat, scrape Prometheus — nunca sai do host |
| Dados — Playwright | net1 | VLAN 20 172.16.0.0/16 |
Carga browser-driven através do NGFW |
| Dados — k6 | net1 | VLAN 30 172.17.0.0/16 |
Carga TLS/HTTP sintética através do NGFW |
| SNMP / OOBI | net1 | VLAN 99 10.254.254.0/24 (VXLAN VNI 254254) |
Polling SNMP + fabric de orquestração OOBI |
| Personas | net1 | VLANs 101-120 — uma VLAN por país, /24 público real |
Endpoints do leg TLS 2 (atrás do VyOS-ISP) |
| Cloner ISP | net1 | VLAN 40 (DHCP) | Saída direta para a internet do cloner de sites — bypassa o NGFW |
Schema v4.3 / ADR-0007 (Realismo de Internet Pública): personas carregam apenas
countryempersonas.yaml; o id da VLAN, o prefixo/24público e o gateway são derivados via lookup contraplatform/network/public-ip-pool.yaml. Endereçamento RFC1918 de persona (10.1.x.0/27) foi o estado v4.2 stale e não deve ser usado.
7. O substrato de cell (ADR-0053)¶
O lado SaaS é construído cell-based desde o Wave-0 para escalar de dezenas a centenas de milhares de clientes sem migração pause-the-world.
| Conceito | Definição |
|---|---|
| Cell | Unidade de isolamento de até 10 000 clientes com seu próprio stack OCTOPUS. Crash de uma cell nunca afeta outras. cell_id = <region>-<n> (ex.: hel1-0). |
| Sharding key | deployment_id (ULID / dpl_*) — a unidade de tráfego, que é o que satura. |
| Plano de controle | Serviços globais de todas as cells: Admin Console, Provisioning Orchestrator, token marketplace, PKI root, audit chain. |
| Plano de dados | Tráfego de cliente por-cell, cell-isolado (rendezvous CONNECT.Art + signaling STUN-coord). |
Wave-1 (live hoje) é uma única cell — hel1-0 em um VPS Hetzner — mas todo
schema já é cell-ready (coluna cell_id em toda primary key), então waves
posteriores são incrementais, nunca um rewrite. O isolamento por tenant usa
RLS Postgres em schema compartilhado (escala a 10k tenants/cell sem 10k
schemas): a tabela tenant_data tem ENABLE/FORCE ROW LEVEL SECURITY com policy
USING (deployment_id = current_setting('octopus.tenant')). O plano de controle
roda privilegiado; o plano de dados conecta com o role tenant_dataplane
(NOSUPERUSER NOBYPASSRLS), então leituras cross-tenant retornam zero linhas.
Um slot (connect-art / stun-coord) é uma entrada de admissão, não um
recurso de runtime escasso: os serviços de plano de dados leem slots para
admitir/rejeitar um deployment_id. Ver F2 HLD §4.6
e ADR-0053.
flowchart LR
subgraph CP["Plano de controle (global)"]
ADMIN["Admin Console"]
ORCH["Provisioning Orchestrator"]
PKI["PKI root / audit chain"]
end
subgraph CELL["Cell hel1-0 (Wave-1)"]
direction TB
CA["CONNECT.Art"]
SC["STUN-coord"]
DB[("tenants · slots · tenant_data<br/>(RLS, schema compartilhado)")]
end
ORCH -->|"AllocateCell · ProvisionTenant · ReserveSlot"| DB
CA -->|"lê slots → admite"| DB
SC -->|"lê slots → admite"| DB
ADMIN -.-> ORCH
classDef cp fill:#0F1A2E,stroke:#00D8FC,color:#FCFCFC,stroke-width:2px
classDef cell fill:#f0fdf4,stroke:#16a34a,stroke-width:1px
class ADMIN,ORCH,PKI cp
class CA,SC,DB cell
8. A economia de tokens (TSU)¶
O billing é medido em TSU (TLSStress Units). O fluxo é deliberadamente dividido para que o saldo autoritativo viva na cloud enquanto o spend se origina on-prem.
sequenceDiagram
autonumber
participant C as Cliente
participant APP as customer-app (AWS)
participant RDS as ledger UTXO RDS
participant DASH as Dashboard on-prem
participant GATE as gate license authorize()
participant PG as Postgres on-prem (notas UTXO)
participant BOOT as bootstrap-controller
participant USAGE as /api/usage/report (cloud)
C->>APP: checkout (Stripe)
APP->>RDS: applyTier — MINT de quota (autoritativo)
Note over DASH,GATE: toda execução de test plan passa pelo gate
DASH->>GATE: authorize(testPlanId, estimatedTokens, features)
GATE->>PG: spendNotes() — queima seriais de nota UTXO
GATE->>PG: sealedAppend() — registro de auditoria WORM
GATE-->>DASH: recibo {sealedHash, burnedSerials, balanceAfter}
DASH->>DASH: run executa — agentes emitem Tick(TSU) por run finalizado
BOOT->>BOOT: drena /var/lib/tlsstress/spend/*.jsonl (horário)
BOOT->>USAGE: POST eventos de uso (client_seq estável → dedup)
Propriedades-chave (fiéis a pkg/metering/README.md, dashboard/src/lib/license/):
- Mint autoritativo no checkout — o customer-app minta a quota no ledger
UTXO do RDS (tokens são notas tamper-evident, não um saldo mutável; Patent
#19, sem coluna
balance, sem race de update). - Spend on-prem — cada módulo emite um
Tick(TSU)por unidade de trabalho finalizada em/var/lib/tlsstress/spend/<module>.jsonl. Um meter quebrado não pode derrubar o módulo (faz fallback para stderr). - Gate de licença como chokepoint —
authorize()emdashboard/src/lib/license/gate.tsé o único chokepoint pelo qual todo test run passa: gasta notas UTXO, faz append no audit hash-chain selado e retorna um recibo assinado. Wave-1 é always-allow (envelope de desenvolvedor); o enforcement (verificação de assinatura, gating de features, caps de concorrência, expiry+grace) liga sob a mesma assinatura no v5.3+. - Reconciliação horária — o bootstrap-controller drena os arquivos de spend e
faz POST para o
/api/usage/reportda cloud; a idempotência é trabalho do controller (client_seqestável por evento → cloud rejeita duplicata no retry).
9. Postura de segurança (alto nível)¶
A postura completa de Zero-Trust-on-Premises (ZTP-prem) de 12 camadas — que defende a bancada contra um operador insider com
kubectl+ root dentro da própria org do cliente — está em SECURITY_ZTP_PREM.md. Esta seção é a baseline operacional que se aplica independentemente do estado de layer-flip do ZTP-prem.
| Camada | Controle |
|---|---|
| Containers | Non-root, capabilities Linux dropadas, seccomp RuntimeDefault, root filesystem read-only onde possível. |
| Rede | NetworkPolicy de egress default-deny; RFC1918 + link-local bloqueados da frota de agentes. Personas atrás do VyOS-ISP; movimento lateral OOBI bloqueado (só a VIP do Infra Stack 10.254.254.100 pode iniciar para IPs OOBI de MÓDULO). |
| Auth | Cookie HttpOnly assinado por HMAC no Dashboard (compare em tempo constante, rate limit por IP); Authorization: Basic legado para callers programáticos. O trigger da cloud é HMAC-SHA256 com verify em tempo constante. |
| Supply chain | gitleaks + trivy por PR, CodeQL semanal; imagens assinadas Cosign-keyless via GitHub OIDC; SBOM SPDX anexado por release tag. |
| Gate de pre-flight | Catálogo de 5 checks antes de cada run (conflito de subnet, alcance NGFW + decrypt mode, frescor da PKI de persona, skew NTP, auth da DUT API). Bypass é logado no audit_log + impresso na capa do report. |
| Dados em repouso | Credenciais da DUT API cifradas com AES-GCM; snapshots sanitizados com hash SHA-256 no Test Run Report (Anexo B/C/D). |
| Isolamento de tenant (cloud) | RLS Postgres com o role tenant_dataplane (NOBYPASSRLS); leitura cross-tenant = 0 linhas (provado live). |
| Auditabilidade | audit_log registra toda mutação de config (ator, IP de origem, JSON before/after); audit hash-chain selado do ZTP-prem (WORM) registra toda decisão de licença/admission/egress. |
10. Topologia de deployment (ADR-0011)¶
A topologia é configurada via platform/topology.yaml em três eixos
independentes, então um lab single-node e um fabric multi-node de prod
compartilham uma única base de código.
| Eixo | Valores | Controla |
|---|---|---|
deployment_nodes |
single · dual · tri · multi |
Número de hosts UCS + distribuição de roles |
l2_fabric |
nexus · none |
Switch L2 externo (ou sua ausência) |
dut_type |
cisco-ftd · cisco-secure-router |
Vendor do DUT — gateia scripts de apply/verify |
Single-node sem switch externo é first-class (l2_fabric: none): NICs do UCS
cabeadas direto no NGFW, tuning Nexus pulado, mas a atestação BPDU de
Linux-bridge continua rodando. O plano OOBI (eth0) é mandatório em todo host em
todo modo. Overlays Kustomize (overlays/dual-node|tri-node|multi-node/) pinam
cada tier de workload ao seu host dedicado via patches de nodeSelector.
11. Referências cruzadas¶
| Tópico | Documento |
|---|---|
| Tour de componentes, diagramas de sequência, topologia DUT | docs/ARCHITECTURE.md |
| Aprofundamento F2 auto-provisionamento + cell-0 | docs/F2_HETZNER_CELL0_ARCHITECTURE.md |
| Segurança ZTP-prem de 12 camadas | docs/SECURITY_ZTP_PREM.md |
| Racional de hyperscale por cells | ADR-0053 |
| Índice de registros de decisão | ADR/README.md |
| Convenções & regras do projeto | CLAUDE.md |