Adds a `role` field (admin|member) to user management:
Schema:
- `role TEXT NOT NULL DEFAULT 'member'` added to users table in both
PostgreSQL V14 migration and libSQL schema/incremental migration
- UserRecord gains `role: String` field
- UserIdentity gains `role: String` field, populated from DB in
DbAuthenticator and defaulting to "admin" for single-user mode
Access control:
- AdminUser extractor: returns 403 Forbidden if role != "admin"
- /api/admin/users/* handlers: require AdminUser (create, list,
detail, update, suspend, activate)
- POST /api/invitations: requires AdminUser (only admins can invite)
- User creation accepts optional "role" param (defaults to "member")
- Invitation acceptance creates users with "member" role
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
GATEWAY_USER_TOKENS never went to production — replaced entirely by
DB-backed user management via /api/admin/users and /api/tokens.
Removed:
- UserTokenConfig struct and GATEWAY_USER_TOKENS env var parsing
- user_tokens field from GatewayConfig
- GatewayChannel::new_multi_auth() constructor
- Env-var user migration block in main.rs (~90 lines)
- multi_tenant auto-detection from GATEWAY_USER_TOKENS (now runtime
via db.has_any_users() in app.rs)
Review fixes (zmanian):
- User ID generation: UUID instead of display-name derivation (#1)
- Invitation accept moved to public router (no auth needed) (#3)
- libSQL get_invitation_by_hash aligned with postgres: filters
status='pending' AND expires_at > now (#4)
- UUID parse: returns DatabaseError::Serialization instead of
unwrap_or_default (#7)
- PostgreSQL SELECT * replaced with explicit column lists (#8)
- Sort order aligned (both backends use DESC) (#6)
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Completes the DB-backed user management feature (#1605):
- Startup migration: when GATEWAY_USER_TOKENS is set and the users
table is empty, inserts env-var users + hashed tokens into DB.
Logs deprecation notice when DB already has users.
- hash_token made pub for reuse in migration code.
- 10 integration tests for UserStore (libsql file-backed):
- has_any_users bootstrap detection
- create/get/get_by_email/list/update user lifecycle
- token create → authenticate → revoke → reject cycle
- suspended user tokens rejected
- wrong-user token revoke returns false
- invitation create → accept → user created
- record_login and record_token_usage timestamps
- libSQL migration: removed FK constraints from V14 (incompatible
with execute_batch inside transactions). Tables in both base SCHEMA
and incremental migration for fresh and existing databases.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Foundation for DB-backed user management (#1605):
- UserRecord, ApiTokenRecord, InvitationRecord types in db/mod.rs
- UserStore sub-trait (17 methods) added to Database supertrait
- PostgreSQL migration V14__users.sql (users, api_tokens, invitations)
- libSQL schema + incremental migration V14
- Full implementations for both PgBackend (via Store delegation) and
LibSqlBackend (direct SQL in libsql/users.rs)
- authenticate_token JOINs api_tokens+users with active/non-revoked
checks; has_any_users for bootstrap detection
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>