hoangsonww / hoangsonww/Learning-Management-System-Fullstack
Multi-Tenant Orgs, Fine-Grained RBAC & Audit Logging
- Dominant language
- HCL
- Stars
- 39
- Forks
- 24
- PR merge metrics
- No merged PRs in 30d
Description
# 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`:
```json
{
"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.
Contributor guide
Assessment
This issue has not been assessed yet.