mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 10:24:02 +00:00
feat(infra): add aws lambda pulumi deployment target
This commit is contained in:
155
docs/runbooks/aws-pulumi-deploy.md
Normal file
155
docs/runbooks/aws-pulumi-deploy.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# AWS Lambda + Pulumi Deployment Runbook
|
||||
|
||||
## Purpose
|
||||
|
||||
Deploy the bot runtime to AWS Lambda as a Bun container image, publish the miniapp to S3 website hosting, and place Cloudflare in front of both public origins.
|
||||
|
||||
This runbook is additive to the current GCP path. It does not replace the existing Terraform/Cloud Run deployment flow.
|
||||
|
||||
## Architecture
|
||||
|
||||
- Bot/API origin: AWS Lambda Function URL backed by `apps/bot/Dockerfile.lambda`
|
||||
- Miniapp origin: S3 website hosting for `apps/miniapp/dist`
|
||||
- Public edge: `api.<domain>` proxied by Cloudflare to the Lambda Function URL
|
||||
- Public edge: `app.<domain>` proxied by Cloudflare to the S3 website endpoint
|
||||
- Scheduler: Supabase Cron calling `https://api.<domain>/jobs/reminder/<type>`
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- AWS account with permissions for ECR, Lambda, IAM, S3, and Secrets Manager
|
||||
- Pulumi backend access
|
||||
- Cloudflare zone access
|
||||
- Supabase project with Cron enabled
|
||||
- Bun `1.3.10`
|
||||
- Docker
|
||||
- AWS CLI
|
||||
|
||||
## Required Pulumi config
|
||||
|
||||
Set these on the target stack:
|
||||
|
||||
```bash
|
||||
cd infra/pulumi/aws
|
||||
|
||||
pulumi config set publicApiHostname "api.example.com"
|
||||
pulumi config set publicMiniappHostname "app.example.com"
|
||||
pulumi config set miniAppAllowedOrigins '["https://app.example.com"]' --path
|
||||
pulumi config set miniAppUrl "https://app.example.com"
|
||||
|
||||
pulumi config set --secret telegramBotToken "<token>"
|
||||
pulumi config set --secret telegramWebhookSecret "<secret>"
|
||||
pulumi config set --secret databaseUrl "<database-url>"
|
||||
pulumi config set --secret schedulerSharedSecret "<scheduler-secret>"
|
||||
pulumi config set --secret openaiApiKey "<openai-key>"
|
||||
```
|
||||
|
||||
Optional:
|
||||
|
||||
```bash
|
||||
pulumi config set environment "prod"
|
||||
pulumi config set appName "household"
|
||||
pulumi config set logLevel "info"
|
||||
pulumi config set purchaseParserModel "gpt-4o-mini"
|
||||
pulumi config set assistantModel "gpt-4o-mini"
|
||||
pulumi config set topicProcessorModel "gpt-4o-mini"
|
||||
pulumi config set memorySize "1024"
|
||||
pulumi config set timeout "30"
|
||||
```
|
||||
|
||||
## Deploy infrastructure
|
||||
|
||||
From the repo root:
|
||||
|
||||
```bash
|
||||
bun run infra:aws:preview -- --stack <stack>
|
||||
bun run infra:aws:up -- --stack <stack> --yes
|
||||
```
|
||||
|
||||
Capture outputs:
|
||||
|
||||
```bash
|
||||
cd infra/pulumi/aws
|
||||
pulumi stack output botOriginUrl --stack <stack>
|
||||
pulumi stack output miniAppWebsiteUrl --stack <stack>
|
||||
pulumi stack output miniAppBucketName --stack <stack>
|
||||
pulumi stack output cloudflareApiCnameTarget --stack <stack>
|
||||
pulumi stack output cloudflareMiniappCnameTarget --stack <stack>
|
||||
```
|
||||
|
||||
## Publish miniapp
|
||||
|
||||
From the repo root:
|
||||
|
||||
```bash
|
||||
export AWS_MINIAPP_BUCKET="<bucket-name>"
|
||||
export BOT_API_URL="https://api.example.com"
|
||||
export AWS_REGION="<region>"
|
||||
|
||||
bun run ops:aws:miniapp:publish
|
||||
```
|
||||
|
||||
## Cloudflare setup
|
||||
|
||||
Create proxied DNS records:
|
||||
|
||||
- `api` CNAME -> Pulumi output `cloudflareApiCnameTarget`
|
||||
- `app` CNAME -> Pulumi output `cloudflareMiniappCnameTarget`
|
||||
|
||||
Recommended Cloudflare settings:
|
||||
|
||||
- SSL/TLS mode: `Flexible` for the S3 website origin path if you keep S3 website hosting
|
||||
- Cache bypass for `api.<domain>/*`
|
||||
- Cache static assets aggressively for `app.<domain>/assets/*`
|
||||
- Optional WAF or rate limits for `/webhook/telegram`
|
||||
- Optional WAF or rate limits for `/jobs/reminder/*`
|
||||
|
||||
Note: S3 website hosting is HTTP-only between Cloudflare and the bucket website endpoint. If you want stricter origin hardening later, move to S3 + CloudFront.
|
||||
|
||||
## Telegram webhook cutover
|
||||
|
||||
```bash
|
||||
export TELEGRAM_WEBHOOK_URL="https://api.example.com/webhook/telegram"
|
||||
export TELEGRAM_BOT_TOKEN="<token>"
|
||||
export TELEGRAM_WEBHOOK_SECRET="<secret>"
|
||||
|
||||
bun run ops:telegram:webhook set
|
||||
bun run ops:telegram:webhook info
|
||||
```
|
||||
|
||||
## Supabase Cron jobs
|
||||
|
||||
Keep the existing HTTP scheduler contract and call the public API through Cloudflare.
|
||||
|
||||
Required endpoints:
|
||||
|
||||
- `POST https://api.<domain>/jobs/reminder/utilities`
|
||||
- `POST https://api.<domain>/jobs/reminder/rent-warning`
|
||||
- `POST https://api.<domain>/jobs/reminder/rent-due`
|
||||
|
||||
Required auth:
|
||||
|
||||
- Header `x-household-scheduler-secret: <scheduler-secret>`
|
||||
|
||||
Suggested schedules:
|
||||
|
||||
- utilities: day 4 at 09:00 `Asia/Tbilisi`
|
||||
- rent-warning: day 1 at 09:00 `Asia/Tbilisi`
|
||||
- rent-due: day 3 at 09:00 `Asia/Tbilisi`
|
||||
|
||||
## Validation
|
||||
|
||||
Run the existing smoke checks with the AWS public URLs:
|
||||
|
||||
```bash
|
||||
export BOT_API_URL="https://api.example.com"
|
||||
export MINI_APP_URL="https://app.example.com"
|
||||
export TELEGRAM_EXPECTED_WEBHOOK_URL="${BOT_API_URL}/webhook/telegram"
|
||||
|
||||
bun run ops:deploy:smoke
|
||||
```
|
||||
|
||||
Also verify:
|
||||
|
||||
- Cloudflare proxies both hostnames successfully
|
||||
- miniapp session and dashboard endpoints succeed via `api.<domain>`
|
||||
- Supabase Cron can hit each reminder endpoint with the shared secret
|
||||
Reference in New Issue
Block a user