iSpotly · data architecture · as-built 2026-07-17
Nothing the player sees reads the Google Sheet live. Every tab flows through one service — sheetCache — that holds it in memory, serves it instantly, and refreshes from the Sheet in the background. So a Sheet edit is never live on the spot: it lands when the cache rolls or an admin busts it. This is the whole map.
Endpoints are live — click one to open the real production JSON in a new tab. Parameterized routes use working example ids (pack 4, song 1, lang=en, terms 3/4).
| Sheet tab | Server cache · TTL | Endpoint(s) | Client surface | Bust it now? |
|---|---|---|---|---|
| SongsDBthe song catalog + stems | songs · 15 min | /api/launch /api/song /api/freeplay/songs /api/songs/random · sign-in only | Daily game, Free Play, QuickPlay pool + client cache 5 min |
yesinvalidate("songs") |
| Packspack defs, price, FreeSongs, section | packs · 15 min | /api/packs /api/packs/:id · eg 4 /api/packs/:id/songs/:n · eg 4/1 | Play More, pack page, pack songs client: list 10 min / pack page 24 HRS |
yesinvalidate("packs") — but a DB pack row overrides the Sheet |
| TOTD-Pickerthe daily-song schedule | totd · 5 min | drives selection → DB → /api/launch (resolveSong) | Today's daily song + enrichedSong 15 min + client 5 min |
yesinvalidate("totd") — but the hourly DB sync must run for it to take effect |
| Genresfather genres + genre picks | genres · 1 hr | /api/songs/random/metadata | QuickPlay genre picker | yesinvalidate("genres") |
| Translationsall app copy, 15 languages | translations · 5 min | /api/translations?lang · eg en | Every piece of text in the app merged over the baked bundle, once per session |
no bustwaits out TTL / hourly sync job only |
| Termsimage URLs, config values, lists | terms · 1 hr | /api/terms/:t/:s · eg 3/4 + OG image inject | Stat tiles, survival cover, socials, share image client snapshot persists across sessions |
no bustTTL only — no invalidation path |
| IntroGamesonboarding intro config | introgames · 30 min | /api/intro | First-visit intro game | no bustTTL only + no empty-guard (can cache blank) |
| Country&Languagegeo → language / intro targeting | countryLang · 6 hrs | /api/intro (targeting) | Which intro/lang a country gets | no bustTTL only + no empty-guard |
| TOTD-Archiveformula table — the schedule ledger | job read/write | jobs only (not a live endpoint) | Records the planned daily songs written by the selection + sync jobs |
n/aformula table — never append rows |
The service · sheetCache
Why "I edited the Sheet and nothing changed"