Add public-release plan (phases 7-10)

Phases: public repo & Docker (7), guest-first optional accounts (8),
production hardening (9), Render deploy (10). Confirmed decisions and
per-phase open questions recorded in each file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
This commit is contained in:
parththakkar106
2026-07-06 16:48:13 +05:30
co-authored by Claude Fable 5
parent db9f904222
commit 466d7bc0e4
5 changed files with 253 additions and 0 deletions
+71
View File
@@ -0,0 +1,71 @@
# Phase 8 — Optional accounts & multi-user
**Goal:** turn the single-user app into a multi-user one where **accounts are optional**:
a visitor can start playing instantly as a guest, and can register (email + password) at any
point to keep their adventures across devices/browsers. This is the largest phase — it touches
every router and most tables.
## Decisions (confirmed)
| Question | Answer |
|---|---|
| Auth method | **Email + password, optional** — guest sessions work without an account |
| Signup policy | **Open signup** (rate-limited) |
| LLM API keys | **BYOK + shared demo key** — users can paste their own key; users without one get limited turns on a server-funded key |
**Ask before implementing:**
- Demo-key specifics: which provider/key funds it, model whitelist (free models only?),
per-user turn/day cap, what the "out of demo turns" message says.
- Guest data retention: how long before unclaimed guest data is deleted (suggestion: 30 days
of inactivity).
- Password reset: skip for v1, or implement email-based reset (requires an email provider)?
## Data model
- [ ] `User` table: id, email (nullable — null means guest), password_hash (nullable),
created_at, last_seen_at, is_guest flag (derivable from email; keep explicit for clarity).
- [ ] Add `user_id` FK to: `Adventure`, `Scenario`, `Script`, `Settings` (and anything else
global today — audit `models.py`). Story cards/actions inherit scope via their parent.
- [ ] Settings becomes **per-user** (endpoint URL, API key, models, memory-bank config).
API key **encrypted at rest** (Fernet with a server-side `SECRET_KEY` env var).
- [ ] Migration (in `migrations.py` style): create a "local user", assign all existing rows to
it — a fresh clone/local install keeps working exactly as before.
- [ ] Demo/starter scenarios: mark as `user_id = NULL` + `is_public` so everyone sees them
(decide exact mechanism when implementing; seed via `seed_demo.py`).
## Auth & sessions
- [ ] Guest flow: first API call with no session → create guest User, set a signed, long-lived
httpOnly session cookie. No signup wall anywhere.
- [ ] Register: email + password (hashed with bcrypt/argon2) **upgrades the current guest user
in place** — same user_id, data automatically kept.
- [ ] Login: standard session issue; logging in from a fresh guest session with existing account
discards the empty guest (or merges — ask if guest has data).
- [ ] Session middleware/dependency: every router handler resolves `current_user`; **every query
filtered by `user_id`** (this is the bulk of the diff — go router by router).
- [ ] Rate limits on register/login endpoints (brute-force protection).
- [ ] Local/self-hosted mode stays frictionless: single auto-created local user, no login UI
unless `MULTI_USER=true` (env var) — resume demo runs multi-user, local clones don't care.
## Shared demo key (BYOK fallback)
- [ ] Server env vars: `DEMO_API_KEY`, `DEMO_ENDPOINT_URL`, `DEMO_MODEL_WHITELIST`,
`DEMO_TURNS_PER_DAY`.
- [ ] If a user has no API key configured: use demo key, restrict model picker to the whitelist,
count turns per user per day, friendly error + "add your own key in Settings" when capped.
- [ ] Turn counting includes memory-bank background calls (or disable memory bank on demo key —
decide when implementing).
## Frontend
- [ ] Auth UI: register/login modal or page, "Save your progress" nudge for guests (subtle,
e.g. in the header), logout, account menu.
- [ ] `api.js`: send cookies (`credentials: include`), handle 401 → re-establish guest session.
- [ ] Settings page: per-user; show demo-key status ("Using shared demo key — N turns left today").
## Exit criteria
Two different browsers hit the deployed app: each gets its own guest world (adventures invisible
to the other), both can play immediately on the demo key. One registers mid-adventure and its
data survives; logging in from the other browser shows the same account data. Local
`start.ps1` / `docker compose up` still works with zero auth friction.