# Changelog ## Unreleased ### Roles and permissions system Replaced the single moderator promote/demote toggle with a full role hierarchy and a runtime-editable, granular permission system. - **Role hierarchy**: SuperAdmin (env-only) > Admin > Moderator > Writer > Guest (absence of a role). SuperAdmin always holds every permission and can never be edited, demoted, or removed through the UI. - **New env var `SUPERADMIN_PUBKEYS`** (comma-separated hex or npub) replaces the old env-admin concept. Falls back to `ADMIN_PUBKEYS` when unset so existing deployments keep working. - **Permission registry**: a central list of granular keys in `backend/src/constants/permissions.ts` is the single source of truth. Adding a key there surfaces it automatically in the API and the Roles matrix page. - **Authorization**: a single `requires(permission)` guard replaces the old role-name middleware and is applied to every protected endpoint. Roles and permissions are resolved live per request, so a stale JWT no longer drives access. SuperAdmin bypasses all checks. - **Data model**: `User.role` is now nullable (null means Guest) and uses the lowercase enum `admin`, `moderator`, `writer`. A new `RolePermission` table maps roles to permission keys. A migration backfills legacy uppercase roles and seeds default permission sets; it is idempotent and safe on a live database. - **New endpoints**: `GET /api/auth/me`, `GET /api/admin/permissions`, `GET /api/admin/roles`, `PUT /api/admin/roles/:role/permissions`, and `PUT /api/users/:pubkey/role` (replacing `POST /api/users/promote` and `POST /api/users/demote`). - **Dashboard**: User Management now uses a per-user role selector with hierarchy enforcement and a locked SuperAdmin badge. A new SuperAdmin-only Roles page renders a permission-by-role matrix. Nav items are gated on resolved permissions. The NIP-05 reserved-username assignment is unchanged. #### Migration notes After pulling, from `backend` run `npm run migrate:deploy` (or, for databases created with `db push`, `npm run db:baseline-and-migrate`). Set `SUPERADMIN_PUBKEYS` in your `.env`. Existing moderators become `moderator`, existing database admins become `admin`, and prior env admins become SuperAdmin.