Deployment
Supported deployment shapes
- Local development — Node.js + Docker for PostgreSQL and Redis
- Self-hosted — Docker Compose on any Linux host
- Split deployment — Static frontend (Vercel) + containerized API
Docker Compose (self-hosted)
The repository ships two Compose files:
| File | Purpose |
|---|---|
docker-compose.yml | Full local stack (PostgreSQL, Redis, API, web) |
docker-compose.prod.yaml | Production-oriented — bring your own DB and secrets |
Production deploy
# Copy and fill in your production secretscp apps/api/.env.example apps/api/.env
docker compose -f docker-compose.prod.yaml --env-file apps/api/.env up --build -dEnvironment variables
API (required)
# Generate with: openssl rand -base64 64JWT_SECRET=ACTIVITY_HMAC_SECRET=
# DatabaseDB_HOST=DB_PORT=5432DB_NAME=DB_USER=DB_PASSWORD=
# RedisREDIS_HOST=REDIS_PORT=6379
# OriginsFRONTEND_URL=https://handoverkey.appCORS_ORIGINS=https://handoverkey.appAPI (optional)
API_PORT=3001REDIS_PASSWORD=JWT_EXPIRES_IN=1hJWT_REFRESH_EXPIRES_IN=7dCOOKIE_DOMAIN=ADMIN_EMAILS=admin@example.comGRACE_PERIOD_HOURS=48TWO_FACTOR_ISSUER=HandoverKeySMTP
SMTP is strongly recommended. Without it, email verification, inactivity reminders, handover notifications, and password resets won’t work.
SMTP_HOST=smtp.gmail.comSMTP_PORT=587SMTP_SECURE=falseSMTP_USER=your@email.comSMTP_PASS=your-app-passwordSMTP_FROM=noreply@handoverkey.appStripe (optional billing)
# Leave blank to disable paid plansSTRIPE_SECRET_KEY=STRIPE_WEBHOOK_SECRET=STRIPE_PRO_PRICE_ID=STRIPE_FAMILY_PRICE_ID=Register your webhook at https://yourdomain.com/api/v1/billing/webhook and subscribe to:
checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, invoice.payment_failed
Web (build-time)
VITE_API_URL=https://api.handoverkey.app/api/v1VITE_WS_URL=wss://api.handoverkey.app/wsLeave both empty in local development — the Vite proxy handles it.
Frontend hosting
The web app is a Vite SPA. Any host must rewrite all non-asset routes to index.html.
A Vercel config is included at apps/web/vercel.json.
Reverse proxy notes
- Forward WebSocket upgrade requests for
/ws - Enable TLS for both origins in production
- Set
FRONTEND_URLandCORS_ORIGINSto match your actual web origin
Health and monitoring
| Endpoint | Purpose |
|---|---|
GET /health | Service health (DB, Redis, queues, realtime) |
GET /metrics | Prometheus-compatible metrics |
Production checklist
- TLS on both web and API origins
- Strong
JWT_SECRETandACTIVITY_HMAC_SECRET(64+ bytes) - PostgreSQL backups and restore tested
- Redis persistence or managed Redis configured
- SMTP credentials configured and tested
-
FRONTEND_URLandCORS_ORIGINSverified -
VITE_API_URLandVITE_WS_URLset -
/healthendpoint wired into monitoring - SPA rewrites confirmed on web host