Type to search pages and rules.

Browse pages

Browser Persistence

Browser storage is the only durable store in a client-only product.

Markdown9 provisions

Intent#

Browser storage is the only durable store in a client-only product. It is small and shared, and it can disappear. Access runs through one adapter, keys carry versions, and shapes migrate. The user can always export what they made.

Standards#

Own storage in Infrastructure#

ruleguidance

Requirement Browser storage MUST be reached only through an Infrastructure adapter implementing an Application-declared interface.

Rationale No Domain type, component, or page touches storage, so a test substitutes an in-memory implementation of the same interface.

litespec/frontend/blazor/browser#own-storage-in-infrastructure

Version and scope every storage key#

ruleguidance

Requirement A storage key MUST use the form {product}.{area}.v{n} and be declared once as a constant beside its adapter.

Rationale The version segment increments when the stored shape changes incompatibly. A raw string literal elsewhere in the code is a second, unversioned declaration.

Example shop.cart.v1 names its product, its area, and its shape version.

litespec/frontend/blazor/browser#version-and-scope-every-storage-key

Provide a migration for every changed shape#

ruleguidance

Requirement A change to a persisted shape MUST ship a migration that reads every previously released version and produces the current one.

Rationale The migration runs at startup before the store finishes loading. Data it cannot interpret is preserved under a quarantine key and reported. Deleting unreadable user data is not a recovery.

litespec/frontend/blazor/browser#provide-a-migration-for-every-changed-shape

Treat reads as fallible#

ruleguidance

Requirement A storage adapter MUST return a typed result covering unavailable, absent, corrupt, and present.

Rationale Storage can be full, disabled, or partitioned by the browser. The application starts and stays usable when it is unavailable, with durable writes disabled and the user told once.

litespec/frontend/blazor/browser#treat-reads-as-fallible

Bound what is stored#

ruleguidance

Requirement A specification persisting a growing collection MUST state its bound and its eviction rule.

Rationale Browser quotas are small and shared across the origin, so unbounded append eventually fails a write the user cannot diagnose. Large generated assets are cached by the service worker rather than written to key storage.

litespec/frontend/blazor/browser#bound-what-is-stored

Provide export and import#

ruleguidance

Requirement Durable state MUST export to one versioned file that imports the same version, transforms an older version, and refuses a newer version.

Rationale The user saves the file, which is the only recovery path in a product with no server. Device-local state is excluded from the export. The file carries its own schema version. A refusal names the application version that wrote the file. A partial import of an unknown shape loses data silently.

litespec/frontend/blazor/browser#provide-export-and-import

Conventions#

Select the storage mechanism per shape#

conventionguidance

Default Use key-value storage for small records, an indexed store for growing or multi-key collections, and the cache API for generated assets.

Replacement A consumer can replace this default with an explicit local convention.

Rationale Serializing a large collection into a single key-value entry rewrites the whole entry on every change.

litespec/frontend/blazor/browser#select-the-storage-mechanism-per-shape

Keep a stable serialization contract#

conventionguidance

Default Give persisted records explicit property names and tolerate unknown properties on read.

Replacement A consumer can replace this default with an explicit local convention.

Rationale A newer build writing an extra field then does not break an older build still installed on another device.

litespec/frontend/blazor/browser#keep-a-stable-serialization-contract

Record the classification#

conventionguidance

Default Store durable and device-local state under separate key prefixes.

Replacement A consumer can replace this default with an explicit local convention.

Rationale Export, clearing, and any future sync can then address each kind independently.

litespec/frontend/blazor/browser#record-the-classification

Verification#

IDMarkEvidence
litespec/frontend/blazor/browser#own-storage-in-infrastructureguidanceDoes every storage call resolve the Application interface?
litespec/frontend/blazor/browser#version-and-scope-every-storage-keyguidanceIs each key a declared constant carrying product, area, and version?
litespec/frontend/blazor/browser#provide-a-migration-for-every-changed-shapeguidanceDoes each changed shape ship a migration reading every released version?
litespec/frontend/blazor/browser#treat-reads-as-fallibleguidanceDoes the adapter return unavailable, absent, corrupt, and present as typed outcomes?
litespec/frontend/blazor/browser#bound-what-is-storedguidanceDoes each persisting specification state its collection bound and eviction rule?
litespec/frontend/blazor/browser#provide-export-and-importguidanceDoes an export reimport to identical durable state, refusing a newer version?
litespec/frontend/blazor/browser#select-the-storage-mechanism-per-shapeguidanceDoes each persisted shape use its declared mechanism?
litespec/frontend/blazor/browser#keep-a-stable-serialization-contractguidanceDoes a record with an unknown property still read?
litespec/frontend/blazor/browser#record-the-classificationguidanceDo durable and device-local keys use separate prefixes?