Skip to content

Finaisse / Blitz Platform

AWS Infrastructure Mapping & Architecture Recommendation

Prepared by: Sekhar Prakash
Date: May 2026
Status: Draft v3 — updated June 2026: Terraform confirmed, RabbitMQ removed (Temporal-only workflows), GHCR confirmed, service count corrected to 16


1. Purpose & Scope

This document maps the current Finaisse production stack (blitz backend, blitz-ui frontend) to equivalent AWS managed services. It serves as the foundation for the AWS infrastructure setup.

The Railway platform will continue to host the staging environment while AWS production infrastructure is built out in phases. US and EU regions are out of scope for this phase and will be addressed based on customer data-residency requirements.

Changes from v2: IaC tooling confirmed as Terraform (multi-cloud scope — AWS + Cloudflare + future Gemini/GCP). RabbitMQ removed — all async workflows are Temporal-managed. Container registry confirmed as GHCR (unchanged). Service count corrected from 6 → 16 (reflects current Railway staging state). Debezium CDC pipeline removed (RabbitMQ dependency eliminated).


2. Current Stack Overview

2.1 Backend — blitz

Runtime: Bun. Framework: Elysia. ORM: Prisma. Language: TypeScript.

The backend is a microservices monorepo. Each service is independently containerised. The API gateway (api, port 10001) is the single entry point for all client traffic.

16 services are targeted for AWS production — 4 infrastructure services and 12 application services, matching the current Railway staging environment.

Infrastructure services (4) — AWS managed equivalents replace these

Service (Railway name)CurrentAWS equivalent
blitz-dbRailway managed PostgreSQLRDS PostgreSQL 16 Multi-AZ
blitz-s3RustFS (S3-compatible, self-hosted)Amazon S3
blitz-temporalTemporal (self-hosted on Railway)Temporal Cloud
blitz-valkeyRailway ValkeyElastiCache Redis 7

Temporal UI (blitz-temporal-ui) runs as a sidecar to Temporal. On AWS, this is provided by Temporal Cloud's built-in UI — no separate deployment needed.

Application services (12) — deployed to ECS Fargate on AWS

ServicePortRoleNotes
blitz-api10001API gateway — single entry point for all clientsPublic-facing via ALB
blitz-ws10002WebSocket server for real-time features
blitz-agents10013AI agent executionSleeping in staging (scale-down)
blitz-excelrw10014Excel read/write (.NET-based)
blitz-emailprocessorAsync email processing workerNo HTTP port
blitz-wfwTemporal workflow workerMinimum 1 GB RAM — OOM at 512 MB; runs system, closehub, cash, coresystem, invoice workers in parallel
blitz-wfwpdfTemporal PDF workflow workerBuilt in GHCR; not yet in Railway staging — add to AWS directly
blitz-recon10015Reconciliation serviceSleeping in staging (scale-down)
blitz-remotecontrol10016Remote control worker
blitz-classicmlClassic ML inference (Python Temporal worker)No HTTP port; task queues: taskqueue-system-ml-training, taskqueue-system-ml-inference
blitz-uiVue 3 Module Federation frontend shellS3 + CloudFront, not ECS

Note: blitz-ui is a static frontend — it is served from S3 + CloudFront, not as an ECS service. See Section 5.5.

Services in the monorepo NOT targeted for initial AWS launch

ServicePortStatus
apimgmt9999Not yet deployed
queue10008Not yet deployed
events10009Not yet deployed
pdfwriter10011Not yet deployed
fs10010Not yet deployed
rulesengine10006Not yet deployed
mcp10012Not yet deployed
scriptrunner10003Not yet deployed
jsontransformer10004Not yet deployed
templaterenderer10005Not yet deployed
email10007Not yet deployed
jobsOverlap with queue unclear — needs review
desktopElectron app — not an ECS candidate

2.2 Frontend — blitz-ui

Framework: Vue 3.5 with Composition API. Build tool: Vite 7. Runtime: Bun. UI library: Vuetify 3 + Syncfusion EJ2.

