|
| 1 | +# Express Backend Deployment |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This document describes the modernized deployment strategy for the `@vue-skuilder/express` backend API. |
| 6 | + |
| 7 | +## New Deployment Strategy |
| 8 | + |
| 9 | +**Workflow**: `.github/workflows/deploy-express-backend.yml` |
| 10 | +**Service**: `express-backend.service` |
| 11 | +**Server**: eduquilt.com |
| 12 | +**Port**: 3000 |
| 13 | +**Routes**: `/express/*` (via Caddy) |
| 14 | +**Deploy Path**: `/home/skuilder/express-backend` → `/home/skuilder/dist/express-backend/{N}` |
| 15 | + |
| 16 | +### Key Improvements from Old Strategy |
| 17 | + |
| 18 | +1. **Versioned Deployments**: Uses numbered versions (1, 2, 3...) instead of git SHAs |
| 19 | + - Easier to track and rollback |
| 20 | + - Automatic cleanup keeps last 5 versions |
| 21 | + |
| 22 | +2. **Built Artifacts**: Deploys `dist/` output instead of source `src/` |
| 23 | + - Faster startup (no JIT compilation) |
| 24 | + - Production-ready code only |
| 25 | + |
| 26 | +3. **Workspace Dependencies**: Properly handles monorepo dependencies |
| 27 | + - Builds and deploys `@vue-skuilder/common` and `@vue-skuilder/db` |
| 28 | + - Uses `file:` references for local packages |
| 29 | + |
| 30 | +4. **Modern Node Environment**: Uses nvm-managed Node.js |
| 31 | + - Consistent with other services |
| 32 | + - Proper PATH setup in systemd |
| 33 | + |
| 34 | +5. **Health Checks**: Verifies deployment before marking success |
| 35 | + - Automatically checks `/express` endpoint |
| 36 | + - Shows service status on failure |
| 37 | + |
| 38 | +6. **Zero-Downtime**: Symlink swap ensures no service interruption |
| 39 | + |
| 40 | +## Directory Structure on Server |
| 41 | + |
| 42 | +``` |
| 43 | +/home/skuilder/ |
| 44 | +├── express-backend/ # Symlink to current version |
| 45 | +│ ├── dist/ # Built Express app |
| 46 | +│ ├── assets/ # Static assets |
| 47 | +│ ├── .env.production # Production environment variables |
| 48 | +│ ├── workspace/ # Monorepo dependencies |
| 49 | +│ │ ├── common/ # @vue-skuilder/common |
| 50 | +│ │ └── db/ # @vue-skuilder/db |
| 51 | +│ ├── package.json # Modified with file: refs |
| 52 | +│ └── node_modules/ # Production dependencies |
| 53 | +└── dist/ |
| 54 | + └── express-backend/ |
| 55 | + ├── 1/ # Previous version |
| 56 | + ├── 2/ # Previous version |
| 57 | + └── 3/ # Current version (symlinked) |
| 58 | +``` |
| 59 | + |
| 60 | +## First-Time Setup |
| 61 | + |
| 62 | +### 1. Create systemd service |
| 63 | + |
| 64 | +```bash |
| 65 | +# On the server |
| 66 | +sudo cp /home/skuilder/express-backend/express-backend.service /etc/systemd/system/ |
| 67 | +sudo systemctl daemon-reload |
| 68 | +sudo systemctl enable express-backend |
| 69 | +``` |
| 70 | + |
| 71 | +**Note**: Verify Node.js path in the service file matches your nvm installation: |
| 72 | +```bash |
| 73 | +which node |
| 74 | +# Should be: /home/skuilder/.nvm/versions/node/v18.20.4/bin/node |
| 75 | +``` |
| 76 | + |
| 77 | +### 2. Verify Caddy routing |
| 78 | + |
| 79 | +Check `/etc/caddy/Caddyfile` has: |
| 80 | +``` |
| 81 | +handle_path /express/* { |
| 82 | + reverse_proxy localhost:3000 |
| 83 | +} |
| 84 | +handle_path /express { |
| 85 | + reverse_proxy localhost:3000 |
| 86 | +} |
| 87 | +``` |
| 88 | + |
| 89 | +### 3. GitHub Secrets Required |
| 90 | + |
| 91 | +- `DO_SSH_KEY`: SSH private key for deployment |
| 92 | +- `DO_USERNAME`: SSH username (likely 'skuilder') |
| 93 | +- `KNOWN_HOSTS`: SSH known_hosts entry for eduquilt.com |
| 94 | +- `EXPRESS_ENV`: Production environment variables file content |
| 95 | + |
| 96 | +The `EXPRESS_ENV` secret should contain all required environment variables: |
| 97 | +```bash |
| 98 | +COUCHDB_SERVER=localhost:5984 |
| 99 | +COUCHDB_PROTOCOL=http |
| 100 | +COUCHDB_ADMIN=admin |
| 101 | +COUCHDB_PASSWORD=*** |
| 102 | +VERSION=production |
| 103 | +NODE_ENV=production |
| 104 | +MAILER_SERVICE_URL=http://localhost:3001/mailer |
| 105 | +APP_URL=https://eduquilt.com |
| 106 | +SUPPORT_EMAIL=support@eduquilt.com |
| 107 | +``` |
| 108 | + |
| 109 | +## Deployment Process |
| 110 | + |
| 111 | +1. **Trigger workflow** via GitHub Actions UI |
| 112 | + - Go to Actions → deploy-express-backend |
| 113 | + - Click "Run workflow" |
| 114 | + - Enter reason for deployment |
| 115 | + |
| 116 | +2. **Workflow builds**: |
| 117 | + - Installs dependencies |
| 118 | + - Builds workspace packages (common, db) |
| 119 | + - Creates `.env.production` from `EXPRESS_ENV` secret |
| 120 | + - Builds Express backend |
| 121 | + - Creates build info |
| 122 | + |
| 123 | +3. **Deploys to server**: |
| 124 | + - Syncs built artifacts (dist/, assets/, package.json) |
| 125 | + - Syncs `.env.production` file |
| 126 | + - Syncs workspace dependencies |
| 127 | + - Installs production dependencies |
| 128 | + - Updates symlink |
| 129 | + - Restarts service |
| 130 | + |
| 131 | +4. **Verifies**: |
| 132 | + - Health check on `/express` |
| 133 | + - Shows service status if failed |
| 134 | + |
| 135 | +5. **Cleanup**: |
| 136 | + - Removes old versions (keeps last 5) |
| 137 | + |
| 138 | +## Rollback Strategy |
| 139 | + |
| 140 | +```bash |
| 141 | +# On the server |
| 142 | +cd /home/skuilder/dist/express-backend/ |
| 143 | +ls -1v # List versions |
| 144 | + |
| 145 | +# Rollback to version N |
| 146 | +sudo ln -sfn /home/skuilder/dist/express-backend/N /home/skuilder/express-backend |
| 147 | +sudo systemctl restart express-backend |
| 148 | + |
| 149 | +# Verify |
| 150 | +curl https://eduquilt.com/express |
| 151 | +systemctl status express-backend |
| 152 | +``` |
| 153 | + |
| 154 | +## Monitoring |
| 155 | + |
| 156 | +```bash |
| 157 | +# Service status |
| 158 | +systemctl status express-backend |
| 159 | + |
| 160 | +# Logs |
| 161 | +journalctl -u express-backend -f |
| 162 | + |
| 163 | +# Check what version is running |
| 164 | +curl https://eduquilt.com/express |
| 165 | + |
| 166 | +# Check symlink |
| 167 | +ls -la /home/skuilder/express-backend |
| 168 | +``` |
| 169 | + |
| 170 | +## Comparison with Old Strategy |
| 171 | + |
| 172 | +| Aspect | Old (deprecated) | New | |
| 173 | +|--------|-----------------|-----| |
| 174 | +| Workflow | `deprecated-deploy-express.yml` | `deploy-express-backend.yml` | |
| 175 | +| Versioning | Git SHA | Sequential numbers | |
| 176 | +| Deploy Path | `/home/skuilder/api` | `/home/skuilder/express-backend` | |
| 177 | +| Artifacts | Source (`src/app.js`) | Built (`dist/app.js`) | |
| 178 | +| Node Runtime | System node | nvm-managed node | |
| 179 | +| Dependencies | Complex workspace resolution | Clean file: references | |
| 180 | +| Health Check | Version string grep | HTTP endpoint check | |
| 181 | +| Cleanup | Manual | Automatic (keep 5) | |
| 182 | + |
| 183 | +## Migration from Old to New |
| 184 | + |
| 185 | +**Do not run both services simultaneously** - they both bind to port 3000. |
| 186 | + |
| 187 | +1. Stop old service: `sudo systemctl stop eqExpress` |
| 188 | +2. Deploy new version via GitHub Actions |
| 189 | +3. Verify new service: `systemctl status express-backend` |
| 190 | +4. If successful, disable old: `sudo systemctl disable eqExpress` |
| 191 | +5. Keep old service file as backup until confirmed stable |
| 192 | + |
| 193 | +## Troubleshooting |
| 194 | + |
| 195 | +### Service won't start |
| 196 | +```bash |
| 197 | +# Check service status |
| 198 | +systemctl status express-backend |
| 199 | + |
| 200 | +# Check logs |
| 201 | +journalctl -u express-backend -n 50 |
| 202 | + |
| 203 | +# Common issues: |
| 204 | +# - Node path incorrect in service file |
| 205 | +# - Missing or invalid .env.production file |
| 206 | +# - Missing required environment variables (check logs) |
| 207 | +# - Port 3000 already in use (old service?) |
| 208 | +# - Workspace dependencies not installed |
| 209 | + |
| 210 | +# Verify .env.production exists and has correct vars |
| 211 | +cat /home/skuilder/express-backend/.env.production |
| 212 | +# Should contain: COUCHDB_SERVER, COUCHDB_PROTOCOL, COUCHDB_ADMIN, |
| 213 | +# COUCHDB_PASSWORD, VERSION, NODE_ENV |
| 214 | +``` |
| 215 | + |
| 216 | +### Health check fails |
| 217 | +```bash |
| 218 | +# Test endpoint directly |
| 219 | +curl -v https://eduquilt.com/express |
| 220 | + |
| 221 | +# Check if service is listening |
| 222 | +ss -tlnp | grep 3000 |
| 223 | + |
| 224 | +# Check Caddy routing |
| 225 | +sudo systemctl status caddy |
| 226 | +``` |
| 227 | + |
| 228 | +### Workspace dependency errors |
| 229 | +```bash |
| 230 | +# Verify workspace packages are present |
| 231 | +ls /home/skuilder/express-backend/workspace/ |
| 232 | + |
| 233 | +# Check package.json has file: references |
| 234 | +cat /home/skuilder/express-backend/package.json | grep "file:" |
| 235 | + |
| 236 | +# Reinstall if needed |
| 237 | +cd /home/skuilder/express-backend |
| 238 | +NODE_ENV=production yarn install --production --immutable |
| 239 | +``` |
0 commit comments