Files
pad/web
xarmian 578494dc43 fix(web): break sse↔sync circular dep via callback inversion (TASK-1242) (#445)
Rolldown's stricter import diagnostics (introduced in TASK-1238 via
Vite 8) flagged that `sync.svelte.ts` was both statically imported
from 5 routes/components AND dynamically imported from `sse.svelte.ts`.
Rolldown's warning:

  [INEFFECTIVE_DYNAMIC_IMPORT] sync.svelte.ts is dynamically imported
  by sse.svelte.ts but also statically imported by [5 files], dynamic
  import will not move module into another chunk.

The original task body's first-cut fix ("convert the dynamic import
to static") was wrong: the dynamic import wasn't there for code-
splitting — the inline comment said "to avoid circular dependency",
and indeed sync.svelte.ts statically imports `sseService`, so a
reverse static import would close the cycle.

Real fix: callback inversion. Mirror the existing `onItemEvent`
pattern by adding `onSyncRequired(callback)` to sseService. Have
syncService subscribe in its `init()` instead of sseService calling
syncService directly. Net result:

  Before: sse  →(dynamic import)→ sync   ──╮
          sync ─(static import)─→ sse  ←──╯  (circular, papered over)

  After:  sse exposes onSyncRequired()
          sync subscribes on init(), receives sync_required pings
          sse has zero imports of sync.svelte.ts (static or dynamic)

Behavior is identical:
  • sse_required server event still triggers `syncService.triggerSync()`
  • sync.svelte.ts still owns the sync coordination decision tree
  • Init order is fine — both modules are evaluated as singletons at
    module-load time; subscription happens during syncService.init()
    which workspace +layout.svelte calls in onMount, well after both
    modules have settled

Verified:
  • `npm run build` — INEFFECTIVE_DYNAMIC_IMPORT warning is gone;
    Rolldown bundle build went from 5.91s → 2.90s as a bonus
  • `make check` — golangci-lint + go test + npm run build +
    svelte-check, 0 errors, same 6 pre-existing warnings
  • Manual UI verify — SSE still works (collection page real-time
    updates, child item progress, comments/reactions, timeline)

Spawned [[TASK-1243]] for a separate pre-existing bug surfaced during
this manual verify: the item DETAIL page never subscribed to
sseService.onItemEvent, so live title/field updates from other clients
don't propagate until manual refresh. Out of scope for this PR.
2026-05-08 08:15:44 -04:00
..
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00

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