The frontend is a multi-app monorepo using Module Federation. Each sub-application is built independently and the main ui shell dynamically loads the others at runtime via URLs baked in at build time.

AppDev PortDescription
ui10000Main application shell (host app)
closehub5001Close Hub standalone app (remote)
invoice5005Invoice management (remote)
journal5003Journal entries (remote)
recon5004Reconciliation (remote)
collections5002Collections management (remote)

Module Federation note: The URLs for each remote app are injected via VITE_*_REMOTE_URL environment variables and compiled into the JavaScript bundle at build time. They cannot be changed without rebuilding. On AWS, these must resolve to the final CloudFront URLs before the build runs — all 6 apps must be built and deployed in a coordinated pipeline.

2.3 Infrastructure — current (Railway)

ComponentCurrent solutionNotes
PostgreSQLRailway managed PostgreSQLTwo databases: finance, mgmt. Multi-schema design.
Redis / ValkeyRailway ValkeySession cache
Object storageRustFS (S3-compatible)S3-compatible API. Used via BLOBACCESSKEY/BLOBSECRETKEY.
Workflow engineTemporal (Railway self-hosted)Used by wfw and wfwpdf.
Message brokerNone (removed)RabbitMQ eliminated — all async work is Temporal-managed.
SecretsRailway environment variablesJWT secret, DB credentials, API keys.
Container registryGHCR (GitHub)Images tagged :latest and :<short-sha>. Confirmed — no migration to ECR.
CI/CDGitHub ActionsBuild, push, deploy workflows in fin-infra.
IaCfin-infra/railway/ (Bun + TypeScript)Provision, deploy, variable sync scripts.

3. IaC Tooling — Terraform (Confirmed)

Decision: Terraform (HCL)

Rationale: Multi-cloud scope requires a single IaC tool that manages AWS, Cloudflare (Pages, DNS, Zero Trust already in use), and future GCP/Gemini infrastructure. Terraform is the only realistic choice for this breadth.

The fin-infra/aws/ folder will sit alongside the existing fin-infra/railway/ folder.

DimensionDecision
ToolTerraform
State backendS3 bucket + DynamoDB lock table (ap-south-1)
Providershashicorp/aws, cloudflare/cloudflare, hashicorp/google (future)
Workspace layoutfin-infra/aws/ — modules per layer (networking, data, compute, frontend)
CI/CDGitHub Actions with OIDC — no long-lived AWS keys in secrets

4. AWS Service Mapping

CurrentAWS equivalentMigration effortNotes
Railway PostgreSQLRDS PostgreSQL 16 (Multi-AZ)Mediumdb.t3.medium. Same Prisma schemas, connection string change only.
Railway ValkeyElastiCache (Redis 7)Lowcache.t3.micro. Drop-in replacement — same Redis protocol.
RustFS (S3-compatible)Amazon S3LowS3-compatible API. Endpoint and credential env var change only. Replace BLOB_HOST/BLOB_PORT with S3 endpoint.
Temporal (Railway self-hosted)Temporal CloudMediumTemporal Cloud free starter tier for initial launch. Revisit self-hosted at scale.
Microservices (Docker)ECS FargateMediumOne ECS service per application service (12 services). Existing Docker images work as-is. wfw needs ≥1 GB task memory.
nginx / Railway routingALB (Application Load Balancer)LowPath/host-based routing replaces nginx.
blitz-ui static buildS3 + CloudFrontMediumVite build output per sub-app. Module Federation remote URLs must be set before build. Coordinated 6-app build pipeline required.
GHCR registryGHCR (unchanged)NoneConfirmed — no migration.
GitHub ActionsGitHub Actions (unchanged)LowDeploy step changes from Railway API call to ECS update-service call.
RabbitMQRemovedAll async workflows managed by Temporal. No messaging layer needed.
fin-infra/railway/ scriptsfin-infra/aws/ (Terraform)MediumSame repo, new folder. Multi-cloud: AWS + Cloudflare + GCP (future).

5. Target AWS Architecture

5.1 Region Selection

Primary region: ap-south-1 (Mumbai)

