Plan: pal-e-docs — Interactive Knowledge Platform
Vision
Replace Jinja with SvelteKit so that
note_type drives the renderer. Static HTML for docs, interactive components for boards. One frontend, one backend, one URL. The sprint board — one board per project — is the killer feature that justifies the migration and proves the pattern.Organizing principles:
- One plan per project. All actionable work lives here. TODOs and bugs link to phases via
parent_slug. Orphan TODOs = untriaged inbox. - One board per project. Boards replace sprints. Permanent kanban, not time-boxed. Column position = scoping depth (Backlog → Todo → Next Up → In Progress → Done).
- note_type drives rendering. A board note renders as an interactive SvelteKit component. A doc note renders as static HTML. Same system, different renderers.
- Playground-first. Design experiments in html-playground before committing to production repos.
- Docker Compose for dev. Postgres + API + frontend containers. No cluster dependency during development.
Projects & Repos Touched
| Repo | Platform | Role |
|---|---|---|
| <code>forgejo_admin/pal-e-docs</code> (future: pal-e-api) | Forgejo | FastAPI backend — notes, blocks, projects, boards, search |
| <code>pal-e-app</code> (new) | Forgejo | SvelteKit frontend — renders notes, interactive boards |
| <code>forgejo_admin/pal-e-docs-mcp</code> | Forgejo | MCP server — board/sprint tool updates |
| <code>forgejo_admin/pal-e-docs-sdk</code> | Forgejo | Python SDK — board/sprint method updates |
| <code>forgejo_admin/html-playground</code> | Forgejo | Design experiments for board UI |
Context
Act 1 (SQLite → Postgres) and Act 2 (Knowledge Engine — blocks, search, compiled pages) are complete. The platform has 262 notes, 32 MCP tools, full-text search, and a block content model. But the frontend is still Jinja server-rendered templates with zero interactivity. Sprint management exists as API + MCP tools but the multi-board/time-boxed sprint model proved wrong — projects need their own cadence and their own boards. This plan unifies the SvelteKit migration and the board redesign into one effort.
Previous Plan
plan-2026-02-26-tf-modularize-postgres — Act 1 + Act 2 (completed). plan-2026-03-01-pal-e-sprints — sprint backend (completed). plan-2026-03-03-sprint-workflow-automation — DORA instrumentation (completed).Depends On
- Block content model (Phase 7) — COMPLETED
- Sprint tables + API (Phase 1 of sprints backend) — COMPLETED
- Full-text search (Phase 5) — COMPLETED
Decisions Made
| Decision | Rationale |
|---|---|
| Boards replace sprints. One board per project. | Projects have different cadences. A cross-project sprint doesn't map to how work actually gets done. |
| Board columns are a scoping pipeline | Backlog (fuzzy) → Todo (defined) → Next Up (scoped) → In Progress (issue exists, agent spawned) → Done. |
| note_type drives rendering | Unifies static docs and interactive components in one system. Sprint board is the first interactive renderer. |
| pal-e-docs = project, not repo | pal-e-api = backend repo. pal-e-app = frontend repo. Eliminates naming confusion. |
| Sprint SDK/MCP rename deferred | Build new stuff against current API first. Renames are high blast radius, low immediate value. |
| Board data stays in pal-e-docs DB | Unified backend. boards + board_items tables replace sprints + sprint_items. |
| One plan per project, TODOs parent to phases | Prevents orphan work. All actionables tracked under one plan. Orphan check = TODOs with null parent_slug. |
Phases
See child phase notes:
list_notes(parent_slug="plan-pal-e-docs")Key Files
TBD — will be populated as phases complete.
Verification
- Board renders in SvelteKit with real data from pal-e-docs API
- Drag-and-drop moves items between columns
- note_type determines renderer (board vs static HTML)
- Docker Compose dev environment works without cluster
- All open TODOs have a parent_slug pointing to a phase
Next Plan Seeds
- DORA dashboard — once board tracks work, Grafana visualizes velocity
- Semantic search UI — search bar with keyword/semantic/hybrid modes
- In-browser editing — block-level CRUD UI for notes
- Quick-jot + inbox — rapid note creation, triage workflow
Related
project-pal-e-docs— project page (needs update)plan-2026-03-01-pal-e-sprints— completed predecessorplan-2026-03-03-sprint-workflow-automation— completed predecessorplan-2026-02-26-tf-modularize-postgres— completed predecessor
Epilogue
- PR #166 nit: inline import pattern —
from pal_e_docs.routes.boards import _status_to_columninside update_note. Consider shared module. - PR #166 nit: broad exception catch —
except Exceptioncould be narrowed. - PR #166 nit: position=0 for all synced items — Consider using
phase.position. - PR #166 nit: duplicated test helpers — Need shared conftest fixtures.
- PR #166 nit: falsy check on status — Status comparison could be more explicit.
- Frontend nit: $lib/constants.ts needed — RESOLVED. Extracted to
$lib/columns.ts(commit 0c4019a). - PR #17 nit: URL sync effect cycles —
$effectfires redundantly. Consider debounce or guard. - PR #17 nit: SvelteURLSearchParams — Use plain
URLSearchParamswhere reactivity not needed. - PR #20 nit: updated_at as column entry proxy — Known API limitation for stuck detection.
- PR #20 nit: inline border-left style — Competes with Tailwind class.
- PR #21 nit: duplicate listProjects() — Layout + home both fetch projects.
- PR #21 nit: unsanitized body HTML — Quick-jot relies on backend sanitization only.
- PR #21 nit: SELECT in isInput guard — Affects all keyboard shortcuts.
- PR #24 nit: missing .env.example — Auth env vars undocumented for local dev.
- PR #24 nit: hardcoded Tailscale URLs — Low priority given tailnet-only deployment.
- PR #24 nit: @ts-expect-error — Should use proper type augmentation in
app.d.ts. - PR #24 nit: unused accessToken — Stored in JWT callback but never consumed. Inflates cookie size.
- PR #24 nit: missing plan slug in PR body — PR template compliance.
- F12 nit: embedding worker NetworkPolicy gap — Worker pod not covered by
app=pal-e-docspolicy. Needs scoped policy in pal-e-deployments. (PR #90 QA) - F12 nit: PromQL float equality —
embedding_total == 0uses float equality. Consider threshold. (PR #90 QA) - F13b-1 nit: sequential board queries — Could parallelize with background jobs. (PR #114 QA)
- F13b-1 nit: dirname resolution — Use resolved
HOOK_DIRinstead ofdirname "$0". (PR #114 QA) - MCP labels nit: normalization duplication — Labels join+strip logic duplicated in create and update. Extract helper. (PR #42 QA)
- SDK labels type mismatch —
pal-e-docs-sdkadd_board_itemtypeslabelsaslist[str] | Noneinstead ofstr | None. Issue #30. (PR #42 discovered scope) - DEFERRED: Phase 5b-2 deploy —
forgejo-api-tokenk8s secret needed inpal-e-docs-secretsfor Forgejo issue sync to work in prod. Code merged (PR #171). - DEFERRED: Phase 5b-3 stale detection —
stale_atfield, periodic sweep, stuck-item flagging. Issue TBD. - DEFERRED: Phase 6 — Token Metrics — Token usage tracking per sprint item. Needs observability foundation (DORA correlation).
- DEFERRED: Phase 8 — Repo Renames — pal-e-docs → pal-e-api, pal-e-docs-mcp → pal-e-mcp, etc. High blast radius, low immediate value.
- DEFERRED: Phase 9 — Jinja Sunset — Remove legacy Jinja templates. Low priority — SvelteKit frontend is primary.
- DEFERRED: Phase 10 — Orchestration Automation — Auto-QA trigger, auto-dev-respawn. Auto-board-sync already absorbed by Agency Phase 11.
- PR #185 nit: write endpoints lack auth gating — POST/PUT/DELETE on
/projectsand/boardshave no auth check. Pre-existing, out of scope for #184. Should be tracked. (F14 QA) - PR #185 nit: /projects/{slug}/notes no project-level is_public gate — Endpoint returns public notes even if the project itself is private. Documented intentionally in test. (F14 QA)
- PR #39 nit: deleteBoardItem DRY — duplicates header construction instead of using
apiFetch. (F14 QA) - PR #39 nit: slugCache auth-state keying — Cache stores slugs from most-privileged request. Anonymous request within 60s TTL could see private slugs in cache (note-detail endpoint still filters). (F14 QA)
- PR #39 nit: sign-in CSS duplication —
.contact-btnand.login-submitare 99% identical. Merge into single class. (F14 QA) → Addressed by F11a subphase. - PR #39 nit: hardcoded portfolio URL —
https://portfolio.tail5b443a.ts.nethardcoded in signin page. Consider env var. (F14 QA)