Skip to content

PWA: installable offline app with IndexedDB local storage - #2

Merged
shashankbl merged 1 commit into
mainfrom
shashankbl/pwa-local
May 20, 2026
Merged

PWA: installable offline app with IndexedDB local storage#2
shashankbl merged 1 commit into
mainfrom
shashankbl/pwa-local

Conversation

@shashankbl

Copy link
Copy Markdown
Contributor

Summary

A separate-architecture branch of PI-hub that turns the app into an installable, offline-capable PWA with all data stored locally on the device after install.

This branch deliberately diverges from `main`: `main` has the server-driven markdown-on-disk model (good for self-hosting or sharing seed data), while this branch is a single-user device-local SPA.

Architecture changes

Layer `main` this branch
Storage `content/*.md` on filesystem, accessed via API routes IndexedDB on the user's device (`lib/idb-store.ts`)
API routes `app/api/**` All deleted
PDF export Server route using `renderToBuffer` Client-side via `pdf().toBlob()` (`lib/pdf-client.ts`)
Installability Web app PWA: manifest + service worker, installable from browser
Offline Requires server Works fully offline after first load
Cross-device sync Edit + git commit + redeploy Backup → Restore via JSON/ZIP on the Settings page

What's new

  • PWA shell — `app/manifest.ts` registers PI-hub as an installable app (name, icons from `/logo.png`, `display: standalone`, dark theme color). Chrome/Edge show an Install button; iOS Safari supports Add to Home Screen.
  • Service worker — `@serwist/next` builds `public/sw.js` that caches the app shell. After first visit, navigation works offline and PDF generation is local.
  • IDB-backed store — same `useStore()` API, but `addProject`/`updateMember`/`assignProjectToCFP`/etc. now write to IndexedDB. Pages don't need changes.
  • Client-side PDF — Export PDF button generates the report in-browser, downloads via blob URL. Bundles `@react-pdf/renderer` into the `/projects/[id]` chunk.
  • Settings page at `/settings`:
    • Download backup (JSON, or ZIP containing JSON + per-entity markdown files)
    • Restore from a previously downloaded JSON or ZIP
    • Wipe all data (double-confirm; clears every IDB store on this device)
  • Sidebar gains a Settings link, pinned at the bottom next to Archives.

Trade-offs

  • Per-device data. Each install on each device has its own data. Use the Settings → Download → Restore flow to move between machines.
  • Per-browser-profile. Chrome profile A and Profile B see different data. Same applies to Incognito.
  • Browser storage eviction. IndexedDB can be evicted by the browser under severe disk pressure (rare). Settings → backup is the user's safety net.
  • No data sharing across PIs. This is a single-user model. `main` is the path if you need shared / multi-user / committable data.

Deployment

Same Next.js project; deploys to Vercel exactly like `main`. The PWA install button appears once the app is served over HTTPS. After install, the app runs offline.

Test plan

  • `npm install && npm run build` — production build compiles
  • `npm run lint && npm run typecheck` — clean
  • `npm run dev` → open http://localhost:3000 → confirm dashboard loads with empty state
  • Create a project, member, CFP — all persist after reload (IDB)
  • Assign member + CFP to a project, change CFP statuses, walk an archive + restore + delete cycle
  • Click Export PDF on a project — file downloads with clean layout
  • /settings → Download JSON → reload → confirm round-trip
  • /settings → Download ZIP, inspect: it contains `backup.json` plus `pi.md`, `projects/.md`, `members/.md`, `cfps/*.md`
  • /settings → Wipe everything → confirm IDB is empty
  • /settings → Restore from a backup → confirm data returns
  • Build, deploy to a Vercel preview, install the PWA from the deployed URL; reload it while offline → app loads and works
  • Verify `/manifest.webmanifest` and `/sw.js` are served at production paths

🤖 Generated with Claude Code

A PWA-mode rewrite of the storage layer for offline-capable, install-
to-device usage. After installing the app from any host, all data
lives locally on that device — no server, no Vercel filesystem.

Changes:
- Storage moved from filesystem markdown to IndexedDB (lib/idb-store.ts,
  using the idb package). Same Store/Project/Member/CFP shapes round-
  trip cleanly through object stores.
- lib/store.tsx replaces fetch() calls with direct IDB reads/writes;
  every page keeps its existing useStore() interface.
- API routes (app/api/**) deleted — no longer needed.
- PDF generation moved client-side via @react-pdf/renderer's pdf()
  API (lib/pdf-client.ts). The Export PDF button generates a blob
  in the browser and triggers a download.
- PWA manifest at app/manifest.ts (name, icons, theme, standalone
  display, start_url).
- Service worker via @serwist/next caches the app shell so the PWA
  launches and navigates offline after first install.
- New /settings page with Download (JSON or ZIP+markdown), Restore
  (JSON or ZIP), and Wipe-everything actions for moving data between
  devices.
- Sidebar gains a Settings entry next to Archives, both pinned to
  the bottom.
- lib/fs-store.ts deleted; report.tsx unchanged (works client- or
  server-side).

Trade-offs:
- Data is per-device, per-browser-profile. The PI moves between
  machines via Settings → Download backup → Restore on the other
  device.
- After install, the app needs no internet to function.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@shashankbl
shashankbl merged commit c1d5d6e into main May 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant