--- # pages-jaqz title: Embedded management UI (static/index.html) status: completed type: feature priority: normal created_at: 2026-07-13T02:09:09Z updated_at: 2026-07-13T17:22:22Z parent: pages-77lk blocked_by: - pages-adl9 --- Single-file management UI per design §4.1/§5, served at GET / via include_str!. Vanilla HTML+CSS+JS inline, no external resources (would break under our own CSP? — the / route is NOT sandboxed; still keep it dependency-free). Features: fetch /api/pages and render list with links; fetch /api/me — show Login with GitHub (/auth/login) or user + Logout (POST /auth/logout); upload card (only when can_upload): file input + drag-drop for .html/.zip, name field defaulting to filename minus extension (mirror core::slug::default_slug_from_filename rules in JS), submit via fetch POST /api/pages?name=... with file as body and its Content-Type (application/zip or text/html), show success with link, 409 -> inline 'name taken' error keeping form state, 403 -> 'not authorized' warning; delete buttons on own pages (confirm()), admins see all-page delete + Users panel (list, can_upload checkboxes -> PATCH). Clean minimal styling, dark-mode friendly via prefers-color-scheme. Serve / with standard security headers (nosniff, no CSP sandbox, a strict same-origin CSP allowing inline script/style is fine). - [x] static/index.html complete UI - [x] GET / route with headers - [x] name defaulting + error paths match API contract - [x] full validation suite passes ## Summary of Changes Single-file management UI (static/index.html, inline CSS/JS, no external resources) served at GET / via include_str!, by a Sonnet agent; Opus review APPROVE (no XSS, contract-faithful, CSP verified). - List/login/logout, drag-drop upload with slug defaulting mirroring core::slug, 201/409/403/401/other handling, owner/admin delete, lazy admin users panel. - Strict non-sandbox CSP on / (inline allowed, connect/img/frame-ancestors locked down) + nosniff/no-referrer/no-store. - Post-review polish: client-side 10 MiB pre-check, dead el() attrs branch removed.