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.01guard 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
DefaultAzureCredentialwith least-privilege role assignments adopted into Pulumi; the Railway-hosted app stays key-based (no Azure MSI path). - Stack rename + naming convention —
devstack renamed toprod; 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
parenthierarchy, including storage/table/search data migration and the Railway endpoint cutover. - Provider split + GitHub — split
src/azure/; added@pulumi/githubmanaging repo settings, labels, environments, and secrets (via ESC); migrated branch protection to a singledevelop+mainruleset withrequired_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-letter —
deadlettercontainer +deadLetterDestinationon all ten application subscriptions, tightened retry (10 attempts / 1h), 30-day lifecycle expiry, and a storage system topic that push-triggers theReplayDeadLetterEventfunction 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.01budget 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
Previous
Server testing
tRPC router test wiring — in-memory database, mocked Azure services, and a controlled auth session.
Next
Azure Pulumi Layout
How Esposter's Azure resources are managed in Pulumi — one resource per file, ARM-aligned source paths, a single prod stack, and a GitHub provider alongside Azure.