# 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.openmicodyssey.com` -> `omo-bot-backend` - `admin.openmicodyssey.com` -> `omo-bot-dashboard` Recommended edge topology: - Internet -> Nginx reverse proxy -> Coolify resources - Nginx routes by hostname to backend/dashboard resource domains or internal ports Optional same-origin pattern: - `admin.openmicodyssey.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` - Internal port: `8787` (Admin API) 3. Add resource `omo-bot-dashboard` from this repository: - Base directory: `admin-dashboard` - Build command: `npm run build` - Publish directory: `/` - Internal port: `80` (typical static web port behind Coolify) 4. Configure domains for each resource and enable TLS certificates. ## 1.1 Nginx Reverse Proxy in Front of Coolify Use this pattern when you want one public edge server in front of Coolify-managed services. Recommended flow: 1. Public DNS for `api.openmicodyssey.com` and `admin.openmicodyssey.com` points to Nginx host. 2. Nginx terminates TLS and forwards traffic to Coolify resource domains or private IP:port targets. 3. Coolify resources stay private or restricted to internal network where possible. Example host-based routing: ```nginx server { listen 80; server_name api.openmicodyssey.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name api.openmicodyssey.com; ssl_certificate /etc/letsencrypt/live/api.openmicodyssey.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.openmicodyssey.com/privkey.pem; location / { proxy_pass http://coolify-backend.internal:8787; proxy_set_header Host $host; 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 https; } } server { listen 80; server_name admin.openmicodyssey.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name admin.openmicodyssey.com; ssl_certificate /etc/letsencrypt/live/admin.openmicodyssey.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/admin.openmicodyssey.com/privkey.pem; location / { proxy_pass http://coolify-dashboard.internal:80; proxy_set_header Host $host; 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 https; } } ``` If you prefer same-origin routing for dashboard + API through one public domain, proxy `location /admin/` and `location /health` to backend while keeping `/` on dashboard. Recommended OAuth callback route: - `https://admin.openmicodyssey.com/oauth/discord/callback` If you use this callback path, make sure dashboard hosting serves the SPA entrypoint for that route instead of returning `404`. ## 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.openmicodyssey.com`) - `VITE_DISCORD_CLIENT_ID` - `VITE_DISCORD_REDIRECT_URI` (recommended: `https://admin.openmicodyssey.com/oauth/discord/callback`) OAuth alignment: - Discord Developer Portal redirect URI must exactly match the dashboard callback URL. - Config DB key `OAUTH_BRIDGE_REDIRECT_URI` must match the same callback URL. - Dashboard env `VITE_DISCORD_REDIRECT_URI` must match the same callback URL. Discord OAuth authorize URL shape: ```text https://discord.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=https%3A%2F%2Fadmin.openmicodyssey.com%2Foauth%2Fdiscord%2Fcallback&scope=identify%20guilds&prompt=consent ``` ## 3. Get Coolify API Token and Resource UUIDs 1. In Coolify, open `Keys & Tokens` -> `API Tokens` and create a token. 2. Copy your Coolify base URL (example: `https://coolify.yourdomain.com`). 3. Find resource UUID for: - `omo-bot-backend` - `omo-bot-dashboard` Deploy API endpoint used by CI: - `GET /api/v1/deploy?uuid=` - Authorization: `Bearer ` ## 4. Configure Gitea Action Secrets/Variables In Gitea repository settings, add Actions secrets: - `COOLIFY_BASE_URL` - `COOLIFY_API_TOKEN` - `COOLIFY_RESOURCE_UUID_BOT` - `COOLIFY_RESOURCE_UUID_DASHBOARD` Current workflow in `.gitea/workflows/ci-cd.yml` triggers backend and dashboard deploys separately via the Coolify Deploy API. ## 5. Domain and DNS Checklist 1. Create DNS records to Nginx edge host (or directly to Coolify if no edge proxy): - `A` record for root/subdomain targets - `CNAME` where appropriate 2. Verify certificates issued on Nginx or Coolify, depending on TLS termination point. 3. Verify Nginx upstreams match deployed ports: - backend -> `8787` - dashboard -> `80` 4. Verify OAuth callback route resolves through dashboard hosting: - `https://admin.openmicodyssey.com/oauth/discord/callback` 5. Verify dashboard can call API at configured `VITE_ADMIN_API_BASE_URL`. 6. Verify API health endpoint over TLS: - `GET https://api.openmicodyssey.com/health` ## 6. 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. Confirm Discord redirects back to `https://admin.openmicodyssey.com/oauth/discord/callback` without `404`. 5. Validate Admin API auth behavior with and without bearer token.