FactorMumbai (ap-south-1)Hyderabad (ap-south-2)
Available since20162022
Service coverageFull — all required services availablePartial — some services still rolling out
Latency from major Indian cities5–15 ms8–20 ms
RecommendationPrimary production regionDR / backup target once stable

US and EU regions will be provisioned later using the same Terraform code with environment parameters.

5.2 Networking

  • VPC: 10.0.0.0/16 in ap-south-1
  • Public subnets (2 AZs): ALB, NAT Gateway
  • Private subnets (2 AZs): ECS Fargate tasks, ElastiCache, Temporal
  • DB subnets (2 AZs): RDS Multi-AZ, isolated subnet group
  • All inter-service communication over private DNS — no public IPs on services

5.3 Compute — ECS Fargate

Each application microservice runs as an independent ECS service within a single ECS cluster.

  • Cluster: finaisse-prod
  • Task definitions: one per service, referencing GHCR images
  • Service discovery: AWS Cloud Map for internal service-to-service calls
  • Auto-scaling: target tracking on CPU/memory per service
  • Existing Docker images require no changes — only environment variable injection changes

Memory sizing exceptions:

ServiceMinimum task memoryReason
blitz-wfw1024 MB (1 GB)Runs 5 Temporal workers in parallel + S3/tenancy init. OOM confirmed at 512 MB.
All others512 MBStandard sizing

5.4 Data Layer

ServiceAWS resourceConfig
PostgreSQLRDS PostgreSQL 16, Multi-AZdb.t3.medium, 100 GB gp3, automated backups 7 days, encryption at rest
Redis / ValkeyElastiCache Redis 7cache.t3.micro, single-AZ for start, upgrade to cluster mode later
Object storageAmazon S3Versioning enabled, SSE-S3, lifecycle rules for old versions
Workflow engineTemporal CloudRecommended for initial launch; revisit self-hosted at scale
SecretsAWS Secrets Manager + SSM Parameter StoreSee Section 6

5.5 Frontend Delivery

The blitz-ui frontend uses Module Federation. The deployment pipeline must:

  1. Build and deploy all 5 remote apps (closehub, invoice, journal, recon, collections) to their S3 prefixes first
  2. Determine their CloudFront URLs
  3. Set VITE_*_REMOTE_URL env vars pointing to those CloudFront URLs
  4. Build and deploy the ui host app with those URLs baked in

Infrastructure:

  • One S3 bucket with path-based prefixes per sub-app (or separate buckets)
  • Single CloudFront distribution with path-based origin routing
  • ACM certificate (free) for TLS at CloudFront
  • Cloudflare DNS for app.finaisse.com → CloudFront (Cloudflare already manages finaisse.com DNS)
  • WAF attached to CloudFront for rate limiting and basic bot protection

This static S3+CloudFront model works for blitz-ui because its backend (blitz-api) is public-facing via ALB — the browser calls the API directly (the nginx /api proxy is replaced by ALB path routing). The pattern requires a publicly-reachable backend.

5.5.1 Management Portal (apimgmt + mgmt UI) — does NOT fit the standard pattern

The tenant-onboarding admin portal cannot use the same "static S3 + public ALB" approach, because apimgmt must stay private (superadmin API; holds tenant DB connection strings — never publicly exposed). Not yet reflected in the service mapping above (this work post-dates the doc). When added to the AWS plan:

  • apimgmt → ECS Fargate service on an internal-only target group (not a public ALB listener). No public route.
  • mgmt UI → must reach that private backend, so it needs an in-network proxy — i.e. it stays a container (nginx) on ECS that proxies /api → the internal apimgmt target, OR a static site fronted by an internal ALB that only an authenticated edge can reach. It does NOT get a plain public S3+CloudFront origin that talks to a public apimgmt.
  • Admin access → gate the mgmt UI hostname (mgmt.finaisse.com) with Cloudflare Access (admins-only policy; WARP SSO), keeping apimgmt non-public. The x-mgmt-api-key guard remains the inner layer.

Net: the main UI can go fully static because its API is public by design; the mgmt UI cannot, because its API is private by design. Tracking: blitz#898 (deploy wiring), blitz#885 (per-tenant DB provisioning).


