feat(backend): Phase 4a PR1 — user status/roles + admin approval queue #4
Reference in New Issue
Block a user
Delete Branch "feat/burgund-backend"
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?
Summary
users.status(pending|active|suspended with CHECK),users.approved_at, and ausers.roleCHECK constraint covering all 6 planned roles. Existing rows default tostatus='active'.user/roles.go— single source of truth for the string values used across Go code.Status,ApprovedAtfields; allRETURNING/Scanclauses updated.RequireAuth + RequireRole("admin"):GET /api/v1/admin/users/pending— list users awaiting approvalPOST /api/v1/admin/users/:id/approve— set active, revoke all sessionsPOST /api/v1/admin/users/:id/reject— set suspended, revoke all sessionsuser_rolein Valkey doesn't outlive the decision.SessionRevokerinterface defined in the user package to avoid an import cycle with the auth package (auth.Repositorysatisfies it at the wiring layer).auth.Service.Loginnow returns"account suspended"before creating a session.Depends on
PRs #2 and #3 (Phase 2 + 3 web changes) should merge before this lands, though there are no code conflicts — this branch only touches
backend/.Test plan
go test ./...passes (all 27 test files green)go build ./...succeedsatlas migrate apply(orgolang-migrate up)POST /api/v1/admin/users/:id/approvewith a non-admin token returns 403POST /api/v1/admin/users/:id/approvewith no token returns 401SELECT revoked_at FROM sessions WHERE user_id = :id)- Migration 000034: add users.status (pending|active|suspended) with CHECK, users.approved_at, and users.role CHECK constraint covering all 6 planned roles (gast, user, veranstalter, haendler, lager, admin). Existing rows default to status='active' to preserve behaviour. - Role and status constants in user/roles.go (single source of truth). - User model extended with Status and ApprovedAt; all repository RETURNING/Scan clauses updated accordingly. - Repository interface extended with ListByStatus and SetStatus. - Admin approval queue: GET /admin/users/pending, POST /admin/users/:id/approve, POST /admin/users/:id/reject. Guarded by RequireAuth + RequireRole("admin"). Approve/reject revokes all target user sessions before updating status (session cache carries stale role data; revocation forces re-login). - SessionRevoker interface defined in user package to avoid import cycle with auth package. auth.Repository satisfies it at the wiring layer. - Login now gates suspended accounts (returns "account suspended" error so new sessions cannot be created after rejection). - Security tests (Iron Law): failing PoC tests written for all three admin endpoints verifying 401 for unauthenticated, 403 for non-admin, and correct status transitions + session revocation for admin.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.