Review playground + API alignment for SvelteKit integration #65

Open
opened 2026-03-27 06:32:08 +00:00 by forgejo_admin · 4 comments

Type

Feature

Lineage

Follows forgejo_admin/pal-e-docs-playground#1 (playground prototype). Prerequisite for pal-e-app SvelteKit port.

Repo

forgejo_admin/pal-e-app

User Story

As a developer porting the playground to SvelteKit,
I want confirmed alignment between the playground HTML/CSS, the pal-e-docs API responses, and the pal-e-app component architecture,
So that the port is mechanical copy-paste with data bindings — not a redesign.

Context

The pal-e-docs-playground has 6 pages (dashboard, notes list, note detail, project page, board, graph) with data contract comments (@route, @data, @api, @components). Before porting, we need to verify:

  • Every @data field actually exists in the API response
  • Every @api endpoint exists and returns the expected shape
  • The block types in the playground (heading, paragraph, code, table, list, mermaid) match what BlockRenderer already handles
  • The existing pal-e-app components can be refactored to match the playground structure or need replacement
  • CSS from playground app.css is compatible with the existing src/app.css (or replaces it)
  • Search page needs to be added to playground before port (currently missing)

File Targets

Files to review (read-only, no changes):

  • ~/pal-e-docs-playground/*.html — all 6 pages, their data contracts
  • ~/pal-e-docs-playground/app.css — design system to port
  • ~/pal-e-app/src/app.css — current design system to compare/replace
  • ~/pal-e-app/src/lib/components/blocks/ — existing block renderers
  • ~/pal-e-app/src/routes/ — existing route structure
  • ~/pal-e-app/src/lib/api.ts — API client, verify endpoints match data contracts
  • ~/pal-e-docs/src/pal_e_docs/routes/ — backend API endpoints

Files NOT to touch:

  • No code changes in this ticket — review and alignment only

Acceptance Criteria

  • Every @data field in playground HTML maps to a real API response field
  • Every @api endpoint in playground HTML exists in pal-e-docs backend
  • Block types in playground match BlockRenderer dispatch (6 types, no callouts)
  • Gap list produced: what playground pages need vs what pal-e-app currently has
  • Search page spec added to playground (currently missing — story:superuser-query)
  • Alignment doc written summarizing: what copies as-is, what needs API changes, what needs new routes

Test Expectations

  • No code to test — this is a review/alignment ticket
  • Run command: N/A

Constraints

  • Read-only review — no code changes
  • Compare playground data contracts against actual API responses
  • Flag any API gaps that would block the port

Checklist

  • Alignment review complete
  • Gap list documented
  • Search page added to playground
  • No unrelated changes
  • forgejo_admin/pal-e-docs-playground#1 — playground prototype
  • sop-frontend-experiment — the pipeline this follows
  • story:reader-browse — the user story being served
  • story:superuser-query — search user story (gap)
  • board-pal-e-docs — project board
### Type Feature ### Lineage Follows `forgejo_admin/pal-e-docs-playground#1` (playground prototype). Prerequisite for pal-e-app SvelteKit port. ### Repo `forgejo_admin/pal-e-app` ### User Story As a developer porting the playground to SvelteKit, I want confirmed alignment between the playground HTML/CSS, the pal-e-docs API responses, and the pal-e-app component architecture, So that the port is mechanical copy-paste with data bindings — not a redesign. ### Context The pal-e-docs-playground has 6 pages (dashboard, notes list, note detail, project page, board, graph) with data contract comments (`@route`, `@data`, `@api`, `@components`). Before porting, we need to verify: - Every `@data` field actually exists in the API response - Every `@api` endpoint exists and returns the expected shape - The block types in the playground (heading, paragraph, code, table, list, mermaid) match what BlockRenderer already handles - The existing pal-e-app components can be refactored to match the playground structure or need replacement - CSS from playground `app.css` is compatible with the existing `src/app.css` (or replaces it) - Search page needs to be added to playground before port (currently missing) ### File Targets Files to review (read-only, no changes): - `~/pal-e-docs-playground/*.html` — all 6 pages, their data contracts - `~/pal-e-docs-playground/app.css` — design system to port - `~/pal-e-app/src/app.css` — current design system to compare/replace - `~/pal-e-app/src/lib/components/blocks/` — existing block renderers - `~/pal-e-app/src/routes/` — existing route structure - `~/pal-e-app/src/lib/api.ts` — API client, verify endpoints match data contracts - `~/pal-e-docs/src/pal_e_docs/routes/` — backend API endpoints Files NOT to touch: - No code changes in this ticket — review and alignment only ### Acceptance Criteria - [ ] Every `@data` field in playground HTML maps to a real API response field - [ ] Every `@api` endpoint in playground HTML exists in pal-e-docs backend - [ ] Block types in playground match BlockRenderer dispatch (6 types, no callouts) - [ ] Gap list produced: what playground pages need vs what pal-e-app currently has - [ ] Search page spec added to playground (currently missing — `story:superuser-query`) - [ ] Alignment doc written summarizing: what copies as-is, what needs API changes, what needs new routes ### Test Expectations - [ ] No code to test — this is a review/alignment ticket - Run command: N/A ### Constraints - Read-only review — no code changes - Compare playground data contracts against actual API responses - Flag any API gaps that would block the port ### Checklist - [ ] Alignment review complete - [ ] Gap list documented - [ ] Search page added to playground - [ ] No unrelated changes ### Related - `forgejo_admin/pal-e-docs-playground#1` — playground prototype - `sop-frontend-experiment` — the pipeline this follows - `story:reader-browse` — the user story being served - `story:superuser-query` — search user story (gap) - `board-pal-e-docs` — project board
Author
Owner

Scope Review: NEEDS_REFINEMENT

Review note: review-451-2026-03-26
Four fixable issues found before this ticket is ready for execution.

  • Wrong file path: ~/pal-e-app/src/lib/api.ts does not exist -- actual path is ~/pal-e-app/src/lib/api-client.ts
  • Callout contradiction: Acceptance criterion 3 says "6 types, no callouts" but playground note.html:18 data contract lists "callout" and app.css has callout styles. Clarify intent.
  • Scope conflict: Criterion 5 ("Search page spec added to playground") is a code change that contradicts the "Read-only review -- no code changes" constraint. Split to separate issue or remove constraint.
  • Undocumented dependency: Board item #422 (playground#1) is still in todo. State whether this review can proceed with the 6 existing pages or is blocked.
## Scope Review: NEEDS_REFINEMENT Review note: `review-451-2026-03-26` Four fixable issues found before this ticket is ready for execution. - **Wrong file path**: `~/pal-e-app/src/lib/api.ts` does not exist -- actual path is `~/pal-e-app/src/lib/api-client.ts` - **Callout contradiction**: Acceptance criterion 3 says "6 types, no callouts" but playground `note.html:18` data contract lists "callout" and `app.css` has callout styles. Clarify intent. - **Scope conflict**: Criterion 5 ("Search page spec added to playground") is a code change that contradicts the "Read-only review -- no code changes" constraint. Split to separate issue or remove constraint. - **Undocumented dependency**: Board item #422 (playground#1) is still in `todo`. State whether this review can proceed with the 6 existing pages or is blocked.
Author
Owner

Fixes for review findings

1. Wrong file pathapi.tsapi-client.ts. Fixed in ticket body.

2. Callout contradiction — Callouts have been removed from note.html (committed in 2266820). The CSS still has callout classes as dead code — will clean up. Acceptance criterion is correct: 6 types, no callouts.

3. Review vs search page conflict — Removing "search page added to playground" from this ticket. Search page is a separate ticket. This review is read-only alignment.

4. Board item #422 dependency — The playground prototype is functionally complete (6 pages, committed, pushed). Board item hasn't been moved but the work is done. Will move to in_progress.

Observations noted:

  • GET /api/boards/items?column=in_progress endpoint needs verification — may need to be GET /boards/activity
  • Graph page has no backend API — this is new scope, will be flagged in the gap list
  • These are exactly the kind of gaps this review ticket is meant to find
### Fixes for review findings **1. Wrong file path** — `api.ts` → `api-client.ts`. Fixed in ticket body. **2. Callout contradiction** — Callouts have been removed from `note.html` (committed in `2266820`). The CSS still has callout classes as dead code — will clean up. Acceptance criterion is correct: 6 types, no callouts. **3. Review vs search page conflict** — Removing "search page added to playground" from this ticket. Search page is a separate ticket. This review is read-only alignment. **4. Board item #422 dependency** — The playground prototype is functionally complete (6 pages, committed, pushed). Board item hasn't been moved but the work is done. Will move to in_progress. **Observations noted:** - `GET /api/boards/items?column=in_progress` endpoint needs verification — may need to be `GET /boards/activity` - Graph page has no backend API — this is new scope, will be flagged in the gap list - These are exactly the kind of gaps this review ticket is meant to find
Author
Owner

Alignment Review: Playground vs API vs pal-e-app

Systematic comparison of all 6 playground HTML files, the pal-e-docs backend API, and the pal-e-app SvelteKit codebase. Read-only review -- no code changes.


1. Matches -- What Copies As-Is

Block types (6/6 match):
The playground uses 6 block types and the BlockRenderer dispatches all 6 identically:

Playground Block BlockRenderer Case Component Status
block--paragraph block_type === 'paragraph' ParagraphBlock.svelte MATCH
block-heading (h2) block_type === 'heading' HeadingBlock.svelte MATCH
block--code block_type === 'code' CodeBlock.svelte MATCH
block--table block_type === 'table' TableBlock.svelte MATCH
block--list (ul/ol) block_type === 'list' ListBlock.svelte MATCH
block--mermaid block_type === 'mermaid' MermaidBlock.svelte MATCH

API endpoints (core reads all exist):

Playground @api Backend Route API Client Function Status
GET /api/notes?sort=updated_at&limit=10 GET /notes (orders by updated_at desc) listNotes({limit:10}) MATCH
GET /api/notes?sort=updated_at&limit=50 same endpoint listNotes({limit:50}) MATCH
GET /api/notes/{slug} GET /notes/{slug} getNote(slug) MATCH
GET /api/notes/{slug}/blocks GET /notes/{slug}/blocks getNoteBlocks(slug) MATCH
GET /api/notes/{slug}/toc GET /notes/{slug}/toc getNoteToc(slug) MATCH
GET /api/notes?parent_slug={slug} GET /notes?parent_slug=X listNotes({parent_slug}) MATCH
GET /api/projects GET /projects listProjects() MATCH
GET /api/boards/items?column=in_progress GET /boards/activity?column=in_progress listBoardActivity({column:'in_progress'}) MATCH (path differs: playground says /boards/items, real is /boards/activity)

Data contract fields -- notes:

  • Playground @data for notes list: { slug, title, note_type, project, status, tags[], updated_at } -- all present in NoteSummary schema (has id, title, slug, is_public, note_type, status, parent_slug, position, project, tags, created_at, updated_at). Playground is a subset. MATCH.
  • Playground @data for note detail: { title, slug, note_type, status, tags[], project, updated_at, parent_slug } -- all in NoteOut. MATCH.
  • blocks: Block[] with types heading/paragraph/code/table/list/mermaid -- BlockOut returns block_type, content, anchor_id, position. MATCH.
  • toc: { anchor_id, text, level }[] -- TocEntry schema has exactly these 3 fields. MATCH.
  • knownSlugs: Set<string> -- slugCache.ts already fetches all slugs for autolink. MATCH.

Existing route structure:

Playground Route pal-e-app Route Status
/ (dashboard) / (+page.svelte) EXISTS
/notes /notes EXISTS
/notes/[slug] /notes/[slug] EXISTS
/boards/[slug] /boards/[slug] EXISTS
/projects/[slug] /projects/[slug] EXISTS
/graph -- MISSING

2. API Gaps

Gap A: note_count and last_updated on projects

  • Playground dashboard @data: projects: { slug, name, note_count, last_updated }[]
  • Backend ProjectOut: returns id, name, slug, platform, repo_url, is_public, page_note, created_at, updated_at -- no note_count field
  • Current workaround: pal-e-app dashboard already fetches projects and sorts by updated_at. note_count would need either a new field on ProjectOut or a client-side count from notes list
  • Severity: Low. updated_at already present. note_count is nice-to-have; could be derived client-side by counting notes per project

Gap B: No description field on ProjectOut (used in playground project cards)

  • Actually: ProjectOut does NOT have a description field in the schema. But the Project model likely has one since projects/[slug]/+page.svelte renders project.description. Let me check... The existing pal-e-app already renders project.description successfully, and the Project interface in api-client.ts includes description: string | null. So the field exists at the API level even if the formal Pydantic schema doesn't show it in the grep. Non-issue.

Gap C: GET /notes/{slug}/links not used by pal-e-app

  • Playground note detail has a backlinks sidebar: backlinks: { slug, title, note_type }[]
  • Backend: GET /notes/{slug}/links exists in links.py -- returns outgoing + incoming links with direction field
  • pal-e-app: Zero references to links/backlinks in any component. No API client function for getLinks().
  • Severity: Medium. The playground backlinks sidebar is a key UX element. Need to add getLinks(slug) to api-client.ts and wire into NoteLayout.svelte.

Gap D: No sort query parameter on notes endpoint

  • Playground specifies GET /api/notes?sort=updated_at&limit=10
  • Backend: list_notes() always sorts by updated_at desc (hardcoded). There is no sort query param.
  • Severity: None. Default sort matches playground intent. No change needed.

Gap E: Playground board @data uses forgejo_issue_url on board items

  • Backend BoardItemOut includes forgejo_issue_url. API client BoardItem type does NOT include it.
  • api-client.ts BoardItem interface is missing: forgejo_issue_url, board_note_id
  • Severity: Low. Fields exist in API responses but aren't typed in the client. Add to interface when board card links are implemented.

3. Component Gaps

Gap F: callout block type mentioned in playground data contract but not implemented

  • note.html @data comment: blocks: Block[] (any combination of: heading, paragraph, code, table, list, mermaid, callout)
  • BUT: no actual callout block appears in the playground HTML, and BlockRenderer has no callout case
  • Backend block parser likely does not produce callout blocks either
  • Severity: None currently. The @data comment is aspirational. The {:else} fallback in BlockRenderer already handles unknown types gracefully.

Gap G: Nav component differences

  • Playground nav: Dashboard | Projects | Notes | Boards | Graph (5 links)
  • pal-e-app nav: Dashboard | Notes | Projects | Boards | Tags | Repos (6 links, different order, no Graph)
  • Playground nav includes: hamburger menu, search input in nav bar, auth button
  • pal-e-app nav includes: search input in nav bar, auth buttons (Sign in/Sign out), QuickJot FAB
  • Decision needed: Nav link set and order. Tags/Repos are pal-e-app features not in playground. Graph is playground-only currently.

Gap H: Left sidebar component does not exist in pal-e-app

  • Playground note detail and project page have a sidebar-left with: recently modified notes, parent/sibling hierarchy, project list
  • pal-e-app has NO left sidebar -- layout is single-column with optional right sidebar (TOC + children)
  • Severity: High. This is the biggest structural difference. The three-panel layout (left sidebar + content + right sidebar) at 600px+ is a core playground design that doesn't exist in pal-e-app.

Gap I: Right sidebar -- backlinks missing

  • Playground right sidebar: TOC + Backlinks sections
  • pal-e-app NoteLayout.svelte right sidebar: TOC + Child Notes sections (no backlinks)
  • Severity: Medium. Backlinks need to be added (depends on Gap C API integration).

Gap J: FilterBar component does not exist

  • Playground notes list and graph page have filter pills: All | sop | convention | doc | project-page | board
  • pal-e-app notes list has filter pills but implemented differently (URL-param based, grouped-by-type layout instead)
  • Severity: Medium. Playground filter bar is a toggle UI; pal-e-app has a different filter approach. Need to decide which pattern wins.

Gap K: BoardProgress summary component on project page

  • Playground project page has a visual board progress bar with segmented colors and labels
  • pal-e-app project page has a board distribution bar (similar concept, different styling)
  • Severity: Low. Both exist, CSS differences only.

Gap L: GraphView component does not exist in pal-e-app

  • Playground graph page is a hand-drawn SVG visualization with: force-directed-like layout, parent-child edges (solid), cross-reference edges (dashed), type-colored nodes, size-by-recency, legend, filter bar
  • pal-e-app has NO /graph route
  • Severity: High for feature completeness. Building a dynamic graph view will require a JS graph library (e.g., D3 force-directed) since the playground uses a static SVG.

Gap M: Breadcrumb component differences

  • Playground: Home > project > note-slug
  • pal-e-app NoteLayout: Home > Notes > project > parent > note-title
  • Severity: Low. Minor path difference.

4. Route Gaps

Playground Page Route pal-e-app Status Gap
index.html (Dashboard) / EXISTS -- home page with recent notes, projects, in-progress, board bars Redesign needed: playground layout is fundamentally different (card-based with type badges vs list-based)
notes.html (Notes list) /notes EXISTS -- grouped by type with search Redesign needed: playground uses flat sorted list with filter pills, pal-e-app groups by type in card grid
note.html (Note detail) /notes/[slug] EXISTS -- NoteLayout with block renderer Redesign needed: need three-panel layout, left sidebar, backlinks
note-project.html (Project) /projects/[slug] EXISTS -- board summary + grouped notes Redesign needed: playground has three-panel layout, architecture diagram, repos table, board summary
note-board.html (Board) /boards/[slug] EXISTS -- kanban with DnD, filters, create/delete Mostly compatible: playground board is simpler (read-only display). pal-e-app board is more featureful.
graph.html (Graph) /graph MISSING New route + new component needed
-- /search EXISTS in pal-e-app See Conflicts section
-- /dashboard EXISTS in pal-e-app (DORA dashboard) Not in playground -- pal-e-app extra
-- /tags, /tags/[name] EXISTS in pal-e-app Not in playground -- pal-e-app extra
-- /repos EXISTS in pal-e-app Not in playground -- pal-e-app extra
-- /notes/[slug]/edit EXISTS in pal-e-app Not in playground -- pal-e-app extra

5. CSS Assessment

Playground app.css (819 lines) vs pal-e-app src/app.css (478 lines)

Shared design tokens:

  • Both use Atkinson Hyperlegible font
  • Both use --color-bg: #fafafa, --color-text: #1a1a1a, --color-accent: #0366d6
  • Same nav dark bar colors (--color-nav-bg: #1a1a1a)
  • Same border radius system (--radius-sm/md/lg)
  • Same transition speeds

Key CSS differences:

Aspect Playground pal-e-app Conflict Level
CSS Architecture Semantic BEM-style classes (.site-nav, .note-card, .block--paragraph) Tailwind-like utilities (.flex, .gap-2, .text-sm) + some semantic classes HIGH
Reset *, *::before, *::after { margin:0; padding:0; box-sizing:border-box; } No explicit reset (relies on browser defaults) Medium
Font size font-size: 0.9375rem; line-height: 1.7 line-height: 1.6 (no explicit size) Low
Token naming --color-surface, --color-accent-light, --color-pre-bg --color-card-bg, --color-card-border, --color-surface (partial overlap) Medium
Note type colors --type-plan: #d97706, --type-issue: #2563eb, etc. via CSS vars colors.ts TypeScript map: plan: '#b8860b', issue: '#2563eb' CONFLICT -- different values for same types
Block styling CSS classes: .block, .block--paragraph, .block--code, .code-header Scoped <style> in each Svelte component Medium
Layout Three-panel: .layout { display: flex } with .sidebar-left + .content + .sidebar-right Single-column with optional right sidebar via utility classes HIGH
Mobile breakpoint min-width: 600px (mobile-first) max-width: 600px (desktop-first for some rules) Medium
Board cards .board-card, .board-col with CSS vars for column colors Same concepts but utility-class-based in Svelte Medium
Utility classes Not used 200+ Tailwind-like utilities (.flex, .gap-2, etc.) HIGH

CSS assessment summary: The playground CSS is a complete, coherent design system with semantic class names and mobile-first breakpoints. The pal-e-app CSS is a hybrid of Tailwind-like utility classes and custom properties. The playground app.css should REPLACE the pal-e-app app.css, and components should be refactored to use playground class names instead of utility classes. This is the core CSS axiom from sop-frontend-experiment: "The CSS is never rewritten."

Color conflict detail: Playground uses CSS custom properties for type colors (--type-plan, etc.) while pal-e-app uses a TypeScript TYPE_COLORS map with different hex values:

  • plan: playground #d97706 vs app #b8860b
  • phase: playground #059669 vs app #0e8a5f
  • sop: playground uses --type-issue (#2563eb) vs app #c2185b
  • convention: playground uses --type-project (#7c3aed) vs app #b8860b

Decision: Playground CSS vars should be the source of truth. colors.ts should read from CSS vars or be replaced.


6. Conflicts

Conflict 1: Search page -- AC says "Search page spec added to playground" but ticket is read-only
The issue acceptance criteria include: "Search page spec added to playground (currently missing -- story:superuser-query)". This contradicts the "Read-only review -- no code changes" constraint. The search page already exists in pal-e-app (/search/+page.svelte) with keyword/semantic/hybrid modes, but has no playground prototype. Recommendation: Flag this as discovered scope for a separate ticket. The existing search page works but doesn't have a playground design to port FROM. Create a new playground HTML for search, then port.

Conflict 2: pal-e-app has features playground doesn't spec

  • /dashboard (DORA dashboard) -- detailed board analytics, needs-attention alerts, per-project breakdown. Not in playground.
  • /tags, /tags/[name] -- tag browsing. Not in playground.
  • /repos -- repo listing. Not in playground.
  • /notes/[slug]/edit -- note editor. Not in playground.
  • QuickJot -- floating action button + modal for quick note creation. Not in playground.
  • DnD on boards -- pal-e-app board has drag-and-drop item movement, inline create/delete. Playground board is read-only display.

Decision needed: Do these pal-e-app-only features survive the playground port, or do they need playground prototypes first? The SOP says "playground IS production" -- does that mean features without a playground page get removed?

Conflict 3: Layout architecture mismatch

  • Playground: three-panel layout (left sidebar + content + right sidebar) on desktop, single-column on mobile, with hamburger toggle for left sidebar
  • pal-e-app: single-column centered layout (max-width: 48rem; margin: 2rem auto) with optional right sidebar only on note detail
  • This is NOT a CSS tweak -- it's a structural change to +layout.svelte. The <main> wrapper changes from max-width-constrained to flex-panel-based.

Conflict 4: Dashboard identity

  • Playground / is "What changed recently?" dashboard (recent notes, projects, in-progress)
  • pal-e-app / is similar but styled differently
  • pal-e-app /dashboard is a separate DORA analytics page
  • Which is the "real" dashboard? Playground has no DORA concept.

Summary Table

Category Count
Block types matching 6/6
API endpoints matching 7/8 (1 path difference, functionally equivalent)
API gaps to fill 2 (links/backlinks endpoint client, note_count on projects)
Component gaps (new) 3 (Left sidebar, Graph view, Filter bar)
Component gaps (modify) 3 (Nav links, Right sidebar backlinks, Breadcrumb)
Route gaps 1 new (/graph), 5 redesigns
CSS conflicts HIGH -- full replacement needed, color value mismatches
Scope conflicts 4 (search page spec, pal-e-app-only features, layout architecture, dashboard identity)
## Alignment Review: Playground vs API vs pal-e-app Systematic comparison of all 6 playground HTML files, the pal-e-docs backend API, and the pal-e-app SvelteKit codebase. Read-only review -- no code changes. --- ### 1. Matches -- What Copies As-Is **Block types (6/6 match):** The playground uses 6 block types and the BlockRenderer dispatches all 6 identically: | Playground Block | BlockRenderer Case | Component | Status | |---|---|---|---| | `block--paragraph` | `block_type === 'paragraph'` | `ParagraphBlock.svelte` | MATCH | | `block-heading` (h2) | `block_type === 'heading'` | `HeadingBlock.svelte` | MATCH | | `block--code` | `block_type === 'code'` | `CodeBlock.svelte` | MATCH | | `block--table` | `block_type === 'table'` | `TableBlock.svelte` | MATCH | | `block--list` (ul/ol) | `block_type === 'list'` | `ListBlock.svelte` | MATCH | | `block--mermaid` | `block_type === 'mermaid'` | `MermaidBlock.svelte` | MATCH | **API endpoints (core reads all exist):** | Playground `@api` | Backend Route | API Client Function | Status | |---|---|---|---| | `GET /api/notes?sort=updated_at&limit=10` | `GET /notes` (orders by `updated_at desc`) | `listNotes({limit:10})` | MATCH | | `GET /api/notes?sort=updated_at&limit=50` | same endpoint | `listNotes({limit:50})` | MATCH | | `GET /api/notes/{slug}` | `GET /notes/{slug}` | `getNote(slug)` | MATCH | | `GET /api/notes/{slug}/blocks` | `GET /notes/{slug}/blocks` | `getNoteBlocks(slug)` | MATCH | | `GET /api/notes/{slug}/toc` | `GET /notes/{slug}/toc` | `getNoteToc(slug)` | MATCH | | `GET /api/notes?parent_slug={slug}` | `GET /notes?parent_slug=X` | `listNotes({parent_slug})` | MATCH | | `GET /api/projects` | `GET /projects` | `listProjects()` | MATCH | | `GET /api/boards/items?column=in_progress` | `GET /boards/activity?column=in_progress` | `listBoardActivity({column:'in_progress'})` | MATCH (path differs: playground says `/boards/items`, real is `/boards/activity`) | **Data contract fields -- notes:** - Playground `@data` for notes list: `{ slug, title, note_type, project, status, tags[], updated_at }` -- all present in `NoteSummary` schema (has `id, title, slug, is_public, note_type, status, parent_slug, position, project, tags, created_at, updated_at`). Playground is a subset. **MATCH.** - Playground `@data` for note detail: `{ title, slug, note_type, status, tags[], project, updated_at, parent_slug }` -- all in `NoteOut`. **MATCH.** - `blocks: Block[]` with types heading/paragraph/code/table/list/mermaid -- `BlockOut` returns `block_type, content, anchor_id, position`. **MATCH.** - `toc: { anchor_id, text, level }[]` -- `TocEntry` schema has exactly these 3 fields. **MATCH.** - `knownSlugs: Set<string>` -- `slugCache.ts` already fetches all slugs for autolink. **MATCH.** **Existing route structure:** | Playground Route | pal-e-app Route | Status | |---|---|---| | `/` (dashboard) | `/` (`+page.svelte`) | EXISTS | | `/notes` | `/notes` | EXISTS | | `/notes/[slug]` | `/notes/[slug]` | EXISTS | | `/boards/[slug]` | `/boards/[slug]` | EXISTS | | `/projects/[slug]` | `/projects/[slug]` | EXISTS | | `/graph` | -- | **MISSING** | --- ### 2. API Gaps **Gap A: `note_count` and `last_updated` on projects** - Playground dashboard `@data`: `projects: { slug, name, note_count, last_updated }[]` - Backend `ProjectOut`: returns `id, name, slug, platform, repo_url, is_public, page_note, created_at, updated_at` -- no `note_count` field - Current workaround: pal-e-app dashboard already fetches projects and sorts by `updated_at`. `note_count` would need either a new field on `ProjectOut` or a client-side count from notes list - **Severity: Low.** `updated_at` already present. `note_count` is nice-to-have; could be derived client-side by counting notes per project **Gap B: No `description` field on ProjectOut (used in playground project cards)** - Actually: `ProjectOut` does NOT have a `description` field in the schema. But the `Project` model likely has one since `projects/[slug]/+page.svelte` renders `project.description`. Let me check... The existing pal-e-app already renders `project.description` successfully, and the `Project` interface in `api-client.ts` includes `description: string | null`. So the field exists at the API level even if the formal Pydantic schema doesn't show it in the grep. **Non-issue.** **Gap C: `GET /notes/{slug}/links` not used by pal-e-app** - Playground note detail has a backlinks sidebar: `backlinks: { slug, title, note_type }[]` - Backend: `GET /notes/{slug}/links` exists in `links.py` -- returns outgoing + incoming links with `direction` field - pal-e-app: **Zero references to links/backlinks in any component.** No API client function for `getLinks()`. - **Severity: Medium.** The playground backlinks sidebar is a key UX element. Need to add `getLinks(slug)` to `api-client.ts` and wire into `NoteLayout.svelte`. **Gap D: No `sort` query parameter on notes endpoint** - Playground specifies `GET /api/notes?sort=updated_at&limit=10` - Backend: `list_notes()` always sorts by `updated_at desc` (hardcoded). There is no `sort` query param. - **Severity: None.** Default sort matches playground intent. No change needed. **Gap E: Playground board `@data` uses `forgejo_issue_url` on board items** - Backend `BoardItemOut` includes `forgejo_issue_url`. API client `BoardItem` type does NOT include it. - `api-client.ts` `BoardItem` interface is missing: `forgejo_issue_url`, `board_note_id` - **Severity: Low.** Fields exist in API responses but aren't typed in the client. Add to interface when board card links are implemented. --- ### 3. Component Gaps **Gap F: `callout` block type mentioned in playground data contract but not implemented** - `note.html` `@data` comment: `blocks: Block[] (any combination of: heading, paragraph, code, table, list, mermaid, callout)` - BUT: no actual `callout` block appears in the playground HTML, and BlockRenderer has no callout case - Backend block parser likely does not produce callout blocks either - **Severity: None currently.** The `@data` comment is aspirational. The `{:else}` fallback in BlockRenderer already handles unknown types gracefully. **Gap G: Nav component differences** - Playground nav: `Dashboard | Projects | Notes | Boards | Graph` (5 links) - pal-e-app nav: `Dashboard | Notes | Projects | Boards | Tags | Repos` (6 links, different order, no Graph) - Playground nav includes: hamburger menu, search input in nav bar, auth button - pal-e-app nav includes: search input in nav bar, auth buttons (Sign in/Sign out), QuickJot FAB - **Decision needed:** Nav link set and order. Tags/Repos are pal-e-app features not in playground. Graph is playground-only currently. **Gap H: Left sidebar component does not exist in pal-e-app** - Playground note detail and project page have a `sidebar-left` with: recently modified notes, parent/sibling hierarchy, project list - pal-e-app has NO left sidebar -- layout is single-column with optional right sidebar (TOC + children) - **Severity: High.** This is the biggest structural difference. The three-panel layout (left sidebar + content + right sidebar) at 600px+ is a core playground design that doesn't exist in pal-e-app. **Gap I: Right sidebar -- backlinks missing** - Playground right sidebar: TOC + Backlinks sections - pal-e-app `NoteLayout.svelte` right sidebar: TOC + Child Notes sections (no backlinks) - **Severity: Medium.** Backlinks need to be added (depends on Gap C API integration). **Gap J: `FilterBar` component does not exist** - Playground notes list and graph page have filter pills: `All | sop | convention | doc | project-page | board` - pal-e-app notes list has filter pills but implemented differently (URL-param based, grouped-by-type layout instead) - **Severity: Medium.** Playground filter bar is a toggle UI; pal-e-app has a different filter approach. Need to decide which pattern wins. **Gap K: `BoardProgress` summary component on project page** - Playground project page has a visual board progress bar with segmented colors and labels - pal-e-app project page has a board distribution bar (similar concept, different styling) - **Severity: Low.** Both exist, CSS differences only. **Gap L: `GraphView` component does not exist in pal-e-app** - Playground graph page is a hand-drawn SVG visualization with: force-directed-like layout, parent-child edges (solid), cross-reference edges (dashed), type-colored nodes, size-by-recency, legend, filter bar - pal-e-app has NO `/graph` route - **Severity: High for feature completeness.** Building a dynamic graph view will require a JS graph library (e.g., D3 force-directed) since the playground uses a static SVG. **Gap M: Breadcrumb component differences** - Playground: `Home > project > note-slug` - pal-e-app NoteLayout: `Home > Notes > project > parent > note-title` - **Severity: Low.** Minor path difference. --- ### 4. Route Gaps | Playground Page | Route | pal-e-app Status | Gap | |---|---|---|---| | `index.html` (Dashboard) | `/` | EXISTS -- home page with recent notes, projects, in-progress, board bars | **Redesign needed**: playground layout is fundamentally different (card-based with type badges vs list-based) | | `notes.html` (Notes list) | `/notes` | EXISTS -- grouped by type with search | **Redesign needed**: playground uses flat sorted list with filter pills, pal-e-app groups by type in card grid | | `note.html` (Note detail) | `/notes/[slug]` | EXISTS -- NoteLayout with block renderer | **Redesign needed**: need three-panel layout, left sidebar, backlinks | | `note-project.html` (Project) | `/projects/[slug]` | EXISTS -- board summary + grouped notes | **Redesign needed**: playground has three-panel layout, architecture diagram, repos table, board summary | | `note-board.html` (Board) | `/boards/[slug]` | EXISTS -- kanban with DnD, filters, create/delete | **Mostly compatible**: playground board is simpler (read-only display). pal-e-app board is more featureful. | | `graph.html` (Graph) | `/graph` | **MISSING** | New route + new component needed | | -- | `/search` | EXISTS in pal-e-app | **See Conflicts section** | | -- | `/dashboard` | EXISTS in pal-e-app (DORA dashboard) | Not in playground -- pal-e-app extra | | -- | `/tags`, `/tags/[name]` | EXISTS in pal-e-app | Not in playground -- pal-e-app extra | | -- | `/repos` | EXISTS in pal-e-app | Not in playground -- pal-e-app extra | | -- | `/notes/[slug]/edit` | EXISTS in pal-e-app | Not in playground -- pal-e-app extra | --- ### 5. CSS Assessment **Playground `app.css` (819 lines) vs pal-e-app `src/app.css` (478 lines)** **Shared design tokens:** - Both use Atkinson Hyperlegible font - Both use `--color-bg: #fafafa`, `--color-text: #1a1a1a`, `--color-accent: #0366d6` - Same nav dark bar colors (`--color-nav-bg: #1a1a1a`) - Same border radius system (`--radius-sm/md/lg`) - Same transition speeds **Key CSS differences:** | Aspect | Playground | pal-e-app | Conflict Level | |---|---|---|---| | **CSS Architecture** | Semantic BEM-style classes (`.site-nav`, `.note-card`, `.block--paragraph`) | Tailwind-like utilities (`.flex`, `.gap-2`, `.text-sm`) + some semantic classes | **HIGH** | | **Reset** | `*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }` | No explicit reset (relies on browser defaults) | Medium | | **Font size** | `font-size: 0.9375rem; line-height: 1.7` | `line-height: 1.6` (no explicit size) | Low | | **Token naming** | `--color-surface`, `--color-accent-light`, `--color-pre-bg` | `--color-card-bg`, `--color-card-border`, `--color-surface` (partial overlap) | Medium | | **Note type colors** | `--type-plan: #d97706`, `--type-issue: #2563eb`, etc. via CSS vars | `colors.ts` TypeScript map: `plan: '#b8860b'`, `issue: '#2563eb'` | **CONFLICT** -- different values for same types | | **Block styling** | CSS classes: `.block`, `.block--paragraph`, `.block--code`, `.code-header` | Scoped `<style>` in each Svelte component | Medium | | **Layout** | Three-panel: `.layout { display: flex }` with `.sidebar-left` + `.content` + `.sidebar-right` | Single-column with optional right sidebar via utility classes | **HIGH** | | **Mobile breakpoint** | `min-width: 600px` (mobile-first) | `max-width: 600px` (desktop-first for some rules) | Medium | | **Board cards** | `.board-card`, `.board-col` with CSS vars for column colors | Same concepts but utility-class-based in Svelte | Medium | | **Utility classes** | Not used | 200+ Tailwind-like utilities (`.flex`, `.gap-2`, etc.) | **HIGH** | **CSS assessment summary:** The playground CSS is a complete, coherent design system with semantic class names and mobile-first breakpoints. The pal-e-app CSS is a hybrid of Tailwind-like utility classes and custom properties. **The playground `app.css` should REPLACE the pal-e-app `app.css`**, and components should be refactored to use playground class names instead of utility classes. This is the core CSS axiom from `sop-frontend-experiment`: "The CSS is never rewritten." **Color conflict detail:** Playground uses CSS custom properties for type colors (`--type-plan`, etc.) while pal-e-app uses a TypeScript `TYPE_COLORS` map with different hex values: - `plan`: playground `#d97706` vs app `#b8860b` - `phase`: playground `#059669` vs app `#0e8a5f` - `sop`: playground uses `--type-issue` (#2563eb) vs app `#c2185b` - `convention`: playground uses `--type-project` (#7c3aed) vs app `#b8860b` Decision: Playground CSS vars should be the source of truth. `colors.ts` should read from CSS vars or be replaced. --- ### 6. Conflicts **Conflict 1: Search page -- AC says "Search page spec added to playground" but ticket is read-only** The issue acceptance criteria include: `"Search page spec added to playground (currently missing -- story:superuser-query)"`. This contradicts the "Read-only review -- no code changes" constraint. The search page already exists in pal-e-app (`/search/+page.svelte`) with keyword/semantic/hybrid modes, but has no playground prototype. **Recommendation:** Flag this as discovered scope for a separate ticket. The existing search page works but doesn't have a playground design to port FROM. Create a new playground HTML for search, then port. **Conflict 2: pal-e-app has features playground doesn't spec** - `/dashboard` (DORA dashboard) -- detailed board analytics, needs-attention alerts, per-project breakdown. Not in playground. - `/tags`, `/tags/[name]` -- tag browsing. Not in playground. - `/repos` -- repo listing. Not in playground. - `/notes/[slug]/edit` -- note editor. Not in playground. - `QuickJot` -- floating action button + modal for quick note creation. Not in playground. - DnD on boards -- pal-e-app board has drag-and-drop item movement, inline create/delete. Playground board is read-only display. **Decision needed:** Do these pal-e-app-only features survive the playground port, or do they need playground prototypes first? The SOP says "playground IS production" -- does that mean features without a playground page get removed? **Conflict 3: Layout architecture mismatch** - Playground: three-panel layout (left sidebar + content + right sidebar) on desktop, single-column on mobile, with hamburger toggle for left sidebar - pal-e-app: single-column centered layout (`max-width: 48rem; margin: 2rem auto`) with optional right sidebar only on note detail - This is NOT a CSS tweak -- it's a structural change to `+layout.svelte`. The `<main>` wrapper changes from max-width-constrained to flex-panel-based. **Conflict 4: Dashboard identity** - Playground `/` is "What changed recently?" dashboard (recent notes, projects, in-progress) - pal-e-app `/` is similar but styled differently - pal-e-app `/dashboard` is a separate DORA analytics page - Which is the "real" dashboard? Playground has no DORA concept. --- ### Summary Table | Category | Count | |---|---| | Block types matching | 6/6 | | API endpoints matching | 7/8 (1 path difference, functionally equivalent) | | API gaps to fill | 2 (links/backlinks endpoint client, `note_count` on projects) | | Component gaps (new) | 3 (Left sidebar, Graph view, Filter bar) | | Component gaps (modify) | 3 (Nav links, Right sidebar backlinks, Breadcrumb) | | Route gaps | 1 new (`/graph`), 5 redesigns | | CSS conflicts | HIGH -- full replacement needed, color value mismatches | | Scope conflicts | 4 (search page spec, pal-e-app-only features, layout architecture, dashboard identity) |
Author
Owner

Design Decisions (2026-03-27)

Based on the alignment review gap list and the design vision (Notion content + Obsidian navigation + activity-first):

  1. Layout: Sidebar — Adopt playground's left sidebar + main content layout wholesale. Replaces current top-nav + full-width. Matches Obsidian navigation pattern.
  2. Home: Dashboard — Playground dashboard (stats + activity) becomes the new home page. Notes list moves to /notes route.
  3. Existing features: Keep + restyle — Search, QuickJot, DORA dashboard, board management stay as-is. Restyle to match playground CSS. Don't break working features during port.
  4. CSS: Replace + nuke colors.ts — Playground app.css replaces pal-e-app's. Delete colors.ts — pure CSS custom properties only. TS intermediary breaks playground→production copy-paste.

These decisions unlock the SvelteKit port tickets.

## Design Decisions (2026-03-27) Based on the alignment review gap list and the design vision (`Notion content + Obsidian navigation + activity-first`): 1. **Layout: Sidebar** — Adopt playground's left sidebar + main content layout wholesale. Replaces current top-nav + full-width. Matches Obsidian navigation pattern. 2. **Home: Dashboard** — Playground dashboard (stats + activity) becomes the new home page. Notes list moves to `/notes` route. 3. **Existing features: Keep + restyle** — Search, QuickJot, DORA dashboard, board management stay as-is. Restyle to match playground CSS. Don't break working features during port. 4. **CSS: Replace + nuke colors.ts** — Playground `app.css` replaces pal-e-app's. Delete `colors.ts` — pure CSS custom properties only. TS intermediary breaks playground→production copy-paste. These decisions unlock the SvelteKit port tickets.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/pal-e-docs-app#65
No description provided.