mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-11 13:28:57 +00:00
fbea9484d6
close() does not retract already-queued event tasks, so on a fast workspace switch a torn-down EventSource's queued events could fire after the next workspace's source existed. BUG-2540 guarded onopen / onerror / 'connected'; the remaining listeners had no guard, so workspace A's stale events dispatched into workspace B's callbacks — spurious sync passes and cross-workspace item events fanned onto B's BroadcastChannel, and the sharp member: a stale 'unauthorized' closed B's LIVE EventSource, flipped the status indicator, and cleared currentWorkspace over A's auth state, with nothing reconnecting until a navigation. Same one-line guard on all four (sync_required, items_bulk_updated, unauthorized, the ITEM_EVENTS loop); unauthorized additionally closes its OWN source rather than whatever eventSource currently points at — the guard has just proven they are the same, and the old shape is what made the stale path destructive. Unit harness (BUG-2540's stubbed-EventSource pattern): fast A→B switch, fire each event type on the torn-down source — zero dispatch into B — with a live-source control arm per leg so a guard silencing both cannot pass. All four legs verified failing on the unguarded build.
Pad Web UI
SvelteKit 2 + Svelte 5 frontend for Pad, compiled to static files and embedded into the Go binary.
Development
npm install
npm run dev # Dev server at localhost:5173 (proxies API to localhost:7777)
npm run build # Production build to build/
npm run check # Type checking with svelte-check
When developing, run the Go backend separately with make dev from the project root.
Building for Production
Do not build in isolation. Always use make build from the project root — this builds the web frontend, then compiles the Go binary with the build output embedded via //go:embed.
Stack
- Svelte 5 with runes (
$state,$derived,$effect) - SvelteKit 2 with
adapter-static(SPA mode) - Tiptap block editor with markdown round-trip
- svelte-dnd-action for drag-and-drop in board/list views
- SSE for real-time updates
- TypeScript throughout
Structure
src/
routes/ SvelteKit pages
+layout.svelte App shell (sidebar + main)
+page.svelte Landing/redirect
[workspace]/
+page.svelte Dashboard (collections, phases, activity)
+layout.svelte SSE connection per workspace
[collection]/
+page.svelte Collection view (board/list)
[collection]/[item]/
+page.svelte Item detail + editor
conventions/ Purpose-built conventions page
playbooks/ Purpose-built playbooks page
settings/ Workspace settings
lib/
api/client.ts HTTP API client
components/
layout/ Sidebar, navigation
editor/ Tiptap editor, raw markdown editor
fields/ FieldEditor, relation picker
items/ ItemCard, ItemDetail
collections/ BoardView, ListView
common/ StatusBadge, badges, modals
search/ CommandPalette
activity/ ActivityFeed
stores/ Svelte 5 reactive stores
workspace.svelte.ts Workspace state
collections.svelte.ts Collection + item state
ui.svelte.ts Sidebar, mobile state
types/index.ts TypeScript types and constants
app.css Global styles and design tokens