## Description of the implemented changes The changes were: - [ ] Bugfixing - [x] New Feature - [ ] Breaking Change - [x] Refactoring **Seeds run only on first startup.** On every application start (e.g. `just run`, Docker entrypoint), seed scripts are still invoked, but they exit immediately when the admin user already exists. This avoids duplicate seed data (e.g. join requests), keeps startup fast after the first run, and works the same in dev and production. ## What has been changed? - **`lib/mv/release.ex`** - Added `bootstrap_seeds_applied?/0`: returns whether the admin user (from `ADMIN_EMAIL` or default `admin@localhost`) exists. We check the admin *user*, not the Admin *role*, so we do not skip when only migrations have run (migrations can create the Admin role for the system actor). - `run_seeds/0`: if `bootstrap_seeds_applied?()` is true, prints “Seeds already applied (admin user exists). Skipping.” and returns without running bootstrap or dev seeds; otherwise unchanged behaviour. - Module docs updated for the new function and the skip behaviour. - **`priv/repo/seeds.exs`** - Ensures the app is started (`Application.ensure_all_started(:mv)`). - If `Mv.Release.bootstrap_seeds_applied?()` is true, prints the same skip message and does not run bootstrap or dev seeds; otherwise runs as before (bootstrap + dev seeds in dev/test). - Comment at the top updated to describe the skip behaviour. - **Documentation** - `CODE_GUIDELINES.md` §1.2.1: seeds run on every start but exit early when already applied; mentions `bootstrap_seeds_applied?/0`. - `docs/admin-bootstrap-and-oidc-role-sync.md`: run_seeds skips when admin user exists; description of `run_seeds/0` updated. - `CHANGELOG.md` [Unreleased]: new “Seeds run only when needed” entry under Changed. ## Definition of Done ### Code Quality - [x] No new technical depths - [x] Linting passed - [x] Documentation is added where needed ### Accessibility - [x] New elements are properly defined with html-tags *(no new UI)* - [x] Colour contrast follows WCAG criteria *(no new UI)* - [x] Aria labels are added when needed *(no new UI)* - [x] Everything is accessible by keyboard *(no new UI)* - [x] Tab-Order is comprehensible *(no new UI)* - [x] All interactive elements have a visible focus *(no new UI)* ### Testing - [x] Tests for new code are written *(existing seeds and release tests cover behaviour; idempotency test still passes when second run skips)* - [x] All tests pass - [x] axe-core dev tools show no critical or major issues *(no UI changes)* ## Additional Notes - **Review focus:** Logic in `Mv.Release` and `priv/repo/seeds.exs`; the “already applied” check is a single DB read for the admin user. On failure (e.g. DB down), `bootstrap_seeds_applied?/0` returns `false`, so seeds run (safe for first deploy). - **Suggested check:** Run `mix test test/seeds_test.exs test/mv/release_test.exs` to confirm seeds and release behaviour. Reviewed-on: #475 Co-authored-by: Simon <s.thiessen@local-it.org> Co-committed-by: Simon <s.thiessen@local-it.org>
62 lines
3.8 KiB
Markdown
62 lines
3.8 KiB
Markdown
# Admin Bootstrap and OIDC Role Sync
|
||
|
||
## Overview
|
||
|
||
- **Admin bootstrap:** In production, the Docker entrypoint runs migrate, then `Mv.Release.run_seeds/0` (skips if admin user already exists unless `FORCE_SEEDS=true`; set `RUN_DEV_SEEDS=true` to also run dev seeds), then `seed_admin/0` from ENV, then the server. Password can be changed without redeploy via `bin/mv eval "Mv.Release.seed_admin()"`.
|
||
- **OIDC role sync:** Optional mapping from OIDC groups (e.g. from Authentik profile scope) to the Admin role. Users in the configured admin group get the Admin role on registration and on each sign-in.
|
||
|
||
## Admin Bootstrap (Part A)
|
||
|
||
### Environment Variables
|
||
|
||
- `RUN_DEV_SEEDS` – If set to `"true"`, `run_seeds/0` also runs dev seeds (members, groups, sample data). Otherwise only bootstrap seeds run.
|
||
- `FORCE_SEEDS` – If set to `"true"`, seeds are run even when the admin user already exists (e.g. after changing bootstrap data such as roles or custom fields). Otherwise seeds are skipped when bootstrap was already applied.
|
||
- `ADMIN_EMAIL` – Email of the admin user to create/update. If unset, seed_admin/0 does nothing.
|
||
- `ADMIN_PASSWORD` – Password for the admin user. If unset (and no file), no new user is created; if a user with ADMIN_EMAIL already exists (e.g. OIDC-only), their role is set to Admin (no password change).
|
||
- `ADMIN_PASSWORD_FILE` – Path to a file containing the password (e.g. Docker secret).
|
||
|
||
### Release Tasks
|
||
|
||
- `Mv.Release.run_seeds/0` – If the admin user already exists (bootstrap already applied), skips unless `FORCE_SEEDS=true`; otherwise runs bootstrap seeds (fee types, custom fields, roles, settings). If `RUN_DEV_SEEDS` env is `"true"`, also runs dev seeds (members, groups, sample data). Safe to call on every start.
|
||
- `Mv.Release.seed_admin/0` – Reads ADMIN_EMAIL and password from ADMIN_PASSWORD or ADMIN_PASSWORD_FILE. If both email and password are set: creates or updates the user with the Admin role. If only ADMIN_EMAIL is set: sets the Admin role on an existing user with that email (for OIDC-only admins); does not create a user. Idempotent.
|
||
|
||
### Entrypoint
|
||
|
||
- rel/overlays/bin/docker-entrypoint.sh – After migrate, runs run_seeds(), then seed_admin(), then starts the server.
|
||
|
||
### Seeds (Dev/Test)
|
||
|
||
- priv/repo/seeds.exs – Uses ADMIN_PASSWORD or ADMIN_PASSWORD_FILE when set; otherwise fallback "testpassword" only in dev/test.
|
||
|
||
## OIDC Role Sync (Part B)
|
||
|
||
### Configuration
|
||
|
||
- `OIDC_ADMIN_GROUP_NAME` – OIDC group name that maps to the Admin role. If unset, no role sync.
|
||
- `OIDC_GROUPS_CLAIM` – JWT claim name for group list (default "groups").
|
||
- Module: Mv.OidcRoleSyncConfig (oidc_admin_group_name/0, oidc_groups_claim/0).
|
||
|
||
### Sign-in page (OIDC-only mode)
|
||
|
||
- `OIDC_ONLY` (or Settings → OIDC → "Only OIDC sign-in") – When set to true/1/yes and OIDC is configured, the sign-in page shows only the Single Sign-On button (password login is hidden). ENV takes precedence over Settings.
|
||
- **Redirect loop fix:** After an OIDC failure (e.g. provider down), the app redirects to `/sign-in?oidc_failed=1`. The plug `OidcOnlySignInRedirect` does not redirect that request back to OIDC, so the sign-in page is shown with the error (no endless redirect).
|
||
|
||
### Sync Logic
|
||
|
||
- Mv.OidcRoleSync.apply_admin_role_from_user_info(user, user_info) – If admin group configured, sets user role to Admin or Mitglied based on user_info groups.
|
||
|
||
### Where It Runs
|
||
|
||
1. Registration: register_with_oidc after_action calls OidcRoleSync.
|
||
2. Sign-in: sign_in_with_oidc prepare after_action calls OidcRoleSync for each user.
|
||
|
||
### Internal Action
|
||
|
||
- User.set_role_from_oidc_sync – Internal update (role_id only). Used by OidcRoleSync; not exposed.
|
||
|
||
## See Also
|
||
|
||
- .env.example – Admin and OIDC group env vars.
|
||
- lib/mv/release.ex – seed_admin/0.
|
||
- lib/mv/oidc_role_sync.ex – Sync implementation.
|
||
- docs/oidc-account-linking.md – OIDC account linking.
|