Infrastructure
Current Stack (Railway — Staging)
Infrastructure Services
| Service | Role | Notes |
|---|---|---|
| PostgreSQL | Primary database (Railway managed) | Two databases: finance, mgmt. Multi-schema. Not covered by the resource-limit converge (uncapped). |
| RustFS | S3-compatible object storage | Self-hosted on Railway. Access via BLOBACCESSKEY/BLOBSECRETKEY. |
| Valkey | Redis-compatible cache | |
| Temporal | Workflow orchestration engine | Self-hosted on Railway. All async work is Temporal-managed. |
| Temporal UI | Temporal dashboard | Private-only (temporal.railway.internal), gated by Cloudflare Access — no raw Railway domain. |
RabbitMQ and Debezium Server are not part of current Railway infra — RabbitMQ was removed platform-wide (2026-07-10; see Gaps & Roadmap), and all async workflows are Temporal-managed. Both containers still exist in blitz's local compose-3rdparty.yaml for local dev only; neither appears in railway/shared/databases.ts.
IaC Code (fin-infra/railway/)
The railway/ directory contains TypeScript scripts that call the Railway GraphQL API directly — no Terraform or Docker Compose.
| File | Purpose |
|---|---|
shared/config.ts | Railway project configuration |
shared/databases.ts | Infra service definitions (Postgres, RustFS, Valkey, Temporal) |
shared/variables.ts | Shared environment variable definitions |
shared/railway-client.ts | Railway GraphQL API client |
shared/resources.ts | Per-service CPU/memory/restart-policy/app-sleep policy |
shared/domains.ts | Declared public/private domain exposure per service |
backend/infrastructure.ts | Microservice definitions (12 backend services) |
frontend/infrastructure.ts | Frontend service definitions — tenant blitz-ui and admin blitz-mgmtui |
scripts/ | Provision, deploy, vars, scale, logs, status, init-db, drift checks |
Service counts — what each number means
Service counts appear across these docs as 10, 11, 12, 14, 16 and 19. They are different denominators, not contradictions — but pages rarely said which they meant, so they read as conflicting. Verified against railway/backend/infrastructure.ts and railway/environments/staging/release.json on 2026-09-15:
| Count | Means |
|---|---|
| 12 | backend microservices (backendServices[]) |
| 2 | frontend nginx services — tenant blitz-ui, admin blitz-mgmtui |
| 14 | services pinned in release.json = 12 backend + 2 frontend. The release/deploy denominator |
| 4 | infrastructure services — Postgres, RustFS/S3, Valkey, Temporal (+ Temporal-UI) |
| 16 | AWS production target = 4 infra + 12 application |
| 19 | everything running on Railway staging = 14 + 4 infra + 1 managed Postgres |
When quoting a count, name the denominator. This table owns them; other pages should link here rather than restate.
Railway API limitation: ${{service.VAR}} variable references do not work via the GraphQL API. All inter-service communication uses static .railway.internal hostnames instead.
Container Registry & Deploy Model
All images are stored in GHCR (ghcr.io/finaisse-org/). Every build still pushes :latest, :<short-sha>, and :<branch-slug> tags, but no deploy path reads :latest any more: all 14 services are pinned to a <service>-vX.Y.Z tag and its digest in railway/environments/staging/release.json. Deploys verify the pinned digest against GHCR before rolling out. See Deploy for the full release path.
CI/CD (GitHub Actions — fin-infra)
See the workflow table in the repo's CLAUDE.md for the current, larger set (11+ workflows including the release-manifest/deploy path, tag-release, and Finboard sync). Key ones:
| Workflow | Trigger | Purpose |
|---|---|---|
provision.yml | Manual | Provision Railway infra |
release-manifest-and-deploy.yml | Manual + on manifest PR merge | The release path — verifies builds, opens a manifest PR, deploys automatically when it's merged |
deploy-staging.yml | Manual | Operations tool — redeploy one service or a tier |
scale-staging.yml | Manual + daily schedule | Scale staging; auto-down fires nightly ~10:00 PM IST. Scale-up is manual only. |
deploy-production.yml | Manual (env approval) | Scaffolding only — cannot currently run (no production secret/environment configured) |
Networking (Railway)
Services communicate over Railway's internal network using .railway.internal hostnames. A service is public only when a domain is explicitly attached (declared in shared/domains.ts, audited by bun run domains:drift) — today that's just the two frontend services; all backends are private-only.
AWS
AWS Terraform has already been written and applied to a preprod environment (cost-parked, not deleted) — this is not a future migration plan. For the current architecture, service mapping, and implementation status, see:
- AWS Architecture — target architecture and service mapping
- AWS Implementation — phase-by-phase progress, resource IDs, decision log
- Gaps & Roadmap — what's deployed vs. dormant, open decisions
Do not maintain a separate AWS migration plan on this page — it duplicated and then contradicted the dedicated docs above as the project progressed.