EmofyEmofy Developers
Conventions

Deployment & Environments

Where each app runs, how environments map to branches, and how secrets flow — Railway, Vercel, OpenTofu, and Infisical.

This page covers how the platform is deployed and configured across environments. For running locally, see Local development setup.

Where things run

WorkloadPlatform
backend (NestJS)Railway — a GHCR Docker image deployed by CI (deploy.yml).
Frontends (account, admin, consumer, docs, marketing)Vercel (Emofy team).
landingA separate Vercel team (not managed by the monorepo's IaC).

The backend is built as an immutable image tagged by commit SHA (ADR-015), so a deploy is a tag change and a rollback is pointing back at a previous SHA.

Environments and branches

Environments map to git branches and to domains (ADR-019):

EnvironmentBranchDomain
developmentdevelopment*.dev.emofy.net
stagingstaging*.staging.emofy.net
productionmainemofy.com.tr

The rule of thumb: emofy.com.tr is production; emofy.net is non-prod.

Infrastructure as code

Infrastructure is managed with OpenTofu (ADR-016):

  • OpenTofu owns the Vercel projects and the Railway environment/project wiring.
  • Secrets never live in TF state. They are owned by Infisical and synced to the deploy targets.
  • Postgres and Redis are Railway-managed and provisioned out-of-band.

Secrets: Infisical SSOT

Secrets follow a single source of truth (ADR-017) with three-way ownership:

Infisical (source of truth)
   ├─▶ local dev   :  pnpm env:pull <env>  →  .env   (then .env.local overrides)
   ├─▶ CI          :  GitHub secrets
   └─▶ runtime     :  synced to Vercel / Railway per deploy target

The schema side is the folder-based @emofy/env SSOT — one schema per deploy target — so a missing or malformed variable fails validation at boot rather than surfacing as a runtime surprise.

Destructive-target guard

Commands that can mutate remote data (migrations/seeds against staging or prod) are gated by ADR-014: a runtime guard plus an agent secret-handling policy. Locally, remember to move .env.local aside so the pulled values apply unmodified when targeting remote infra.

CI/CD

GitHub Actions runs the PR checks (check-types, lint, test) and the deploy pipeline. The backend's deploy.yml builds and pushes the Docker image to GHCR; Railway deploys the new SHA. Frontends deploy through Vercel's git integration.

Before shipping, pnpm ship:pre runs pre-flight verification (state sync + deferred-work checks). For the day-to-day workflow, see docs/ai-context/WORKFLOW.md in the repo.

Next

On this page