This guide describes the reproducible deployment workflow with environment promotion for the TalentTrust Backend. The system provides automated, secure, and tested deployments across development, staging, and production environments.
Development → Staging → Production
- Development: Continuous deployment from
developbranch - Staging: Deployment from
stagingbranch for pre-production testing - Production: Deployment from
mainbranch with additional safeguards
-
Environment Configuration (
src/config/environment.ts)- Manages environment-specific settings
- Validates configuration for each environment
- Supports multiple deployment targets
-
Deployment Validator (
src/deployment/validator.ts)- Pre-deployment validation checks
- Configuration validation
- Health check capabilities
-
Environment Promoter (
src/deployment/promoter.ts)- Manages promotion between environments
- Enforces promotion paths
- Provides rollback capabilities
-
GitHub Actions Workflow (
.github/workflows/deploy.yml)- Automated CI/CD pipeline
- Multi-stage deployment process
- Security scanning and validation
Deployments are triggered automatically on push to specific branches:
- Push to
develop→ Deploy to Development - Push to
staging→ Deploy to Staging - Push to
main→ Deploy to Production
Manual deployments can be triggered via GitHub Actions:
- Go to Actions tab in GitHub
- Select "Deployment Pipeline" workflow
- Click "Run workflow"
- Select target environment and version
- Click "Run workflow" button
-
Determine Environment
- Identifies target environment based on branch or manual input
- Sets deployment flags
-
Build and Test
- Installs dependencies
- Runs linter
- Executes test suite with coverage check (95% minimum recommended)
- Builds application
- Uploads build artifacts
-
Security Scan
- Runs npm audit
- Checks for known vulnerabilities
- Reports security issues
-
Validate Deployment
- Validates environment configuration
- Checks deployment readiness
- Verifies environment-specific requirements
-
Deploy
- Downloads build artifacts
- Deploys to target environment
- Creates deployment record
-
Health Check
- Waits for deployment stabilization
- Performs health checks
- Notifies deployment status
All environments require:
NODE_ENV: Environment name (development, staging, production)
PORT: Server port (default: 3001)API_BASE_URL: API base URLDEBUG: Enable debug logging (true/false)DATABASE_URL: Database connection stringCORS_ALLOWED_ORIGINS: Comma-separated list of allowed originsMAX_REQUEST_SIZE: Maximum request body size (default: 10mb)
- No special requirements
- Uses Stellar testnet
- Allows localhost CORS origins
- Should use Stellar testnet (mainnet allowed with warning)
- Should not use localhost CORS origins
- Debug mode allowed
- Must use Stellar mainnet
- Must not use localhost or wildcard CORS origins
- Debug mode not recommended
- Requires production-grade configuration
- Development → Staging ✅
- Staging → Production ✅
- Development → Production ❌ (not allowed)
- Production → Any ❌ (cannot promote from production)
import { promoteDeployment } from './src/deployment/promoter';
const result = await promoteDeployment({
from: 'staging',
to: 'production',
version: 'v1.2.0',
initiatedBy: 'user@example.com',
timestamp: new Date(),
});
if (result.success) {
console.log('Promotion successful:', result.promotionId);
} else {
console.error('Promotion failed:', result.error);
}- Critical bugs discovered in production
- Performance degradation
- Security vulnerabilities
- Failed deployment
import { rollbackDeployment } from './src/deployment/promoter';
const result = await rollbackDeployment({
environment: 'production',
targetVersion: 'v1.1.0',
reason: 'Critical bug in payment processing',
initiatedBy: 'user@example.com',
});
if (result.success) {
console.log('Rollback successful:', result.rollbackId);
} else {
console.error('Rollback failed:', result.error);
}- Development environment does not support rollback
- Target version must exist and be valid
- Rollback does not automatically revert database migrations
- Dependency Scanning: npm audit checks for known vulnerabilities
- Configuration Validation: Ensures secure configuration for each environment
- Test Coverage: Minimum 95% coverage recommended
- Linting: Code quality checks
- Requires approval via GitHub environment protection rules
- Validates Stellar mainnet configuration
- Prevents wildcard or localhost CORS origins
- Warns if debug mode is enabled
Store sensitive configuration in GitHub Secrets:
- Go to repository Settings → Secrets and variables → Actions
- Add environment-specific secrets
- Reference in workflow:
${{ secrets.SECRET_NAME }}
All deployments create records with:
- Timestamp
- Environment
- Commit SHA
- Initiating user
- Deployment status
Post-deployment health checks verify service readiness by making a real HTTP
request to the /health/ready endpoint of the deployed service.
performHealthCheck(baseUrl, httpClient?) in src/deployment/validator.ts
implements a production-grade readiness probe with the following guarantees:
What it does
-
SSRF guard —
baseUrlis validated byisSafeUrlfromsrc/utils/ssrf.tsbefore any network call is made. Private addresses (RFC-1918, loopback 127.x, link-local 169.254.x, IPv6 ULA/loopback, cloud metadata) are blocked in all environments. In production (NODE_ENV=production) the block is unconditional and cannot be overridden bySSRF_ALLOW_PRIVATE_HOSTS. -
Target endpoint — the probe calls
GET <baseUrl>/health/ready, served bysrc/health.tsand registered at/health/readyin Express. The endpoint runs dependency probes (SQLite, Stellar RPC, Redis) and returns200when all pass, or503when any fail. -
Accurate response time —
Date.now()is captured immediately before theclient.get()call and the difference is taken immediately after the awaited response, soresponseTimein the result reflects true network round-trip latency. -
Bounded timeout — the default (non-injected) HTTP client is created with
timeout: 5000(5 seconds). The probe returnsunhealthyif the connection is refused (ECONNREFUSED) or aborted (ECONNABORTED). -
Injectable HTTP client — pass a custom
AxiosInstanceas the second argument to avoid real network calls in tests. -
Error handling — errors from both the default
createHttpClientinterceptor (HttpResponseError) and raw Axios errors from injected clients are handled; both paths setstatusCodeanderrorindetails.
Result shape
interface HealthCheckResult {
service: string; // always "talenttrust-backend"
status: 'healthy' | 'unhealthy'; // healthy only on HTTP 200
timestamp: Date;
details?: {
baseUrl: string;
responseTime: number; // ms, measured around the real request
statusCode?: number; // present on HTTP responses
error?: string; // present on unhealthy results
};
}Outcome matrix
| Scenario | status |
details.error |
|---|---|---|
HTTP 200 from /health/ready |
healthy |
— |
| HTTP 503 (dependency down) | unhealthy |
HTTP 503 |
| Connection refused | unhealthy |
Connection refused |
| Timeout (>5 s) | unhealthy |
Request timeout |
| Private/internal URL | unhealthy |
URL not safe for SSRF |
| Any other error | unhealthy |
error message |
Usage example
import { performHealthCheck } from './src/deployment/validator';
// Default (real network, 5 s timeout)
const result = await performHealthCheck('https://api.example.com');
if (result.status !== 'healthy') {
console.error('Service not ready:', result.details);
process.exit(1);
}
// Injected client (tests / custom timeout)
import axios from 'axios';
const client = axios.create({ timeout: 10_000 });
const result = await performHealthCheck('https://api.example.com', client);Security notes
- The SSRF guard is applied before any I/O. An attacker-controlled
baseUrlcannot route the probe to cloud metadata (169.254.169.254), internal services (10.x,192.168.x), or loopback (127.x). - Error messages returned in
details.errorare safe machine-readable tokens (HTTP 503,Connection refused,Request timeout) — no stack traces, internal hostnames, or topology are leaked. - In production the guard is always applied regardless of environment variables.
/health/ready endpoint (GET /health/ready)
Served by src/health.ts. Runs three dependency probes concurrently:
| Probe | Dependency | Timeout |
|---|---|---|
db |
SQLite SELECT 1 |
3 000 ms |
stellar-rpc |
Soroban RPC reachability | 3 000 ms |
queue |
Redis PING |
3 000 ms |
Returns 200 { status: "ready" } when all probes pass, 503 { status: "not-ready" }
otherwise. Also returns 503 when the service is draining during a blue-green
handoff.
Cause: Invalid environment configuration
Solution: Check environment variables and configuration requirements
NODE_ENV=production npm run build
node -e "const { loadEnvironmentConfig } = require('./dist/config/environment'); console.log(loadEnvironmentConfig());"Cause: Insufficient test coverage
Solution: Add tests for uncovered code paths
npm test -- --coverageCause: Outdated dependencies with known vulnerabilities
Solution: Update dependencies
npm audit fix
npm audit fix --force # For breaking changesCause: Attempting invalid promotion (e.g., dev → prod)
Solution: Follow valid promotion paths (dev → staging → prod)
- Check GitHub Actions logs for detailed error messages
- Review deployment validation output
- Consult security scan results
- Contact DevOps team for infrastructure issues
-
Always test in staging before production
- Deploy to staging first
- Run integration tests
- Verify functionality
- Then promote to production
-
Use semantic versioning
- Tag releases with version numbers
- Follow semver conventions (MAJOR.MINOR.PATCH)
- Document breaking changes
-
Monitor deployments
- Watch health check results
- Monitor application logs
- Set up alerts for failures
-
Keep dependencies updated
- Regularly run
npm audit - Update dependencies promptly
- Test after updates
- Regularly run
-
Document configuration changes
- Update environment variable documentation
- Communicate changes to team
- Update deployment guide as needed
- Review and update dependencies monthly
- Audit security vulnerabilities weekly
- Review deployment logs regularly
- Update documentation as system evolves
- Create feature branch
- Modify workflow files
- Test in development environment
- Submit pull request
- Review and merge