Files
suaveplan/openspec/changes/enterprise-browser-pwa/tasks.md
2026-05-27 23:29:53 +01:00

127 lines
5.8 KiB
Markdown

# 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/`.