feat(persistence): local-first story persistence (IndexedDB + Supabase skeleton)
Remove Cloudflare D1 entirely (4 API routes, lib/db/, Drizzle config/migrations, drizzle-orm/drizzle-kit deps, wrangler D1/R2/KV bindings) and replace with browser-local-first architecture: Open-source build (IndexedDB, no auth): - lib/persistence/ 5-file module: types, idb adapter (zero-dep, fault-tolerant, post-open invalidation retry), localStore (CRUD + sync-reserved metadata + slim/rebuild + retention-cap eviction with tombstone reap + sync-state protection + last-resort bounded fallback), sessionSlim (voice strip + styleRef absent-delete), cloudStore (Supabase skeleton, server-only) - Autosave: persistence fingerprint (history.length:lastBeatCount:playerName), serial saveChain, failure rollback retry, replaySourceRef guard (prevents replayed shared stories from clobbering user saves) - clientStoryPersistence.ts: thin facade (SaveResult discriminated union) - Stories page: /[locale]/stories with 3-language i18n (zh-CN/en/ja) - Homepage: book icon entry point in header Commercial build (Supabase, skeleton only): - Single table public.stories (JSONB + RLS 4 policies on auth.uid()=user_id) - supabase/migrations/ DDL (idempotent) - cloudStore.ts server-only repository, AUTH_ENABLED short-circuit - Not wired to client this phase Featured stories: pure fallback (buildFallbackCards + localizeCards), no D1 Includes fixes from 3 rounds of subagent code-review (tasks 16-30): - CR1: autosave restructure, coerceOrientation, D1 comment cleanup - CR2: fingerprint+serial+rollback+replay guard, idb post-open retry, enforceRetentionCap latent defense, sessionSlim absent invariant - CR3: single-scene share guard (replaySourceRef), insert-beat fingerprint (beats.length), pass3 overflow double-count fix, detach gate unification
This commit is contained in:
+4
-30
@@ -59,34 +59,8 @@
|
||||
//
|
||||
// See .dev.vars.example for a full reference of all variables.
|
||||
// ────────────────────────────────────────────────────────────────────
|
||||
|
||||
// ── Cloudflare D1 database (story persistence — optional) ───────────
|
||||
// Not required for core gameplay. Uncomment and fill in your ID if needed:
|
||||
// wrangler d1 create infiplot-db
|
||||
// "d1_databases": [
|
||||
// {
|
||||
// "binding": "DB",
|
||||
// "database_name": "infiplot-db",
|
||||
// "database_id": "<your-d1-database-id>"
|
||||
// }
|
||||
// ],
|
||||
|
||||
// ── Cloudflare R2 bucket (asset storage — optional) ─────────────────
|
||||
// Not required for core gameplay. Uncomment if needed:
|
||||
// wrangler r2 bucket create infiplot-assets
|
||||
// "r2_buckets": [
|
||||
// {
|
||||
// "binding": "R2_BUCKET",
|
||||
// "bucket_name": "infiplot-assets"
|
||||
// }
|
||||
// ],
|
||||
|
||||
// ── Cloudflare KV namespace (reserved for future use) ───────────────
|
||||
// Uncomment if needed: wrangler kv namespace create KV
|
||||
// "kv_namespaces": [
|
||||
// {
|
||||
// "binding": "KV",
|
||||
// "id": "<your-kv-namespace-id>"
|
||||
// }
|
||||
// ]
|
||||
//
|
||||
// Story persistence is browser-local (IndexedDB) in the open-source build and
|
||||
// Supabase (Postgres) in the commercial build — no Cloudflare D1/R2/KV
|
||||
// bindings are used.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user