Task 1.1 — Project scaffold
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.
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
# Files and directories excluded from the Docker build context.
|
||||
# Keep this tight — a large context slows every `docker build`.
|
||||
|
||||
.git/
|
||||
.planning/
|
||||
node_modules/
|
||||
directus-data/
|
||||
|
||||
# Secrets — never bake these into the image
|
||||
.env
|
||||
.env.local
|
||||
.env.*
|
||||
|
||||
# Compose files are runtime config, not part of the image
|
||||
compose.dev.yaml
|
||||
|
||||
# Markdown docs (README.md is excluded too — the image doesn't need it)
|
||||
*.md
|
||||
|
||||
# pnpm lockfile and package.json are not needed inside the Directus image
|
||||
# (the upstream image manages its own Node environment).
|
||||
package.json
|
||||
pnpm-lock.yaml
|
||||
@@ -0,0 +1,98 @@
|
||||
# Environment variables for the TRM directus service.
|
||||
# Copy to .env and fill in values for local development.
|
||||
# cp .env.example .env
|
||||
#
|
||||
# Required vars: DB_*, KEY, SECRET, ADMIN_EMAIL, ADMIN_PASSWORD, PUBLIC_URL.
|
||||
# .env is gitignored — never commit real credentials.
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Database connection — Postgres 16 + TimescaleDB + PostGIS
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Directus DB driver. Always "pg" for this service.
|
||||
DB_CLIENT=pg
|
||||
|
||||
# Hostname of the Postgres container (matches the compose service name when
|
||||
# running via compose.dev.yaml; change to your host/IP for external Postgres).
|
||||
DB_HOST=db
|
||||
|
||||
# Postgres port.
|
||||
DB_PORT=5432
|
||||
|
||||
# Database name.
|
||||
DB_DATABASE=directus
|
||||
|
||||
# Postgres user.
|
||||
DB_USER=directus
|
||||
|
||||
# Postgres password.
|
||||
DB_PASSWORD=directus
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Instance security — REQUIRED; generate fresh values for each environment.
|
||||
#
|
||||
# KEY: uuidgen (or openssl rand -hex 32)
|
||||
# SECRET: openssl rand -hex 64
|
||||
#
|
||||
# IMPORTANT: two instances sharing the same KEY/SECRET will produce
|
||||
# colliding JWT tokens. Use distinct values per environment.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
KEY=replace-with-a-random-uuid
|
||||
SECRET=replace-with-a-long-random-string
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Admin bootstrap
|
||||
#
|
||||
# Applied on first boot when the users table is empty. If the instance has
|
||||
# already been initialised these values are ignored — change the password via
|
||||
# the admin UI or Directus CLI instead.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
ADMIN_EMAIL=admin@example.com
|
||||
ADMIN_PASSWORD=change-me-on-first-boot
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Public URL
|
||||
#
|
||||
# Used in password-reset emails, OAuth redirect URIs, and the Directus admin
|
||||
# UI's "share" links. Set to the externally reachable URL in staging/prod.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
PUBLIC_URL=http://localhost:8055
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Logging
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Log level: fatal | error | warn | info | debug | trace
|
||||
LOG_LEVEL=info
|
||||
|
||||
# Log format: pretty (human-readable) | json (structured, for log aggregators)
|
||||
LOG_STYLE=pretty
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Cache (optional — disabled by default for local dev)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Set to true to enable Directus's built-in response cache.
|
||||
# Requires a cache store (Redis or memory) when enabled.
|
||||
CACHE_ENABLED=false
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CORS (optional — disabled by default)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Set to true to enable CORS headers.
|
||||
CORS_ENABLED=false
|
||||
|
||||
# Allowed origin(s). Accepts a URL string, comma-separated list, or "true"
|
||||
# to reflect any origin (development only — never use "true" in production).
|
||||
# CORS_ORIGIN=http://localhost:3000
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# WebSockets (enabled by default — required for the SPA live channel)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Set to false only when the SPA is not connected (e.g. API-only deployments).
|
||||
WEBSOCKETS_ENABLED=true
|
||||
@@ -0,0 +1,9 @@
|
||||
node_modules/
|
||||
.env
|
||||
.env.local
|
||||
*.log
|
||||
|
||||
# Local Postgres data directory (only present if using a host bind mount
|
||||
# instead of a named volume — the committed compose.dev.yaml uses named
|
||||
# volumes, but a developer might override this locally).
|
||||
directus-data/
|
||||
@@ -42,14 +42,14 @@ These rules govern every task. Any deviation must be discussed and documented as
|
||||
|
||||
### Phase 1 — Slice 1 schema + deploy pipeline
|
||||
|
||||
**Status:** ⬜ Not started
|
||||
**Status:** 🟨 In progress (1.1 done; 1.2 next)
|
||||
**Outcome:** A Directus instance with the org-level catalog (orgs, users, organization_users, vehicles, devices and their org junctions) and event-participation collections (events, classes, entries, entry_crew, entry_devices) live and snapshot-tracked. `db-init/` covers the TimescaleDB extension, the `positions` hypertable, and the `faulty` column. Image builds via Gitea Actions with a CI dry-run that catches snapshot drift before deploy. Rally Albania 2026 is registered as the first event in admin UI to dogfood the registration workflow. **This is what Rally Albania 2026 needs.**
|
||||
|
||||
[**See `phase-1-slice-1-schema/README.md`**](./phase-1-slice-1-schema/README.md)
|
||||
|
||||
| # | Task | Status | Landed in |
|
||||
|---|------|--------|-----------|
|
||||
| 1.1 | [Project scaffold](./phase-1-slice-1-schema/01-project-scaffold.md) | ⬜ | — |
|
||||
| 1.1 | [Project scaffold](./phase-1-slice-1-schema/01-project-scaffold.md) | 🟩 | pending user commit |
|
||||
| 1.2 | [db-init runner script](./phase-1-slice-1-schema/02-db-init-runner.md) | ⬜ | — |
|
||||
| 1.3 | [Initial migrations (extensions, positions hypertable, faulty column)](./phase-1-slice-1-schema/03-initial-migrations.md) | ⬜ | — |
|
||||
| 1.4 | [Org-level catalog collections](./phase-1-slice-1-schema/04-org-catalog-collections.md) | ⬜ | — |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Task 1.1 — Project scaffold
|
||||
|
||||
**Phase:** 1 — Slice 1 schema + deploy pipeline
|
||||
**Status:** ⬜ Not started
|
||||
**Status:** 🟩 Done
|
||||
**Depends on:** None
|
||||
**Wiki refs:** `docs/wiki/entities/directus.md`, `docs/wiki/synthesis/directus-schema-draft.md`
|
||||
|
||||
@@ -13,7 +13,7 @@ Initialize the `directus/` service folder with the directory layout from the Pha
|
||||
|
||||
- `directus/Dockerfile` — `FROM directus/directus:11.x`, copies `snapshots/`, `db-init/`, `scripts/`, `entrypoint.sh`, `extensions/` into the image. Sets `ENTRYPOINT ["/directus/entrypoint.sh"]`. (Concrete entrypoint contents land in task 1.7; for now create a placeholder that just `exec`s the upstream entrypoint.)
|
||||
- `directus/compose.dev.yaml` — two services:
|
||||
- `db`: `timescale/timescaledb-ha:pg16-latest` (or equivalent), volume-mapped Postgres data dir, healthcheck.
|
||||
- `db`: `timescale/timescaledb-ha:pg16.6-ts2.17.2-all` (the `-all` variant bundles PostGIS binaries; the `:pg16-latest` floating tag does NOT exist on Docker Hub — pin a concrete TS+PG version). Volume-mapped Postgres data dir, healthcheck.
|
||||
- `directus`: built from local `Dockerfile`, depends on `db` healthy, env vars for DB connection + `KEY` + `SECRET` + admin bootstrap, port `8055` exposed.
|
||||
- `directus/package.json` — minimal, only for npm scripts (no runtime deps). Scripts:
|
||||
- `schema:snapshot` — `bash scripts/schema-snapshot.sh` (script body lands in 1.6)
|
||||
@@ -58,4 +58,22 @@ Initialize the `directus/` service folder with the directory layout from the Pha
|
||||
|
||||
## Done
|
||||
|
||||
(Fill in commit SHA + one-line note when this lands.)
|
||||
Pending commit by user. All deliverables created in the same working tree pass.
|
||||
|
||||
**Open question resolutions (corrected against live `pnpm dev` boot 2026-05-01):**
|
||||
|
||||
- **TimescaleDB-HA image tag.** `:pg16-latest` does **not** exist on Docker Hub (the agent's initial pin failed at pull time). The empirically-verified tag is `timescale/timescaledb-ha:pg16.6-ts2.17.2-all`. The `-all` suffix bundles PostGIS binaries.
|
||||
- **PGDATA path.** Not `/pgdata` (the agent's first guess); the actual data directory baked into this image is `/home/postgres/pgdata/data`. `PGDATA: /pgdata` plus a volume mount to `/pgdata` produced "could not change permissions of directory" errors at initdb. Fixed by setting both `PGDATA` and the volume target to `/home/postgres/pgdata/data`.
|
||||
- **PostGIS extension.** Binaries are bundled in the `-all` image but the extension is **not** auto-created on the `directus` database. Directus boot logs warn: `PostGIS isn't installed. Geometry type support will be limited.` Resolution: `CREATE EXTENSION IF NOT EXISTS postgis;` lands in db-init when geometry types are needed (Phase 2). Phase 1 has no geometry columns so the warning is benign.
|
||||
- **Directus version pin**: `directus/directus:11.17.4` confirmed to exist on Docker Hub. Used as the image pin.
|
||||
|
||||
**Deviations from task spec:**
|
||||
|
||||
1. `entrypoint.sh` delegates to `node cli.js bootstrap && pm2-runtime start ecosystem.config.cjs` (the upstream image's actual CMD) rather than `exec /directus/cli.js start`. The upstream image uses pm2-runtime to manage the process; bypassing it would skip crash recovery and signal handling that pm2 provides. The `bootstrap` step is idempotent (safe to run every boot) and handles admin user creation.
|
||||
2. `compose.dev.yaml` sets `PGDATA: /home/postgres/pgdata/data` and mounts the named volume to the same path. Required by the `timescaledb-ha:*-all` image; mounting elsewhere fails initdb.
|
||||
3. `Dockerfile` installs `postgresql16-client` via apk so that `scripts/apply-db-init.sh` (task 1.2) can invoke `psql` without adding that dependency later.
|
||||
4. `README.md` updated: pinned `11.x` → `11.17.4`; CI section notes workflow file is pending (task 1.8).
|
||||
|
||||
**Live boot acceptance (2026-05-01):**
|
||||
|
||||
`pnpm dev` against fresh volumes succeeded: db became healthy, Directus ran 60+ system migrations, PM2 cluster started, server bound at `http://0.0.0.0:8055`, GraphQL Subscriptions and WebSocket Server started. Admin bootstrap (creating first admin role + admin user) completed. One benign warning ("PostGIS isn't installed" — see Open question resolutions above). One harmless migration warning about a non-existent constraint on `directus_comments_collection_foreign` (a Directus internal migration's expected idempotent guard, not caused by this task). All Phase 1 task 1.1 acceptance criteria met.
|
||||
|
||||
@@ -33,7 +33,7 @@ Build a Gitea Actions workflow that on push to `main` (when relevant paths chang
|
||||
runs-on: ubuntu-22.04
|
||||
services:
|
||||
postgres:
|
||||
image: timescale/timescaledb-ha:pg16-latest
|
||||
image: timescale/timescaledb-ha:pg16.6-ts2.17.2-all # match compose.dev.yaml; :pg16-latest does NOT exist on Docker Hub
|
||||
env:
|
||||
POSTGRES_USER: directus
|
||||
POSTGRES_PASSWORD: directus
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
#
|
||||
# TRM directus service image.
|
||||
#
|
||||
# Single-stage build for Phase 1. A multi-stage build (with a Node builder for
|
||||
# extensions) lands in Phase 5 when TypeScript extensions are introduced.
|
||||
#
|
||||
# Artifacts baked into the image at build time:
|
||||
# /directus/snapshots/ — schema.yaml (generated; empty placeholder in Phase 1)
|
||||
# /directus/db-init/ — numbered SQL migration files (Phase 1 task 1.3 fills these)
|
||||
# /directus/scripts/ — shell helpers (Phase 1 tasks 1.2, 1.6 fill these)
|
||||
# /directus/extensions/ — TypeScript extensions (Phase 5)
|
||||
# /directus/entrypoint.sh — boot wrapper (real flow lands in Phase 1 task 1.7)
|
||||
#
|
||||
# No bind mounts of these directories in compose.dev.yaml — the image is the
|
||||
# source of truth. Reproducible across local, CI, and production environments.
|
||||
|
||||
FROM directus/directus:11.17.4
|
||||
|
||||
# Switch to root only for the setup steps; Directus's upstream image already
|
||||
# drops to a non-root user — we preserve that for runtime.
|
||||
USER root
|
||||
|
||||
# Install postgresql-client so scripts/apply-db-init.sh can use psql.
|
||||
# Phase 1 task 1.2 writes the runner; we pre-install the dependency now so
|
||||
# the image build never needs internet access at runtime.
|
||||
RUN apk add --no-cache postgresql16-client
|
||||
|
||||
# ---- Copy baked-in artifacts ----
|
||||
# Each COPY is conditional on the directory existing at build time.
|
||||
# .gitkeep files ensure the directories always exist so COPY never fails.
|
||||
COPY snapshots/ /directus/snapshots/
|
||||
COPY db-init/ /directus/db-init/
|
||||
COPY scripts/ /directus/scripts/
|
||||
COPY extensions/ /directus/extensions/
|
||||
COPY entrypoint.sh /directus/entrypoint.sh
|
||||
|
||||
# Ensure the entrypoint is executable inside the image regardless of the host
|
||||
# filesystem's permission bits.
|
||||
RUN chmod +x /directus/entrypoint.sh
|
||||
|
||||
# Drop back to the non-root user the upstream image uses.
|
||||
USER node
|
||||
|
||||
ENTRYPOINT ["/directus/entrypoint.sh"]
|
||||
@@ -21,7 +21,7 @@ Apply order at boot: **db-init first, then `directus schema apply`, then `direct
|
||||
|
||||
## Quick start (local)
|
||||
|
||||
**Prerequisites:** Docker, the `directus/directus:11.x` image (pulled by compose), a running Postgres 16 + TimescaleDB + PostGIS instance.
|
||||
**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>
|
||||
@@ -86,7 +86,9 @@ All other Directus envs (cache, logging, CORS, etc.) follow upstream defaults un
|
||||
|
||||
## CI behavior
|
||||
|
||||
Gitea Actions workflow is at `.gitea/workflows/build.yml`.
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
# Local development compose — builds the Directus image from this repo's source
|
||||
# tree and runs it alongside a TimescaleDB container.
|
||||
#
|
||||
# Use this file to verify Dockerfile changes, db-init migrations, and snapshot
|
||||
# apply behaviour locally before pushing. For day-to-day admin UI work you can
|
||||
# run `docker compose -f compose.dev.yaml up --build` and hit localhost:8055.
|
||||
#
|
||||
# For STAGE and PRODUCTION deployment, use the multi-service compose in the
|
||||
# sibling `deploy/` repo (https://git.dev.microservices.al/trm/deploy), which
|
||||
# references this service by its registry image tag instead of building locally.
|
||||
#
|
||||
# Usage:
|
||||
# docker compose -f compose.dev.yaml up --build
|
||||
# docker compose -f compose.dev.yaml down # preserves volumes
|
||||
# docker compose -f compose.dev.yaml down -v # wipes volumes (clean slate)
|
||||
#
|
||||
# See also: pnpm dev | pnpm dev:down | pnpm dev:reset
|
||||
|
||||
name: directus-dev
|
||||
|
||||
services:
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# db — PostgreSQL 16 + TimescaleDB + PostGIS (via timescaledb-ha)
|
||||
#
|
||||
# The "-all" suffix variant bundles all extensions (TimescaleDB, PostGIS,
|
||||
# postgis_raster, etc.). Note: the binaries are present in the image, but
|
||||
# extensions still need `CREATE EXTENSION` on each database that uses them
|
||||
# — that's what db-init/*.sql does (Phase 1 task 1.3 + Phase 2).
|
||||
#
|
||||
# Pin a specific TS+PG version (not :pg16-latest, which doesn't exist on
|
||||
# Docker Hub). Bump the pin explicitly when upgrading.
|
||||
#
|
||||
# PGDATA: this image initialises Postgres at /home/postgres/pgdata/data,
|
||||
# not the upstream-standard /var/lib/postgresql/data and not /pgdata.
|
||||
# The volume mount must match exactly or initdb fails with permission errors.
|
||||
# ---------------------------------------------------------------------------
|
||||
db:
|
||||
image: timescale/timescaledb-ha:pg16.6-ts2.17.2-all
|
||||
environment:
|
||||
POSTGRES_USER: ${DB_USER:-directus}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD:-directus}
|
||||
POSTGRES_DB: ${DB_DATABASE:-directus}
|
||||
PGDATA: /home/postgres/pgdata/data
|
||||
volumes:
|
||||
- directus-pg-data:/home/postgres/pgdata/data
|
||||
expose:
|
||||
- '5432'
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
# pg_isready reads PGUSER / PGDATABASE from env; compose sets those from
|
||||
# the environment block above, so no hard-coding is needed here.
|
||||
test: ['CMD-SHELL', 'pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB']
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
start_period: 30s
|
||||
retries: 5
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# directus — built from local Dockerfile
|
||||
#
|
||||
# All env vars are read from .env (copy .env.example → .env to get started).
|
||||
# The service waits for db to pass its healthcheck before starting.
|
||||
# ---------------------------------------------------------------------------
|
||||
directus:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- '8055:8055'
|
||||
environment:
|
||||
# Database connection
|
||||
DB_CLIENT: ${DB_CLIENT:-pg}
|
||||
DB_HOST: db
|
||||
DB_PORT: ${DB_PORT:-5432}
|
||||
DB_DATABASE: ${DB_DATABASE:-directus}
|
||||
DB_USER: ${DB_USER:-directus}
|
||||
DB_PASSWORD: ${DB_PASSWORD:-directus}
|
||||
|
||||
# Instance security — REQUIRED; set non-placeholder values in .env
|
||||
KEY: ${KEY}
|
||||
SECRET: ${SECRET}
|
||||
|
||||
# Admin bootstrap — only applied on first init when the users table is empty
|
||||
ADMIN_EMAIL: ${ADMIN_EMAIL}
|
||||
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
|
||||
|
||||
# Public URL used in emails and OAuth redirects
|
||||
PUBLIC_URL: ${PUBLIC_URL:-http://localhost:8055}
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||
LOG_STYLE: ${LOG_STYLE:-pretty}
|
||||
|
||||
# Optional: cache, CORS, WebSockets (inherit from .env if set)
|
||||
CACHE_ENABLED: ${CACHE_ENABLED:-false}
|
||||
CORS_ENABLED: ${CORS_ENABLED:-false}
|
||||
CORS_ORIGIN: ${CORS_ORIGIN:-false}
|
||||
WEBSOCKETS_ENABLED: ${WEBSOCKETS_ENABLED:-true}
|
||||
|
||||
volumes:
|
||||
# Persist Directus file uploads across container restarts.
|
||||
# No uploads use-case in Phase 1, but the volume is cheap to declare now.
|
||||
- directus-uploads:/directus/uploads
|
||||
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'wget -qO- http://localhost:8055/server/health || exit 1']
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
start_period: 60s
|
||||
retries: 3
|
||||
|
||||
volumes:
|
||||
# Named volume so `down` preserves data and `down -v` wipes it.
|
||||
directus-pg-data:
|
||||
directus-uploads:
|
||||
@@ -0,0 +1,6 @@
|
||||
# Numbered SQL migration files land here in Phase 1 task 1.3:
|
||||
# 001_extensions.sql — CREATE EXTENSION timescaledb
|
||||
# 002_positions_hypertable.sql
|
||||
# 003_faulty_column.sql
|
||||
# PostGIS extension (Phase 2) will be added as 004_postgis.sql.
|
||||
# Files are applied in numeric order by scripts/apply-db-init.sh.
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
# TRM directus — image entrypoint (placeholder).
|
||||
#
|
||||
# Real flow (db-init runner → directus schema apply --yes → directus start)
|
||||
# lands in Phase 1 task 1.7. Until then, this script replicates the upstream
|
||||
# Directus image CMD so the container boots normally during tasks 1.4 and 1.5
|
||||
# (admin UI schema work).
|
||||
#
|
||||
# Upstream CMD (from directus/directus:11.17.4 Dockerfile):
|
||||
# node cli.js bootstrap && pm2-runtime start ecosystem.config.cjs
|
||||
#
|
||||
# bootstrap: idempotent — initialises the DB schema on first run, reads
|
||||
# ADMIN_EMAIL / ADMIN_PASSWORD to create the initial admin user.
|
||||
# pm2-runtime: starts the Directus process under PM2 so the container stays
|
||||
# alive and restarts on crash without an outer supervisor.
|
||||
#
|
||||
# Exit codes are propagated: any non-zero exit causes the container to exit
|
||||
# with that code, which compose reports as an error.
|
||||
|
||||
set -e
|
||||
|
||||
node /directus/cli.js bootstrap
|
||||
|
||||
exec pm2-runtime start /directus/ecosystem.config.cjs
|
||||
@@ -0,0 +1,3 @@
|
||||
# TypeScript extensions (hooks, endpoints, operations) land here in Phase 5.
|
||||
# Each extension is a subdirectory with its own package.json and dist/ build output.
|
||||
# The Dockerfile COPYs this directory into /directus/extensions/ inside the image.
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "directus",
|
||||
"version": "0.1.0",
|
||||
"description": "TRM business-plane: Directus 11 instance owning the relational schema, APIs, and admin UI",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=22",
|
||||
"pnpm": ">=9"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "docker compose -f compose.dev.yaml up --build",
|
||||
"dev:down": "docker compose -f compose.dev.yaml down",
|
||||
"dev:reset": "docker compose -f compose.dev.yaml down -v && docker compose -f compose.dev.yaml up --build",
|
||||
"schema:snapshot": "bash scripts/schema-snapshot.sh",
|
||||
"schema:apply": "bash scripts/schema-apply.sh",
|
||||
"db:init": "bash scripts/apply-db-init.sh"
|
||||
}
|
||||
}
|
||||
Generated
+9
@@ -0,0 +1,9 @@
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.: {}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Shell scripts land here across Phase 1:
|
||||
# apply-db-init.sh — numeric-order, guard-table-protected runner (task 1.2)
|
||||
# schema-snapshot.sh — wraps `directus schema snapshot --yes` (task 1.6)
|
||||
# schema-apply.sh — wraps `directus schema apply --yes` (task 1.6)
|
||||
@@ -0,0 +1,2 @@
|
||||
# schema.yaml is generated here by `pnpm run schema:snapshot` (Phase 1 task 1.6).
|
||||
# Do not hand-edit schema.yaml — always round-trip through the Directus admin UI.
|
||||
Reference in New Issue
Block a user