PH0.1 — Compose base: db, LDAP, Keycloak realm, nginx, OSRM #3

Closed
opened 2026-09-11 09:02:07 +00:00 by bart · 2 comments
Collaborator

Parent

Row PH0.1 in docs/12-implementation-plan.md (branch, owned paths and doc section are defined there).

What to build

A fresh clone runs docker compose up and gets PostgreSQL+PostGIS, OpenLDAP with five users in five groups (admin, planner, technician, viewer, ingest), a Keycloak realm federated to that LDAP (group → realm role, locale mapper, no realm-local users), nginx, and an OSRM service behind a profile. The api/worker/web services are declared but behind --profile app until PH0.2/PH0.5 land.

Acceptance criteria

  • docker compose up from a fresh clone brings db, openldap, keycloak and nginx to healthy
  • Logging in to Keycloak as each of the five LDAP users yields exactly the realm role of that user's LDAP group
  • polaris and keycloak databases exist with PostGIS enabled
  • Clients polaris-web (PKCE), polaris-api (bearer) and fleetpulse (client-credentials) exist in the realm
  • OSRM and pgadmin/phpldapadmin only start with their profiles; .env.example and root README document the startup

Blocked by

  • None (can start immediately)
## Parent Row **PH0.1** in `docs/12-implementation-plan.md` (branch, owned paths and doc section are defined there). ## What to build A fresh clone runs `docker compose up` and gets PostgreSQL+PostGIS, OpenLDAP with five users in five groups (admin, planner, technician, viewer, ingest), a Keycloak realm federated to that LDAP (group → realm role, locale mapper, no realm-local users), nginx, and an OSRM service behind a profile. The api/worker/web services are declared but behind `--profile app` until PH0.2/PH0.5 land. ## Acceptance criteria - [x] `docker compose up` from a fresh clone brings db, openldap, keycloak and nginx to healthy - [x] Logging in to Keycloak as each of the five LDAP users yields exactly the realm role of that user's LDAP group - [x] `polaris` and `keycloak` databases exist with PostGIS enabled - [x] Clients `polaris-web` (PKCE), `polaris-api` (bearer) and `fleetpulse` (client-credentials) exist in the realm - [x] OSRM and pgadmin/phpldapadmin only start with their profiles; `.env.example` and root README document the startup ## Blocked by - None (can start immediately)
Owner

🚧 Started — session working this on branch feature/infra-compose-base (owns: infra/**, root README.md, .env.example), in an isolated worktree off main. Will tick acceptance criteria live as they are met and open a PR (Closes #3) when done.

🚧 Started — session working this on branch `feature/infra-compose-base` (owns: infra/**, root README.md, .env.example), in an isolated worktree off `main`. Will tick acceptance criteria live as they are met and open a PR (`Closes #3`) when done.
patrick self-assigned this 2026-09-11 09:45:08 +00:00
Owner

Implemented in #49 (feature/infra-compose-base). All acceptance criteria verified live (fresh docker compose up, down -v, and re-run from scratch — not just docker compose config): db/openldap/keycloak/nginx reach healthy automatically; a full LDAP sync imports all 5 users with 0 failures and each logs in with exactly their own realm role (checked by decoding the issued JWT, aud includes polaris-api); polaris/keycloak databases exist with postgis/postgis_topology enabled; polaris-web/polaris-api/fleetpulse clients all present with the right auth types; osrm/pgadmin/phpldapadmin/api/worker/web stay off without their profile flag.

Two things the ticket didn't foresee, both documented inline where they matter:

  1. LDAP bootstrap can't use osixia's own custom-ldif mechanism as a straight bind mount. That image chowns then deletes each file under bootstrap/ldif/custom/ after importing it — fatal ("Device or resource busy") against a single bind-mounted file, and if you instead bind-mount the directory it silently deletes the real repo file from the host. Went with a one-shot ldap-init compose service that runs ldapadd -c against the running directory instead (idempotent: a second run just logs "already exists" per entry and still exits 0). Commented in docker-compose.yml.

  2. docs/07-architecture.md's ${env.VAR} placeholders for the LDAP bind DN/password aren't something Keycloak's realm importer or plain LDIF actually resolve — that's envsubst-style templating neither format supports natively, and wiring up an entrypoint wrapper to do it felt like scope creep for M0. Went with fixed, clearly-commented dev-only credentials baked into bootstrap.ldif / realm-polaris.json instead (documented in infra/compose/.env.example and root README.md — same password for all five bootstrap users, fixed LDAP bind password, fixed fleetpulse client secret). Rotating these for anything beyond a local compose stack is a small follow-up, not blocking M0.

Also touched the root .gitignore (one line, infra/osrm/data/) since prepare.sh writes multi-GB extract/dataset files there and no infra/**-scoped ignore exists yet.

Implemented in #49 (`feature/infra-compose-base`). All acceptance criteria verified live (fresh `docker compose up`, `down -v`, and re-run from scratch — not just `docker compose config`): db/openldap/keycloak/nginx reach healthy automatically; a full LDAP sync imports all 5 users with 0 failures and each logs in with exactly their own realm role (checked by decoding the issued JWT, `aud` includes `polaris-api`); `polaris`/`keycloak` databases exist with `postgis`/`postgis_topology` enabled; `polaris-web`/`polaris-api`/`fleetpulse` clients all present with the right auth types; `osrm`/`pgadmin`/`phpldapadmin`/`api`/`worker`/`web` stay off without their profile flag. Two things the ticket didn't foresee, both documented inline where they matter: 1. **LDAP bootstrap can't use osixia's own custom-ldif mechanism as a straight bind mount.** That image chowns then deletes each file under `bootstrap/ldif/custom/` after importing it — fatal ("Device or resource busy") against a single bind-mounted file, and if you instead bind-mount the *directory* it silently deletes the real repo file from the host. Went with a one-shot `ldap-init` compose service that runs `ldapadd -c` against the running directory instead (idempotent: a second run just logs "already exists" per entry and still exits 0). Commented in `docker-compose.yml`. 2. **`docs/07-architecture.md`'s `${env.VAR}` placeholders for the LDAP bind DN/password aren't something Keycloak's realm importer or plain LDIF actually resolve** — that's envsubst-style templating neither format supports natively, and wiring up an entrypoint wrapper to do it felt like scope creep for M0. Went with fixed, clearly-commented **dev-only** credentials baked into `bootstrap.ldif` / `realm-polaris.json` instead (documented in `infra/compose/.env.example` and root `README.md` — same password for all five bootstrap users, fixed LDAP bind password, fixed `fleetpulse` client secret). Rotating these for anything beyond a local compose stack is a small follow-up, not blocking M0. Also touched the root `.gitignore` (one line, `infra/osrm/data/`) since `prepare.sh` writes multi-GB extract/dataset files there and no `infra/**`-scoped ignore exists yet.
patrick stopped working 2026-09-11 10:03:10 +00:00
15 seconds
patrick deleted spent time 2026-09-11 10:03:27 +00:00
-
patrick deleted spent time 2026-09-11 10:03:27 +00:00
- 15 seconds
Sign in to join this conversation.
No labels
ready-for-agent
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
patrick/Polaris#3
No description provided.