Deployment Guide (Production)
1) PostgreSQL Setup
- Create database:
CREATE DATABASE prosperous_data_hub;
- Apply schema:
psql -U postgres -d prosperous_data_hub -f database/schema.sql
- Ensure DB accepts SSL connections if deploying on managed host.
2) Backend Deployment (Node.js + PM2 + Nginx)
- Copy backend env and set values:
cd backend
cp .env.example .env
- Install and start:
npm install
pm2 start ecosystem.config.js
pm2 save
pm2 startup
- Nginx reverse proxy sample:
server {
listen 80;
server_name api.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
- Enable HTTPS with Certbot:
sudo certbot --nginx -d api.yourdomain.com
Render (Recommended for this project)
- Create a new Web Service in Render and connect this repository.
- Set Root Directory to
backend.
- Set commands:
- Build Command:
npm install
- Start Command:
npm start
- Set Health Check Path to
/health.
- Add required environment variables:
DATABASE_URL
JWT_SECRET (16+ chars, recommended 32+)
PAYMENT_CALLBACK_TOKEN (8+ chars)
ADMIN_EMAIL
CORS_ORIGIN (your frontend domain, e.g. https://your-frontend.vercel.app)
APP_BASE_URL (your backend public URL, e.g. https://your-service.onrender.com)
- Optional: deploy using
render.yaml at repository root to auto-configure service settings.
Common Render failure causes:
- Root directory left as repository root (no backend
package.json found).
- Missing required env vars (
DATABASE_URL, JWT_SECRET, PAYMENT_CALLBACK_TOKEN, ADMIN_EMAIL).
- Invalid
APP_BASE_URL (must be a valid URL).
3) Frontend Deployment (Vercel)
- Push
frontend directory to a Git repository.
- In Vercel:
- Framework: Next.js
- Root directory:
frontend
- Environment variable:
NEXT_PUBLIC_API_URL=https://data-hub-6kwj.onrender.com
- Deploy.
Note: the frontend is intentionally kept on the stable Next.js 16.2.x line.
It passes build and Playwright validation, but npm audit still reports a moderate upstream PostCSS advisory through Next’s bundled dependency tree.
This is an external package-chain issue rather than an application-code defect.
4) Environment Variables
Backend .env required keys:
- PORT
- NODE_ENV
- DATABASE_URL
- JWT_SECRET
- JWT_EXPIRES_IN
- CORS_ORIGIN (set to your deployed frontend origin, for example
https://your-frontend-domain.com)
- APP_BASE_URL
-
| PAYMENT_PROVIDER (SIMULATED |
HUBTEL |
EXPRESSPAY) |
- PAYMENT_CALLBACK_TOKEN
-
| PAYMENT_CALLBACK_PROVIDER (AUTO |
HUBTEL |
EXPRESSPAY |
TOKEN) |
-
| VTU_PROVIDER (SIMULATED |
REAL) |
- ADMIN_EMAIL
- Optional provider keys for Hubtel/ExpressPay/VTU:
- HUBTEL_SIGNING_SECRET
- EXPRESSPAY_SIGNING_SECRET
- HUBTEL_CALLBACK_SECRET
- EXPRESSPAY_CALLBACK_SECRET
- VTU_API_KEY (required when
VTU_PROVIDER=REAL)
- VTU_BASE_URL (required when
VTU_PROVIDER=REAL)
- VTU_SIMULATE_FAILURE_SUFFIX (optional, only for simulated VTU failure testing)
Going Live for Real Data Delivery
For real customer purchases (not simulation):
- Set
VTU_PROVIDER=REAL in backend environment.
- Set
VTU_BASE_URL to your VTU aggregator API base URL.
- Set
VTU_API_KEY to your live provider API key/token.
- Redeploy backend and run a live sandbox purchase test.
- Keep wallet refund checks enabled (already built-in) for failed provider responses.
Frontend .env.local:
- NEXT_PUBLIC_API_URL (set to your deployed backend URL, for example
https://data-hub-6kwj.onrender.com)
5) Optional Docker Deployment
From project root:
docker compose up --build
Services:
- Frontend: http://localhost:3000
- Backend: http://localhost:4000
- PostgreSQL: localhost:5432
6) Security Best Practices
Environment Variables
- Never commit
.env files - Only commit .env.example with placeholder values
- Use strong secrets - Generate cryptographically secure values for
JWT_SECRET and PAYMENT_CALLBACK_TOKEN
# Generate a secure 32-character secret
node -e "console.log(require('crypto').randomBytes(16).toString('hex'))"
- Rotate credentials regularly - Plan quarterly rotation for all API keys and secrets
- Use secrets management - Use Render Secrets, AWS Secrets Manager, or similar for production
CORS Configuration
- Production: Set
CORS_ORIGIN to your exact frontend domain (never use *)
CORS_ORIGIN=https://yourdomain.com
- Allow multiple domains only if necessary:
CORS_ORIGIN=https://yourdomain.com,https://www.yourdomain.com
Database Security
- Use strong database password - Generate random password with 16+ characters
- Enable SSL/TLS - Always use SSL connections to database in production
- Limited access - Restrict database access to application servers only
- Backup strategy - Daily automated backups with encryption
- Audit logging - Enable database audit logs for compliance
API Security
- Rate limiting - Already enabled (100 req/min per IP)
- Input validation - All endpoints validate request data with Zod schemas
- Error handling - Errors don’t expose sensitive information or stack traces
- HTTPS only - All production endpoints must use HTTPS
- Security headers - Helmet.js configured for standard security headers
Payment Security
- Webhook validation - All payment callbacks verify signatures
- PCI Compliance - No card data stored; payment providers handle PCI compliance
- Idempotency keys - Prevent duplicate payments through idempotency protection
- Test provider first - Use provider’s sandbox before going live
Monitoring & Logging
- Application Monitoring - Set up APM (Application Performance Monitoring)
- Error Tracking - Send errors to Sentry, Rollbar, or similar
- Audit Trails - Log all financial transactions
- Alerting - Set up alerts for errors, failed payments, and unusual activity
7) Operations Checklist
8) Automated Tests
Backend:
Frontend (Playwright):
cd frontend
npx playwright install
npm run test:e2e