# Phase 4 Specification β€” Admin UI + Polish **Author:** Daedalus 🎨 **Date:** 2026-04-20 **Status:** Draft β€” Pending Director Approval --- ## Overview Phase 4 completes the HoffDesk Blog with a functional-minimal admin interface for content management. The static site generation (Phase 3) is complete; this phase adds the human interface for creating, editing, and publishing posts. **Scope:** Admin dashboard, post editor with live preview, image management, and polish. --- ## Design Principles 1. **Function over flourish** β€” Clean, purposeful UI that gets out of the way 2. **Two-second publish** β€” From "I want to publish" to "it's live" in two clicks 3. **No surprises** β€” Clear draft/published states, obvious regeneration triggers 4. **Mobile-respectful** β€” Desktop-primary for admin, but works on tablet --- ## Page Architecture ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ADMIN HEADER β”‚ β”‚ [HoffDesk Logo] Blog Admin [Logout] β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ SIDEBAR β”‚ β”‚ MAIN CONTENT AREA β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Dashboard β”‚ β”‚ Post List / Editor β”‚ β”‚ β”‚ β”‚ All Posts β”‚ β”‚ Preview Pane β”‚ β”‚ β”‚ β”‚ Drafts β”‚ β”‚ Status Widget β”‚ β”‚ β”‚ β”‚ Published β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ ───────── β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ + New Postβ”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ ACTIONS β”‚ β”‚ β”‚ β”‚ [Rebuild] β”‚ β”‚ β”‚ β”‚ [Deploy] β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ FOOTER: last build time, deploy status β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## Views & Routes | Route | View | Description | |-------|------|-------------| | `/admin/blog/` | Dashboard | Stats widget + recent activity + quick actions | | `/admin/blog/posts` | Post List | Filterable table (draft/published/all), sort by updated | | `/admin/blog/posts/new` | Editor | Create new post, auto-save to draft | | `/admin/blog/posts/{slug}/edit` | Editor | Edit existing post, see history/status | | `/admin/blog/images` | Image Manager | Browse post images, copy paths | --- ## Editor: Split-Pane Design ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ [Back] Test Post [Save Draft] [Publish] β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ METADATA β”‚ EDITOR β”‚ β”‚ ─────────────────── β”‚ ─────────────────────────────────── β”‚ β”‚ Title β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ [________________] β”‚ β”‚ Markdown Source β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚ β”‚ Category β”‚ β”‚ β”‚ # Heading β”‚β”‚ β”‚ β”‚ [Dropdown β–Ό] β”‚ β”‚ β”‚ β”‚β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Paragraph text here... β”‚β”‚ β”‚ β”‚ Tags β”‚ β”‚ β”‚ β”‚β”‚ β”‚ β”‚ [tag1, tag2, ... ] β”‚ β”‚ β”‚ - List item β”‚β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Another item β”‚β”‚ β”‚ β”‚ Excerpt β”‚ β”‚ β”‚ β”‚β”‚ β”‚ β”‚ [ ] β”‚ β”‚ β”‚ `code inline` β”‚β”‚ β”‚ β”‚ [ ] β”‚ β”‚ β”‚ β”‚β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚ β”‚ Cover Image β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ [Browse or URL__] β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ ─────────────────── β”‚ β”‚ Live Preview (rendered HTML) β”‚ β”‚ β”‚ STATUS β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚ β”‚ ● Draft β”‚ β”‚ β”‚ # Heading β”‚β”‚ β”‚ β”‚ Updated: 2 min ago β”‚ β”‚ β”‚ β”‚β”‚ β”‚ β”‚ [Regenerate] [Del] β”‚ β”‚ β”‚ Paragraph text here... β”‚β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## HTMX Interaction Patterns | Interaction | HTMX Pattern | |-------------|--------------| | Post list filter | `hx-get` on select change, target list container | | Save draft | `hx-post` auto-save on blur/debounce (3s) | | Live preview | `hx-post` to preview endpoint, swap preview pane | | Publish toggle | `hx-post` to publish endpoint, swap status widget | | Regenerate site | `hx-post` to regenerate endpoint, show spinner + toast | | Deploy | `hx-post` with confirmation, show progress | --- ## Required API Endpoints Daedalus requires these backend endpoints from Socrates: | Endpoint | Method | Purpose | |----------|--------|---------| | `/api/blog/admin/posts` | GET | List all posts (with status filter) | | `/api/blog/admin/posts` | POST | Create new draft | | `/api/blog/admin/posts/{slug}` | GET | Get full post (incl. raw Markdown) | | `/api/blog/admin/posts/{slug}` | PATCH | Update post metadata/content | | `/api/blog/admin/posts/{slug}/preview` | POST | Render Markdown β†’ HTML preview | | `/api/blog/admin/posts/{slug}/publish` | POST | Publish draft | | `/api/blog/admin/posts/{slug}/unpublish` | POST | Revert to draft | | `/api/blog/admin/posts/{slug}/regenerate` | POST | Trigger single post regen | | `/api/blog/admin/rebuild` | POST | Full rebuild (all posts) | | `/api/blog/admin/deploy` | POST | Deploy to Cloudflare Pages | --- ## Design Tokens (Extends Sprint 1) Admin UI reuses existing Sprint 1 tokens with admin-specific additions: | New Token | Base Token | Usage | |-----------|-----------|-------| | `admin-sidebar-bg` | `bg-secondary` | Sidebar background | | `admin-border` | `border-default` | Panel separators | | `admin-ok` | `status-healthy` | Published status | | `admin-pending` | `status-degraded` | Draft status | | `admin-danger` | `status-critical` | Destructive actions | --- ## File Structure (Deliverables) ``` workspace-daedalus/blog/admin/ β”œβ”€β”€ templates/ β”‚ β”œβ”€β”€ admin_base.html.j2 # Layout with sidebar β”‚ β”œβ”€β”€ admin_dashboard.html.j2 # Stats + recent + actions β”‚ β”œβ”€β”€ admin_post_list.html.j2 # Filterable post table β”‚ β”œβ”€β”€ admin_editor.html.j2 # Split-pane editor β”‚ └── admin_images.html.j2 # Image browser β”œβ”€β”€ static/ β”‚ └── admin.css # Admin-specific styles (~200 lines) └── components/ # HTMX partial templates β”œβ”€β”€ post_row.html.j2 β”œβ”€β”€ status_widget.html.j2 └── preview_pane.html.j2 ``` --- ## Deliverables Checklist - [ ] `admin_base.html.j2` β€” layout with nav, sidebar, footer - [ ] `admin_dashboard.html.j2` β€” stats, recent posts, rebuild/deploy buttons - [ ] `admin_post_list.html.j2` β€” filterable table with HTMX - [ ] `admin_editor.html.j2` β€” split-pane with live preview - [ ] `admin_images.html.j2` β€” simple image browser - [ ] `admin.css` β€” admin-specific styles (extends blog.css) - [ ] HTMX partials for dynamic updates - [ ] Mobile-responsive basics (admin is desktop-primary but not broken on tablet) --- ## Timeline Estimate | Task | Hours | Blockers | |------|-------|----------| | Admin base + dashboard | 2 | None | | Post list with HTMX filters | 2 | API endpoints | | Editor (split-pane + preview) | 3 | Preview endpoint | | Image manager | 1 | Image path strategy | | Polish, mobile pass, integration | 2 | Socrates wiring | **Total: ~10 hours of focused work** --- ## Open Questions for Socrates 1. **Auto-save interval** β€” 3s debounce on editor? Or manual save only? 2. **Image upload** β€” Should I build a simple "copy path" helper, or do you want actual upload endpoint? (Git workflow preferred?) 3. **Preview endpoint** β€” `/api/blog/admin/posts/{slug}/preview` POST with Markdown body? 4. **Conflict detection** β€” If Matt edits on two devices, last-write-wins or optimistic locking? --- ## Dependencies | Dependency | Source | Status | |------------|--------|--------| | Sprint 1 Design Tokens | `shared/design-tokens/sprint-1.md` | βœ… Ready | | Blog CSS | `workspace-daedalus/blog/static/blog.css` | βœ… Ready | | Admin API endpoints | Socrates | πŸ”„ Pending | | Preview rendering endpoint | Socrates | πŸ”„ Pending | --- ## Next Steps 1. Matt approves spec 2. Socrates reviews and answers open questions 3. Socrates delivers admin API endpoints 4. Daedalus implements templates and CSS 5. Integration testing 6. Phase 4 complete --- *Document: `shared/project-docs/blog/phase-4-spec-admin-ui.md`* *Author: Daedalus 🎨* *For: Matt (Director), Socrates 🧠 (Backend)*