diff --git a/backend/app/api/routes/users.py b/backend/app/api/routes/users.py
index a5d080a..7ad3d8a 100644
--- a/backend/app/api/routes/users.py
+++ b/backend/app/api/routes/users.py
@@ -19,9 +19,17 @@ def get_users(
return db.query(User).all()
+@router.get("/users/students")
+def get_student_users(
+ db: Session = Depends(get_db),
+ current_user: User = Depends(require_roles("admin", "teacher")),
+):
+ return db.query(User).filter(User.role == "student").all()
+
+
@router.get("/users/{user_id}")
def get_user_by_id(
- user_id: str,
+ user_id: uuid.UUID,
db: Session = Depends(get_db),
current_user: User = Depends(require_roles("admin")),
):
@@ -31,17 +39,9 @@ def get_user_by_id(
return user
-@router.get("/users/students")
-def get_student_users(
- db: Session = Depends(get_db),
- current_user: User = Depends(require_roles("admin", "teacher")),
-):
- return db.query(User).filter(User.role == "student").all()
-
-
@router.put("/users/{user_id}")
def update_user(
- user_id: str,
+ user_id: uuid.UUID,
user: UserDto,
db: Session = Depends(get_db),
current_user: User = Depends(require_roles("admin")),
diff --git a/backend/tests/test_admin_users.py b/backend/tests/test_admin_users.py
new file mode 100644
index 0000000..b5b6da6
--- /dev/null
+++ b/backend/tests/test_admin_users.py
@@ -0,0 +1,88 @@
+import uuid
+
+from fastapi.testclient import TestClient
+
+from app.auth import get_current_user
+from app.database import get_db
+from app.main import app
+from app.models import User
+
+
+def _user(role: str, prefix: str) -> User:
+ suffix = uuid.uuid4().hex[:8]
+ return User(
+ id=uuid.uuid4(),
+ firstname=prefix.title(),
+ lastname="User",
+ username=f"{prefix}_{suffix}",
+ email=f"{prefix}_{suffix}@example.test",
+ hashed_password="unchanged-password-hash",
+ role=role,
+ )
+
+
+def _client(db_session, current_user: User) -> TestClient:
+ app.dependency_overrides[get_db] = lambda: db_session
+ app.dependency_overrides[get_current_user] = lambda: current_user
+ return TestClient(app)
+
+
+def test_admin_can_fetch_user_detail_by_uuid_on_sqlite(db_session):
+ admin = _user("admin", "admin")
+ student = _user("student", "student")
+ db_session.add_all([admin, student])
+ db_session.commit()
+
+ client = _client(db_session, admin)
+ try:
+ response = client.get(f"/api/users/{student.id}")
+ finally:
+ app.dependency_overrides.clear()
+
+ assert response.status_code == 200
+ assert response.json()["id"] == str(student.id)
+ assert response.json()["role"] == "student"
+
+
+def test_admin_can_update_user_role_by_uuid_without_changing_password(db_session):
+ admin = _user("admin", "admin")
+ student = _user("student", "student")
+ db_session.add_all([admin, student])
+ db_session.commit()
+
+ client = _client(db_session, admin)
+ try:
+ response = client.put(
+ f"/api/users/{student.id}",
+ json={
+ "firstname": student.firstname,
+ "lastname": student.lastname,
+ "username": student.username,
+ "email": student.email,
+ "password": "",
+ "role": "teacher",
+ },
+ )
+ finally:
+ app.dependency_overrides.clear()
+
+ db_session.refresh(student)
+ assert response.status_code == 200
+ assert student.role == "teacher"
+ assert student.hashed_password == "unchanged-password-hash"
+
+
+def test_static_student_list_route_is_not_shadowed_by_user_detail(db_session):
+ teacher = _user("teacher", "teacher")
+ student = _user("student", "student")
+ db_session.add_all([teacher, student])
+ db_session.commit()
+
+ client = _client(db_session, teacher)
+ try:
+ response = client.get("/api/users/students")
+ finally:
+ app.dependency_overrides.clear()
+
+ assert response.status_code == 200
+ assert [item["id"] for item in response.json()] == [str(student.id)]
diff --git a/docs/ux-overhaul/admin-accessibility-review.md b/docs/ux-overhaul/admin-accessibility-review.md
new file mode 100644
index 0000000..c5549bc
--- /dev/null
+++ b/docs/ux-overhaul/admin-accessibility-review.md
@@ -0,0 +1,22 @@
+# Admin Accessibility Review
+
+Date: 2026-07-13
+
+## Implemented Checks
+
+- One named page `h1`, logical section headings, semantic `main`, tables, captions, headers, definition lists, forms, labels, and buttons.
+- Desktop semantic tables have equivalent mobile records with the same identity, status, and primary action.
+- Search/filter result counts and asynchronous states use live status semantics through shared components.
+- Status always includes text; no meaning relies on color.
+- Controls have 44px minimum height, visible tokenized focus rings, and no hover-only actions.
+- Shared confirmation dialog traps focus, supports Escape, restores focus, names the object and consequence, and exposes action errors.
+- Badge images use meaningful alt text; missing images have a named alternative.
+- Form validation associates visible labels and `aria-invalid`; badge form errors are announced.
+- Long names, usernames, and email addresses wrap in detail definitions.
+- Existing shell skip link, mobile drawer focus behavior, and reduced-motion foundation remain unchanged.
+
+## Validation
+
+Karma coverage exercises state semantics, privacy omission, confirmation gating, navigation, deep-link roles, and image naming. Seeded Playwright covers primary Admin navigation, filtering, dialog cancel, unauthorized deep link, and 390px overflow when services are available.
+
+Manual screen-reader and browser zoom execution remains open with seeded browser infrastructure. Sorting and pagination are not present because current APIs return unpaged lists and this phase does not invent server behavior.
diff --git a/docs/ux-overhaul/admin-action-risk-matrix.md b/docs/ux-overhaul/admin-action-risk-matrix.md
new file mode 100644
index 0000000..ac909d8
--- /dev/null
+++ b/docs/ux-overhaul/admin-action-risk-matrix.md
@@ -0,0 +1,14 @@
+# Admin Action Risk Matrix
+
+Date: 2026-07-13
+
+| Action | Classification | Object / backend behavior | Reversible | Confirmation / permission | Recovery and audit gap |
+| --- | --- | --- | --- | --- | --- |
+| Review user/course/org/badge/report | Informational | GET only | N/A | Guarded route and backend auth | Retryable partial/error states. |
+| Create badge | Consequential | Creates badge and optional uploaded image | No delete API | Valid form; `admin` | Failure leaves UI unchanged; uploaded orphan cleanup not supported. |
+| Change platform role | Privilege-changing | Rewrites full user DTO including role | Yes by another update | Names user and access impact; `admin`; self-change disabled | Failure retains old role; no audit/final-admin enforcement. |
+| Delete user | Destructive | Deletes user plus authored posts/threads, badge awards, and unit links | No | Names user, scope, unaffected objects, irreversibility; `admin`; self-delete disabled in UI | Failure retains record; no restore/audit/final-admin protection. |
+| Delete course | Destructive | Deletes course record | No | Names course, learner-access impact, no archive/restore; `admin` | Failure retains record; no restore/audit. |
+| Switch organization | Consequential | Reissues token with active organization | Yes | Existing shell interaction | Existing session recovery. Not redesigned here. |
+
+Unsupported disable/restore, invitation resend, organization archive/delete, badge edit/delete, moderation, and platform-setting actions are absent.
diff --git a/docs/ux-overhaul/admin-badge-data-contract.md b/docs/ux-overhaul/admin-badge-data-contract.md
new file mode 100644
index 0000000..8915552
--- /dev/null
+++ b/docs/ux-overhaul/admin-badge-data-contract.md
@@ -0,0 +1,20 @@
+# Admin Badge Data Contract
+
+Date: 2026-07-13
+
+| Field/capability | Verified contract | Admin UI behavior |
+| --- | --- | --- |
+| ID | UUID | Used only for API identity; not displayed. |
+| Name | `title`, required | Displayed and searchable. |
+| Description | Optional text | Displayed; missing value is stated. |
+| Image | Optional `image_url` | Named image alt text; explicit missing-image alternative. |
+| Earning criteria | No field/API | Not invented or editable. |
+| Course/program relation | No badge relation in response | Not shown. Certifications may reference a badge separately. |
+| Active/inactive | No field/API | Not shown. |
+| Create | `POST /api/badges`, `admin` | Supported with validation and success/error states. |
+| Upload | `POST /api/upload/badge`, `admin` | Optional image upload during creation. |
+| Edit | No endpoint | Read-only unavailable. |
+| Delete/archive | No endpoint | No control or confirmation shown. |
+| Assignment | `POST /api/students/{student_id}/badges/{badge_id}`, `admin` | Verified but not added to broad badge administration because no scoped learner-selection workflow was approved. |
+
+Badge reads require authentication but are not admin-only. `super_admin` therefore receives a read-only catalog; it receives no create/upload control.
diff --git a/docs/ux-overhaul/admin-moderation-capability-map.md b/docs/ux-overhaul/admin-moderation-capability-map.md
new file mode 100644
index 0000000..304b5f8
--- /dev/null
+++ b/docs/ux-overhaul/admin-moderation-capability-map.md
@@ -0,0 +1,13 @@
+# Admin Moderation Capability Map
+
+Date: 2026-07-13
+
+| Content type | Read API | Action API | Authorization | Reversible/auditable | Admin decision |
+| --- | --- | --- | --- | --- | --- |
+| Threads | `GET /api/threads*` | Create/update/delete | None | Delete is irreversible; no audit | Not exposed. APIs have no auth, scope, ownership, flag, lock, hide, restore, or moderator contract. |
+| Posts | `GET /api/posts*` | Create/update/delete | None | Delete is irreversible; no audit | Not exposed for the same reason. |
+| Course discussions | No scoped moderation API | None | None verified | No | Not exposed. |
+| Uploaded content | No asset-list API | Upload only | Role-specific upload checks | No delete/audit | No moderation or asset-library UI. Badge upload remains inside badge creation. |
+| Flags/reports | No API | None | None | No | No queue, counts, or controls. |
+
+No `/admin/moderation` route is introduced. A platform queue built from unscoped thread/post CRUD would imply authorization, reports, and consequences that do not exist.
diff --git a/docs/ux-overhaul/admin-privacy-review.md b/docs/ux-overhaul/admin-privacy-review.md
new file mode 100644
index 0000000..32715f2
--- /dev/null
+++ b/docs/ux-overhaul/admin-privacy-review.md
@@ -0,0 +1,18 @@
+# Admin Privacy Review
+
+Date: 2026-07-13
+
+## High-Risk Surfaces And Mitigations
+
+| Surface | Risk | Production mitigation |
+| --- | --- | --- |
+| User directory | Broad disclosure of contact/security data | Shows display name, role, and creation date only. Email and username appear only after opening one protected record. Raw ID is not visible. |
+| Backend user serialization | ORM response may include hashed password/internal fields | Typed frontend projection never renders unknown fields. Dedicated backend response schema remains a gap. |
+| User detail | Mixing platform identity with learner progress | Shows identity and platform role only; no learner progress, demographics, tokens, password data, or global activity. |
+| Organizations | Cross-organization disclosure | Uses membership-scoped `/api/orgs`; neutral unavailable state for unknown deep links; does not infer members/admins/classes/invites. |
+| Courses | Learner and author identity exposure | Shows curriculum/governance metadata, not learner progress or teacher assignment data. Creator/organization UUIDs are not displayed. |
+| Reporting | Misleading or identifying analytics | Uses aggregate documented counts only; no learner/organization ranking or individual activity. |
+| Errors | Sensitive payload leakage | User-facing messages are neutral and do not echo backend payloads or identifiers. |
+| Destructive operations | Hidden scope | Confirmations state known cascades and unaffected organizations/courses. |
+
+Backend authorization remains authoritative for every API call and `RoleGuard` protects deep links after session bootstrap. The frontend does not log administrative payloads. Organization and learner contexts remain separate.
diff --git a/docs/ux-overhaul/admin-production-audit.md b/docs/ux-overhaul/admin-production-audit.md
new file mode 100644
index 0000000..c3de0d7
--- /dev/null
+++ b/docs/ux-overhaul/admin-production-audit.md
@@ -0,0 +1,48 @@
+# Platform Admin Production Audit
+
+Date: 2026-07-13
+
+## Authorization Summary
+
+The platform role stored on `User.role` is the backend authority. `require_roles()` performs exact string matching and does not implement inheritance. Organization roles are separate `OrganizationMembership.role` values. Frontend permissions and hidden navigation are presentation only.
+
+`admin` is the only role authorized for the current user directory, user updates/deletion, Admin overview analytics, course list/detail/write operations, badge creation/assignment, and badge image upload. `super_admin` is not an alias for `admin`: it can bypass organization-name update membership checks and can read unscoped V2 analytics, but it is rejected by the core Admin endpoints above. The current shell previously displayed an Admin area for both roles while legacy Admin routes allowed only `admin`.
+
+## Route And Screen Audit
+
+| Current route or surface | User goal | Authorized role from backend | APIs | Sensitivity | Current actions | Backend enforcement | UX, accessibility, and responsive risks | Recommendation / owner |
+| --- | --- | --- | --- | --- | --- | --- | --- | --- |
+| `/home` Admin dashboard | Assess platform state | `admin`; `super_admin` cannot call its core APIs | `GET /api/analytics/overview`, `/api/users`, `/api/courses`, course governance endpoints | Platform user counts; learner recommendations | Read summaries; legacy page also deletes users/courses | Exact role checks for lists; governance allows staff roles | 546-line dashboard mixes operational oversight, learner intervention data, and destructive actions; partial failures are difficult to distinguish; dense mobile layout | Canonical `/admin`; Admin. Keep `/home` as a legacy landing until dynamic compatibility routing is retired. |
+| `/home/admin/users` | Review and manage accounts | `admin` | `GET /api/users`, `DELETE /api/users/{id}` | Names, email, username, role, created date; API also serializes hashed password unless excluded by ORM serialization | Immediate delete | Exact `admin` check; delete cascades posts, threads, badges, unit links and user | No loading/error/empty state, no confirmation, no search/filter, raw role text, table overflows mobile | Canonical `/admin/users`; Admin. Minimize visible fields and require exact destructive confirmation. |
+| No user-detail route | Inspect one account and change role | `admin` | `GET/PUT /api/users/{id}` | Identity, email, role | Full DTO update; role change possible | Exact `admin` check; no role allowlist, final-admin protection, or self-lockout protection | Missing UI; PUT requires complete identity DTO and optional empty password convention | Add `/admin/users/:userId`; Admin. Allow verified role changes except self-change; confirm privilege changes; document backend gaps. |
+| `/workspace/learners/users` | Duplicate user list | `admin` | Same as user list | Same | Same | Same | Duplicate namespace suggests organization ownership | Keep as compatibility route; canonical `/admin/users`; Admin. |
+| `/home/admin/courses` | Oversee courses | `admin` for list/write | `GET/DELETE /api/courses`, course governance endpoints | Curriculum metadata and learner-facing availability | Legacy create/edit/delete | Exact `admin`/`teacher` on core course CRUD | “Product” language, authoring controls mixed into Admin, immediate delete, no states, table overflows | Canonical `/admin/courses`; Admin oversight only. Link to detail oversight; keep authoring out of Admin. |
+| `/workspace/products/manage` | Duplicate course management | `admin` | Same as course list | Same | Same | Same | Duplicates Admin and Studio concepts | Compatibility alias only; canonical `/admin/courses`; Admin. |
+| `/home/admin/badges` | Create and inspect badges | Read: any authenticated user; create/upload/assign: `admin` | `GET/POST /api/badges`, `POST /api/upload/badge`, assignment endpoint | Public recognition metadata and images | Create and upload | Explicit `admin` checks on writes | Missing load/error/empty/submission states; inaccessible image; file restrictions not explained; no edit/delete API exists | Canonical `/admin/badges`; Admin. Create supported; existing badges read-only. |
+| `/workspace/settings/badges` | Duplicate badge management | Route says `admin` | Same as badge list | Same | Same | Same | Wrong settings ownership | Compatibility alias only; canonical `/admin/badges`; Admin. |
+| `/workspace/analytics` | Review workspace/content analytics | Several staff roles including `super_admin` | V2 analytics endpoints | Organization/workspace aggregate operational data | Read only | Exact role list plus workspace scoping; admins/super admins unscoped | Content/Studio reporting is not the same as platform Admin reporting | Keep in Studio. Add `/admin/reports` using only `/analytics/overview` for `admin`; no cross-link for `super_admin` unless definitions match. |
+| `/workspace/commercial` | Community project surface | Creator roles | V2/community APIs | Community operational data | Varies | Creator-role route checks | Not moderation and not Admin oversight | Community owner; remove from Admin navigation. Preserve route. |
+| `/workspace/settings` | Preferences/settings | Creator roles | Preferences APIs | User preferences | Edit preferences | Existing auth | Exposed as “Platform settings” without a platform-settings API | Keep as user/Studio settings; omit from Admin navigation. |
+| `/workspace/review-center` | Content review | Creator roles | V2 review APIs | Content review state | Content workflow actions | Creator-role checks | Belongs to Studio; not platform moderation | Studio owner; do not migrate. |
+| `/workspace/access` | Product access grants | Creator roles | V2 access-grant APIs | Learner access | Grant/revoke | V2 role and workspace checks | Organization/content access, not platform account access | Organization/Studio owner; do not migrate. |
+| Organization selector/header | See organizations for current account | Any authenticated user | `GET /api/orgs` | Organization identity, current membership role | Switch active organization; create organization elsewhere | List is restricted to current user's memberships; PATCH allows member content/org admin or platform `super_admin` | Cannot provide platform-wide oversight, counts, members, admins, sections, or invitations | Add `/admin/organizations` as explicitly scoped read-only membership visibility. Detail is limited to returned organization metadata. Admin owner for visibility; self-service remains Organization. |
+| Threads/posts routes | Discuss or mutate community content | No authentication dependency | CRUD `/api/threads`, `/api/posts` | User-generated content and author identifiers | Create/update/delete | No authentication, scope, ownership, moderation role, report, restore, lock, or audit behavior | Unsafe for platform moderation; deletion irreversible and unscoped | No Admin route. Document as backend security/moderation gap; Community future change. |
+| Upload routes | Upload lesson assets | Badge upload: `admin`; coloring/storybook: `admin` or `teacher` | `/api/upload/*` | Uploaded files | Create file | Exact role checks | No asset list, metadata, delete, ownership, or moderation APIs | Badge upload stays inside badge creation. No Admin asset library. |
+
+## Destructive Behavior
+
+- User deletion permanently removes the user plus authored posts/threads, student badges, and unit links. The endpoint has no self-delete protection, final-admin protection, audit record, dry run, or restore.
+- Course deletion permanently deletes the course through the current CRUD endpoint and has no archive/restore contract.
+- Badge deletion, badge edit, organization archive/delete, account disable/restore, invitation resend, role removal, membership management, and platform settings are not supported by verified APIs.
+
+## Route Migration Decision
+
+The canonical family is `/admin`, `/admin/users`, `/admin/users/:userId`, `/admin/organizations`, `/admin/organizations/:organizationId`, `/admin/courses`, `/admin/courses/:courseId`, `/admin/badges`, and `/admin/reports`. Moderation and platform settings routes are omitted. Legacy routes remain guarded aliases; no broad deletion is part of this phase.
+
+## Primary Risks And Mitigations
+
+- **Authorization mismatch:** exact backend role checks remain authoritative; `super_admin` receives only the supported overview limitation state and organization visibility.
+- **Privacy:** broad user lists show name, role, and created date only. Email and username are confined to an individual detail view. Password hashes, tokens, and raw identifiers are never rendered.
+- **Responsive tables:** lists switch from semantic desktop tables to equivalent mobile records without hiding primary actions.
+- **High-impact actions:** shared confirmation names the object, consequence, scope, and irreversibility; UI updates only after API success.
+- **Partial failures:** each overview source reports independently so one failed request does not make successful counts appear absent.
diff --git a/docs/ux-overhaul/admin-production-implementation.md b/docs/ux-overhaul/admin-production-implementation.md
new file mode 100644
index 0000000..aac58dc
--- /dev/null
+++ b/docs/ux-overhaul/admin-production-implementation.md
@@ -0,0 +1,45 @@
+# Platform Admin Production Implementation
+
+Date: 2026-07-13
+
+## Delivered
+
+- Canonical guarded routes under `/admin` for overview, users/detail, organizations/detail, courses/detail, badges, and reports.
+- Role-accurate navigation and canonical Admin login destination.
+- Partial-failure Admin overview with supported user, role, organization-membership, course, badge, and analytics counts.
+- Privacy-minimized responsive user directory; individual identity/role detail; confirmed role changes; self-role/self-delete prevention; confirmed permanent deletion.
+- Explicitly scoped, read-only organization visibility using only current-account memberships.
+- Course oversight and governance summary separated from Content Studio; no authoring controls; confirmed destructive deletion.
+- Badge creation/upload for `admin`, read-only catalog for compatible `super_admin`, accessible image naming, and explicit unsupported lifecycle behavior.
+- Defined platform report over `/api/analytics/overview`.
+- Shared loading, empty, error, permission, success, and confirmation patterns across new pages.
+- Seeded Admin Playwright smoke and guarded student deep-link scenario.
+
+## Components Created
+
+`AdminOverviewComponent`, `AdminUserDetailComponent`, `AdminOrganizationsComponent`, and `AdminReportsComponent`; shared Admin production layout styles in `frontend/src/styles/_admin-production.scss`.
+
+## Components Migrated
+
+`AdminUsersComponent`, `AdminCoursesComponent`, `AdminBadgesComponent`, role selector, route configuration, shell navigation, and permission navigation mapping.
+
+## APIs Used
+
+`GET /api/users`, `GET/PUT/DELETE /api/users/{id}`, `GET /api/orgs`, `GET /api/courses`, `GET /api/courses/{id}`, `GET /api/courses/{id}/governance-summary`, `DELETE /api/courses/{id}`, `GET/POST /api/badges`, `POST /api/upload/badge`, and `GET /api/analytics/overview`.
+
+## Not Implemented
+
+Moderation, platform settings, platform-wide organization directory/membership oversight, organization lifecycle actions, badge edit/delete/archive, account disable/restore, invitation actions, audit logs, asset library, and unsupported `super_admin` inheritance.
+
+## Backend Repair
+
+The existing user detail and update route parameters now use `uuid.UUID`, preventing UUID-column binding failures. The existing static `/api/users/students` route is registered before `/api/users/{user_id}` so it is no longer shadowed. No schema, migration, new endpoint, seed behavior, or JWT behavior changed.
+
+## Verification
+
+- Frontend unit tests: `245 SUCCESS` (baseline was 233).
+- Backend unit tests: `224 passed`, including new UUID detail/update and static student-route regressions.
+- Production build: passes; existing Sass mixed-declaration deprecation warnings remain.
+- Playwright discovery: 3 tests in 2 files, including 2 Admin scenarios.
+- Seeded browser execution: executed serially against a disposable, model-created SQLite database because Docker/PostgreSQL were unavailable. The Admin oversight, unauthorized Admin deep-link, and student flagship flows pass. Result: `3 passed`.
+- OpenSpec: `openspec validate overhaul-role-based-ui-ux-experience --strict` passes.
diff --git a/docs/ux-overhaul/admin-reporting-data-contract.md b/docs/ux-overhaul/admin-reporting-data-contract.md
new file mode 100644
index 0000000..a809e5e
--- /dev/null
+++ b/docs/ux-overhaul/admin-reporting-data-contract.md
@@ -0,0 +1,20 @@
+# Admin Reporting Data Contract
+
+Date: 2026-07-13
+
+Source: `GET /api/analytics/overview`, authorized for `admin` only.
+
+| Metric | Definition |
+| --- | --- |
+| Students | Users whose platform role equals `student`. |
+| Teachers | Users whose platform role equals `teacher`; instructors are not included. |
+| Courses | All course records. |
+| Active students | Distinct student IDs with an enrollment record; this is not time-window activity. |
+| Total enrollments | All `StudentCourse` records. |
+| Incomplete enrollments | Total enrollments minus completed enrollment records. The backend field is `pending_enrollments`; UI avoids implying an invitation/approval state. |
+| Lessons completed | Completed `SegmentProgress` records. |
+| Units completed | Completed `StudentUnitProgress` records. |
+| Courses completed | `StudentCourse` records with status `completed`. |
+| Course completion rate | Completed course enrollments divided by total enrollments, rounded by backend. |
+
+The report does not claim trends, active account state, engagement, growth, organization comparison, audit events, or time ranges. Workspace/V2 analytics remain Studio reporting and are not merged into Admin.
diff --git a/docs/ux-overhaul/admin-responsive-review.md b/docs/ux-overhaul/admin-responsive-review.md
new file mode 100644
index 0000000..917470b
--- /dev/null
+++ b/docs/ux-overhaul/admin-responsive-review.md
@@ -0,0 +1,16 @@
+# Admin Responsive Review
+
+Date: 2026-07-13
+
+Target widths: 1440, 1280, 768, and 390 CSS pixels.
+
+- Page width is constrained to the shared 72rem content maximum with responsive page padding.
+- Overview metrics and shortcuts use auto-fit grids; alert/attention content remains first in DOM order.
+- User and course desktop tables switch below 768px to equivalent stacked records. Desktop tables are removed from layout rather than left focusable off-screen.
+- Organization and badge collections use auto-fit grids with a 13rem minimum bounded by container width.
+- Filter fields and commands become full-width at mobile sizes; controls retain 44px touch height.
+- Detail definition grids switch from two columns to one; identifiers use `overflow-wrap`.
+- Dialog responsiveness and focus behavior are supplied by the shared confirmation component.
+- No component uses viewport-scaled font sizes, negative letter spacing, fixed page widths, or pointer-only actions.
+
+Automated build/unit validation passes. Seeded Playwright executes through a disposable SQLite fallback, and the Admin flow completes its 390px horizontal-overflow assertion. The browser smoke suite passes all three scenarios.
diff --git a/docs/ux-overhaul/admin-role-access-contract.md b/docs/ux-overhaul/admin-role-access-contract.md
new file mode 100644
index 0000000..ebccd38
--- /dev/null
+++ b/docs/ux-overhaul/admin-role-access-contract.md
@@ -0,0 +1,31 @@
+# Admin Role And Access Contract
+
+Date: 2026-07-13
+
+## Role Sources
+
+Platform role is `User.role`; organization role is `OrganizationMembership.role`. They are additive in the frontend session but are checked independently by backend dependencies. There is no role inheritance.
+
+| Role | Product status | Platform scope | Assignable in Admin user detail | Backend notes |
+| --- | --- | --- | --- | --- |
+| `student` | Implemented | Learner | Yes | Exact role checks protect learner APIs. |
+| `teacher` | Implemented | Educator | Yes | Course CRUD and educator APIs recognize it. |
+| `admin` | Implemented | Platform | Yes, with confirmation | Only role accepted by core Admin user, summary, and badge-write APIs. |
+| `org_admin` | Implemented | Organization membership | No | Must be managed as organization membership; not through platform role control. |
+| `content_admin` | Implemented | Organization/content membership | No | Studio/content access; not a platform Admin role. |
+| `instructor` | Partial | Educator compatibility | No | Several educator endpoints still omit it. |
+| `parent` | Partial | Unsupported portal | No | No complete navigation/API experience. |
+| `viewer` | Partial | Unsupported portal | No | No complete navigation/API experience. |
+| `super_admin` | Partial | Organization update bypass and V2 analytics | No | Does not inherit `admin`; core Admin APIs reject it. |
+
+## Role Change Contract
+
+- Admin can change another account among `student`, `teacher`, and `admin` through `PUT /api/users/{id}`.
+- The complete safe identity DTO is resubmitted because the endpoint is not role-specific; password is sent as empty so the backend leaves it unchanged.
+- Confirmation names the user and explains platform-area impact. UI state changes only after success.
+- Self-role changes are disabled. The backend has no final-admin or self-lockout protection, so the UI also documents this unresolved enforcement gap.
+- Organization roles and partial roles are not offered. Navigation is re-evaluated on next authenticated session; authenticated self-change is not exposed.
+
+## Known Authorization Gaps
+
+The backend accepts arbitrary `role` strings in `UserDto`, serializes ORM user objects without a dedicated privacy response schema, and does not protect the last administrator. Frontend constraints reduce accidental misuse but are not security boundaries.
diff --git a/docs/ux-overhaul/admin-super-admin-compatibility.md b/docs/ux-overhaul/admin-super-admin-compatibility.md
new file mode 100644
index 0000000..ce123aa
--- /dev/null
+++ b/docs/ux-overhaul/admin-super-admin-compatibility.md
@@ -0,0 +1,17 @@
+# Admin Super-Admin Compatibility
+
+Date: 2026-07-13
+
+`super_admin` is a partial role, not an inherited superset of `admin`.
+
+| Surface | `admin` | `super_admin` | Evidence |
+| --- | --- | --- | --- |
+| Admin shell/overview | Full supported overview | Visible limitation state | Frontend role navigation; core overview API is admin-only. |
+| Users | Read/write/delete | Rejected | `require_roles("admin")`. |
+| Courses | Read/write/delete | Rejected | `require_roles("admin", "teacher", "student")` and explicit write list. |
+| Badges | Read/create/assign/upload | Read only | Badge list requires auth; writes compare role to `admin`. |
+| Organizations | Current memberships only | Current memberships only; PATCH bypass exists | List is membership-scoped for every role; PATCH explicitly bypasses for super admin. |
+| Admin report | Available | Rejected | Overview analytics requires `admin`. |
+| V2 analytics | Unscoped | Unscoped | V2 role list and visibility helper include both. This remains Studio reporting. |
+
+Canonical `/admin` accepts both roles. Users, courses, and reports routes accept only `admin`; organizations and badge catalog accept both. Navigation mirrors these facts. No control is exposed solely because the role is named `super_admin`.
diff --git a/docs/ux-overhaul/backend-gap-register.md b/docs/ux-overhaul/backend-gap-register.md
new file mode 100644
index 0000000..fb8a649
--- /dev/null
+++ b/docs/ux-overhaul/backend-gap-register.md
@@ -0,0 +1,17 @@
+# Backend Gap Register
+
+Date: 2026-07-13
+
+| Role | User need | Current frontend behavior | API limitation | Privacy/security implication | Blocks current workflow | Future OpenSpec change | Priority |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| Teacher/instructor | Scoped learner review | Read-only/scoped UI | No complete class-scoped review/feedback persistence | Avoid global learner disclosure | Yes for persistent feedback | Educator review and feedback contract | High |
+| Teacher/instructor | Moderate class discussion | Hidden | Thread/post APIs have no auth or class scope | Unscoped destructive access | Yes | Authenticated scoped discussion moderation | Critical |
+| Instructor | Use educator analytics consistently | Partial states | Several analytics role lists omit instructor | Role may expose navigation that API rejects | Partial | Instructor authorization alignment | High |
+| Admin | Platform-wide organization oversight | Shows current account memberships only | `/api/orgs` is membership-scoped; no member/admin/section summaries | Inferring or bypassing scope risks cross-org disclosure | Yes for requested oversight | Platform organization directory with explicit permission and minimized response | High |
+| Admin | Safe role management | Limits roles; blocks self-change | Arbitrary role strings; no final-admin/self-lockout check; full DTO update | Privilege escalation and lockout risk | Partial | Role-specific allowlisted mutation with critical-admin invariant | Critical |
+| Admin | Privacy-safe user reads | Typed UI omits sensitive fields; detail deep links work after the UUID route repair | ORM user serialization lacks dedicated minimized summary/detail response schemas | Hashed/internal fields may cross the API boundary even though the UI omits them | No for current UI; yes for API-level minimization | Admin user summary/detail response schemas | High |
+| Admin | Disable/restore account | No controls | No status or mutation API | Invented frontend state would be unenforced | Yes | Account access-state lifecycle | Medium |
+| Admin | Moderation/report queue | No route/control | No authenticated scope, flags, reports, restore, lock, or audit | Unsafe cross-community disclosure and deletion | Yes | Platform safety and moderation capability | Critical |
+| Admin | Audit high-impact actions | Confirmation only | No audit log/event contract | Destructive/privilege changes lack accountability | No, but operational risk | Administrative audit events | High |
+| Admin | Badge lifecycle | Create/read only | No edit/archive/delete/criteria relation | Credential meaning cannot be governed | Partial | Badge lifecycle and criteria contract | Medium |
+| Admin/super admin | Consistent privilege model | Role-accurate limitation state | Exact checks conflict with presumed super-admin inheritance | Name can cause unsafe assumptions | Partial | Explicit platform permission policy replacing name inference | High |
diff --git a/docs/ux-overhaul/production-route-migration.md b/docs/ux-overhaul/production-route-migration.md
index ecd3a79..93453cb 100644
--- a/docs/ux-overhaul/production-route-migration.md
+++ b/docs/ux-overhaul/production-route-migration.md
@@ -1,10 +1,10 @@
# Production Route Migration
-Phase 1 preserves route compatibility and establishes canonical role destinations without deleting deep links. Phase 2 begins the student `/learn` migration while keeping legacy student deep links available. Phase 3 adds canonical teacher `/teach` routes while preserving `/home` and workspace cohort deep links.
+Phase 1 preserves route compatibility and establishes canonical role destinations without deleting deep links. Phase 2 begins the student `/learn` migration while keeping legacy student deep links available. Phase 3 adds canonical teacher `/teach` routes while preserving `/home` and workspace cohort deep links. Phase 4 adds the guarded `/admin` family and retains legacy Admin deep links.
| Current route | Canonical route | Role | Redirect behavior | Guard behavior | Migration phase | Removal criteria | Deep-link risk |
| --- | --- | --- | --- | --- | --- | --- | --- |
-| `/home` | `/teach` for teacher/instructor; `/home` remains admin transitional | teacher, instructor, admin, super_admin-compatible | No redirect | `HomeSessionGuard`; child guards unchanged | Phase 3 teacher alias added | Remove teacher reliance only after `/teach` smoke tests and usage validation | High |
+| `/home` | `/teach` for teacher/instructor; `/admin` for admin/super_admin-compatible | teacher, instructor, admin, super_admin-compatible | No redirect; legacy role dashboard remains | `HomeSessionGuard`; child guards unchanged | Phase 4 Admin canonical landing added | Remove role-dashboard reliance only after compatibility redirect and usage validation | High |
| `/teach` | `/teach` | teacher, instructor | No redirect; role landing now points here | `HomeSessionGuard`; child guards unchanged | Phase 3 | None planned | Low |
| `/teach/classes` | `/teach/classes` | teacher, instructor, org_admin | No redirect | `HomeSessionGuard` plus `RoleGuard` section roles | Phase 3 | None planned | Low |
| `/teach/classes/:id` | `/teach/classes/:id` | teacher, instructor, org_admin | No redirect | `HomeSessionGuard` plus `RoleGuard` section roles; frontend verifies route section is in authorized section list | Phase 3 | None planned | Low |
@@ -22,9 +22,13 @@ Phase 1 preserves route compatibility and establishes canonical role destination
| `/workspace` | `/workspace` | content_admin | No redirect | `HomeSessionGuard` plus existing role guards | Phase 1 | None planned | Medium |
| `/workspace/learners` | `/workspace/learners` | org_admin | No redirect | Existing creator-role guard | Phase 1 | Replace only if organization home becomes a dedicated route | Medium |
| `/workspace/commercial` | `/workspace/commercial` with visible label `Community` | admin/content_admin/org_admin/teacher/instructor via existing creator role set | No redirect | Existing creator-role guard | Phase 1 | Add alias and deprecation only after community surface is redesigned | Medium |
-| `/home/admin/users` | `/home/admin/users` | admin | No redirect | Existing `RoleGuard` admin-only | Phase 1 | Dedicated Admin IA route exists and old path is aliased | High |
-| `/home/admin/courses` | `/home/admin/courses` | admin | No redirect | Existing `RoleGuard` admin-only | Phase 1 | Dedicated Admin IA route exists and old path is aliased | High |
-| `/home/admin/badges` | `/home/admin/badges` | admin | No redirect | Existing `RoleGuard` admin-only | Phase 1 | Dedicated Admin IA route exists and old path is aliased | High |
+| `/home/admin/users` and `/workspace/learners/users` | `/admin/users` | admin | Legacy routes remain; canonical navigation uses `/admin/users` | `HomeSessionGuard` plus `RoleGuard` admin-only | Phase 4 | Add explicit redirects after bookmark/usage validation | Medium |
+| No legacy detail | `/admin/users/:userId` | admin | New route | `HomeSessionGuard` plus `RoleGuard` admin-only; backend exact admin check | Phase 4 | None planned | Low |
+| No platform directory route | `/admin/organizations` and `:organizationId` | admin, super_admin | New scoped read-only routes | `HomeSessionGuard` plus `RoleGuard`; API returns current-account memberships only | Phase 4 | Replace only after platform directory API is approved | Low |
+| `/home/admin/courses` and `/workspace/products/manage` | `/admin/courses` | admin | Legacy routes remain; canonical navigation uses `/admin/courses` | `HomeSessionGuard` plus `RoleGuard` admin-only | Phase 4 | Add explicit redirects after bookmark/usage validation | Medium |
+| No legacy oversight detail | `/admin/courses/:courseId` | admin | New route | `HomeSessionGuard` plus `RoleGuard` admin-only | Phase 4 | None planned | Low |
+| `/home/admin/badges` and `/workspace/settings/badges` | `/admin/badges` | admin; super_admin read-only compatible | Legacy routes remain admin-only; canonical route permits supported read compatibility | `HomeSessionGuard` plus `RoleGuard`; writes remain backend admin-only | Phase 4 | Add explicit redirects after bookmark/usage validation | Medium |
+| `/workspace/analytics` | `/admin/reports` for platform counts; workspace route remains Studio analytics | admin | No redirect because definitions differ | `HomeSessionGuard` plus `RoleGuard` admin-only | Phase 4 | None; keep reporting domains separate | Low |
| `/home/sections` | `/teach/classes` | teacher, instructor, org_admin | No redirect | Existing `RoleGuard` section roles | Phase 3 alias added | Remove only after teacher bookmarks and smoke tests move to `/teach/classes` | High |
| `/home/sections/:id` | `/teach/classes/:id` | teacher, instructor, org_admin | No redirect | Existing `RoleGuard` section roles | Phase 3 alias added | Remove only after class detail deep links have compatibility redirects | High |
| `/home/courses` | `/home/courses` | teacher, instructor, student transitional | No redirect | Existing child route, no added guard | Phase 1 | Course library split is implemented and tested | Medium |
@@ -40,8 +44,8 @@ Phase 1 preserves route compatibility and establishes canonical role destination
- `instructor`: `/teach`
- `content_admin`: `/workspace`
- `org_admin`: `/workspace/learners`
-- `admin`: `/home`
-- `super_admin`: `/home`
+- `admin`: `/admin`
+- `super_admin`: `/admin` with partial compatibility state
## Route Compatibility Notes
@@ -53,3 +57,5 @@ Phase 1 preserves route compatibility and establishes canonical role destination
- No dedicated unit route was added because existing APIs do not expose unit-level student progress or direct-link authorization.
- Phase 3 adds canonical Teach routes without deleting `/home/sections`, `/home/sections/:id`, or `/workspace/learners/cohorts` compatibility routes.
- Teacher course preview intentionally avoids `/api/start-course`; it uses `/api/courses/{id}` only.
+- Phase 4 does not add moderation or platform-settings routes because no safely authorized capability exists.
+- `super_admin` is not treated as inherited `admin`; unsupported child routes stay guarded and hidden.
diff --git a/docs/ux-overhaul/shared-component-status.md b/docs/ux-overhaul/shared-component-status.md
index a7dea39..cd54b90 100644
--- a/docs/ux-overhaul/shared-component-status.md
+++ b/docs/ux-overhaul/shared-component-status.md
@@ -45,11 +45,23 @@
- Global teacher assignment list is still a class-first alias because no global assignment API was verified.
- Teacher feedback panels remain deferred because no feedback persistence endpoint was verified.
+## Added Or Migrated In Admin Phase
+
+| Component/screen | Path | Status | Notes |
+| --- | --- | --- | --- |
+| Admin production layout | `frontend/src/styles/_admin-production.scss` | Production active | Shared Admin page, panel, filter, semantic table/mobile record, status, action, and detail patterns. |
+| Admin overview | `frontend/src/app/pages/admin-overview/` | Production active | Independent partial-failure counts, limitations, and supported shortcuts. |
+| Admin users/detail | `frontend/src/app/pages/admin-users/`, `admin-user-detail/` | Production active | Privacy-minimized responsive list, confirmed role changes and deletion. |
+| Admin organizations | `frontend/src/app/pages/admin-organizations/` | Production active, read-only | Explicit current-account membership scope and neutral deep-link handling. |
+| Admin courses | `frontend/src/app/pages/admin-courses/` | Production active | Oversight/governance only; confirmed delete; no authoring controls. |
+| Admin badges | `frontend/src/app/pages/admin-badges/` | Production active | Create/upload for admin, read-only compatibility, accessible images. |
+| Admin reports | `frontend/src/app/pages/admin-reports/` | Production active | Defined current aggregate counts only. |
+| Confirmation dialog | `frontend/src/app/components/echo-confirmation-dialog/` | Adopted in Admin | User role, user delete, and course delete consequences use shared focus-safe dialog. |
+
## Required Future Adoption
-- Admin user deletes/role changes.
-- Course archive/delete/publish actions.
-- Badge create/update/delete flows.
+- Course archive/publish actions if supported outside Studio.
+- Badge update/delete flows if APIs are approved.
- Organization invite revocation.
- Access grant revoke flows.
- Product publish/review transitions.
diff --git a/frontend/package.json b/frontend/package.json
index adccd93..6cfd95f 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -7,7 +7,8 @@
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
- "smoke:demo:student": "playwright test tests/demo/student-flagship-smoke.spec.ts"
+ "smoke:demo:student": "playwright test tests/demo/student-flagship-smoke.spec.ts",
+ "smoke:demo:admin": "playwright test tests/demo/admin-platform-smoke.spec.ts"
},
"private": true,
"dependencies": {
diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts
index 352fc5b..f7731d3 100644
--- a/frontend/playwright.config.ts
+++ b/frontend/playwright.config.ts
@@ -9,6 +9,7 @@ export default defineConfig({
timeout: 10_000,
},
fullyParallel: false,
+ workers: 1,
forbidOnly: !!process.env['CI'],
retries: process.env['CI'] ? 1 : 0,
reporter: [['list']],
diff --git a/frontend/src/app/app.routes.spec.ts b/frontend/src/app/app.routes.spec.ts
index 1b28b3d..d7220b7 100644
--- a/frontend/src/app/app.routes.spec.ts
+++ b/frontend/src/app/app.routes.spec.ts
@@ -15,6 +15,9 @@ import { SectionDetailComponent } from './pages/section-detail/section-detail.co
import { TeacherCurriculumComponent } from './pages/teacher-curriculum/teacher-curriculum.component';
import { TeacherCoursePreviewComponent } from './pages/teacher-curriculum/teacher-course-preview.component';
import { TeacherLearnerDetailComponent } from './pages/teacher-learner-detail/teacher-learner-detail.component';
+import { AdminOverviewComponent } from './pages/admin-overview/admin-overview.component';
+import { AdminUsersComponent } from './pages/admin-users/admin-users.component';
+import { AdminOrganizationsComponent } from './pages/admin-organizations/admin-organizations.component';
function findRoute(routeList: Routes, path: string): Route | undefined {
const exactRoute = routeList.find(candidate => candidate.path === path);
@@ -120,6 +123,30 @@ describe('app routes', () => {
expect(findRoute(routes, 'teach/curriculum')?.canActivate).toContain(RoleGuard);
});
+ it('adds guarded canonical Admin routes while preserving legacy aliases', () => {
+ [
+ 'admin',
+ 'admin/users',
+ 'admin/users/:userId',
+ 'admin/organizations',
+ 'admin/organizations/:organizationId',
+ 'admin/courses',
+ 'admin/courses/:courseId',
+ 'admin/badges',
+ 'admin/reports',
+ 'home/admin/users',
+ 'home/admin/courses',
+ 'home/admin/badges',
+ ].forEach(path => expect(findRoute(routes, path)).withContext(path).toBeTruthy());
+
+ expect(findRoute(routes, 'admin/')?.component).toBe(AdminOverviewComponent);
+ expect(findRoute(routes, 'admin/users')?.component).toBe(AdminUsersComponent);
+ expect(findRoute(routes, 'admin/organizations')?.component).toBe(AdminOrganizationsComponent);
+ expect(findRoute(routes, 'admin/users')?.canActivate).toContain(RoleGuard);
+ expect(findRoute(routes, 'admin/users')?.data?.['roles']).toEqual(['admin']);
+ expect(findRoute(routes, 'admin/organizations')?.data?.['roles']).toEqual(['admin', 'super_admin']);
+ });
+
it('maps Learner Portal V2 routes to V2 pages while reusing lesson runtime', () => {
const learnRoute = findRoute(routes, 'learn');
const learnerShell = learnRoute?.children?.find(route => route.path === '');
diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts
index 303aea7..7e1d717 100644
--- a/frontend/src/app/app.routes.ts
+++ b/frontend/src/app/app.routes.ts
@@ -45,6 +45,10 @@ import { CommercialDashboardComponent } from './pages/commercial-dashboard/comme
import { TeacherCurriculumComponent } from './pages/teacher-curriculum/teacher-curriculum.component';
import { TeacherCoursePreviewComponent } from './pages/teacher-curriculum/teacher-course-preview.component';
import { TeacherLearnerDetailComponent } from './pages/teacher-learner-detail/teacher-learner-detail.component';
+import { AdminOverviewComponent } from './pages/admin-overview/admin-overview.component';
+import { AdminUserDetailComponent } from './pages/admin-user-detail/admin-user-detail.component';
+import { AdminOrganizationsComponent } from './pages/admin-organizations/admin-organizations.component';
+import { AdminReportsComponent } from './pages/admin-reports/admin-reports.component';
const creatorRoles = ['admin', 'teacher', 'content_admin', 'org_admin', 'instructor'];
const studioRoles = ['content_admin', 'org_admin'];
@@ -58,6 +62,22 @@ export const routes: Routes = [
{ path: 'registration', component: RegistrationComponent },
{ path: 'onboarding/organization', component: OnboardingOrganizationComponent },
{ path: 'access-denied', component: AccessDeniedComponent },
+ {
+ path: 'admin',
+ component: HomeComponent,
+ canActivate: [HomeSessionGuard],
+ children: [
+ { path: '', component: AdminOverviewComponent, canActivate: [RoleGuard], data: { roles: ['admin', 'super_admin'] } },
+ { path: 'users', component: AdminUsersComponent, canActivate: [RoleGuard], data: { roles: ['admin'] } },
+ { path: 'users/:userId', component: AdminUserDetailComponent, canActivate: [RoleGuard], data: { roles: ['admin'] } },
+ { path: 'organizations', component: AdminOrganizationsComponent, canActivate: [RoleGuard], data: { roles: ['admin', 'super_admin'] } },
+ { path: 'organizations/:organizationId', component: AdminOrganizationsComponent, canActivate: [RoleGuard], data: { roles: ['admin', 'super_admin'] } },
+ { path: 'courses', component: AdminCoursesComponent, canActivate: [RoleGuard], data: { roles: ['admin'] } },
+ { path: 'courses/:courseId', component: AdminCoursesComponent, canActivate: [RoleGuard], data: { roles: ['admin'] } },
+ { path: 'badges', component: AdminBadgesComponent, canActivate: [RoleGuard], data: { roles: ['admin', 'super_admin'] } },
+ { path: 'reports', component: AdminReportsComponent, canActivate: [RoleGuard], data: { roles: ['admin'] } },
+ ],
+ },
{
path: 'teach',
component: HomeComponent,
diff --git a/frontend/src/app/models/course.ts b/frontend/src/app/models/course.ts
index c1c6594..a50a538 100644
--- a/frontend/src/app/models/course.ts
+++ b/frontend/src/app/models/course.ts
@@ -16,5 +16,9 @@ export interface Course {
/** Optional number of ratings */
ratingCount?: number;
units?: Unit[];
- created_at: Date;
+ created_at?: Date;
+ created_by?: string | null;
+ organization_id?: string | null;
+ revision_status?: string;
+ published_at?: string | null;
}
diff --git a/frontend/src/app/pages/admin-badges/admin-badges.component.html b/frontend/src/app/pages/admin-badges/admin-badges.component.html
index 21d6c30..6c50a77 100644
--- a/frontend/src/app/pages/admin-badges/admin-badges.component.html
+++ b/frontend/src/app/pages/admin-badges/admin-badges.component.html
@@ -1,36 +1,19 @@
-
-
-
-
Admin
-
Manage Badges
-
Create and preview recognition moments for students.
-
- Engagement
-
-
-
-
-
-
-
{{ badge.title }}
-
{{ badge.description }}
-
-
-
-
+
+
Admin / Badges
Badge administration
Create supported recognition badges and review the current catalog. Editing, deleting, archiving, and criteria management are not available from current APIs.
+
+
+
+
+
Create badge
+
Read-only badge catalog
The current backend permits badge writes only for the admin role. No write controls are shown for this role.
Deleting this course permanently removes the current course record and can disrupt learning access. The current API does not provide archive or restore.
Platform visibility is limited to organizations associated with the current account. Organization self-service remains in the Organization area.
+
+
+
+
+
+
Scoped organization visibility
The current API does not provide a platform-wide organization directory, member counts, administrator counts, invitations, sections, or organization lifecycle status. These values are not inferred.
Members, organization administrators, invitations, classes, assigned learning, and status are read-only unavailable because no platform-scoped read API exposes them. No organization-changing actions are shown.
Review platform access, learning resources, and supported operational status.
+
+
+
+
+
+
+
+
+
+
+
Needs attention
+
+
No verified platform attention queue is available.
+
Review users, course governance, and organizations directly. Community reports and moderation actions are not presented because the current APIs do not provide authorized, scoped queues.
Counts are current database totals returned by the endpoint. They do not define time windows, trends, active account status, organization ranking, engagement scores, or audit history.
Account identity and platform access. Learning progress and private profile data are not shown here.
{{ roleLabel(user.role) }}
+
+
+
Identity
Display name
{{ displayName }}
Username
{{ user.username }}
Email
{{ user.email }}
Created
{{ user.created_at | date:'medium' }}
Platform role
{{ roleLabel(user.role) | titlecase }}
Organization memberships
Not available from the current user API
+
+
Role and access
+
Your own role cannot be changed here.
This prevents accidental loss of access. The backend does not provide a protected self-role workflow.
+
+
Organization administrator and content administrator access is organization-scoped and is not assigned through this control. Partially implemented roles are not assignable here.
+
+
+
High-impact actions
Deleting this account is permanent and may remove authored discussions, badge awards, and learning links. It does not delete organizations or courses.
+
+
+
+ 0 && filteredUsers.length === 0" variant="empty" title="No users match these filters" body="Change the name search or role filter to see more accounts.">
+
+
+