chore(deploy): simplify docker-compose and add Forgejo CI/CD

- Remove Convex from docker-compose (runs separately)
- Add .forgejo/workflows/ci.yml with auto-deploy to Coolify
- Update DEVELOPMENT.md with dev/prod architecture diagram
- Rename branch from develop to dev in all workflows
This commit is contained in:
nxtkofi 2026-05-17 18:58:17 +02:00
parent 374bba1a93
commit 1c2adc1f1e
4 changed files with 150 additions and 64 deletions

49
.forgejo/workflows/ci.yml Normal file
View file

@ -0,0 +1,49 @@
name: CI
on:
push:
branches: [main, dev]
pull_request:
branches: [main, dev]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Lint
run: pnpm lint
- name: Build
run: pnpm build
deploy-dev:
if: github.ref == 'refs/heads/dev'
needs: lint
runs-on: ubuntu-latest
steps:
- name: Deploy to Coolify (Dev)
run: |
curl -X POST "${{ secrets.COOLIFY_DEV_WEBHOOK }}"
deploy-prod:
if: github.ref == 'refs/heads/main'
needs: lint
runs-on: ubuntu-latest
steps:
- name: Deploy to Coolify (Prod)
run: |
curl -X POST "${{ secrets.COOLIFY_PROD_WEBHOOK }}"

View file

@ -2,9 +2,9 @@ name: CI
on: on:
push: push:
branches: [main, develop] branches: [main, dev]
pull_request: pull_request:
branches: [main, develop] branches: [main, dev]
jobs: jobs:
lint: lint:

View file