6. Secrets & Environment Variables

The stack uses 100+ environment variables across services. These split into two AWS storage tiers:

AWS Secrets Manager (~20 secrets, ~$8/month)

Actual credentials that should be rotated and audited:

SecretServices
JWTSECRETAll backend
DATABASE_URL, MANAGEMENT_DATABASE_URLAll backend
DATABASE_HOST, DATABASE_USER, DATABASE_PASSWORD, DATABASE_PORTAll backend
BLOBACCESSKEY, BLOBSECRETKEYAll backend (file ops)
GOOGLE_API_KEYagents, wfw, docai services
OPENAI_API_KEYagents
LLAMA_CLOUD_API_KEYagents
VITE_SYNCFUSION_LICENSEKEYblitz-ui build only
MINDSDB_MCP_ACCESS_TOKENmcp
SENTRY_DSNAll backend services + blitz-ui

SSM Parameter Store (~80 params, effectively free)

Non-secret configuration that changes between environments:

CategoryExample vars
Infrastructure endpointsBLOB_HOST, BLOB_PORT, TEMPORAL_HOST, TEMPORAL_PORT, REDIS_URL
AI model selectionGEMINI_MODEL_NAME, GEMINI_DOCAI_MODEL, DEFAULT_MODEL, DEFAULT_CHAT_MODEL, all DEFAULT_*_MODEL vars
Google Cloud configGOOGLE_CLOUD_PROJECT_ID, GOOGLE_CLOUD_LOCATION, GOOGLE_DOCUMENT_AI_PROCESSOR_ID
CID matching tuning~19 CID_* vars (thresholds, confidence levels)
Reconciliation tuning~23 MATCHING_* vars
Cash app configCASHAPP_BULK_ENABLED, CASHAPP_BULK_BATCH_SIZE, CASHAPP_CREATE_JOURNAL
Feature flagsTENANCY_ENABLED, NODE_ENV, DEFAULT_LOGLEVEL
Queue namesCDCEVENTS_QUEUE_NAME, EVENTS_QUEUE_NAME, JOBSEXECUTION_QUEUE_NAME
IntegrationsRC_SERVER_URL, RC_API_KEY, MCP_SERVER_URL, CDG_API_URL

7. Identity & Access — Zoho as SSO/IdP for AWS

Zoho can be used as the SAML 2.0 identity provider for AWS IAM Identity Center (formerly AWS SSO). This is the recommended setup for a team already using Zoho.

How it works

AWS IAM Identity Center federates with Zoho Directory via SAML 2.0. Once configured, the Zoho login page becomes the entry point for AWS console access. You assign Zoho users or groups to AWS accounts and permission sets from the IAM Identity Center console.

What happens to your existing root account password login

  • The root account (created with your email + password) is never federated — it stays as-is and is used only for break-glass situations (billing, account recovery, disabling IAM Identity Center itself). AWS best practice: remove MFA-less root access, store root credentials in a vault, and never use it day-to-day.
  • All day-to-day console access moves to IAM Identity Center → Zoho SSO. Team members log in at your IAM Identity Center URL (e.g. finaisse.awsapps.com/start) using their Zoho credentials.
  • Your personal root email + password continues to work as a fallback but should never be the normal path.

