Esposter

Infra

packages/infra manages Esposter's cloud footprint as Pulumi TypeScript. A single prod stack owns both the development and production Azure resource groups plus the GitHub repository settings (labels, environments, secrets, branch rulesets). Everything runs on free or near-free SKUs, and the whole estate is cost-guarded: $0.01 budgets trigger Logic App automation that stops Function Apps and deletes Event Grid subscriptions the moment anything exits the free tier.

  • Azure Pulumi migration — how resources are laid out in Pulumi: one resource per file, ARM-aligned paths, provider split, naming convention.
  • Cost & Security Posture — the budget guard cycle and why each hardening step is deliberately deferred.
  • Event Grid dead-letter — failed deliveries land in a blob container whose writes push-trigger an automatic, attempt-capped replay.
  • Observability — why App Insights and Log Analytics are deliberately not provisioned, and what the estate relies on instead.
  • Pulumi source of truth — Function App runtime settings managed in Pulumi.
  • Roadmap — open items (key-auth-gated hardening); every item links its proposal.
  • Deferred — ideas waiting on a trigger.

Deeper operational reference lives beside the code in packages/infra/docs/ (naming conventions, security constraints, search indexes, stacks), and Pulumi coding conventions live in the pulumi-infra skill.

Shipped

  • Pulumi adoption — imported the manually-created Azure resources into Pulumi (one resource per file, protect: true).
  • Posture review — cost / security / network / identity review; recorded constraints and follow-ups. → Cost & Security Posture
  • Safe cleanup — Web PubSub trace ACL left as-is (Azure rejects ACL changes on Free_F1).
  • Storage safety — disabled blob versioning (unused, paid), kept 7-day blob/container soft delete, kept Standard_LRS.
  • Observability cost controls$0.01 guard budgets wired to Logic App stop/delete automation.
  • Workflow review — mapped the Function App / Logic App / API connection / Event Grid automation into the stop-start + delete-restore free-tier guard cycle.
  • Managed identity / RBAC — Azure Functions use DefaultAzureCredential with least-privilege role assignments adopted into Pulumi; the Railway-hosted app stays key-based (no Azure MSI path).
  • Stack rename + naming conventiondev stack renamed to prod; adopted the CAF-aligned naming convention (packages/infra/docs/azure/naming-conventions.md).
  • Naming migration — migrated all dev + prod resources (stateless, stateful, monitoring) to the convention with parent hierarchy, including storage/table/search data migration and the Railway endpoint cutover.
  • Provider split + GitHub — split src/azure/; added @pulumi/github managing repo settings, labels, environments, and secrets (via ESC); migrated branch protection to a single develop+main ruleset with required_approving_review_count: 0.
  • Post-migration verification — smoke-tested uploads, messages, push, search, Web PubSub, and function processing; confirmed the prod search indexer populated messages-index.
  • Event Grid dead-letterdeadletter container + deadLetterDestination on all ten application subscriptions, tightened retry (10 attempts / 1h), 30-day lifecycle expiry, and a storage system topic that push-triggers the ReplayDeadLetterEvent function with a two-attempt cap and a quarantine prefix. → Event Grid dead-letter
  • Observability removal — deleted App Insights, Log Analytics, smart-detector rules, and scheduled-query alerts (dev + prod) to stay in the free tier; the $0.01 budget guard is the cost ceiling. → Observability
  • Pulumi source of truth — adopted the Function Apps' runtime app settings into Pulumi; secrets flow from ESC. → Pulumi source of truth