2026-04-20 Daily Notes
Blog Module Phase 1 β COMPLETE β
Implemented the full blog backend in hoffdesk-api/blog/:
Files created:
blog/__init__.pyβ Module initblog/models.pyβ Pydantic models matching the API spec (PostSummary, PostDetail, PostListResponse, CreatePostRequest, UpdatePostRequest, etc.)blog/storage.pyβ SQLite schema + Markdown I/O (frontmatter parsing, CRUD, FTS5, tag management, rebuild from Markdown files)blog/service.pyβ Business logic (CRUD, publish/unpublish, related posts, categories, tags, rebuild)blog/router.pyβ FastAPI routes for all public + admin endpointstests/test_blog_api.pyβ 36 integration tests, all passing
Key design decisions:
- SQLite is a derived index β fully rebuildable from Markdown source files
- FTS5 virtual table for future server-side search (client-side Lunr.js/Fuse.js for Sprint 1)
- Categories table pre-seeded with 8 categories (general, engineering, family, projects, behind-scenes, homelab, openclaw, ai-news)
- Markdown files in
data/blog/posts/{slug}/index.mdare source of truth - Static generation is Phase 3 β
/admin/posts/{slug}/regeneratereturns placeholder response - Admin auth is CF Access at the edge β FastAPI trusts headers, no auth middleware needed
Wired into main.py:
- Blog router mounted at
/api/blogwith CORS updated for POST/PATCH/DELETE - Draft blog post seeded:
the-night-i-broke-dns
Test results: 36/36 passing
- Public read: list, get, related, categories, tags
- Admin write: create, update, delete (soft), publish, unpublish
- Full workflow: createβpublishβreadβupdateβarchive