diff --git a/deploy/docker/postgres-init.sql b/deploy/docker/postgres-init.sql new file mode 100644 index 00000000..6bfc53fb --- /dev/null +++ b/deploy/docker/postgres-init.sql @@ -0,0 +1,41 @@ +-- Dev-stack seed: pre-create the `admin` user row without the `user:` prefix. +-- +-- Why: the UI login controller stores the local admin as `user_id='user:admin'` +-- (JWT `sub` format), but the alerting + outbound controllers resolve the FK +-- via `authentication.name` with the `user:` prefix stripped, i.e. `admin`. +-- In k8s these controllers happily insert `admin` because production admins are +-- provisioned through the admin API with unprefixed user_ids. In the local +-- docker stack there's no such provisioning step, so the FK check fails with +-- "alert_rules_created_by_fkey violation" on the first rule create. +-- +-- Seeding a row with `user_id='admin'` here bridges the gap so E2E smokes, +-- API probes, and manual dev sessions can create alerting rows straight away. +-- Flyway owns the schema in tenant_default; this script only INSERTs idempotently +-- and is gated on the schema existing. + +DO $$ +DECLARE + schema_exists bool; + table_exists bool; +BEGIN + SELECT EXISTS( + SELECT 1 FROM information_schema.schemata WHERE schema_name = 'tenant_default' + ) INTO schema_exists; + IF NOT schema_exists THEN + RAISE NOTICE 'tenant_default schema not yet migrated — skipping admin seed (Flyway will run on server start)'; + RETURN; + END IF; + + SELECT EXISTS( + SELECT 1 FROM information_schema.tables + WHERE table_schema = 'tenant_default' AND table_name = 'users' + ) INTO table_exists; + IF NOT table_exists THEN + RAISE NOTICE 'tenant_default.users not yet migrated — skipping admin seed'; + RETURN; + END IF; + + INSERT INTO tenant_default.users (user_id, provider, email, display_name) + VALUES ('admin', 'local', '', 'admin') + ON CONFLICT (user_id) DO NOTHING; +END $$; diff --git a/docker-compose.yml b/docker-compose.yml index 2b4420da..6f4ff657 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -130,6 +130,25 @@ services: retries: 10 restart: unless-stopped + # Run-once seeder: waits for the server to be healthy (i.e. Flyway migrations + # finished) and inserts a `user_id='admin'` row (without the `user:` prefix) + # so alerting-controller FKs succeed. See deploy/docker/postgres-init.sql for + # the full rationale. Idempotent — exits 0 if the row already exists. + cameleer-seed: + image: postgres:16 + container_name: cameleer-seed + depends_on: + cameleer-server: + condition: service_healthy + environment: + PGPASSWORD: cameleer_dev + volumes: + - ./deploy/docker/postgres-init.sql:/seed.sql:ro + entrypoint: ["sh", "-c"] + command: + - "psql -h cameleer-postgres -U cameleer -d cameleer -v ON_ERROR_STOP=1 -f /seed.sql" + restart: "no" + volumes: cameleer-pgdata: cameleer-chdata: