387c3c4cfa
Phase 1 task 1.1 lands. Directus 11.17.4 boots locally end-to-end against a TimescaleDB+PostGIS container; admin UI serves at :8055, admin bootstrap from env vars works, named volumes preserve data across down/up cycles. Scaffold: - Dockerfile — FROM directus/directus:11.17.4. Pre-installs postgresql16-client (ahead of task 1.2's db-init runner needing psql). Bakes in /directus/snapshots, /directus/db-init, /directus/scripts, /directus/extensions, /directus/entrypoint.sh. - compose.dev.yaml — db (timescale/timescaledb-ha:pg16.6-ts2.17.2-all) + directus (local build), healthchecks, named volumes directus-pg-data + directus-uploads. - entrypoint.sh — placeholder using upstream's actual flow (node cli.js bootstrap && pm2-runtime start ecosystem.config.cjs); the real db-init -> schema apply -> start wrapper lands in task 1.7. - package.json — scripts-only (dev, dev:down, dev:reset, schema:snapshot, schema:apply, db:init), no runtime deps. - .env.example — sectioned, fully documented, KEY/SECRET marked required with generation hints. - .gitignore, .dockerignore — match the processor service conventions. - snapshots/, db-init/, scripts/, extensions/ — empty with .gitkeep, filled by later Phase 1 tasks (1.3, 1.6) and Phase 5. Lessons locked in (against the empirical pnpm dev boot): - timescale/timescaledb-ha:pg16-latest does NOT exist on Docker Hub. Pin a concrete version (we used pg16.6-ts2.17.2-all). - This image's data directory is /home/postgres/pgdata/data, not /pgdata or /var/lib/postgresql/data. PGDATA env var and the volume mount must both target it. - The -all variant bundles PostGIS binaries but the extension is not auto-created on the directus database; CREATE EXTENSION lands in Phase 2 alongside the geofences/SLZs/waypoints collections. - The upstream image's CMD is bootstrap + pm2-runtime, not a simple cli.js start. Bypassing pm2 would lose crash recovery. These corrections folded into 01-project-scaffold.md (deliverable line + Done section), 08-gitea-ci-dryrun.md (CI service tag), and the inline comments in compose.dev.yaml so future implementers don't re-discover them. Status: ROADMAP marks 1.1 done, Phase 1 in progress, 1.2 next.
97 lines
4.7 KiB
Markdown
97 lines
4.7 KiB
Markdown
# directus
|
|
|
|
The TRM business plane. Directus 11 instance owning the relational schema (`organizations`, `users`, `events`, `entries`, course definition, penalty system, timing tables), exposing it through auto-generated REST/GraphQL APIs and the admin UI, and enforcing role-based permissions.
|
|
|
|
For the architectural specification see [`../docs/wiki/entities/directus.md`](../docs/wiki/entities/directus.md). For the work plan and task status see [`.planning/ROADMAP.md`](./.planning/ROADMAP.md).
|
|
|
|
This service is part of the [TRM](https://git.dev.microservices.al/trm) (Time Racing Management) platform.
|
|
|
|
---
|
|
|
|
## Schema management — at a glance
|
|
|
|
Schema is **defined and migrated through Directus**, with two artifact directories:
|
|
|
|
- **`snapshots/schema.yaml`** — Directus collections, fields, relations. Generated locally via `directus schema snapshot`, applied at container startup via `directus schema apply`.
|
|
- **`db-init/*.sql`** — schema Directus does not manage: the [[postgres-timescaledb]] `positions` hypertable, the `faulty` column, PostGIS-specific DDL, etc. Sequential numbered files (`001_`, `002_`, …) applied by `scripts/apply-db-init.sh` with a `migrations_applied` guard table to skip already-run files.
|
|
|
|
Apply order at boot: **db-init first, then `directus schema apply`, then `directus start`.** Any failure halts boot.
|
|
|
|
---
|
|
|
|
## Quick start (local)
|
|
|
|
**Prerequisites:** Docker, the `directus/directus:11.17.4` image (pulled automatically by compose), a running Postgres 16 + TimescaleDB + PostGIS instance (provided by `compose.dev.yaml`).
|
|
|
|
```bash
|
|
git clone <repo-url>
|
|
cd directus
|
|
cp .env.example .env
|
|
# Edit .env — at minimum set DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE, KEY, SECRET
|
|
docker compose -f compose.dev.yaml up --build
|
|
```
|
|
|
|
Admin UI lands at `http://localhost:8055`. Default admin credentials are read from `ADMIN_EMAIL` / `ADMIN_PASSWORD` in `.env`.
|
|
|
|
After making schema changes in the admin UI, snapshot before commit:
|
|
|
|
```bash
|
|
pnpm run schema:snapshot
|
|
git add snapshots/schema.yaml && git commit
|
|
```
|
|
|
|
---
|
|
|
|
## Test the image locally
|
|
|
|
`compose.dev.yaml` builds the image from source and runs it next to a TimescaleDB+PostGIS container. Useful for verifying Dockerfile changes, db-init migrations, or snapshot apply behavior before pushing.
|
|
|
|
```bash
|
|
docker compose -f compose.dev.yaml down -v # wipe volumes for a fresh run
|
|
docker compose -f compose.dev.yaml up --build
|
|
```
|
|
|
|
The entrypoint runs db-init, then `directus schema apply`, then `directus start`. Watch the logs to confirm each step exits 0.
|
|
|
|
---
|
|
|
|
## Production / stage deployment
|
|
|
|
This service is **not** deployed standalone. It runs as part of the platform stack defined in the [`deploy/`](https://git.dev.microservices.al/trm/deploy) repo, which Portainer pulls and runs on the stage and production hosts.
|
|
|
|
The image itself is published to `git.dev.microservices.al/trm/directus:main` on every push to `main` (see CI behavior below). The `deploy/` repo's `compose.yaml` references that image.
|
|
|
|
To pin a specific commit in production, set `DIRECTUS_TAG=<sha>` in the deploy stack's environment variables.
|
|
|
|
> **Note:** The `deploy/compose.yaml` will need a `directus` service entry referencing this image, plus a TimescaleDB+PostGIS service if not already present, before this service can run in stage/production. See `.planning/phase-1-slice-1-schema/07-image-and-dockerfile.md`.
|
|
|
|
---
|
|
|
|
## Environment variables
|
|
|
|
See `.env.example` for the full list. Required for boot:
|
|
|
|
| Variable | Description |
|
|
|---|---|
|
|
| `DB_CLIENT` | `pg` (always) |
|
|
| `DB_HOST` / `DB_PORT` / `DB_DATABASE` / `DB_USER` / `DB_PASSWORD` | Postgres connection |
|
|
| `KEY` | Directus instance key (random UUID) |
|
|
| `SECRET` | Directus JWT signing secret (random) |
|
|
| `ADMIN_EMAIL` / `ADMIN_PASSWORD` | Bootstrap admin (only used on first init) |
|
|
| `PUBLIC_URL` | External-facing URL of the instance |
|
|
|
|
All other Directus envs (cache, logging, CORS, etc.) follow upstream defaults unless overridden.
|
|
|
|
---
|
|
|
|
## CI behavior
|
|
|
|
Gitea Actions workflow lands at `.gitea/workflows/build.yml` in Phase 1 task 1.8 — not yet present.
|
|
|
|
When the workflow exists:
|
|
|
|
- **Push to `main`** (only when `snapshots/`, `db-init/`, `extensions/`, `Dockerfile`, or the workflow file itself changes): builds the image, spins up a throwaway Postgres + TimescaleDB + PostGIS via `services:`, runs `apply-db-init.sh` and `directus schema apply --yes` against it as a **dry-run**, then publishes the image tagged `:main` if the dry-run exits 0. Auto-deploys to stage if a Portainer webhook is configured via `secrets.PORTAINER_WEBHOOK_URL`.
|
|
- **Manual trigger** (`workflow_dispatch`): same flow, run on demand.
|
|
|
|
The dry-run is non-negotiable — it catches snapshot drift, broken db-init scripts, and incompatible schema changes before they touch any real DB.
|