Skip to content

Multi-Tenant Orgs, Fine-Grained RBAC & Audit Logging #16

Description

@hoangsonww

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

  1. 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.
  2. 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).
  3. Audit Logging

    • Append-only events for CRUD & auth actions with actor, resource, before/after snapshot hashes.
    • Queryable with filters (date, actor, org, resource).
  4. 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

  • Every core entity has orgId, and all CRUD is tenant-scoped by default.
  • RBAC resolver returns correct decision for at least 12 representative scenarios (unit tests).
  • Per-resource ACL can grant a TA grade on a single course without update rights.
  • Audit entries created for CREATE/UPDATE/DELETE + auth events (login/logout), viewable via API/UI.
  • Org switcher affects data scope across the app; unauthorized access returns 403.
  • Performance: permission check p95 < 5ms (cached), audit write p95 < 15ms.
  • Documentation updated (README, ARCHITECTURE.md, API docs).

Rollout Plan

  1. Phase 0: Hidden behind FEATURE_MULTI_TENANT=false flag.
  2. Phase 1: Enable for internal test orgs; migrate seed data with default org.
  3. 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

  • Schema updates & backfill scripts.
  • DRF middleware, permission classes, helpers, tests.
  • Redis caching for policy resolution.
  • New endpoints (orgs, members, ACL, audit) + Swagger updates.
  • Angular: Org switcher, Admin pages, guards/directives.
  • Observability: counters for allow/deny, audit write failures.
  • Docs & runbooks.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdocumentationImprovements or additions to documentationenhancementNew feature or requestgood first issueGood for newcomershelp wantedExtra attention is neededquestionFurther information is requested

Projects

Status
Backlog

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions