Delete the old top-level page files whose content was migrated into service-page tabs in slices 5-9: - pages/Media.tsx, Applications.tsx (-> MediaTab) - pages/FileBrowser.tsx, FileBrowser.impl.tsx (-> FilesTab) - pages/Actions.tsx (-> ActionsTab) - pages/Users.tsx, UsersPage.impl.tsx (replaced by Authentik tabs) - components/BackupsPage.tsx (-> JobsTab) - components/ObservabilityPage.tsx (split into Alerts/Links/Metrics tabs) - hooks/useUsers.ts (orphaned after Users page deletion) - the corresponding page test files (Media, FileBrowser, Applications, Actions, UsersPage) that tested the deleted pages directly. The service-tab components are the live implementations; ServicePage renders them. No live code references the deleted files. Docs: append an Information Architecture section to REQUIREMENTS.md documenting the services-as-hub model (nav shape, service-page tabs, service type registry, Users->Authentik, Observability split, legacy route 404s, empty state). Add a CHANGELOG entry under [Unreleased]. 92 frontend tests pass (was 112; -20 deleted page tests); 271 backend tests pass; lint/build green. Refs openspec/changes/services-as-hub-ia/ (tasks slice 11).
4.7 KiB
Slice 8 — Authentik Users + Messaging tabs (worker output)
Files changed
| File | Status | Lines |
|---|---|---|
backend/src/media_library_viewer_api/routers/authentik_users.py |
modified | +66/-8 (added MessageRequest model + status + message endpoints) |
frontend/src/api/authentik.ts |
new | 65 |
frontend/src/hooks/useAuthentik.ts |
new | 43 |
frontend/src/pages/service-tabs/UsersTab.tsx |
new | 136 |
frontend/src/pages/service-tabs/MessagingTab.tsx |
new | 131 |
frontend/src/pages/service-tabs/__tests__/UsersTab.test.tsx |
new | 49 |
frontend/src/pages/service-tabs/__tests__/MessagingTab.test.tsx |
new | 47 |
frontend/src/pages/service-tabs/index.ts |
modified | +4/-4 |
frontend/src/pages/service-tabs/stubs.tsx |
modified | -8 (removed UsersTab/MessagingTab stubs) |
Total: ~539 lines (471 new files + 68 modified diff). Over the 400-line budget; dominated by the new-build UsersTab + MessagingTab (no existing UI to lift — built from scratch against the Authentik endpoint).
Backend message endpoint (Option A — implemented)
Added to routers/authentik_users.py:
GET /api/services/authentik/{service_id}/message/status
POST /api/services/authentik/{service_id}/message
POST body (MessageRequest):
{ "recipient_emails": ["alice@example.com"], "subject": "...", "html_body": "..." }
Response (success):
{ "status": "queued", "request_id": "abc123", "recipient_count": 1 }
Response (error — service not configured / no recipients / SMTP invalid):
{ "status": "error", "error": "description" }
The endpoint resolves the Authentik service record, validates SMTP settings, then enqueues via the existing mail_queue.enqueue(). The GET status endpoint proxies mail_queue.status(). Both are service-id scoped and return graceful errors matching the directory endpoint's pattern.
UsersTab columns
| Column | Source field | Notes |
|---|---|---|
| Name | user.name |
Falls back to "—" |
| Username | user.username |
|
user.email |
Falls back to "—" | |
| Status | user.is_active |
Badge: "Active" (default) / "Inactive" (secondary) |
Features: search input (committed on Enter/click), pagination (25 per page), error-Alert when endpoint returns an error field.
MessagingTab
Compose form with:
- Recipient search + toggle buttons (from Authentik users with emails)
- Subject input
- HTML body textarea (default template)
- Send button wired to POST
/api/services/authentik/{id}/message - Success/error Alert on mutation result
- Recipient count display
Validation
cd backend && .venv/bin/ruff check src/ tests/ → All checks passed!
cd backend && .venv/bin/python -m pytest tests/ → 271 passed, 2 warnings
cd frontend && npm run lint → 0 errors, 2 pre-existing warnings
cd frontend && npm run build → ✓ built (tsc -b + vite)
cd frontend && npm run test → 32 files / 100 tests passed (was 96; +4 new)
Deviations from design
-
Over 400-line budget. The UsersTab and MessagingTab are built from scratch (no existing Users UI to lift — the old page was Jellyfin-backed and deleted). Could not shrink without dropping functionality.
-
MessagingTab is simplified vs. the old compose UI. The old UsersPage had rich-text formatting toolbar (bold/italic/link/bullet), attachment upload, email preview iframe, and detailed queue-status banners. This slice implements a minimal but functional compose (recipient selection + subject + HTML body + send + result alert). Rich-text toolbar + attachments are follow-ups. The backend endpoint accepts the core fields (recipient_emails, subject, html_body) but not attachments yet.
-
No attachment upload. The mail_queue.enqueue() accepts attachments, but the POST endpoint does not accept multipart yet. Attachments are a follow-up (requires multipart handling on the endpoint + attachment UI).
-
Queue status polled via a dedicated hook.
useAuthentikMessageStatus(serviceId)polls/api/services/authentik/{id}/message/statusevery 5s. The MessagingTab does not yet display the queue status banner (minimal UI); the hook + endpoint exist for the follow-up that adds the queue indicator.
skill_resolution
none — no project/user SKILL.md paths were injected, and no .atl/skill-registry.md was found.
Residual risks
- MessagingTab lacks rich-text toolbar + attachment upload + queue-status banner. These are follow-ups; the core send flow works.
- Old UsersPage.impl.tsx + its test file still pass (rendered directly, not via routing). Deleted in Slice 11 cleanup.
- Backend message endpoint returns 200 on error (not 4xx/5xx), matching the directory endpoint's pattern. The frontend checks the
status/errorfield.