Production Checklist
Use this checklist before going live with any deployment target.
Pre-Deployment
- Code committed and pushed to GitHub main branch
- Backend builds successfully (
npm run build) - Frontend builds successfully (
npm run build) - All tests pass (
npm testin backend and frontend) - Development environment working with current code
Phase 1: Authentication (30 min)
Clerk Setup
- Created Clerk production instance
- Added authorized domains (frontend + backend URLs)
- Added redirect URLs:
https://<your-domain>/* - Copied production API keys (
pk_live_...,sk_live_...)
OAuth Providers (Production Requires Custom Credentials)
Clerk development instances use shared OAuth credentials. Production instances require your own. Without them, social login buttons redirect with an empty client_id, resulting in a 404 error.
Google OAuth:
- Created OAuth client at Google Cloud Console
- Added Clerk redirect URI:
https://clerk.<your-domain>/v1/oauth_callback - Entered Client ID and Client Secret in Clerk Dashboard
GitHub OAuth:
- Created OAuth app at GitHub Developer Settings
- Set callback URL to Clerk callback URL
- Entered Client ID and Client Secret in Clerk Dashboard
Microsoft OAuth (if enabled):
- Registered app in Azure Portal
- Added Clerk redirect URI
- Entered Application ID and Client Secret in Clerk Dashboard
Phase 2: Infrastructure Setup (30 min)
Backend
- Service deployed and running
- Persistent storage configured (volume/disk/Blob)
- All environment variables set (see Environment Variables)
-
ENCRYPTION_SECRETset to a stable random value -
SESSION_SECRETset to a strong random value -
CORS_ORIGINset to frontend URL (withhttps://) -
AGENT_SERVER_URLset to backend URL (withhttps://)
Frontend
- Service deployed and running
-
VITE_CLERK_PUBLISHABLE_KEYset (withVITE_prefix) - API URL configured (via
VITE_API_URLor nginx proxy)
Elasticsearch
- Elastic Cloud deployment active
-
ELASTICSEARCH_CLOUD_IDandELASTICSEARCH_API_KEYconfigured - Connection verified via Analytics → Setup
Phase 3: Domain Configuration (20 min)
- Custom domains added to hosting provider
- DNS records created (CNAME for Render/Vercel, A/AAAA for Fly.io)
- DNS propagation verified:
dig <your-domain> +short - TLS certificates provisioned (auto via Let's Encrypt)
- HTTPS working for both frontend and backend
- Clerk DNS records added (
clerk.<domain>CNAME) - Environment variables updated with custom domain URLs
Phase 4: Testing (30 min)
Basic Access
- Frontend loads at production URL
- Redirects to Clerk sign-in page
- No SSL certificate warnings
- HTTPS enforced (HTTP redirects to HTTPS)
Authentication
- Google sign-in works
- GitHub sign-in works
- Microsoft sign-in works (if enabled)
- Sign-out works
- Re-authentication works after session expiry
Module Testing
- Browser: View test list
- Browser: View test details and files
- Analytics: Setup page accessible
- Analytics: Dashboard renders with ES data
- Agent: Enrollment token creation
- Agent: Agent management page loads
API Verification
curl https://<backend-domain>/api/health
# Expected: {"status":"ok","service":"ProjectAchilles",...}
- Health endpoint responds
- CORS headers present on cross-origin requests
- Rate limiting active (enrollment: 300/15min per IP; agent device: 30/min per agent)
Browser Console
- No JavaScript errors
- No CORS errors
- No mixed content warnings
- Auth headers present in network requests
Phase 5: Security
- HTTPS enforced on all endpoints
- Session cookies marked as Secure and HttpOnly
- CORS restricted to production domain only
- No secrets committed to the repository
- Strong SESSION_SECRET (32+ characters)
- Strong ENCRYPTION_SECRET (32+ characters)
- Rate limiting active on auth and enrollment endpoints
- Elasticsearch credentials stored encrypted
Post-Deployment
- Set up monitoring/alerting for downtime
- Document production URLs and configuration
- Store API keys securely (password manager or vault)
- Schedule post-deployment review
- Test agent enrollment and task execution end-to-end
Verify what is deployed
GET /api/health reports the build identity, so "did this deploy pick up that
fix?" is answerable without logging into the hosting provider:
curl -s https://<tenant>.agent.projectachilles.io/api/health
{
"status": "ok",
"service": "ProjectAchilles",
"version": "2.1.0",
"commit": "6085fd7abcdef...",
"commit_short": "6085fd7",
"branch": "main",
"timestamp": "2026-09-01T23:00:00.000Z"
}
Compare commit_short against git log --oneline -5 origin/main.
commit is populated automatically on Render, Vercel and Railway, which each
inject their own variable. For Docker Compose, VPS and on-prem installs, stamp
it at build time:
docker build --build-arg GIT_COMMIT=$(git rev-parse HEAD) -t achilles-backend backend/
Without it the endpoint still reports the correct version; commit is simply
null.