Data model¶
Content items¶
Every authored thing is a ContentItem, a discriminated union on kind with nine variants. The content schema reference is generated from the schema package and lists every field.
The current SCHEMA_VERSION is 2.
Lifecycle¶
flowchart LR
d["Draft<br/>editable"] -->|"publish(changeNote)"| v["Version n<br/>immutable"]
v --> h["Head<br/>points at n"]
d -->|"archive"| x["Archived"]
| Node | Meaning |
|---|---|
| Draft | The single working copy per item. Saved with an etag; a stale etag raises ConflictError |
| Version n | A published snapshot. The next publish writes n+1; earlier versions stay for history |
| Head | The pointer the manifest and the player read |
| Archived | A flag on the head. Hidden from the manifest, not deleted |
IndexedDB¶
Database guidepost, version 1. An install made before the product rename is copied in on first start and the original is left in place (see upgrading). Stores:
| Store | Key | Holds |
|---|---|---|
apps |
appKey |
Application settings, origins, theme |
segments |
id |
Audience segments (in the schema, not evaluated) |
drafts |
id, index by-app |
Working copies |
versions |
key, index by-id |
Published snapshots |
heads |
id, index by-app |
Latest version and archived flag |
progress |
contentId |
Per-item progress for the local user |
assets |
sha256 |
Uploaded files, content addressed |
Settings live in storage.local. The frame registry and picker sessions live in storage.session.
Migrations¶
migrateItem upgrades older items when they are read. Index n in the migration table upgrades schema n to n+1. The only step today is 1 to 2, which adds tags and locale (default en-CA). The comment in the code states the rule: add a step, never edit one.
Bundle format¶
.guidepost.zip, read and written by BundleCodec:
| Entry | Content |
|---|---|
bundle.json |
The Bundle: schemaVersion, exportedAt, sourceMode, apps, segments, items |
assets/<sha256> |
Raw bytes of each referenced asset |
signature.json |
Optional. Read and returned; nothing verifies it today |
Items in an older bundle are migrated on read, not rejected. A zip without bundle.json is rejected. Import takes a conflict mode (skip, overwrite or new-version) and returns a report of what was imported, skipped, overwritten, versioned, plus missing references and the asset count.
Gotchas¶
- The
progressstore is keyed by content id only. There is one record per item per browser profile; version handling is in the engine's eligibility check, not the key. - Assets are content addressed, so the same file is stored once.
- A change to the database layout needs an IndexedDB version bump. None has been made yet.