Skip to content
Last updated: Sep 25, 2026

Infrastructure ​

Current Stack (Railway — Staging) ​

Infrastructure Services ​

ServiceRoleNotes
PostgreSQLPrimary database (Railway managed)Two databases: finance, mgmt. Multi-schema. Not covered by the resource-limit converge (uncapped).
RustFSS3-compatible object storageSelf-hosted on Railway. Access via BLOBACCESSKEY/BLOBSECRETKEY.
ValkeyRedis-compatible cache
TemporalWorkflow orchestration engineSelf-hosted on Railway. All async work is Temporal-managed.
Temporal UITemporal dashboardPrivate-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.

FilePurpose
shared/config.tsRailway project configuration
shared/databases.tsInfra service definitions (Postgres, RustFS, Valkey, Temporal)
shared/variables.tsShared environment variable definitions
shared/railway-client.tsRailway GraphQL API client
shared/resources.tsPer-service CPU/memory/restart-policy/app-sleep policy
shared/domains.tsDeclared public/private domain exposure per service
backend/infrastructure.tsMicroservice definitions (12 backend services)
frontend/infrastructure.tsFrontend 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:

CountMeans
12backend microservices (backendServices[])
2frontend nginx services — tenant blitz-ui, admin blitz-mgmtui
14services pinned in release.json = 12 backend + 2 frontend. The release/deploy denominator
4infrastructure services — Postgres, RustFS/S3, Valkey, Temporal (+ Temporal-UI)
16AWS production target = 4 infra + 12 application
19everything 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:

WorkflowTriggerPurpose
provision.ymlManualProvision Railway infra
release-manifest-and-deploy.ymlManual + on manifest PR mergeThe release path — verifies builds, opens a manifest PR, deploys automatically when it's merged
deploy-staging.ymlManualOperations tool — redeploy one service or a tier
scale-staging.ymlManual + daily scheduleScale staging; auto-down fires nightly ~10:00 PM IST. Scale-up is manual only.
deploy-production.ymlManual (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:

Do not maintain a separate AWS migration plan on this page — it duplicated and then contradicted the dedicated docs above as the project progressed.

Finaisse Internal — Confidential. Access-restricted; not for external distribution.