@ -42,11 +42,44 @@ npx convex dev
This connects to your self-hosted Convex instance. Ensure CLI version matches your backend image version. This connects to your self-hosted Convex instance. Ensure CLI version matches your backend image version.
## Coolify Deployment (Convex Self-Hosted) ## Architecture Overview
### 1. Deploy Convex Backend ```
┌─────────────────────────────────────────────────────────────┐
│ LOCAL DEV │
│ pnpm dev --webpack → npx convex dev → DEV CONVEX DB │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ FORGEJO / GIT │
│ main branch ──► PROD DEPLOY │
│ dev branch ──► DEV DEPLOY │
└─────────────────────────────────────────────────────────────┘
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ COOLIFY (PROD) │ │ COOLIFY (DEV) │
│ Next.js Docker Container │ │ Next.js Docker Container │
│ (frontend) │ │ (frontend) │
└─────────────────────────────┘ └─────────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ CONVEX (PROD DB) │ │ CONVEX (DEV DB) │
│ Self-hosted on Coolify │ │ Self-hosted on Coolify │
│ or Convex Cloud │ │ or Convex Cloud │
└─────────────────────────────┘ └─────────────────────────────┘
```
On Coolify, create a new service using this docker-compose: ### Convex Backend
Convex runs **separately** from the Next.js frontend. You need two instances:
- **Dev**: for local development + dev environment testing
- **Prod**: for production
On Coolify, create a new service for each Convex backend using the official docker-compose:
```yaml ```yaml
services: services:
@ -66,7 +99,6 @@ services:
CONVEX_SITE_ORIGIN: '${SERVICE_URL_BACKEND_SITE}' CONVEX_SITE_ORIGIN: '${SERVICE_URL_BACKEND_SITE}'
DO_NOT_REQUIRE_SSL: '${DO_NOT_REQUIRE_SSL:-true}' DO_NOT_REQUIRE_SSL: '${DO_NOT_REQUIRE_SSL:-true}'
DATABASE_URL: '${DATABASE_URL:-}' DATABASE_URL: '${DATABASE_URL:-}'
# ... (see README.md for full config)
healthcheck: healthcheck:
test: ['CMD-SHELL', 'curl -f http://localhost:3210/version'] test: ['CMD-SHELL', 'curl -f http://localhost:3210/version']
interval: 5s interval: 5s
@ -91,7 +123,7 @@ volumes:
> **Best practice**: Copy the [official self-hosted config](https://github.com/get-convex/convex-backend/blob/main/self-hosted/docker/docker-compose.yml) and adapt env vars for Coolify. > **Best practice**: Copy the [official self-hosted config](https://github.com/get-convex/convex-backend/blob/main/self-hosted/docker/docker-compose.yml) and adapt env vars for Coolify.
### 2. Generate Admin Key ### Generate Admin Key
SSH into the server and run: SSH into the server and run:
@ -291,11 +323,11 @@ docker run -p 3000:3000 --env-file .env.local my-app
### Docker Compose ### Docker Compose
Full-stack deployment with Convex backend: Frontend-only deployment:
```bash ```bash
# Start everything (Next.js + Convex backend + Convex dashboard) # Build and start Next.js app
docker compose up docker compose up --build
``` ```
Services: Services:
@ -303,8 +335,8 @@ Services:
| Service | Port | Description | | Service | Port | Description |
|---------|------|-------------| |---------|------|-------------|
| `app` | 3000 | Next.js application | | `app` | 3000 | Next.js application |
| `backend` | 3210 | Convex backend API |
| `dashboard` | 6791 | Convex admin dashboard | > **Note**: Convex backend runs separately. See [Coolify Deployment](#coolify-deployment) for Convex setup.
### Server Components in Docker ### Server Components in Docker
@ -339,17 +371,66 @@ CONVEX_SELF_HOSTED_ADMIN_KEY=your-admin-key
### Coolify Deployment ### Coolify Deployment
1. Push code to your Forgejo repo #### 1. Setup Two Environments
2. In Coolify, create a new service from your repo
3. Select `docker-compose.yml` as the deployment method
4. Set environment variables in Coolify UI
5. Deploy
> **Note**: The `app` service depends on `backend` (Convex). Make sure your Convex backend is accessible from the Coolify server. Create two services in Coolify:
| Service | Branch | Convex DB | Domain |
|---------|--------|-----------|--------|
| `my-app-prod` | `main` | Prod | `app.example.com` |
| `my-app-dev` | `dev` | Dev | `dev-app.example.com` |
#### 2. Configure Webhooks (Auto-Deploy)
In each Coolify service, copy the **Deploy Webhook URL** and add it to Forgejo Secrets:
```bash
# Forgejo → Repo Settings → Secrets
COOLIFY_PROD_WEBHOOK=https://coolify.example.com/webhooks/...
COOLIFY_DEV_WEBHOOK=https://coolify.example.com/webhooks/...
```
The `.forgejo/workflows/ci.yml` automatically triggers deploy on push:
- `main` branch → Prod webhook
- `dev` branch → Dev webhook
#### 3. Set Environment Variables
In each Coolify service, set env vars:
**Prod**:
```bash
NEXT_PUBLIC_SITE_URL=https://app.example.com
NEXT_PUBLIC_CONVEX_URL=https://convex-prod.example.com
NEXT_PUBLIC_CONVEX_SITE_URL=https://convex-site-prod.example.com
CONVEX_SELF_HOSTED_URL=https://convex-prod.example.com
CONVEX_SELF_HOSTED_ADMIN_KEY=prod-admin-key
```
**Dev**:
```bash
NEXT_PUBLIC_SITE_URL=https://dev-app.example.com
NEXT_PUBLIC_CONVEX_URL=https://convex-dev.example.com
NEXT_PUBLIC_CONVEX_SITE_URL=https://convex-site-dev.example.com
CONVEX_SELF_HOSTED_URL=https://convex-dev.example.com
CONVEX_SELF_HOSTED_ADMIN_KEY=dev-admin-key
```
#### 4. Local Development Connects to Dev
Your `.env.local` should point to the **dev** Convex:
```bash
CONVEX_SELF_HOSTED_URL='https://convex-dev.example.com'
CONVEX_SELF_HOSTED_ADMIN_KEY='dev-admin-key'
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_CONVEX_URL=https://convex-dev.example.com
NEXT_PUBLIC_CONVEX_SITE_URL=https://convex-site-dev.example.com
```
### Health Check ### Health Check
The Next.js app exposes a health endpoint at `/api/health` (add if needed) or you can check if the app is running: Verify the app is running:
```bash ```bash
curl http://localhost:3000 curl http://localhost:3000

View file

@ -1,5 +1,4 @@
services: services:
# Next.js Application
app: app:
build: build:
context: . context: .
@ -7,52 +6,9 @@ services:
ports: ports:
- '${PORT:-3000}:3000' - '${PORT:-3000}:3000'
environment: environment:
NODE_ENV: production NODE_ENV: '${NODE_ENV:-production}'
NEXT_PUBLIC_SITE_URL: '${NEXT_PUBLIC_SITE_URL}' NEXT_PUBLIC_SITE_URL: '${NEXT_PUBLIC_SITE_URL}'
NEXT_PUBLIC_CONVEX_URL: '${NEXT_PUBLIC_CONVEX_URL}' NEXT_PUBLIC_CONVEX_URL: '${NEXT_PUBLIC_CONVEX_URL}'
NEXT_PUBLIC_CONVEX_SITE_URL: '${NEXT_PUBLIC_CONVEX_SITE_URL}' NEXT_PUBLIC_CONVEX_SITE_URL: '${NEXT_PUBLIC_CONVEX_SITE_URL}'
CONVEX_SELF_HOSTED_URL: '${CONVEX_SELF_HOSTED_URL}' CONVEX_SELF_HOSTED_URL: '${CONVEX_SELF_HOSTED_URL}'
CONVEX_SELF_HOSTED_ADMIN_KEY: '${CONVEX_SELF_HOSTED_ADMIN_KEY}' CONVEX_SELF_HOSTED_ADMIN_KEY: '${CONVEX_SELF_HOSTED_ADMIN_KEY}'
depends_on:
- backend
# Convex Backend
backend:
image: 'ghcr.io/get-convex/convex-backend:latest'
stop_grace_period: 10s
stop_signal: SIGINT
ports:
- '${PORT:-3210}:3210'
- '${SITE_PROXY_PORT:-3211}:3211'
volumes:
- 'data:/convex/data'
environment:
INSTANCE_NAME: '${INSTANCE_NAME}'
INSTANCE_SECRET: '${INSTANCE_SECRET}'
CONVEX_CLOUD_ORIGIN: '${SERVICE_URL_BACKEND}'
CONVEX_SITE_ORIGIN: '${SERVICE_URL_BACKEND_SITE}'
DO_NOT_REQUIRE_SSL: '${DO_NOT_REQUIRE_SSL:-true}'
DATABASE_URL: '${DATABASE_URL:-}'
healthcheck:
test: ['CMD-SHELL', 'curl -f http://localhost:3210/version']
interval: 5s
start_period: 10s
timeout: 5s
retries: 10
# Convex Dashboard
dashboard:
image: 'ghcr.io/get-convex/convex-dashboard:latest'
stop_grace_period: 10s
stop_signal: SIGINT
ports:
- '${DASHBOARD_PORT:-6791}:6791'
environment:
PORT: '6791'
NEXT_PUBLIC_DEPLOYMENT_URL: '${SERVICE_URL_BACKEND}'
depends_on:
backend:
condition: service_healthy
volumes:
data: null