Design a fast, reliable permission system that supports role-based rules with per-course granularity, so users never feel lag when the app decides what they can do. Examples: Teaching Assistants can grade only their assigned courses; Course Managers can edit content but not student grades. After OIDC sign-in, load the user’s full permission list from Postgres and cache it in Redis under user:{id} (store as a Set). A lightweight Django middleware should authorize each API request by checking Redis set membership; on a cache miss, fetch from Postgres, rebuild the cache, and proceed. The cache TTL must match the OIDC access token lifetime. When an admin updates roles or permissions, immediately invalidate and refresh the affected user’s cache.

Admin APIs
- POST /v1/admin/users/{userId}/permissions (assign)
- DELETE /v1/admin/users/{userId}/permissions (revoke)
- GET /v1/admin/users/{userId}/permissions (list)
Access control: OIDC bearer token, Admin only.