Production runs as a docker-compose stack on the deploy host (`10.0.0.52`). The stack has four services: PostgreSQL, the Hono API, the Vite SPA served by Caddy, and the Bun worker. Deploys are normally driven by Gitea Actions, but every step below can be run by hand.
Caddy (in the `spa` container) serves the built SPA and reverse-proxies `/api/*` and `/mcp*` to the `api` service. The API is also exposed directly on :3001 for debugging.
The workflow lives at `.gitea/workflows/ci.yml` and runs on the self-hosted runner `projecte-runner`, which is colocated with the deploy host. The runner must be registered once (see "Setting up the runner" below) before any job can run.
- **`quality`** — runs on every push and pull request: `bun install --frozen-lockfile` → `bun run typecheck` → web build (`cd apps/web && bun run build`) → `docker compose build`. A failed quality gate blocks the deploy job.
- **`deploy`** — runs on pushes to `main` and on `workflow_dispatch`. It checks out the code and runs `bash script/deploy.sh` with `DEPLOY_DIR` defaulting to `/home/projecte/ProjectE`.
- **`smoke`** — runs after `deploy` (also on deploy failure): API health at `http://localhost:3000/api/health`, SPA root returns HTML, and a login POST to `/api/auth/credentials` using `INITIAL_ADMIN_EMAIL`/`INITIAL_ADMIN_PASSWORD` from the host `.env`.
Fill in `POSTGRES_PASSWORD`, `DATABASE_URL`, `AUTH_SECRET` (or `NEXTAUTH_SECRET`), `INITIAL_ADMIN_EMAIL`, `INITIAL_ADMIN_PASSWORD`, and, as needed, `NODE_ENV`, `PUBLIC_URL`, `COOKIE_SECURE`, and `ALLOWED_HOSTS`. `deploy.sh` sources it, and docker-compose reads the `POSTGRES_PASSWORD` and `DATABASE_URL` values from it.
- `db:sync` — `drizzle-kit push --force`, which syncs the schema in `packages/db/src/schema.ts` to the database
- `db:triggers` — `script/apply-triggers.ts`, which applies the search-vector triggers from `drizzle/0005_search_vector_trigger.sql` (`CREATE OR REPLACE FUNCTION` + `DROP TRIGGER IF EXISTS`)
Compose images are rebuilt from the checkout, so there are no pinned image tags to restore. To roll back a bad release:
1. Revert the checkout to the previous good commit: `git revert <sha>` (or `git checkout <sha>`) and push to `main`
2. Re-run the manual deploy steps (`docker compose build`, `docker compose up -d`)
The `project-e-pg-data` volume is untouched by deploys and rollbacks, so the database survives both. If a deploy failed, `deploy.sh` exits non-zero with the recent API logs; do not force it past a failing health check.
- The `project-e-pg-data` Docker volume contains the live database. **Do not delete it.** Back it up (volume snapshot or `pg_dump`) before major schema work.
- Port 3000 is the SPA (Caddy); port 3001 is the API directly (for debugging).