Token Economy — Checklist de Deploy & Ativação (ADR-0103/0104)¶
Aplica em produção a cadeia completa: hardening (PR #1242), antifraude L1/L2/L3
(PRs #1244–#1248) e a remediação da auditoria (PR #1275 — inclui o cron novo
expire-tickets). Não há migrations novas além das já versionadas (até a
0021) — o deploy é código + ativação de crons + variáveis de ambiente.
Verificação local (refeita a cada PR da cadeia): tsc · eslint · vitest
(customer-app + dashboard) · next build · go build/vet/test ·
terraform fmt/validate (infra/cron).
0. Pré-requisitos (já devem existir)¶
-
STRIPE_WEBHOOK_SECRET,STRIPE_SECRET_KEY,LICENSE_JWT_SECRETsetados no App Runner. -
CRON_SECRETno Secrets Manager (tlsstress-phase0/cron-secret) e como env do App Runner. -
DATABASE_URL/OCTOPUS_CUSTOMER_DB_URLapontando para o RDS de prod.
1. Variáveis de ambiente novas (opcionais — só quando aplicável)¶
-
STRIPE_PRICE_BOOST_100K/_1M/_10M/_100M— obrigatórias para qualquer SKU de boost ofertado. Sem elas, boost-checkout retorna 503 e o auto-refill é no-op (não cobra). Crie os Prices no Stripe e preencha. -
LICENSE_JWT_SECRETS— só ao rotacionar a chave de licença (JSON{"v1":"<antigo≥32>","v2":"<novo≥32>"}); aponteLICENSE_JWT_SECRETpara o novo eLICENSE_JWT_KIDpara o novo kid. Sem rotação, deixe ausente. -
TLSSTRESS_SPKI_PINS— só em rotação de CA (controller on-prem). Verdocs/token-economy/spki-pin-rotation.md. -
ZTP_PREM_PW_LEASE_SECONDS— só com o gate L2 ligado (Dashboard on-prem, opcional). Teto do lease por run de Playwright (default 60s); runs mais longas que o teto são sub-cobradas — calibre com o ciclo típico. -
REQUIRE_TPM_ATTESTATION=true— opcional (cloud). Endurece a policy L3-posture: negausage/authorizede tiersdefensesem TPM 2.0 (default: só avisa viausage.authorize.attestation_gap). -
METRICS_TOKEN— p/ scrape Prometheus do ledger (/api/metrics). Sem ela o endpoint responde 503 (não exposto). Desde 2026-06-10 é secret-ref (tlsstress-phase0/metrics-token, string PLAIN, gerida no TF principal); idemCRON_SECRET(tlsstress-phase0/cron-secret, PLAIN — formato JSON legado foi aposentado na rotação). - Migrations 0022–0025 — aplicadas pelo fluxo normal de migrations: 0022 (api_keys/webhooks/outbound_events/rate_cards/tsu_budgets), 0023 (L1 usage_pubkey/seq/nonces), 0024 (L3 quote scaffold + L4 index), 0025 (MSSP tier + parent index).
-
USAGE_ATTESTATION_MODE— opcional (cloud).advisory(default) loga mismatch de envelope L1 e segue;enforcerejeita reports não-assinados.
2. Stripe Dashboard — inscrever os event types no endpoint do webhook¶
No endpoint app.tlsstress.art/api/stripe/webhook, garanta que estão inscritos:
- [ ] charge.refunded (clawback proporcional — delta-cumulativo desde #1275)
- [ ] charge.dispute.created (clawback total + suspensão em chargeback)
- [ ] checkout.session.async_payment_succeeded (métodos de pagamento assíncronos)
- [ ] checkout.session.completed, invoice.paid, invoice.payment_failed,
customer.subscription.*
⚠️ O webhook retorna 5xx em falha transitória (para o Stripe reentregar) — em todos os handlers, inclusive o mint de boost (H1, #1275). Isso é esperado: confira a aba "Failed/Pending" do Stripe após o deploy; eventos não-terminais são reprocessados idempotentemente.
3. Deploy do customer-app (App Runner)¶
-
mainjá contém a cadeia completa (#1242 → #1275). Disparar o build/deploy do App Runner (AutoDeploy=false — deploy manual via console ou pipeline). - Aguardar health:
GET https://app.tlsstress.art/api/health→ 200.
4. Ativar os crons (3 do token-economy)¶
Escolha uma via por ambiente:
K8s (staging / on-cluster):
- [ ] kubectl apply -f pkg/octopus/customer-app/infra/cron/auto-refill-cronjob.yaml
- [ ] kubectl apply -f pkg/octopus/customer-app/infra/cron/reconcile-ledger-cronjob.yaml
- [ ] kubectl apply -f pkg/octopus/customer-app/infra/cron/expire-tickets-cronjob.yaml
- [ ] kubectl apply -f pkg/octopus/customer-app/infra/cron/deliver-webhooks-cronjob.yaml
- [ ] kubectl apply -f pkg/octopus/customer-app/infra/cron/expiring-notes-cronjob.yaml
- [ ] kubectl apply -f pkg/octopus/customer-app/infra/cron/mssp-tier-review-cronjob.yaml
AWS (SaaS): todos os 6 crons são geridos pelo stack consolidado
pkg/octopus/customer-app/infra/cron/terraform/ (Lambda em VPC → NAT →
App Runner direct URL — a URL pública 403a egress de datacenter via
Cloudflare; ver README do módulo). terraform plan deve dar No changes.
- [ ] Pré-req: secret customer-app-cron-secrets (key CRON_SECRET) no namespace customer-app.
EventBridge (prod / App Runner):
- [ ] cd pkg/octopus/customer-app/infra/cron && terraform init && terraform plan
- [ ] Revisar o plan (Lambdas + schedules + IAM por módulo; reusa o secret
tlsstress-phase0/cron-secret) e terraform apply.
Cadência: auto-refill horário · reconcile-ledger diário (03:00 UTC) ·
expire-tickets horário (:20) · deliver-webhooks a cada 5 min ·
expiring-notes diário (09:00 UTC). (expire-transfers é pré-existente — diário.)
⚠️
expire-ticketsé obrigatório quando o gate L2 estiver ativo — sem ele, um crash entre authorize e run-complete deixa o débito pré-pago preso num ticketactivepara sempre (achado H2 da auditoria). O sweep forfeita apósexpires_at+ 24h de grace (use-it-or-lose-it, sem auto-refund — antifraude); casos legítimos de crash → refund manual via admin grant, com o logusage.tickets.expired(stranded_tsu) como evidência.
5. Verificação pós-deploy¶
- Disparar manualmente o watchdog (deve responder 200):
Esperado:
curl -s -X POST https://app.tlsstress.art/api/cron/reconcile-ledger \ -H "x-cron-secret: $CRON_SECRET" | jqstaleBillingWebhooks: 0,overspentUtxos: 0,staleActiveTickets: 0. - Disparar manualmente o sweep de tickets (deve responder 200):
Esperado:
curl -s -X POST https://app.tlsstress.art/api/cron/expire-tickets \ -H "x-cron-secret: $CRON_SECRET" | jq{"expiredTickets": 0, "strandedTsu": 0}num ambiente limpo. - Logs do App Runner: nenhum
stripe.invoice.unmapped_price.CRITICAL(indicariaSTRIPE_PRICE_*faltando). - Executar o roteiro de validação em staging (
staging-validation.md) antes de liberar tráfego de produção.
6. Rollback¶
- Código: redeploy do App Runner para a revisão anterior (sem migration → rollback limpo).
- Crons:
kubectl delete cronjob auto-refill reconcile-ledger expire-tickets -n customer-app(K8s) outerraform destroy -target=...dos recursos novos (EventBridge). - Sem alteração de schema, então não há rollback de banco a fazer.