2026-01-18
Accounts, cloud save, and the F2P split

You can now make an account, sign in, and have your in-progress run follow you across devices. The auth piece is next-auth on the credentials provider with bcrypt-hashed passwords. No social sign-in. Less moving parts.
Cloud save is one row per user in a cloud_saves table — an entire RunState as JSONB plus an updatedAt timestamp. The client persists locally with Zustand, then a background sync component pushes the JSON to /api/run/save on every state change with debounce. On login, we pull the server copy and merge by recency.
The bigger decision was the F2P split, which I want in writing before the shop ships:
- Free, forever: the entire game. All classes (when they ship), all acts, every card, every relic, every event, every boss.
- Paid: cosmetics. Skins, card backs, name effects, map themes, avatar frames. Bundles for repeat customers.
What is notfor sale, ever: cards, relics, energy, progress unlocks, save slots, ascension levels, retries, stamina, daily lives. If I'm wrong about this commercially the project fails — that's a risk I'm taking deliberately.
Payment provider will be Lemon Squeezy when I get there. Until then a mock provider grants the cosmetic on purchase intent so I can build the surrounding UI without stalling on the API integration.