Skip to content

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_SECRET setados no App Runner.
  • CRON_SECRET no Secrets Manager (tlsstress-phase0/cron-secret) e como env do App Runner.
  • DATABASE_URL / OCTOPUS_CUSTOMER_DB_URL apontando para o RDS de prod.

1. Variáveis de ambiente novas (opcionais — só quando aplicável)

  • STRIPE_PRICE_BOOST_100K / _1M / _10M / _100Mobrigató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_SECRETSsó ao rotacionar a chave de licença (JSON {"v1":"<antigo≥32>","v2":"<novo≥32>"}); aponte LICENSE_JWT_SECRET para o novo e LICENSE_JWT_KID para o novo kid. Sem rotação, deixe ausente.
  • TLSSTRESS_SPKI_PINSsó em rotação de CA (controller on-prem). Ver docs/token-economy/spki-pin-rotation.md.
  • ZTP_PREM_PW_LEASE_SECONDSsó 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=trueopcional (cloud). Endurece a policy L3-posture: nega usage/authorize de tiers defense sem TPM 2.0 (default: só avisa via usage.authorize.attestation_gap).
  • METRICS_TOKENp/ 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); idem CRON_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_MODEopcional (cloud). advisory (default) loga mismatch de envelope L1 e segue; enforce rejeita 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)

  • main já 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 ticket active para sempre (achado H2 da auditoria). O sweep forfeita após expires_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 log usage.tickets.expired (stranded_tsu) como evidência.

5. Verificação pós-deploy

  • Disparar manualmente o watchdog (deve responder 200):
    curl -s -X POST https://app.tlsstress.art/api/cron/reconcile-ledger \
      -H "x-cron-secret: $CRON_SECRET" | jq
    
    Esperado: staleBillingWebhooks: 0, overspentUtxos: 0, staleActiveTickets: 0.
  • Disparar manualmente o sweep de tickets (deve responder 200):
    curl -s -X POST https://app.tlsstress.art/api/cron/expire-tickets \
      -H "x-cron-secret: $CRON_SECRET" | jq
    
    Esperado: {"expiredTickets": 0, "strandedTsu": 0} num ambiente limpo.
  • Logs do App Runner: nenhum stripe.invoice.unmapped_price.CRITICAL (indicaria STRIPE_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) ou terraform destroy -target=... dos recursos novos (EventBridge).
  • Sem alteração de schema, então não há rollback de banco a fazer.