mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-26 22:37:03 +00:00
8eb4519fe7
* feat(editor): a tab that dies with unconfirmed edits offers them on the next open (TASK-3606) The unload prompt and teardown flush never run when a tab dies outright (a mobile process kill, a browser crash). This is the simple alternative to IDEA-3494's Y.Doc persistence: nothing CRDT-shaped is stored. - crashDraft.ts: while the open item holds edits the server may not have (editsAtRiskOnClose, or a dirty raw editor), its markdown is kept every 2s in the kept-draft store with the seq and body it was edited from. It is cleared only when the same item reports nothing at risk and the kept text is still its own. Switching items clears nothing. Bodies over 1M characters are not kept, and nothing is kept during a confirmed sign-out discard. - refusedRawDraft: optional baseSeq/baseBody (back-compatible). A full store sweeps expired drafts, evicts the user's oldest other one, and retries once. Storage stays localStorage: on :7777 the largest body is 158K chars (about 316 KB UTF-16) against a ~5 MB quota (design note on TASK-3606). - The next open offers it through the existing notice and expected_seq restore. The notice is producer-neutral now. When the item has moved past the draft's base seq, it warns that restoring replaces the newer version and makes Copy the primary button (lead ruling). baseBody is stored for the follow-up "apply my changes" restore. Claude-Session: https://claude.ai/code/session_01FAVXA5mJ5BNhKmv95jxQkQ * perf(editor): the crash-draft keeper serializes only when the document changed (TASK-3606 codex r1) Every tick while edits were at risk serialized the whole document, even an unchanged one. The provider now counts every doc update (docVersion, local and remote), and the keeper skips serializing while that version, or a raw editor's pending text, matches its last write. Claude-Session: https://claude.ai/code/session_01FAVXA5mJ5BNhKmv95jxQkQ * fix(editor): a crash draft is never filed under a user who did not type it (TASK-3606 codex r2) The keeper keys drafts by the signed-in user. After an identity change, and before the reload re-stamps identityEpochAtLoad, the editor still held the previous user's text. The snapshot now returns nothing unless the identity is the one the item was loaded under, the teardown flush's own fence. The identity listener already keeps that text for its author. Claude-Session: https://claude.ai/code/session_01FAVXA5mJ5BNhKmv95jxQkQ * test(items): the identity-epoch census names the crash-draft snapshot's fence (TASK-3606) The page-load epoch is read at six sites now. The sixth is crashDraftSnapshot's guard, which keeps a previous user's typing out of the next user's draft key (codex round 2 on #2086). Claude-Session: https://claude.ai/code/session_01FAVXA5mJ5BNhKmv95jxQkQ
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
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