# gandora storage contract The page keeps everything through one object, `db`, in `index.html`. Today it is IndexedDB in the browser; a backend replaces it by implementing the same four calls and pointing `db` at the new implementation. Nothing else in the page touches storage (`brain.js` reads through `db.all()` too). ``` db.put(row, store = "tracks") // create or replace, keyed by row.id db.all(store = "tracks") // every row, newest first (tracks by `made`, stations by `last`) db.del(id, store = "tracks") db.open() // internal; a backend adapter can drop it ``` Two stores. ## tracks ``` { id: "1760998800000-211979153", // spec.made + "-" + hash32(title); stable, made by the page made: 1760998800000, // ms epoch, when the DJ wrote it kept: false, // pinned by KEEP (the only pin) plays: 3, // play starts + loop passes blob: Blob, // the audio (FLAC from Venice, mp3 from Runware); a backend may return { url } instead spec: { // the song on paper: enough to re-render it anywhere title, tags, lyrics, bpm, key, energy, line, // what the DJ wrote (tags = the music prompt, <= 500 chars) seed, station, stationId, // where it came from reaction: "🔥 ❤️ \"less snare\" [skipped]", // the listener's reactions, in order; words quoted, skips bracketed guess: 0.71, // the taste net's prediction when it was cooked (optional) plays, id, made // mirrored for convenience } } ``` ## stations ``` { id: "s-1760998800000-211979153", // "s-" + ms + hash32(seed) seed: "rainy trains", name: "Platform Nine", // chosen by the DJ on the first track, then stable taste: { like: [...], avoid: [...], notes: [...] }, // last 8 of each, in words, fed to the DJ history: [ { id, title, tags, bpm, key, energy, reaction, made } ], // last 8 tracks, no blobs made: 1760998800000, last: 1761002400000, // touched on every play and reaction played: 23 } ``` ## what a backend adds - identity: rows are per listener; `/user/station/track` links need the listener in the key - `blob` as a URL the `