Feature: Multi-Tenant Orgs, Fine-Grained RBAC & Audit Logging
Summary
Add native multi-tenancy (organizations, sub-orgs/programs), role-based access control with fine-grained permissions (resource-level & action-level), and a tamper-evident audit log across LMS entities. This enables schools/companies to isolate data, delegate administration, and meet compliance needs.
Motivation
- Current model assumes a single global tenant; enterprise users need org isolation and delegated admin.
- Instructors need scoped capabilities (course owner vs. grader vs. TA).
- Compliance (FERPA/GDPR/ISO) requires who did what, when, to which resource.
Goals
-
Organizations & Scoping
- Users belong to one or more Organizations (and optional SubOrgs/Departments).
- All core entities (Course, Lesson, Quiz, Enrollment, Progress, Notification) are tenant-scoped.
-
RBAC
- System roles:
platform_admin, org_admin, instructor, grader, ta, student, viewer.
- Resource permissions:
read, create, update, delete, grade, publish, enroll_manage.
- Policy resolution: role → permissions + optional per-resource overrides (ACLs).
-
Audit Logging
- Append-only events for CRUD & auth actions with actor, resource, before/after snapshot hashes.
- Queryable with filters (date, actor, org, resource).
-
Admin UX
- Angular admin screens for Org management, Role assignment, and Audit log views.
Non-Goals
- SSO/SCIM (can be a follow-up).
- Full ABAC with attribute policies (keep RBAC + simple ACL for now).
Proposed Design
Data Model (MongoDB)
Collections (new or extended):
-
organizations: { _id, name, slug, parentOrgId?, createdAt }
-
user_org_memberships: { userId, orgId, roles: [string], createdAt }
-
acl_overrides: { resourceType, resourceId, orgId, subjectType: 'user'|'role', subjectId, permissions: [string] }
-
Extend each resource with orgId (and optional subOrgId).
-
audit_events:
{
"ts": "2025-10-16T12:00:00Z",
"actorId": "user...",
"orgId": "org...",
"action": "COURSE_UPDATE",
"resource": {"type": "course", "id": "..." },
"beforeHash": "sha256:...",
"afterHash": "sha256:...",
"meta": {"ip":"...", "ua":"...", "reason":"..."}
}
Backend (Django + DRF)
-
Middleware
OrgContextMiddleware: resolves active orgId from JWT claim, header (X-Org-Id), or membership default; validates access.
AuditMiddleware: captures request/response, calculates content hashes, emits audit_events.
-
Permission Classes
IsOrgMember, HasRole(role), HasPermission(resource, action), HasAclOverride.
-
Decorators/Helpers
@tenant_scoped(model_field="orgId") to auto-filter queries.
check_perm(user, orgId, resource, action) resolver with cache.
-
Endpoints (new)
POST /api/orgs (platform_admin)
GET /api/orgs/:id/members | POST /api/orgs/:id/members assign roles
GET /api/audit?orgId=&actor=&resourceType=&from=&to=
POST /api/acl create/update per-resource overrides
-
Caching
- Redis cache for
user→org→roles/permissions (TTL 5–15 min) with bust on membership/ACL change.
Frontend (Angular)
-
Org Switcher in header for users with multiple orgs.
-
Admin → Organizations: CRUD, member list, role assignment.
-
Admin → Roles & Permissions: read-only matrix view (initially, roles fixed in code/config).
-
Admin → Audit Log: filterable table with export (CSV/JSON).
-
Guards & Directives:
canPerm="course.update" directive to conditionally render actions (publish, edit, grade).
- Route guards enforcing tenant scope.
Security & Compliance
- All queries must include
orgId filters (enforced via decorator/mixins).
- Audit entries are append-only; use hash chaining (
prevHash) for tamper evidence (optional Phase 2).
- PII minimization in audit payload; store diffs as hashes, not raw content where possible.
Acceptance Criteria
Rollout Plan
- Phase 0: Hidden behind
FEATURE_MULTI_TENANT=false flag.
- Phase 1: Enable for internal test orgs; migrate seed data with default org.
- Phase 2: Enable ACL UI + Audit Log UI for all admins.
Migration Notes
- Backfill script to set a default
orgId on existing docs.
- Create a default Organization and assign all users.
- Re-index collections on
(orgId, ...) compound keys for common queries.
Tasks
Feature: Multi-Tenant Orgs, Fine-Grained RBAC & Audit Logging
Summary
Add native multi-tenancy (organizations, sub-orgs/programs), role-based access control with fine-grained permissions (resource-level & action-level), and a tamper-evident audit log across LMS entities. This enables schools/companies to isolate data, delegate administration, and meet compliance needs.
Motivation
Goals
Organizations & Scoping
RBAC
platform_admin,org_admin,instructor,grader,ta,student,viewer.read,create,update,delete,grade,publish,enroll_manage.Audit Logging
Admin UX
Non-Goals
Proposed Design
Data Model (MongoDB)
Collections (new or extended):
organizations:{ _id, name, slug, parentOrgId?, createdAt }user_org_memberships:{ userId, orgId, roles: [string], createdAt }acl_overrides:{ resourceType, resourceId, orgId, subjectType: 'user'|'role', subjectId, permissions: [string] }Extend each resource with
orgId(and optionalsubOrgId).audit_events:{ "ts": "2025-10-16T12:00:00Z", "actorId": "user...", "orgId": "org...", "action": "COURSE_UPDATE", "resource": {"type": "course", "id": "..." }, "beforeHash": "sha256:...", "afterHash": "sha256:...", "meta": {"ip":"...", "ua":"...", "reason":"..."} }Backend (Django + DRF)
Middleware
OrgContextMiddleware: resolves activeorgIdfrom JWT claim, header (X-Org-Id), or membership default; validates access.AuditMiddleware: captures request/response, calculates content hashes, emitsaudit_events.Permission Classes
IsOrgMember,HasRole(role),HasPermission(resource, action),HasAclOverride.Decorators/Helpers
@tenant_scoped(model_field="orgId")to auto-filter queries.check_perm(user, orgId, resource, action)resolver with cache.Endpoints (new)
POST /api/orgs(platform_admin)GET /api/orgs/:id/members|POST /api/orgs/:id/membersassign rolesGET /api/audit?orgId=&actor=&resourceType=&from=&to=POST /api/aclcreate/update per-resource overridesCaching
user→org→roles/permissions(TTL 5–15 min) with bust on membership/ACL change.Frontend (Angular)
Org Switcher in header for users with multiple orgs.
Admin → Organizations: CRUD, member list, role assignment.
Admin → Roles & Permissions: read-only matrix view (initially, roles fixed in code/config).
Admin → Audit Log: filterable table with export (CSV/JSON).
Guards & Directives:
canPerm="course.update"directive to conditionally render actions (publish, edit, grade).Security & Compliance
orgIdfilters (enforced via decorator/mixins).prevHash) for tamper evidence (optional Phase 2).Acceptance Criteria
orgId, and all CRUD is tenant-scoped by default.gradeon a single course withoutupdaterights.Rollout Plan
FEATURE_MULTI_TENANT=falseflag.Migration Notes
orgIdon existing docs.(orgId, ...)compound keys for common queries.Tasks