Setup steps (high level)

  1. Enable IAM Identity Center in ap-south-1 (or us-east-1 — it's a global service, pick one region).
  2. In Zoho Directory, add AWS as a SAML application — Zoho has a pre-built AWS template.
  3. Exchange SAML metadata between Zoho and IAM Identity Center.
  4. Create Permission Sets in IAM Identity Center (e.g. AdministratorAccess for Sekhar, ReadOnly for others).
  5. Assign Zoho users/groups to the AWS prod account with those permission sets.
  6. Team accesses AWS via the IAM Identity Center portal URL using Zoho credentials.

GitHub Actions OIDC

Terraform pipelines in GitHub Actions must use IAM roles assumed via OIDC — no long-lived AWS access keys in GitHub secrets. This applies to all three cloud providers (AWS OIDC, Cloudflare API token via Actions secret, GCP Workload Identity Federation when needed).


8. Phased Migration Plan

Railway staging continues to run throughout. Each phase is independently deployable and reversible before the final DNS cutover.

PhaseScopeKey activities
1 — FoundationNetworking + data layerVPC, subnets, security groups, RDS, S3, Secrets Manager, SSM Parameter Store, IAM roles, IAM Identity Center + Zoho SSO. Terraform state backend (S3 + DynamoDB). IaC only — no application traffic.
2 — Data migrationPostgreSQL + RustFS → S3Migrate Railway PostgreSQL to RDS. Validate Prisma connections. Migrate RustFS buckets to S3. Run parallel briefly.
3 — ComputeECS Fargate + ALBECS cluster, task definitions for all 12 application services, ALB listener rules. Run parallel with Railway.
4 — WorkflowsTemporal CloudCut over wfw and wfwpdf to Temporal Cloud. Validate all workflow task queues. ElastiCache cutover.
5 — FrontendS3 + CloudFrontCoordinated 6-app Module Federation build and deploy. Cloudflare DNS points app.finaisse.com → CloudFront.
6 — CutoverDNS + Railway decommissionFinal DNS cutover for API. Monitor for 1 week. Decommission Railway production.
7 — ObservabilityMonitoring + alertingCloudWatch Logs, Container Insights, X-Ray tracing (connect to existing OTEL_EXPORTER_URL OpenTelemetry integration), SNS alerts, dashboards per domain. Sentry error tracking across all services (see Section 10, item 10). Sentry SDK integration in blitz/blitz-ui is a pre-launch code change — must be done before Phase 6 cutover.
8 — Security hardeningCompliance + hardeningWAF rules, GuardDuty, AWS Config rules, IAM least-privilege audit, KMS encryption, VPC Flow Logs.

9. Estimated Monthly Cost (ap-south-1)

Estimates are for the 12 application services at lean production sizing.

ServiceConfigurationEst. USD/month
RDS PostgreSQLdb.t3.medium, Multi-AZ, 100 GB gp3$80–$120
ECS Fargate12 services (wfw at 1 GB, others 512 MB)$180–$300
ElastiCachecache.t3.micro, single-AZ$20–$30
ALBApplication Load Balancer$20–$30
CloudFront + S3Frontend delivery + object storage$10–$30
Secrets Manager~20 secrets$8–$12
SSM Parameter Store~80 params (standard tier)$0
CloudWatchLogs, metrics, dashboards$15–$30
NAT GatewayOutbound from private subnets$30–$50
Temporal CloudStarter tier$0–$25
Total (estimated)$363–$627

Cost increases as additional services from the monorepo are brought to production.


10. Open Items & Decisions Required

#ItemStatus
1IaC toolingTerraform — multi-cloud scope (AWS + Cloudflare + GCP/Gemini)
2RabbitMQ / messagingRemoved — all async workflows are Temporal-managed
3Container registryGHCR — no migration to ECR
4Service scope for AWS16 services (4 infra → AWS managed, 12 app → ECS Fargate + S3/CloudFront)
5Zoho SSOSet up IAM Identity Center + Zoho SAML before Phase 1
6wfwpdf staging gapBuilt in GHCR but not in Railway staging — deploy directly to AWS in Phase 3
7jobs serviceUnclear if this overlaps with queue or is separate — needs review before expanding beyond 16
8OllamaCurrently in compose for local LLM. On AWS, replace with Bedrock or external API endpoint. Decision needed for agents service.
9Hyderabad DRConfirm when to bring ap-south-2 online as a DR target
10Sentry error trackingPre-launch code change required in blitz + blitz-ui before Phase 6 cutover. Create Sentry org, add @sentry/node to all Bun/Elysia services, @sentry/vue to blitz-ui, sentry-sdk to blitz-classicml (Python). One SENTRY_DSN per service or shared project with service tags. Start with Sentry cloud free tier; evaluate self-hosted Glitchtip later if data residency requires it.

Document prepared with Claude Code (Anthropic) — Finaisse internal use only