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
- Function over flourish — Clean, purposeful UI that gets out of the way
- Two-second publish — From "I want to publish" to "it's live" in two clicks
- No surprises — Clear draft/published states, obvious regeneration triggers
- 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
- Auto-save interval — 3s debounce on editor? Or manual save only?
- Image upload — Should I build a simple "copy path" helper, or do you want actual upload endpoint? (Git workflow preferred?)
- Preview endpoint —
/api/blog/admin/posts/{slug}/previewPOST with Markdown body? - 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
- Matt approves spec
- Socrates reviews and answers open questions
- Socrates delivers admin API endpoints
- Daedalus implements templates and CSS
- Integration testing
- Phase 4 complete
Document: shared/project-docs/blog/phase-4-spec-admin-ui.md
Author: Daedalus 🎨
For: Matt (Director), Socrates 🧠 (Backend)