feat(infra): compose base with LDAP, Keycloak and OSRM profiles #49
No reviewers
Labels
No labels
in-progress
in-review
ready-for-agent
seam-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
patrick/Polaris!49
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/infra-compose-base"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
PH0.1 — Compose base: db, LDAP, Keycloak realm, nginx, OSRM
docker compose -f infra/compose/docker-compose.yml up(no profiles) bringsdb(Postgres 17 + PostGIS),openldap,keycloakandnginxto healthy.api/worker/webstay behind--profile appuntil PH0.2/PH0.5 land their Dockerfiles;osrmbehind--profile osrm;pgadmin/phpldapadminbehind--profile tools.Everything below was verified live in this session (fresh
docker compose up,down -v, and re-run from scratch), not justconfig-validated.What's in this PR
infra/compose/docker-compose.yml+docker-compose.dev.yml— services, profiles, healthchecks.infra/db/init/01-databases.sql— creates thekeycloakdatabase, enablespostgis/postgis_topologyonpolaris.infra/ldap/bootstrap.ldif— basedc=polaris,dc=local,ou=people/ou=groups, fivegroupOfNames(admin/planner/technician/viewer/ingest) each with one matchinginetOrgPerson. Applied by a one-shotldap-initservice runningldapaddagainst the live directory, not osixia's own custom-ldif bootstrap mechanism — that mechanism deletes each imported ldif file after success, which is fatal ("Device or resource busy") against a bind-mounted file, or silently deletes the repo file if the mount targets a bind-mounted directory instead. Documented inline in the compose file.infra/keycloak/realm-polaris.json— realm roles matching the LDAP groups; clientspolaris-web(PKCE, plus an audience mapper injectingpolaris-apiand alocaleprotocol mapper),polaris-api(bearer-only),fleetpulse(client-credentials, roleingestvia its service-account user — the only "user" entry in the file, not a human). LDAP User Federation withrole-ldap-mapper(groupcn→ realm role,LDAP_ONLY) and username/first-name/last-name/email attribute mappers. No realm-local human users.infra/nginx/default.conf+ a standalonenginxgateway service — single browser origin,/api→api,/→web, upstream hostnames resolved lazily via Docker's embedded DNS so the gateway stays healthy whileapi/webaren't running yet.infra/osrm/prepare.sh— Geofabrik NL extract →osrm-extract/-partition/-customize(MLD) intoinfra/osrm/data(git-ignored).infra/compose/.env.example, rootREADME.md— startup sequence, profiles table, default dev logins.Verified end-to-end (fresh
docker compose up, no manual steps)db,openldap,keycloak,nginxall reachhealthyautomatically (~30s from a colddocker compose up).admin/planner/technician/viewer/ingestlogs in and receives exactly their own realm role in the access token (decoded JWTrealm_access.roles), withaudcorrectly includingpolaris-api.polarisandkeycloakdatabases exist;postgis3.5.2 andpostgis_topologyenabled onpolaris.polaris-web(public, PKCE),polaris-api(bearer-only),fleetpulse(confidential,serviceAccountsEnabled) all present in the realm.osrm,pgadmin,phpldapadmin,api,worker,weball stay off by default and only appear with their profile flag (checked viadocker compose config/pswith each profile combination).docker compose -f infra/compose/docker-compose.yml config(and with--profile app --profile osrm --profile tools, and withdocker-compose.dev.ymllayered) all validate cleanly.Notable deviations from the ticket's sketch (see issue comment)
docs/07-architecture.mdsketches LDAP bind/user credentials as${env.VAR}placeholders resolved by envsubst. LDAP has no env-substitution of its own and Keycloak's realm importer has none either, so this PR instead bakes fixed, clearly-documented dev-only credentials intobootstrap.ldif/realm-polaris.json(same password for all five bootstrap users, fixed LDAP bind password, fixedfleetpulseclient secret) and documents them ininfra/compose/.env.exampleand rootREADME.md. Rotating these for anything beyond a local compose stack is a follow-up.Also adds
infra/osrm/data/to the root.gitignore(the only touch outsideinfra/**/README.md/.env.example) sinceprepare.sh's output is multi-GB and noinfra/**-scoped ignore file exists yet.Closes #3
🤖 Generated with Claude Code
https://claude.ai/code/session_01LoNrSy7Reyp7evkfcdHeLX