CAPYN is platform-neutral. The current codebase is suitable for a hosted developer demo or public alpha; it is not yet approved for custody or real-money settlement.
Service shape
Deploy the web and API as separate services with separate environment scopes:
Browser ──► web service ──► API service ──► PostgreSQL
Agent ────────────────────► API service ──► MockPaymentExecutor
The web service has no direct database access. The API is the only application component allowed to mutate authority state.
When a public-alpha account is limited to one application service, CAPYN_SERVICE=combined starts the same built web and API processes on private loopback ports and exposes them through a small first-party HTTP proxy. This is a deployment adapter for the synthetic, memory-backed demo only; the domain and application boundaries remain separate in code. Durable or customer-data environments should use the preferred separate-service shape above.
Web service
Build from the monorepo root:
corepack pnpm install --frozen-lockfile
corepack pnpm --filter @capyn/web... build
Start:
corepack pnpm --filter @capyn/web start
The command binds to 0.0.0.0 and respects the platform-provided PORT. Set CAPYN_SERVICE=web, NEXT_PUBLIC_SITE_URL and NEXT_PUBLIC_API_URL before the build. Use /healthz as the health endpoint.
API service
Build:
corepack pnpm install --frozen-lockfile
corepack pnpm --filter @capyn/api... build
Apply checked-in migrations before starting a PostgreSQL-backed release:
corepack pnpm db:migrate
Start directly:
corepack pnpm --filter @capyn/api start
For a shared monorepo deployment, set CAPYN_SERVICE=api and run corepack pnpm start. The root launcher applies checked-in migrations when CAPYN_STORAGE=postgres, then starts the API. The web service uses the same root command with CAPYN_SERVICE=web. A constrained demo can use CAPYN_SERVICE=combined; CAPYN_INTERNAL_API_PORT and CAPYN_INTERNAL_WEB_PORT default to 4100 and 3100 and must differ from the platform PORT.
Use /health as the process health endpoint. A production-ready health strategy should add a separate readiness check that verifies the database and required executor dependencies without disclosing internal details.
Railway deployment
Create independent web and API services from the same repository. Configure each service with the commands above, let Railway assign each service's PORT, and set:
- web:
CAPYN_SERVICE=web,NEXT_PUBLIC_SITE_URL,NEXT_PUBLIC_API_URL; - API:
CAPYN_SERVICE=api,CAPYN_STORAGE=postgres,DATABASE_URL,API_KEY_PEPPER,WEB_ORIGIN,TRUST_PROXY=truebehind Railway ingress, andDEMO_HUMAN_AUTH=falsefor any non-demo environment; - API bootstrap: omit
BOOTSTRAP_TOKENunless a controlled onboarding operation requires it. - optional billing: set all four Stripe variables from Configuration, then deliver subscribed events to
/v1/billing/webhooks/stripe.
Provision PostgreSQL as a managed service and restrict connectivity to the API service. No container-specific configuration is required by CAPYN.
For a one-service synthetic demo, set CAPYN_SERVICE=combined, CAPYN_STORAGE=memory, DEMO_HUMAN_AUTH=true, pin DEMO_HUMAN_USER_ID to a least-privilege seeded approver, and make WEB_ORIGIN, NEXT_PUBLIC_SITE_URL and NEXT_PUBLIC_API_URL the same HTTPS public origin. Set the matching browser-visible demo identity and disable management controls. Do not configure Stripe or real customer data in this topology. Verify it locally with corepack pnpm smoke:combined after the normal build.
The checked-in railway.json explicitly selects Railway's native Railpack builder, builds only the API/web dependency graphs, starts the root service launcher and checks /healthz. This prevents an older service-level Dockerfile setting from surviving a source swap; CAPYN contains no Dockerfile.
Current public-alpha instance
The synthetic public alpha is live at judgecat-production.up.railway.app. It runs CAPYN_SERVICE=combined, CAPYN_STORAGE=memory, a human adapter pinned to the seeded approver, hidden organisation-administration controls and MockPaymentExecutor. Deployments reset its state, and it must not receive customer data, real provider credentials or real settlement instructions.
Railway's free-plan resource ceiling required a recoverable source swap onto an existing stopped service. The prior volume and domain records were preserved and CAPYN does not read the mounted volume. The intended customer-data topology remains separate web/API services with managed PostgreSQL.
Pre-deployment checklist
For a public demo:
- run
corepack pnpm check; - run
corepack pnpm docs:check; - run
corepack pnpm audit --prod; - build with final public origins and run
corepack pnpm smoke:production; - confirm no
.env, real credentials or customer data is committed; - set the canonical web and API origins;
- verify
/healthz,/health,/,/docs,/dashboardand one authorization request; - confirm the interface states clearly that execution is simulated;
- when billing is enabled, complete a test-mode Checkout, replay its webhook and confirm one subscription audit event.
Before real money, every item in the Security production gate is mandatory. Hosting the current MVP does not satisfy that gate.
Rollout and rollback
- the public-alpha root launcher applies checked-in, idempotent migrations before a PostgreSQL API process starts; move this to an explicit release job before operating multiple API replicas;
- keep schema changes backward compatible while old and new processes overlap;
- deploy API before web when the web needs a new API contract;
- retain the previous build for immediate rollback;
- do not roll back a migration destructively without a reviewed data-recovery plan;
- record deployment identity and version in operational audit/observability systems.
The current mock executor has no external settlement state to reconcile. A real executor requires an outbox, provider idempotency and reconciliation before rollout can be considered safe.