# Tasks: enterprise-browser-pwa **Change ID**: enterprise-browser-pwa **Package**: `@suaveplan/pwa` **Target path**: `browser/platform/pwa` **Prerequisite packages on Verdaccio**: `@suaveplan/cache-browser`, `@suaveplan/error`, `@suaveplan/logger`, `@suaveplan/schema-registry` --- ## 0. Pre-flight (non-negotiable) - [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each) - [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest. ## 1. Scaffold - [ ] Create directory tree per `proposal.md`. - [ ] `package.json` v0.0.0, `"sideEffects": false`. - `dependencies`: `@suaveplan/cache-browser workspace:^`, `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `@suaveplan/logger workspace:^`, `@suaveplan/schema-registry workspace:^`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`, `tslib catalog:build` - `devDependencies`: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `happy-dom catalog:testing`, `@playwright/test catalog:testing`, `@suaveplan/testing workspace:^` - Subpath exports: `"."`, `"./core/service-worker/service-worker"`, `"./core/sync-queue/sync-queue"`, `"./core/push-notifications/push-notifications"`, `"./core/install-prompt/install-prompt"`, `"./core/routing/routing"` - [ ] `tsconfig.json`, `vitest.config.ts` (pool: forks, happy-dom environment, `fileParallelism: false`). --- ## 2. Error codes - [ ] `SW_REGISTRATION_FAILED`, `SW_UPDATE_FAILED`, `PUSH_PERMISSION_DENIED`, `PUSH_UNSUPPORTED`, `SYNC_QUEUE_EXCEEDED`. - [ ] `registerPwaErrorCodes()` — call eagerly. --- ## 3. Types (`src/types/common.ts`) - [ ] `SwState`, `SwRegistrationOptions`, `SwRegistrationResult`, `PushPermission`, `PushSubscriptionResult`, `PushNotificationOptions`, `SyncQueueConfig`, `SyncQueueEntry`, `InstallPromptState`, `InstallPromptListener`. - [ ] Write `common.md`. --- ## 4. `SyncQueueEntry` schema (`src/schema/sync-queue-schema/`) - [ ] `sync-queue-schema.ts` — `SyncQueueEntrySchema` (method, URL, headers, body, metadata); `registerSyncQueueSchema()`. - [ ] Write `sync-queue-schema.md`. --- ## 5. SyncQueue storage backends (`src/core/sync-queue/storage/`) - [ ] `storage.ts` — `StorageBackend` interface: `enqueue`, `dequeue`, `getAll`, `clear`, `getDepth`. - [ ] `IndexedDBSyncStorage` via `@suaveplan/cache-browser`; `LocalStorageSyncStorage` fallback; `MemorySyncStorage` for tests. - [ ] Write `storage.test.ts`. Write `storage.md`. --- ## 6. `SyncQueue` (`src/core/sync-queue/`) - [ ] `sync-queue.ts` — composing `StorageBackend`; `enqueue()` validates via `SyncQueueEntrySchema`; throws `SYNC_QUEUE_EXCEEDED` over max. - [ ] `flush()` with exponential backoff; background-sync hook via `SyncManager` where supported. - [ ] Wire OTel metrics. - [ ] Write `sync-queue.test.ts` (enqueue, flush, backoff, clear, storage-backend swap). Write `sync-queue.md`. --- ## 7. `ServiceWorkerManager` (`src/core/service-worker/`) - [ ] `service-worker.ts` — register, unregister, update, skipWaiting, update-interval polling. - [ ] Throw `SW_REGISTRATION_FAILED` / `SW_UPDATE_FAILED` on failure. - [ ] Split tests into four files ≤ 500 lines: registration, update, lifecycle, events. - [ ] Write `service-worker.md`. --- ## 8. `PushNotificationManager` (`src/core/push-notifications/`) - [ ] `push-notifications.ts` — permission query, subscribe/unsubscribe, notify. - [ ] Throw `PUSH_PERMISSION_DENIED` / `PUSH_UNSUPPORTED` on failure. - [ ] Tests use real `PushManager` fixture via injectable adapter (no `vi.stubGlobal`). - [ ] Write `push-notifications.test.ts`, `push-notifications.md`. --- ## 9. `InstallPromptManager` (`src/core/install-prompt/`) - [ ] `install-prompt.ts` — capture `beforeinstallprompt`, expose `prompt()`, state listeners. - [ ] Wire OTel histogram `pwa.install_prompt_latency_ms`. - [ ] Write `install-prompt.test.ts`, `install-prompt.md`. --- ## 10. Routing DSL (`src/core/routing/`) - [ ] `routing.ts` — `swRoute(pattern, strategy)`, `networkFirst`, `cacheFirst`, `staleWhileRevalidate`. - [ ] Strategies accept `ttl`, `cacheName`, `fallback` options. - [ ] Write `routing.test.ts` (pattern matching, strategy selection). Write `routing.md`. --- ## 11. Integration test (`tests/integration.test.ts`) - [ ] `SyncQueue` with `MemorySyncStorage` — enqueue, flush, backend swap. - [ ] `ServiceWorkerManager` registration + update cycle. - [ ] Routing DSL: register routes, simulate fetch, assert strategy applied. --- ## 12. Playwright E2E (`e2e/pwa.spec.ts`) - [ ] Chromium, WebKit, Firefox. - [ ] SW install → page reload → SW active. - [ ] SW update → `skipWaiting` → new SW takes over. - [ ] `SyncQueue` survives page reload via IndexedDB backend. - [ ] Push subscribe/unsubscribe (no real push server needed — test the subscribe call). --- ## 13. Docs + verify - [ ] Write `.md` per module (≥200 words, API reference, examples). - [ ] Write `README.md` with IndexedDB migration guide, routing DSL reference. - [ ] `bunx turbo lint typecheck test --filter=@suaveplan/pwa` — green. - [ ] `bunx turbo test:coverage` — 100%. - [ ] No `@ts-expect-error` in `src/` or tests. No `vi.stubGlobal`. - [ ] Playwright E2E green on Chromium, WebKit, Firefox. - [ ] `bun scripts/publish.ts --package @suaveplan/pwa`. - [ ] Archive to `openspec/archive/2026-04-24-enterprise-browser-pwa/`.