Files
manage/.pi-tmp/svc-hub-slice8-out.md
T
Developer a8dfbd5dc6 Cleanup: delete dead top-level pages + update docs (Slice 11)
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).
2026-06-26 20:11:02 +00:00

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
Email 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

  1. 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.

  2. 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.

  3. 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).

  4. Queue status polled via a dedicated hook. useAuthentikMessageStatus(serviceId) polls /api/services/authentik/{id}/message/status every 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/error field.