88 lines
8.1 KiB
Markdown
88 lines
8.1 KiB
Markdown
# Tasks — enterprise-browser-storage-browser
|
|
|
|
> Every checkbox MUST reflect work actually done in this change. Do not retroactively tick boxes for work that was already in main when this change opened. Do not tick a box for a test that doesn't exist or doesn't pin the requirement it claims to verify. Retroactive ticking is the failure mode this template guards against.
|
|
|
|
## 1. Spec authoring
|
|
|
|
- [x] 1.1 Read `../suaveplan/enterprise/storage-browser.md` end-to-end
|
|
- [x] 1.2 Read `openspec/specs/storage/spec.md`
|
|
- [x] 1.3 Read `openspec/AGENTS.md` Sections 13 and 14
|
|
- [x] 1.4 Draft `proposal.md` from `openspec/templates/proposal.md`
|
|
- [x] 1.5 Fill in `## Source mapping` table — every requirement cites a line range OR appears in the "no source line" table with justification
|
|
- [x] 1.6 Draft `specs/storage/spec.md` from `openspec/templates/spec-delta.md`
|
|
- [x] 1.7 Every requirement in the spec delta carries a `**Verified by:**` line naming concrete `it(...)` titles
|
|
|
|
## 2. Implementation
|
|
|
|
- [x] 2.1 Scaffold `packages/browser/storage/storage-browser/` with directory tree per `proposal.md`
|
|
- [x] 2.2 Write `package.json` v0.0.0, `"sideEffects": false`
|
|
- Dependencies: `@suaveplan/storage workspace:^`, `@suaveplan/crypto workspace:^`, `@suaveplan/events workspace:^`, `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `@suaveplan/logger workspace:^`, `@suaveplan/broadcast-channel workspace:^`, `@suaveplan/schema-registry workspace:^`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`, `tslib catalog:build`
|
|
- DevDependencies: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `fake-indexeddb (^6.0.0) — must be added to catalog:testing before implementation`, `@playwright/test catalog:testing`, `@suaveplan/testing workspace:^`
|
|
- Subpath exports: `"."`, `"./indexeddb"`, `"./localstorage"`, `"./register"`, `"./types"`
|
|
- [x] 2.3 Write `tsconfig.json`, `vitest.config.ts` (pool: forks, `fileParallelism: false`)
|
|
- [x] 2.4 Implement `src/error-codes.ts`: `STORAGE_QUOTA_EXCEEDED`, `STORAGE_KEY_NOT_FOUND`, `STORAGE_ENCRYPTION_FAILED`, `STORAGE_COMPRESSION_FAILED`, `STORAGE_CONCURRENCY_CONFLICT`; `registerStorageBrowserErrorCodes()` called eagerly
|
|
- [x] 2.5 Implement `src/types/types.ts`: `StorageEntry`, `StorageMetadata`, `BatchOperation`, `StorageEvent`, `ListOptions`, `IndexedDBStorageConfig`, `LocalStorageStorageConfig`; write `types.md`
|
|
- [x] 2.6 Implement `src/indexeddb/store/store.ts`: IDB `openDB`, upgrade handler, CRUD transactions (`get`/`set`/`delete`/`clear`/`list`)
|
|
- [x] 2.7 Implement `src/indexeddb/ttl/ttl.ts`: proactive sweep via `requestIdleCallback` + `expiresAt` cursor; batch-delete expired rows
|
|
- [x] 2.8 Implement `src/indexeddb/migrations/migrations.ts`: `MigrationRunner` accepting step-wise callbacks by schema version
|
|
- [x] 2.9 Implement `src/indexeddb/adapter/indexeddb.ts`: `IndexedDBStorage` composing store + TTL + migrations; `batch(ops)` in single IDB transaction; optimistic concurrency via `updatedAt` compare-and-set; OTel metrics + BroadcastChannel invalidation
|
|
- [x] 2.10 Implement `src/localstorage/store/store.ts`: Base64+JSON envelope, namespace prefixing, CRUD
|
|
- [x] 2.11 Implement `src/localstorage/ttl/ttl.ts`: TTL expiry on read + periodic sweep
|
|
- [x] 2.12 Implement `src/localstorage/adapter/localstorage.ts`: `LocalStorageStorage` composing store + TTL; OTel metrics + BroadcastChannel invalidation
|
|
- [x] 2.13 Implement `src/wrappers/encrypted/encrypted.ts`: `EncryptedStorage` wrapping any `AbstractStorage`; AES-GCM via `@suaveplan/crypto`; throw `STORAGE_ENCRYPTION_FAILED` on key error
|
|
- [x] 2.14 Implement `src/wrappers/compressed/compressed.ts`: `CompressedStorage` with `CompressionStream` gzip above configurable threshold; throw `STORAGE_COMPRESSION_FAILED` on stream error
|
|
- [x] 2.15 Implement `src/sync/broadcast/broadcast-sync.ts`: `BroadcastStorageSync` emitting `set`/`delete`/`clear` on a typed channel
|
|
- [x] 2.16 Implement `src/observable/observe-storage/observe-storage.ts`: `observeStorage(storage, key): AsyncIterable<StorageEvent>` backed by BroadcastChannel
|
|
- [x] 2.17 Implement `src/register.ts`: `registerIndexedDBStorage()` and `registerLocalStorageStorage()` — explicit factory registration, intentionally not a side-effect
|
|
- [x] 2.18 Wire OTel metrics: counter `storage.<operation>_total{backend}`, histogram `storage.op_ms{backend,operation}`, counter `storage.ttl_evictions_total`
|
|
|
|
## 3. Tests
|
|
|
|
- [x] 3.1 Unit tests at `src/indexeddb/store/store.test.ts`: CRUD, concurrent transactions (fake-indexeddb)
|
|
- [x] 3.2 Unit tests at `src/indexeddb/ttl/ttl.test.ts`: sweep deletes expired, leaves fresh
|
|
- [x] 3.3 Unit tests at `src/indexeddb/migrations/migrations.test.ts`: versioned upgrade callbacks
|
|
- [x] 3.4 Unit tests at `src/indexeddb/adapter/indexeddb.test.ts`: full CRUD, TTL, batch, concurrency conflict, cross-tab invalidation event, quota exceeded
|
|
- [x] 3.5 Spec-conformance tests at `src/indexeddb/adapter/indexeddb.spec-conformance.test.ts`: type-level conformance, OTel metric assertions with real MeterProvider, strict-mode behaviours
|
|
- [x] 3.6 Unit tests at `src/localstorage/store/store.test.ts`: Base64 round-trip, namespace isolation
|
|
- [x] 3.7 Unit tests at `src/localstorage/ttl/ttl.test.ts`: expiry on read, sweep
|
|
- [x] 3.8 Unit tests at `src/localstorage/adapter/localstorage.test.ts`: full CRUD, TTL, namespace, broadcast events
|
|
- [x] 3.9 Unit tests at `src/wrappers/encrypted/encrypted.test.ts`: encrypted round-trip, raw storage sees ciphertext
|
|
- [x] 3.10 Unit tests at `src/wrappers/compressed/compressed.test.ts`: large payload compressed, small payload passes through
|
|
- [x] 3.11 Unit tests at `src/sync/broadcast/broadcast-sync.test.ts`: cross-tab invalidation event, clear event propagation
|
|
- [x] 3.12 Unit tests at `src/observable/observe-storage/observe-storage.test.ts`: iterator yields on remote mutation, iterator completes on abort
|
|
- [x] 3.13 Unit tests at `src/register.test.ts`: import does not register, explicit registration works
|
|
- [x] 3.14 Unit tests at `src/error-codes.test.ts`: all codes registered
|
|
- [x] 3.15 Integration test at `tests/integration.test.ts`: both adapters via same `AbstractStorage` interface; encrypted + compressed wrappers stacked over IndexedDB; batch operations atomicity. ≤500 lines.
|
|
- [x] 3.16 Playwright E2E at `e2e/storage-browser.spec.ts`: Chromium, WebKit, Firefox; cross-tab invalidation; quota-exceeded guard surfaces `STORAGE_QUOTA_EXCEEDED`; encrypted payload not readable in raw IDB
|
|
- [x] 3.17 Every `it(...)` carries `{ timeout: 5000 }` (or 30000 for genuinely async)
|
|
|
|
## 4. Documentation
|
|
|
|
- [x] 4.1 Sibling `.md` for every implementation `.ts` (≥200 words, basic + advanced examples, full API reference)
|
|
- [x] 4.2 Root `README.md` with subpath table, cross-tab guide, wrapper composition, links to every co-located `.md`
|
|
- [x] 4.3 Update `CLAUDE.md` package listing if this is a new package
|
|
|
|
## 5. Pre-archive verification (the 5-gate triple)
|
|
|
|
- [x] 5.1 `bun run check` — Biome 0 errors / 0 warnings / 0 info across the whole monorepo
|
|
- [x] 5.2 `bunx turbo lint typecheck test --filter=@suaveplan/storage-browser` — green
|
|
- [x] 5.3 `bunx turbo test:coverage --filter=@suaveplan/storage-browser` — 100/100/100/100
|
|
- [x] 5.4 `bun scripts/openspec-conformance.ts @suaveplan/storage-browser` — exit 0, no `error` findings
|
|
- [x] 5.5 `bunx turbo build --filter=@suaveplan/storage-browser` — green
|
|
|
|
## 6. Pre-archive 7-row checklist (AGENTS.md Section 13)
|
|
|
|
- [x] 6.1 Generics threaded; `expectTypeOf` assertions on every literal-type claim
|
|
- [x] 6.2 Zod schemas wired at every declared boundary
|
|
- [x] 6.3 Every error code in `error-codes.ts` thrown by at least one production path
|
|
- [x] 6.4 Strict-mode behaviors tested both on and off
|
|
- [x] 6.5 OTel instruments emitted from production paths and asserted with a real in-memory `MeterProvider`
|
|
- [x] 6.6 Lifecycle dedup tested where claimed (in-flight Promise, idempotent set/load)
|
|
- [x] 6.7 No retroactive tick — every box above reflects work done in this change
|
|
|
|
## 7. Archive
|
|
|
|
- [x] 7.1 Fold spec delta into `openspec/specs/storage/spec.md`
|
|
- [x] 7.2 Move `openspec/changes/enterprise-browser-storage-browser/` → `openspec/archive/<yyyy-mm-dd>-enterprise-browser-storage-browser/`
|
|
- [x] 7.3 Refresh `MANIFEST.md` if package set or deps changed
|