AWS Production Implementation Log
Tracks actual progress of the Finaisse AWS production setup phase by phase.
Architecture decisions and service mapping: see AWS Architecture.
Started: June 2026
Primary region: ap-south-1 (Mumbai) — preprod + production
Future production region: us-east-1 (planned, not started)
IaC: Terraform (fin-infra/aws/) — all resources via Terraform, no manual console provisioning
Registry: GHCR (unchanged)
Terraform Root Structure
aws/
├── global/
│ ├── bootstrap/ S3 state bucket + DynamoDB lock table (local state, run once)
│ ├── control-tower/ Landing Zone, OUs, SCPs, GuardDuty, budgets, Access Analyzer
│ ├── aft/ Account Factory for Terraform — account vending pipeline
│ ├── identity-center/ Zoho SAML SSO, permission sets, group → account assignments
│ └── iam/ GitHub Actions OIDC provider
├── aft-accounts/
│ ├── preprod/ AFT account request — triggers preprod account vending
│ └── production/ AFT account request — triggers production account vending
├── environments/
│ ├── preprod/ VPC, RDS, S3, KMS, WAF, Secrets, IAM, Flow Logs
│ └── production/ Same — production-grade sizing and settings
└── modules/
├── networking/ VPC, subnets, IGW, NAT, security groups
├── rds/ PostgreSQL 16, CMK encryption, force_ssl, configurable retention
├── s3/ App data + frontend buckets, SSE, versioning, lifecycle
├── secrets/ Secrets Manager — all app secrets, CMK encrypted
├── iam/ ECS task execution + task roles
├── kms/ CMKs for RDS, S3, Secrets Manager (auto-rotating)
├── waf/ WAFv2 — managed rules, SQLi, rate limiting, WAF logs
├── flow-logs/ VPC Flow Logs to S3
├── elasticache/ ElastiCache Valkey 7.2 (Redis-compatible), at-rest encryption
├── ssm/ SSM Parameter Store — non-secret config (80 vars)
└── ecs/ ECS Fargate cluster, ALB, ACM cert, CloudWatch logs, GHCR pullApply order (first-time setup)
1. global/bootstrap → terraform apply (S3 + DynamoDB — local state)
2. Console (2 actions only) → Enable IAM Identity Center
→ Run Control Tower Landing Zone wizard
3. global/control-tower → terraform apply (OUs, SCPs, GuardDuty, budgets, alerts)
4. global/aft → terraform apply (AFT pipeline infrastructure)
5. aft-accounts/preprod → terraform apply (vends finaisse-preprod account)
6. global/iam → terraform apply (GitHub Actions OIDC)
7. global/identity-center → terraform apply (Zoho SSO, permission sets, groups)
8. environments/preprod → terraform apply (all preprod infrastructure)Phase 0 — Account Foundation
Status: In progress — bootstrap + control-tower + iam done; identity-center remaining
Scope: AWS Organization, Control Tower, IAM Identity Center, account structure
Decisions made
| Item | Decision |
|---|---|
| IaC tool | Terraform (multi-cloud: AWS + Cloudflare + future GCP) |
| Region | ap-south-1 (Mumbai) — data residency, latency, RBI alignment |
| Multi-account | Yes — management + preprod + production (separate accounts) |
| Account governance | AWS Control Tower + Account Factory for Terraform (AFT) |
| SSO | Zoho SAML → IAM Identity Center (GitHub Team plan excludes SAML) |
| Control Tower timing | Set up before any member accounts — retrofitting at 5+ accounts is painful (prior experience) |
| AWS Config | Disabled until SOC 2 prep — re-enable in control-tower/main.tf |
| Hyderabad (ap-south-2) | Rejected — ElastiCache and CloudFront not available |
| Control Tower vs manual org | Control Tower chosen — guardrails, AFT account vending, audit accounts out of the box |
Checklist
One-time manual prerequisites
- [x] MFA enabled on root account
- [x] IAM user
terraform-admincreated with AdministratorAccess (631461173580) - [x] Enable IAM Identity Center in console — instance
ssoins-65951502a8bf87ba, ap-south-1 - [x] Run Control Tower Landing Zone wizard in console — version 4.0, Security OU created
Terraform — global/bootstrap
- [x]
terraform apply—finaisse-terraform-stateS3 + lock viause_lockfile = true
Terraform — global/control-tower ✅ complete (2026-06-18)
- [x] Organization
o-1iqncs111v,InfrastructureOUou-1a46-ykv31eq7+ProductionOUou-1a46-0mkolro2 - [x] Log Archive account
430597289467+ Audit account236353235135under Security OU - [x] GuardDuty enabled org-wide, delegated to Audit account
- [x] AWS Config recorder created but disabled (re-enable for SOC 2)
- [x] SCPs applied to Infrastructure + Production OUs:
- Deny non-approved regions (ap-south-1 only)
- Require IMDSv2 on all EC2
- Deny leaving organization
- Deny disabling GuardDuty
- Require S3 encryption
- Deny CloudTrail deletion
- [x] Monthly budget alert ($200 org, $100 preprod) + cost anomaly detection ($20 threshold, IMMEDIATE via SNS)
- [x] SNS ops alerts topic → sekhar@finaisse.com
- [x] IAM Access Analyzer (ACCOUNT scope — upgrade to ORGANIZATION after trusted access setup)
- [x] AWS Health events → SNS
- [x] Alternate account contacts (billing / security / ops)
Workload accounts (direct, AFT removed)
- [x]
finaisse-preprodaccount219366469126— under NonProd OU - [x]
finaisse-productionaccount049211686059— under Production OU
Terraform — global/identity-center
- [ ] Zoho SAML metadata URL obtained from Zoho Directory →
terraform.tfvars - [ ]
terraform apply— SSO wired, 3 permission sets created (Admin, Developer, ReadOnly) - [ ] Groups created:
platform-engineers,developers,ops-finance - [ ] Account assignments: platform-engineers = admin in preprod + production
- [ ] Delete
terraform-adminIAM user key after SSO is verified
Terraform — global/iam ✅ complete (2026-06-18)
- [x] GitHub Actions OIDC provider
arn:aws:iam::631461173580:oidc-provider/token.actions.githubusercontent.com - [x]
finaisse-github-actionsrole — trusted by allfinaisse-org/*repos
Notes
(Record decisions, blockers, and deviations from the plan here as work proceeds)
Phase 1 — Foundation Infrastructure
Status: ✅ Complete (2026-06-26) — preprod applied
Scope: VPC, RDS, S3, KMS, WAF, Secrets Manager, IAM, VPC Flow Logs
Depends on: Phase 0 complete (preprod account must exist)
What's been Terraformed
| Module | What it provisions |
|---|---|
modules/kms | CMKs for RDS, S3, Secrets Manager — auto-rotating, CloudTrail auditable |
modules/networking | VPC 10.1.0.0/16, public/private/db subnets ×2 AZs, IGW, NAT, SGs |
modules/rds | PostgreSQL 16, CMK encrypted, force_ssl, 7d backup retention (preprod) — ⚠️ bump to PG18 before Phase 2 migration: dumps use uuidv7(), a PG18-only built-in (see Phase 2 notes) |
modules/s3 | App data + frontend buckets, SSE, versioning, lifecycle |
modules/secrets | Secrets Manager — 7 app secrets, CMK encrypted |
modules/iam | ECS task execution role (pull images, inject secrets) + task role (S3 access) |
modules/waf | WAFv2 — Common rules, KnownBadInputs, SQLi rules, 1000 req/5min rate limit |
modules/flow-logs | VPC Flow Logs → S3, 90d retention (preprod) |
Preprod environment settings (locals.tf)
| Setting | Preprod | Production |
|---|---|---|
| VPC CIDR | 10.1.0.0/16 | 10.0.0.0/16 |
| RDS instance | db.t3.small | db.t3.medium |
| RDS storage | 20 GB | 100 GB |
| RDS Multi-AZ | No | Yes |
| RDS deletion protection | No | Yes |
| RDS backup retention | 7 days | 30 days |
| WAF rate limit | 1000 req/5min | 500 req/5min |
| Flow log retention | 90 days | 365 days |
Outputs (preprod)
| Resource | Value |
|---|---|
| VPC | vpc-03af2e1cb93c624a1 |
| RDS endpoint | finaisse-preprod.cxacwseokgi8.ap-south-1.rds.amazonaws.com:5432 |
| App data bucket | finaisse-preprod-app-data |
| Frontend bucket | finaisse-preprod-frontend |
| ECS task execution role | arn:aws:iam::219366469126:role/finaisse-ecs-task-execution-preprod |
| ECS task role | arn:aws:iam::219366469126:role/finaisse-ecs-task-preprod |
Checklist
- [x]
assume_roleset inenvironments/preprod/providers.tf— preprod account219366469126 - [x]
terraform.tfvarsfilled in (gitignored, local only) - [x]
terraform init && terraform plan - [x]
terraform apply— 69 resources created - [ ] Verify RDS endpoint reachable from within VPC (Phase 2 task)
- [ ] Verify Secrets Manager secrets created ✅ (visible in AWS console)
- [ ] Verify WAF web ACL created (ALB association done in Phase 3)
- [ ] Verify Flow Logs S3 bucket receiving logs
Estimated monthly cost (Phase 1 only, preprod)
| Resource | Cost |
|---|---|
| RDS db.t3.small | ~$25/month |
| NAT Gateway | ~$35/month |
| KMS (3 CMKs) | ~$3/month |
| WAF | ~$5/month |
| S3 + Flow Logs | ~$3/month |
| GuardDuty | ~$3/month |
| CloudTrail | Free (management events) |
| Secrets Manager (7 secrets) | ~$2/month |
| Total | ~$76/month |
Notes
Cost management (preprod idle): NAT Gateway destroyed and RDS stopped to save ~$60/month while not actively testing. To resume: aws rds start-db-instance --db-instance-identifier finaisse-preprod --region ap-south-1 --profile finaisse-mgmt then terraform apply to recreate NAT GW.
⚠️ AWS auto-restarts stopped RDS after 7 days — re-stop manually if not testing, or it will resume billing at ~$25/month.
Phase 2 — Data Migration
Status: Not started
Scope: Railway PostgreSQL → RDS, RustFS → S3
Depends on: Phase 1 complete
Checklist
- [ ] Dump Railway PostgreSQL (
finance+mgmtdatabases) - [ ] Restore to RDS, validate schema and row counts
- [ ] Run
prisma migrate deployagainst RDS — confirm no drift - [ ] Migrate RustFS bucket contents to S3
- [ ] Validate file access via updated env vars pointing to S3
- [ ] Run Railway + RDS in parallel briefly (read-only validation period)
Notes
(Record decisions, blockers, and deviations from the plan here as work proceeds)
⚠️ Postgres version: dumps require PG18 on the target — RDS module is currently PG16. Finaisse backups come from a PostgreSQL 18 source and use DEFAULT uuidv7() on primary-key columns. uuidv7() is a built-in function in PG18 only — it does not exist in 16 or 17. Restoring a current dump into a < 18 server fails on every CREATE TABLE with ERROR: function uuidv7() does not exist, and with pg_restore --exit-on-error aborts after the schema with 0 rows loaded (observed 2026-06-19 restoring into Railway staging, which is PG17).
Implications for this phase:
- The
modules/rdsversion (PostgreSQL 16, see Phase 1) must be bumped to 18 before the Railway → RDS migration, or the restore will fail identically. - Workaround if a target must stay < 18: pre-install a
uuidv7()shim intopg_catalog(so the dump's unqualified call resolves underpg_restore's emptysearch_path) and restore without--exit-on-error(benign "already exists" collisions otherwise abort the run). Reference implementation:fin-infra/railway/scripts/restore.sh. - Always validate restores by real row counts (
SELECT sum(n_live_tup)), not "pg_restore finished" — auuidv7()-aborted restore leaves a complete-looking schema with no data.
Presigned URLs are not browser-usable on Railway today. The backend can presign (/api/fs/v1/files/contents/presign/:bucket/*, libs/fs/src/fs.service.ts), but URLs are signed against the client's endpoint — http://s3.railway.internal:9000 — which a browser cannot resolve. The UI currently sidesteps this by streaming bytes through blitz-api (POST/GET /api/fs/v1/files/contents/... with Bearer auth), never consuming presigned URLs directly. On AWS this changes: S3 presigned URLs point at a real, browser-reachable host, so we can move uploads/downloads to direct presigned PUT/GET and stop proxying large files through the API. When wiring that, confirm the S3 client endpoint/region used for signing matches the public bucket host (no forcePathStyle hostname mismatch) — otherwise presigned links 403.
Phase 3 — Compute
Status: ✅ Complete (2026-07-02) — preprod applied
Scope: ECS Fargate cluster, ALB, ACM wildcard cert, ElastiCache Valkey, SSM, Cloudflare DNS
Depends on: Phase 1 complete (Phase 2 data migration happens after services are validated)
What was built
| Module | What it provisions |
|---|---|
modules/ecs/cluster.tf | ECS cluster finaisse-preprod, Container Insights, CloudWatch log groups (30d), GHCR pull secret in Secrets Manager |
modules/ecs/alb.tf | ALB (public subnets), HTTP→HTTPS redirect, HTTPS listener (TLS 1.3), WAF association, ACM wildcard cert *.finaisse.com, Cloudflare DNS validation, wildcard CNAME *.finaisse.com → ALB |
modules/ecs/services.tf | 10 ECS services: 2 ALB-exposed, 4 internal HTTP, 4 workers; task definitions for all; GHCR image pull via repositoryCredentials |
modules/elasticache/ | ElastiCache Valkey 7.2, single node (preprod), cache.t3.micro, at-rest encryption |
modules/ssm/ | SSM Parameter Store — non-secret config: node-env, jwtname, temporal config, redis-url, blob host/port, Google Cloud project |
Service architecture
Services split into three groups to avoid Terraform target-group-without-ALB errors:
| Group | Services | ALB exposure |
|---|---|---|
alb_services | blitz-api (10001), blitz-ws (10002) | Path-based routing via ALB |
internal_services | blitz-agents (10013), blitz-excelrw (10014), blitz-recon (10015), blitz-remotecontrol (10016) | VPC-internal only |
worker_services | blitz-emailprocessor, blitz-wfw, blitz-wfwpdf, blitz-classicml | No port — desired_count=0 until Temporal Cloud |
ALB routing (path-based):
- Priority 10:
/api/ws*→ blitz-ws target group - Priority 20:
/api*→ blitz-api target group - Default: 503 "Frontend not yet deployed (Phase 5)"
ACM cert: *.finaisse.com with finaisse.com SAN — both SANs share one CNAME validation record in Cloudflare (Cloudflare de-duplicates them). The wildcard covers all tenant subdomains (acme.finaisse.com, etc.) — no per-tenant cert needed.
Tenant resolution: blitz-api resolves tenants by full-hostname match (Host header → tenant.domainname DB column) — not subdomain parsing. ALB forwards the original Host header unchanged.
GHCR image pull: repositoryCredentials → Secrets Manager secret finaisse/ghcr-pull-secret (username + PAT). Images: ghcr.io/finaisse-org/<service>:latest.
Worker services at desired_count=0: Railway Temporal is .railway.internal — not reachable from the AWS VPC. Workers will be scaled up after Temporal Cloud is configured in Phase 4.
Outputs (preprod)
| Resource | Value |
|---|---|
| ECS cluster | finaisse-preprod |
| ALB DNS name | finaisse-preprod-1644844663.ap-south-1.elb.amazonaws.com |
| ElastiCache endpoint | finaisse-preprod.2r7obj.ng.0001.aps1.cache.amazonaws.com |
| Wildcard DNS | *.finaisse.com → ALB (Cloudflare CNAME, proxied=false) |
Checklist
ECS cluster
- [x] ECS cluster
finaisse-preprod(Fargate) - [x] Container Insights enabled
- [x] CloudWatch log groups per service (30-day retention)
- [x] GHCR pull credentials in Secrets Manager
Task definitions
- [x] blitz-api — 512 MB, port 10001
- [x] blitz-ws — 512 MB, port 10002
- [x] blitz-agents — 512 MB, port 10013
- [x] blitz-excelrw — 512 MB, port 10014
- [x] blitz-recon — 512 MB, port 10015
- [x] blitz-remotecontrol — 512 MB, port 10016
- [x] blitz-emailprocessor — 512 MB, worker
- [x] blitz-wfw — 1024 MB, worker (min 1 GB — OOM observed at 512 MB)
- [x] blitz-wfwpdf — 512 MB, worker
- [x] blitz-classicml — 512 MB, worker
ALB + DNS
- [x] ALB in public subnets
- [x] ACM wildcard cert
*.finaisse.com(covers all tenant subdomains) - [x] HTTP → HTTPS redirect
- [x] HTTPS listener with TLS 1.3 (
ELBSecurityPolicy-TLS13-1-2-2021-06) - [x] Target groups for blitz-api and blitz-ws only (internal services have no ALB exposure)
- [x] Path-based listener rules (ws priority 10, api priority 20)
- [x] WAF web ACL associated with ALB
- [x] Cloudflare wildcard CNAME
*.finaisse.com→ ALB (proxied=false)
ElastiCache
- [x] ElastiCache Valkey 7.2,
cache.t3.micro, single node (preprod) - [x] At-rest encryption enabled; transit encryption disabled (
redis://— notrediss://) - [x]
REDIS_URLpassed to all ECS tasks from ElastiCache output
Validation (pending — blocked on RDS start + NAT GW)
- [ ] Start RDS (
aws rds start-db-instance --db-instance-identifier finaisse-preprod --region ap-south-1 --profile finaisse-mgmt) - [ ] Confirm NAT Gateway exists (destroyed for cost savings — recreate with
terraform applyif needed) - [ ] All 6 HTTP ECS services running and healthy (images pulled from GHCR via NAT GW)
- [ ] Test:
curl https://<tenant>.finaisse.com/api/health→ 200 - [ ] Test: WebSocket upgrade at
wss://<tenant>.finaisse.com/api/ws - [ ] Run parallel with Railway before traffic cutover
Estimated monthly cost (Phase 3 additions, preprod)
| Resource | Cost |
|---|---|
| ECS Fargate (6 HTTP services × 0.25 vCPU / 512 MB) | ~$30/month |
| ALB | ~$20/month |
| ElastiCache cache.t3.micro | ~$15/month |
| ACM certificate | Free |
| Phase 3 total | ~$65/month |
| Running total (Phase 1 + 3) | ~$141/month |
Decisions made
| Decision | Rationale |
|---|---|
| Path-based ALB routing (not host-based) | Matches current Railway nginx pattern — zero frontend changes needed |
Wildcard *.finaisse.com ACM cert | Covers all tenant subdomains without per-tenant cert management |
| Internal services have no ALB exposure | agents, excelrw, recon, remotecontrol are called by blitz-api within VPC only |
Worker desired_count=0 | Railway Temporal (.railway.internal) unreachable from AWS VPC — unblock in Phase 4 with Temporal Cloud |
| ElastiCache pulled into Phase 3 | Services need REDIS_URL to start — can't defer to Phase 4 |
proxied=false on Cloudflare wildcard | ALB handles TLS via ACM; WAF is on the ALB — Cloudflare proxying would double-encrypt |
Phase 4 — Workflows
Status: Not started
Scope: Temporal Cloud — connect worker services, scale up from desired_count=0
Depends on: Phase 3 complete
Note: ElastiCache was pulled into Phase 3 (services needed REDIS_URL to start).
Checklist
- [ ] Sign up for Temporal Cloud, create namespace
finaisse-preprod - [ ] Update
temporal_hostinaws/environments/preprod/terraform.tfvars(or SSM) — Temporal Cloud endpoint - [ ] Run
terraform apply— SSM parameter/finaisse/preprod/temporal-hostupdates, ECS tasks redeploy - [ ] Scale workers: set
worker_desired_count = 1inenvironments/preprod/main.tf→terraform apply - [ ] Validate
wfwtask queues (system, closehub, cash, coresystem, invoice) - [ ] Validate
wfwpdfPDF task queue - [ ] Validate
classicmlML task queues - [ ] Validate
emailprocessoremail task queue
Notes
(Record decisions, blockers, and deviations from the plan here as work proceeds)
Phase 5 — Frontend
Status: Not started
Scope: Module Federation build + S3/CloudFront + Cloudflare DNS
Depends on: Phase 3 complete (CloudFront URLs needed before build)
Checklist
- [ ] S3 bucket for frontend assets, path-based prefixes per sub-app
- [ ] CloudFront distribution with path-based origin routing
- [ ] ACM certificate for
app.finaisse.com(us-east-1 — required for CloudFront) - [ ] Determine final CloudFront URLs for all 6 sub-apps
- [ ] Set
VITE_*_REMOTE_URLenv vars for all 5 remotes - [ ] Build and deploy 5 remote apps to S3 first
- [ ] Build and deploy
uihost app with remote URLs baked in - [ ] Cloudflare DNS:
app.finaisse.com→ CloudFront distribution - [ ] WAF attached to CloudFront distribution
Notes
(Record decisions, blockers, and deviations from the plan here as work proceeds)
Phase 6 — Cutover
Status: Not started
Depends on: Phases 3–5 complete + Sentry integrated in blitz/blitz-ui
Pre-cutover gate — all must be true
- [ ] All ECS services healthy for 48+ hours under test traffic
- [ ] Temporal Cloud workflows validated end-to-end
- [ ] Frontend loading correctly from CloudFront
- [ ] Sentry integrated in all services
- [ ] CloudWatch alarms configured and tested
- [ ] Rollback plan documented and rehearsed
Checklist
- [ ] Cloudflare DNS:
api.finaisse.com→ ALB - [ ] Monitor for 1 week — error rates, latency, Sentry alerts
- [ ] Decommission Railway production services (Railway moves to dev-only)
- [ ] Archive Railway IaC (keep
fin-infra/railway/for staging/dev)
Notes
(Record decisions, blockers, and deviations from the plan here as work proceeds)
Phase 7 — Observability
Status: Not started
Checklist
- [ ] CloudWatch Log Groups per service (verify retention set to 30 days)
- [ ] Container Insights enabled on ECS cluster
- [ ] CloudWatch alarms: CPU > 80%, memory > 80%, ALB 5xx rate > 1%
- [ ] SNS ops alerts already configured (Phase 0) — wire CloudWatch alarms to it
- [ ] Sentry organisation created
- [ ]
@sentry/nodeadded to all Bun/Elysia services - [ ]
@sentry/vueadded to blitz-ui shell app - [ ]
sentry-sdkadded to blitz-classicml - [ ]
SENTRY_DSNin Secrets Manager, injected into all ECS task definitions
Notes
(Record decisions, blockers, and deviations from the plan here as work proceeds)
Future — Cloudflare IaC
Cloudflare (DNS, Zero Trust, Gateway policies) was set up manually via the dashboard — not yet under Terraform. The Cloudflare Terraform provider (cloudflare/cloudflare) supports all of this. Future task: add a cloudflare/ root in fin-infra alongside aws/, import existing resources, and bring Cloudflare fully under IaC.
- [ ] Add
cloudflare/Terraform root to fin-infra - [ ] Import existing DNS records
- [ ] Import Zero Trust / Gateway policies
- [ ] Import Access applications (internal docs, mgmt UI)
Future — SOC 2 / Compliance Readiness
When a compliance requirement arrives, re-enable in a single Terraform PR:
- [ ] Enable AWS Config recorder (
control-tower/main.tf— flipis_enabled = false → true) - [ ] Enable Security Hub (
aws_securityhub_accountresource, org-wide) - [ ] Enable CloudTrail data events (S3 reads/writes)
- [ ] Enable GuardDuty malware protection + EKS audit logs if applicable
- [ ] Penetration test (required for most frameworks)
- [ ] Data classification policy documented
- [ ] Incident response runbook reviewed and rehearsed
- [ ] Backup restore tested and documented
Decision Log
| Date | Decision | Rationale |
|---|---|---|
| 2026-06-04 | Terraform over CDK | Multi-cloud scope: AWS + Cloudflare + future GCP/Gemini |
| 2026-06-04 | RabbitMQ removed | All async workflows are Temporal-managed |
| 2026-06-04 | GHCR retained | No benefit to migrating to ECR |
| 2026-06-16 | 16 services confirmed | 4 infra (→ AWS managed) + 11 ECS app services + 1 frontend |
| 2026-06-16 | Sentry for error tracking | No error tracking exists today; CloudWatch alone insufficient |
| 2026-06-17 | ap-south-1 (Mumbai) | Data residency, RBI alignment, full service catalog; Hyderabad rejected (missing ElastiCache/CloudFront) |
| 2026-06-17 | Control Tower + AFT | Governance from day 1; retrofitting at 5+ accounts is painful (prior experience) |
| 2026-06-17 | Zoho SSO over GitHub SSO | GitHub SAML requires Enterprise plan; Zoho already in use and covers all staff |
| 2026-06-17 | Security baseline in Phase 0/1 | KMS CMKs, WAF, GuardDuty, SCPs pulled forward — not deferred to Phase 8 |
| 2026-06-17 | AWS Config disabled initially | Re-enable at SOC 2 prep; saves ~$5-8/month until needed |
| 2026-06-17 | All resources via Terraform | No manual console provisioning; two unavoidable exceptions: IAM Identity Center enable + Control Tower wizard |
| 2026-06-17 | Production region: us-east-1 | Future — not started; preprod in Mumbai (ap-south-1) first |
| 2026-07-02 | Path-based ALB routing | Matches current Railway nginx pattern — no frontend changes needed |
| 2026-07-02 | Wildcard *.finaisse.com ACM cert | Covers all tenant subdomains; both SANs share one Cloudflare CNAME validation record |
| 2026-07-02 | Internal services not ALB-exposed | agents, excelrw, recon, remotecontrol are VPC-internal; only api + ws face the internet |
| 2026-07-02 | Worker desired_count=0 | Railway Temporal not reachable from AWS VPC — unblock after Temporal Cloud (Phase 4) |
| 2026-07-02 | ElastiCache moved to Phase 3 | Services need REDIS_URL at startup; cannot defer to Phase 4 |
| 2026-07-02 | Cloudflare proxied=false on wildcard | ALB terminates TLS via ACM; WAF on ALB — Cloudflare proxy would break certificate chain |