# Deployment Guide This document covers production deployment for the `omo-bot` Coolify project with **two separate resources**: - `omo-bot-backend` (Node.js bot + Admin API) - `omo-bot-dashboard` (React/Vite static dashboard from `admin-dashboard/`) ## Deployment Topology Recommended domains: - `api.yourdomain.com` -> `omo-bot-backend` - `admin.yourdomain.com` -> `omo-bot-dashboard` Optional same-origin pattern: - `admin.yourdomain.com` serves dashboard and reverse-proxies `/admin/*` + `/health` to backend. ## 1. Create Coolify Project and Resources 1. In Coolify, create (or open) project `omo-bot`. 2. Add resource `omo-bot-backend` from this repository: - Build context: repository root - Start command: `npm start` - Port: `8787` (Admin API) if exposed 3. Add resource `omo-bot-dashboard` from this repository: - Base directory: `admin-dashboard` - Build command: `npm run build` - Publish directory: `dist` 4. Configure domains for each resource and enable TLS certificates. ## 2. Configure Runtime Variables Backend (`omo-bot-backend`) minimum: - `DATABASE_URL` - `CONFIG_DB_ENABLED=true` - Any temporary legacy vars needed for first-time `db:seed` Dashboard (`omo-bot-dashboard`) minimum: - `VITE_ADMIN_API_BASE_URL` (for split-domain deployment, set to `https://api.yourdomain.com`) - `VITE_DISCORD_CLIENT_ID` - `VITE_DISCORD_REDIRECT_URI` (must match Discord OAuth2 redirect list) OAuth alignment: - Discord Developer Portal redirect URI must match dashboard redirect domain. - Config DB key `OAUTH_BRIDGE_REDIRECT_URI` must match the same URI. ## 3. Get Coolify Deployment Hooks and Tokens For each resource (`omo-bot-backend` and `omo-bot-dashboard`): 1. Open resource in Coolify. 2. Go to Deployments/Webhooks (name may vary by Coolify version). 3. Copy the Deploy Webhook URL. 4. If webhook auth token is enabled, copy the token. Store both resources separately: - Backend deploy hook URL/token - Dashboard deploy hook URL/token ## 4. Configure Gitea Action Secrets/Variables In Gitea repository settings, add Actions secrets: - `COOLIFY_DEPLOY_HOOK_URL_BOT` - `COOLIFY_DEPLOY_TOKEN_BOT` (optional) - `COOLIFY_DEPLOY_HOOK_URL_DASHBOARD` - `COOLIFY_DEPLOY_TOKEN_DASHBOARD` (optional) Current workflow in `.gitea/workflows/ci-cd.yml` uses a single pair: - `COOLIFY_DEPLOY_HOOK_URL` - `COOLIFY_DEPLOY_TOKEN` If you use separate resources with separate hooks, update workflow deploy step to call both hooks. ## 5. Example Deploy Step for Two Coolify Resources ```yaml deploy-coolify: name: Deploy to Coolify runs-on: ubuntu-latest needs: - bot-checks - dashboard-checks if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} steps: - name: Trigger backend deploy env: HOOK_URL: ${{ secrets.COOLIFY_DEPLOY_HOOK_URL_BOT }} HOOK_TOKEN: ${{ secrets.COOLIFY_DEPLOY_TOKEN_BOT }} run: | if [ -z "$HOOK_URL" ]; then echo "Missing COOLIFY_DEPLOY_HOOK_URL_BOT" exit 1 fi if [ -n "$HOOK_TOKEN" ]; then curl --fail --show-error --silent -X POST -H "Authorization: Bearer $HOOK_TOKEN" "$HOOK_URL" else curl --fail --show-error --silent -X POST "$HOOK_URL" fi - name: Trigger dashboard deploy env: HOOK_URL: ${{ secrets.COOLIFY_DEPLOY_HOOK_URL_DASHBOARD }} HOOK_TOKEN: ${{ secrets.COOLIFY_DEPLOY_TOKEN_DASHBOARD }} run: | if [ -z "$HOOK_URL" ]; then echo "Missing COOLIFY_DEPLOY_HOOK_URL_DASHBOARD" exit 1 fi if [ -n "$HOOK_TOKEN" ]; then curl --fail --show-error --silent -X POST -H "Authorization: Bearer $HOOK_TOKEN" "$HOOK_URL" else curl --fail --show-error --silent -X POST "$HOOK_URL" fi ``` ## 6. Domain and DNS Checklist 1. Create DNS records to Coolify host: - `A` record for root/subdomain targets - `CNAME` where appropriate 2. Verify certificates issued for both domains. 3. Verify dashboard can call API at configured `VITE_ADMIN_API_BASE_URL`. 4. Verify API health endpoint over TLS: - `GET https://api.yourdomain.com/health` ## 7. Post-Deploy Verification 1. `npm run register:commands` (if bot app/guild IDs changed). 2. Confirm bot online in Discord and slash commands visible. 3. Open dashboard URL and run OAuth login flow. 4. Validate Admin API auth behavior with and without bearer token.