Add 5-phase plan to self-host on Coolify (docker-compose) with a MongoDB Atlas backend, an in-process cron scheduler, DynamoDB->Atlas migration, and full AWS teardown. Red-teamed and validated; decommission scope verified against live AWS/Cloudflare accounts. Include free-tier audit and S3-elimination research reports. Ignore wrangler local cache.
11 KiB
phase, title, status, priority, dependencies, effort
| phase | title | status | priority | dependencies | effort | |
|---|---|---|---|---|---|---|
| 5 | AWS Full Decommission | pending | P1 |
|
S |
Phase 5: AWS Full Decommission
Overview
After migration + cutover verify (Phase 4), delete everything miti99bot ever deployed to AWS, plus verify/clean the legacy pre-AWS services (Cloudflare, GCP — section D). The trap: sam delete only removes CloudFormation-managed resources — the GitHub OIDC IAM role, the SSM Parameter Store secrets, and SAM's own S3 deploy bucket were created manually outside CloudFormation (aws/README.md steps 2-4) and must be deleted separately or they linger (and the secrets keep your bot token/Gemini key sitting in the cloud). GitHub itself is already clean (verified: no stored secrets/keys — AWS deploy used OIDC only).
This phase is informed by a git-history scan of every template.yaml version + the aws/ setup docs, verified against the live account on 2026-06-27 (admin profile). Account 225603493174, region ap-southeast-1.
Live verification (2026-06-27, read-only): stack miti99bot = UPDATE_COMPLETE. The account has exactly TWO CloudFormation stacks (miti99bot + aws-sam-cli-managed-default) and ONE OIDC provider — so miti99bot is the sole SAM project AND the sole OIDC consumer, which makes the shared-resource deletes (OIDC provider, SAM bucket) safe and unconditional. SSM holds exactly the 4 known secrets (no FireAnt/VNAppMob extras). SAM deploy bucket: aws-sam-cli-managed-default-samclisourcebucket-ctwpsmoxnwvm.
Requirements
- Functional: zero miti99bot resources remain in AWS after this phase; Cost Explorer trends to $0.
- Functional: run ONLY after Phase 4
--verifypasses and the bot is confirmed live on Coolify (DynamoDB holds the only copy of prod data until migrated). - Non-functional: do NOT delete account-shared resources (OIDC provider, SAM bucket) if other stacks/repos use them — verify first.
- Non-functional: executed by the user with the
adminprofile (this session has no AWS credentials); plan provides the exact commands.
Architecture — Complete Resource Inventory
A. CloudFormation-managed → removed by sam delete --stack-name miti99bot
From the current template.yaml:
AWS::DynamoDB::Table—miti99bot-data(destroyed — must be migrated first)AWS::Serverless::Function—miti99bot+ its Function URL + the LWA layer referenceAWS::Logs::LogGroup—/aws/lambda/miti99bot(+AWS::Logs::MetricFilterColdStartInitDuration)AWS::SQS::Queue—miti99bot-cron-dlqAWS::IAM::Role—SchedulerExecutionRoleAND the SAM-auto-generated Lambda execution rolemiti99bot-BotFunctionRole-*(both CFN-managed;sam deleteremoves both — no separate action) + the public Function-URL invokeAWS::Lambda::PermissionsAWS::Scheduler::Schedule—miti99bot-lolschedule-daily-pushAWS::Budgets::Budget—miti99bot-monthly(only if AlertEmail was set)
Historical (git history shows earlier template.yaml used these, since replaced by Scheduler): AWS::Events::Rule, AWS::Events::Connection, AWS::Events::ApiDestination. CloudFormation deleted them when the template changed, so they are NOT orphans — but a post-delete tag sweep (step 6) confirms.
B. Created manually OUTSIDE CloudFormation → sam delete does NOT touch these
From aws/README.md:
- SSM Parameter Store SecureStrings (
aws/README.md:23-39, verified — exactly these 4, no extras):/miti99bot/prod/telegram-bot-token,/miti99bot/prod/telegram-webhook-secret,/miti99bot/prod/gemini-api-key,/miti99bot/prod/cron-shared-secret. These hold live secrets — deleting them is the security-relevant step. - IAM role
github-deploy-miti99bot+ inline policymiti99bot-deploy(aws/README.md:57-73). - IAM OIDC identity provider
token.actions.githubusercontent.com(aws/README.md:43-53) — verified as the account's ONLY OIDC provider and used solely by miti99bot → safe to delete. - SAM managed S3 deploy bucket
aws-sam-cli-managed-default-samclisourcebucket-ctwpsmoxnwvm+ its bootstrap stackaws-sam-cli-managed-default— verified miti99bot is the sole SAM project → safe to delete the bucket + bootstrap stack. - Bootstrap
adminIAM user + access keys (aws/README.md:15) — user's discretion; out of scope unless they want a full account wipe.
C. Not deletable / self-expiring (no action)
- Custom CloudWatch metric namespace
miti99bot(metrics age out; not billable, not deletable).
D. Legacy services from the pre-AWS lineage (verify + clean — not AWS)
The bot's history is Cloudflare Worker (original) → [Cloud Run port, abandoned] → AWS → Coolify (this plan). Two legacy footprints to confirm:
- Cloudflare (verified live 2026-06-27, account
miti99/7774466151858e13a3c482af5f9ccd6b):- KV namespaces: only
claude-statusremains — NO miti99bot KV → the legacy bot KV namespace was already deleted. ✅ no action. - D1 databases: none → legacy
trading_tradesD1 already deleted. ✅ no action. - Workers: 4 exist —
claude-status-webhook,rplace,miti-loki(Grafana Loki log-shipper), andmiti-telegram. All confirmed (user, 2026-06-27) as separate active projects, NOT the legacy miti99bot.miti-telegramis a different single-chat notifier the user still uses. - Conclusion: Cloudflare is fully clean — NO action. The legacy miti99bot Worker was already deleted during the May 2026 migration; only its data stores (KV/D1) were ever in scope and both are gone.
- KV namespaces: only
- GCP project
miti99bot-prod— almost certainly never created (Cloud Run port superseded before phase-01 ran; no bootstrap artifacts ever existed). Optional certainty check:gcloud projects list | grep miti99bot→ if a project exists,gcloud projects delete miti99bot-prod. Low probability.
Related Code Files
- Create:
docs/aws-decommission-runbook.md— the ordered teardown commands below (so it's repeatable + auditable). - Modify:
.github/workflows/deploy.yml— delete or disable (the AWS deploy path is retired; otherwise a push tomainre-creates the stack). On thefeature/selfhostedbranch this file is replaced by the Coolify flow. - Modify:
README.md/docs/deploy-aws*.md— mark the AWS deployment path as retired, point to the Coolify guide. - Keep (do not delete):
aws/dir +template.yamlin git history — useful if AWS is ever revisited; they cost nothing as files.
Implementation Steps (runbook — user runs with admin profile)
Precondition: Phase 4 done — data migrated, --verify green, bot live on Coolify, Telegram webhook pointed at Coolify, EventBridge schedule already disabled at cutover.
AWS_PROFILE=admin; REGION=ap-southeast-1; ACCT=225603493174
# 1. Final safety check — confirm bot is NOT serving from AWS anymore
aws --profile $AWS_PROFILE cloudformation describe-stacks --stack-name miti99bot \
--query "Stacks[0].StackStatus" # exists → about to be deleted
# 2. Delete the CloudFormation stack (DynamoDB, Lambda, FunctionUrl, Logs, SQS, Scheduler, IAM role, Budget)
aws --profile $AWS_PROFILE sam delete --stack-name miti99bot --region $REGION --no-prompts
# (or: aws cloudformation delete-stack --stack-name miti99bot ; then wait)
aws --profile $AWS_PROFILE cloudformation wait stack-delete-complete --stack-name miti99bot
# 3. Delete SSM secrets (NOT managed by CFN)
aws --profile $AWS_PROFILE ssm get-parameters-by-path --path /miti99bot --recursive \
--query "Parameters[].Name" --output text # list what exists first
for P in telegram-bot-token telegram-webhook-secret gemini-api-key cron-shared-secret; do
aws --profile $AWS_PROFILE ssm delete-parameter --name /miti99bot/prod/$P
done
# delete any extra /miti99bot/* the list in step 3 revealed
# 4. Delete the GitHub deploy IAM role (inline policy first, then role)
aws --profile $AWS_PROFILE iam delete-role-policy \
--role-name github-deploy-miti99bot --policy-name miti99bot-deploy
aws --profile $AWS_PROFILE iam delete-role --role-name github-deploy-miti99bot
# 5. OIDC provider — verified sole consumer = miti99bot, safe to delete.
# (Re-confirm it's still the only one before deleting, in case the account changed.)
aws --profile $AWS_PROFILE iam list-open-id-connect-providers
aws --profile $AWS_PROFILE iam delete-open-id-connect-provider \
--open-id-connect-provider-arn arn:aws:iam::$ACCT:oidc-provider/token.actions.githubusercontent.com
# 6. SAM S3 deploy bucket + bootstrap stack — verified miti99bot is the sole SAM project.
# (Re-confirm only miti99bot + aws-sam-cli-managed-default stacks exist first.)
aws --profile $AWS_PROFILE cloudformation list-stacks \
--query "StackSummaries[?StackStatus!='DELETE_COMPLETE'].StackName" --output text
aws --profile $AWS_PROFILE s3 rb \
s3://aws-sam-cli-managed-default-samclisourcebucket-ctwpsmoxnwvm --force
aws --profile $AWS_PROFILE cloudformation delete-stack --stack-name aws-sam-cli-managed-default
# 7. Verify nothing tagged app=miti99bot remains
aws --profile $AWS_PROFILE resourcegroupstaggingapi get-resources \
--tag-filters Key=app,Values=miti99bot --region $REGION
aws --profile $AWS_PROFILE cloudformation list-stacks \
--query "StackSummaries[?contains(StackName,'miti99bot')].[StackName,StackStatus]" --output table
Then in the repo (on feature/selfhosted): remove/disable .github/workflows/deploy.yml and mark AWS docs retired.
Success Criteria
cloudformation describe-stacks --stack-name miti99bot→ does not exist (DELETE_COMPLETE).- No
/miti99bot/*SSM parameters remain (secrets purged from cloud). github-deploy-miti99botrole gone; OIDC provider gone OR confirmed still needed by another project.- SAM bucket emptied/deleted OR
miti99bot/prefix cleared (and rationale recorded). resourcegroupstaggingapi get-resourcesforapp=miti99botreturns empty..github/workflows/deploy.ymlremoved/disabled somainpushes no longer recreate the stack.- Cost Explorer shows $0 for the following billing period.
- Cloudflare verified clean (2026-06-27): KV + D1 already gone; all 4 Workers confirmed as separate active projects (no legacy bot remnant). No action.
- GCP checked: no
miti99bot-prodproject exists (or deleted). - GitHub confirmed clean: no AWS secrets/keys stored;
deploy-aws.ymlremoved (only OIDC was used, nothing to revoke beyond the role deleted above).
Risk Assessment
- Deleting before migration completes (Critical):
sam deletedestroysmiti99bot-data(DynamoDB). Mitigation: hard dependency on Phase 4--verify; runbook step 1 is an explicit precondition check. Never run Phase 5 standalone. - Deleting shared account resources: verified on 2026-06-27 that miti99bot is the sole OIDC consumer and sole SAM project, so steps 5-6 are safe. Mitigation: the runbook re-confirms (list-first) before each delete in case the account changes before you run it; if a new stack/provider appears, leave the shared resource (it costs ~nothing).
- Re-creation by CI: a
mainpush withdeploy.ymlstill active would rebuild the whole stack post-teardown. Mitigation: disable/delete the workflow as part of this phase (and it's already superseded onfeature/selfhosted). - Lost rollback: per the Phase 4 validated decision, teardown ends the AWS rollback option. Mitigation: that was explicitly accepted; optionally keep the stack a few days before running step 2.
- Secret hygiene: rotate the Telegram bot token + Gemini key after teardown if you want defense-in-depth (they lived in SSM and CloudWatch under the accepted trade-offs). Optional.