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

99 lines
4.7 KiB
Markdown

# 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`):
```json
{ "recipient_emails": ["alice@example.com"], "subject": "...", "html_body": "..." }
```
**Response** (success):
```json
{ "status": "queued", "request_id": "abc123", "recipient_count": 1 }
```
**Response** (error — service not configured / no recipients / SMTP invalid):
```json
{ "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.