Phase: Block Renderer + Jinja2 Sunset

phase-pal-e-docs-note-renderer Phase

Goal: Build SvelteKit block-based rendering for all note types and remove the Jinja2 frontend entirely.
Owner: Dev agent
Repo: forgejo_admin/pal-e-app (primary), forgejo_admin/pal-e-docs (Jinja2 removal)
Depends on: phase-pal-e-docs-app-scaffold, phase-pal-e-docs-sprint-board-component

Scope

Absorbs the original Phase 4 (Note Renderer) and Phase 9 (Jinja Sunset) into a single deliverable. The Jinja2 frontend is ~320 lines of Python routing + ~460 lines of templates. The block API already exists. The gap is smaller than the plan assumed — no reason to maintain two frontends in parallel.

Deliverables

  • 7 block renderer componentsHeadingBlock, ParagraphBlock, TableBlock, ListBlock, CodeBlock, MermaidBlock, BlockRenderer (dispatcher). All render from blocks API JSON.
  • /notes/[slug] route — fetches blocks from API, renders with block components. Breadcrumb, metadata badges, TOC sidebar, child notes sidebar, anchor links on headings.
  • /notes listing route — search, type-grouped display, tag/project/note_type filters.
  • /projects and /projects/[slug] routes — project list + detail with notes grouped by type.
  • /tags and /tags/[name] routes — tag cloud + filtered note listing.
  • /repos route — repos grouped by project.
  • Autolink support<code>slug-ref</code> patterns in paragraph/list blocks auto-link to /notes/{slug}. Server-side slug cache with 60s TTL.
  • Landing page — overview dashboard with projects, boards, and top tags.
  • DOMPurify sanitization — all {@html} inputs sanitized via isomorphic-dompurify. Defense-in-depth.
  • Shared color systemsrc/lib/colors.ts with 16-type color map extracted from duplicated constants.
  • PR #9 merged — 30 files changed, +2609/-183. Closes Issue #8.
  • Jinja2 removal NOT YET DONE — SvelteKit serves all routes. Jinja2 templates still in pal-e-docs backend (separate repo, separate PR). Tracked as follow-up.

Out of Scope

  • Auth (login/logout) — deferred, tracked by pal-e-docs Issue #2
  • Dropping html_content column — keep as cache for now, remove after search migration
  • In-browser editing — future phase

Key Architectural Decision

SvelteKit renders from blocks, not from html_content. The blocks table (5,197 rows, 6 types) is the source of truth. html_content is a denormalized cache maintained by recompile() — kept for search compatibility but not consumed by the frontend.
  • plan-pal-e-docs — parent plan
  • phase-pal-e-docs-jinja-sunset — absorbed into this phase
  • phase-pal-e-docs-sprint-board-component — board kanban (already built, pattern to follow)