Skip to content
Open the portal
Developer docs

Deployment and operations

Engineers12 min read

The full click-by-click guide, with screenshots of each console, is planning/STRATL_DEPLOYMENT_GUIDE.html in the backend repository. This page is the engineer’s summary of the same deployment.

Part Runs on Address
API and PostgreSQL Railway (one project: the api service from the backend repository, and a Postgres service) api.stratl.ai
Portal Vercel (project from the web repository) app.stratl.ai, forwarding /api to the API
Website Vercel (project from the website repository) stratl.ai
Docs Vercel (project from the docs repository) docs.stratl.ai
Custody AWS: one S3 bucket and one KMS alias prefix per offered region, created by deploy/cloudformation/managed-custody.yaml; an IAM user with put, get and sign only per region
Email Resend, with a verified sending domain notifications@stratl.ai
  1. Create a Railway project with a PostgreSQL service; pick the region; turn on backups.

  2. Add the api service from the backend repository. The Dockerfile at the repository root builds it; migrations run at start; Railway waits for the health check (/healthz) before switching traffic.

  3. Variables (Raw Editor). Generate the secret with openssl rand -base64 48.

    STRATL_ENV=production
    STRATL_DATABASE_URL=${{Postgres.DATABASE_URL}}
    STRATL_SECRET_KEY=<the openssl output>
    STRATL_CUSTODY_BACKEND=s3-kms
    STRATL_CUSTODY_REGIONS=in=ap-south-1:stratl-records-in
    AWS_ACCESS_KEY_ID=<from the CloudFormation stack>
    AWS_SECRET_ACCESS_KEY=<from the CloudFormation stack>
    STRATL_LOG_LEVEL=INFO
    PORT=8000
    RESEND_API_KEY=<from Resend>
    RESEND_FROM_EMAIL=notifications@stratl.ai
    RESEND_FROM_NAME=Stratl
    STRATL_PUBLIC_URL=https://api.stratl.ai
    ANTHROPIC_API_KEY=<optional, for notice drafting>

    STRATL_ENV=production turns on secure cookies and stops codes being shown on screen; the API refuses to start in production with the default secret key. Every setting.

  4. Before deploying, prove custody from your machine with the same AWS values: uv run --directory api python scripts/check_custody.py.

  5. Deploy, read the logs, test on the temporary Railway address, then attach api.stratl.ai.

Three separate Vercel projects, one per repository, Node 22. The portal needs one variable, VITE_PUBLIC_API_URL=https://api.stratl.ai, which is only the address printed in the Get started snippets; its vercel.json rewrites /api/* to the API so the session cookie stays first-party, and sets no-store on those responses. The website and the docs need no variables. Attach app.stratl.ai, stratl.ai (with www redirecting) and docs.stratl.ai.

Create the stack from deploy/cloudformation/managed-custody.yaml in each region you offer; after the first, pass its ApiUserName as ExistingApiUserName so one IAM user spans regions. Create an access key for that user. The template creates a versioned, encrypted, public-access-blocked bucket with Object Lock available, and one managed IAM policy per region that allows put, get and sign only (managed, not inline: IAM caps inline policies at 2048 bytes per user, which one region already fills). Custody.

Add your domain, add the DMARC record Resend suggests so inboxes trust you, create an API key. Without a key the API logs codes instead of sending them, which is only acceptable locally.

  1. Sign up at app.stratl.ai/signup; the region list should show only the regions you configured.
  2. Send a real record from your laptop with the SDK snippet on Get started.
  3. Walk the five steps of Get started to a verified bundle.
  4. On the Custody page the storage location should start with s3:// and the key card should say it is held in KMS. Redeploy the API and check the key id and chain head are unchanged. In the AWS console the bucket should hold a folder named after the workspace with records, checkpoints, artifacts and keys.
You want to Do
Ship a backend change Push to main in the backend. Railway builds, runs migrations at start, waits for the health check
Ship a portal, website or docs change Push to main in that repository. Vercel deploys; every pull request gets a preview
Change both API and portal in one feature Two repositories, two pushes. Deploy the backend first so the UI never calls something the API lacks
Undo a bad deploy Railway: Deployments → the last good one → Redeploy. Vercel: Instant Rollback. A backend rollback does not undo a migration
Update the offline verifier in the portal make wasm-export in the backend, then commit and push the two files in the web repository
Update the API reference in the docs make openapi in the backend, then commit and push in the docs repository
Read logs Railway → api service → Deployments → View logs. Logs never contain content
Rotate the Resend key or the AWS access key Change the variable in Railway; the service restarts. Never change STRATL_SECRET_KEY casually: it voids codes waiting to be used