πŸ“„ 2026-04-20.md 1,756 bytes Apr 20, 2026 πŸ“‹ Raw

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 init
  • blog/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 endpoints
  • tests/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.md are source of truth
  • Static generation is Phase 3 β€” /admin/posts/{slug}/regenerate returns 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/blog with 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

Next: Phase 2 (Admin API + auth) and Phase 3 (static generation with Daedalus' templates)