12 KiB
Change Request CR-011 — Settings Screen and Company Backup
Numbering note (added when implemented): this request arrived titled "CR-008 — Settings Screen and Company Backup" for "Phase 10H", applying to "CR-001 through CR-007". CR-008 to CR-010 and Phases 10H–10J already existed, so it is stored as CR-011 and done as Phase 10K: every "10H.n" below means 10K.n. Its decisions 0.5.53–0.5.58 are recorded as 0.5.71 No accounts yet, 0.5.72 Backup code, 0.5.73 Several devices, 0.5.74 New company, 0.5.75 Company name, 0.5.76 Display preferences (0.5.53–0.5.70 were in use). Decision 0.5.18 (testable clock, clock-offset endpoint) is the same number here. "CR-001 through CR-007" means the build as it stands (CR-001 to CR-010).
Project: Deadhead: Space Freight Tycoon
Applies to: a build with Phases 1–10 and CR-001 through CR-007 complete
Do this: as Phase 10H, after Phase 10G and before Phase 11
Related docs: implementation-plan.md, the earlier change requests, DECISIONS.md
1. Why
There is no place for player preferences, no way to start over (needed constantly for playtesting), and no protection against losing a company.
Accounts: no sign-up. Players keep starting instantly as a guest. But a guest company currently lives only in a session on one device: clearing browser data, reinstalling the PWA, or switching phones loses it for good, and the GDD promises web and mobile can share one company. So this change adds a lightweight backup code instead of accounts: the player can view a code and enter it on any device to restore their company. No email, no password, no third-party sign-in. Full account linking stays deferred.
2. What's on the screen
The screen opens from a gear icon in the header, not a new bottom-nav tab (the bottom nav is already full).
| Section | Items |
|---|---|
| Company | Company name (rename) · Back up company (show backup code) · Restore a company (enter code) · Start a new company |
| Display | Clock: 12-hour / 24-hour · Countdowns: real time / game time / both · Reduced motion (on/off) |
| Help | Reset map view · Show tips again |
| About | Game version and build · Copy debug info |
| Developer | Only in non-production builds: advance clock, add credits, finish all flights |
No Notifications section until push notifications exist. Don't add placeholder items.
3. Rules for this change
- All rules in
implementation-plan.md§0.1 apply: steps in order, one commit per step, each step's test must pass. - Display and Help settings are device preferences. Store them on the device (local storage), not on the server. Wrap every storage read and write so the app works with defaults if storage is unavailable.
- Company settings are server data and go through the API with the usual validation and row locks (Step 6.14).
- Destructive actions (new company, restore over an existing company) always require explicit confirmation.
- Update
architecture.mdfor schema or API changes andprogress.mdafter every step. - Stop for the user's review at the end of Phase 10H.
4. Decisions
Record these in DECISIONS.md and implementation-plan.md §0.5.
- 0.5.53 No accounts yet. Players remain guests. Account linking (email, Apple, Google) stays deferred (add to §0.3).
- 0.5.54 Backup code. Each player can have one backup code: random, at least 80 bits of entropy, shown as groups of letters and digits that avoid look-alike characters (no 0/O, 1/I/L). The server stores only a hash. Generating a new code invalidates the old one. Entering a valid code on any device signs that device into the same player. Restore attempts are rate-limited per IP and per device.
- 0.5.55 Several devices. More than one device may be signed into the same player at once; the server is authoritative, so this is safe.
- 0.5.56 New company. Starting a new company deletes all of the player's company data and recreates the starting state exactly as guest creation does (CR-001 tutorial state, new world seed). The player record and backup code stay the same.
- 0.5.57 Company name. Players can rename their company: 3–32 characters, letters, digits, spaces, and basic punctuation, trimmed. The default name is generated from the world seed.
- 0.5.58 Display preferences. Clock defaults to the device's locale format. Countdowns default to "real time". Reduced motion defaults to the device's reduced-motion setting and can be overridden.
5. Steps — Phase 10H
Step 10H.1 — Client: device preferences store
- Add a small preferences store for: clock format, countdown format, reduced motion, dismissed tips, and saved map camera. Defaults per decision 0.5.58. Persist to local storage, with every read and write wrapped so failures fall back to defaults silently.
- Test: With empty storage, defaults are returned (locale clock, real-time countdowns, reduced motion matching a mocked OS setting). Saved values survive a reload. With storage access mocked to throw, the store still works in memory and no error reaches the UI.
Step 10H.2 — Client: settings screen and entry point
- Add a gear icon to the header that opens the Settings screen with the sections in §2. The Developer section renders only in non-production builds.
- Test: Component test: the gear opens Settings; all sections render; the Developer section is absent when the build mode is production.
Step 10H.3 — Client: display options applied everywhere
- Route every clock display through one time-format helper that respects the clock preference.
- Route every countdown (arrivals, rest, shop time, board refresh, contract expiry, priority windows) through one countdown helper that shows real time, game time, or both ("4m 16s · 4.3 game h").
- Reduced motion turns off: map background parallax, animated screen transitions, and decorative pulses. Ships still move on the map, but without easing or trails.
- Test: Unit tests for both helpers in each mode. Component test: switching the clock to 24-hour changes the HQ clock; switching countdowns to "both" changes a contract card's expiry text. With reduced motion on, the map's parallax factor is zero.
Step 10H.4 — Client: reset map view and show tips again
- "Reset map view" restores the default camera (centered, default zoom) and clears the saved camera.
- "Show tips again" clears the dismissed-tips list so one-time hints (for example the CR-001 intro card) can show again.
- Test: Component test: after panning and resetting, the camera matches the default. After clearing tips, a previously dismissed tip renders again.
- Amended by CR-017: A second one-time tip, the skill point pop-up (
skill-points), which "Show tips again" also brings back (Step 17.6).
Step 10H.5 — Server: rename company
- Add a "rename company" endpoint per decision 0.5.57. Player state includes the company name.
- Test: A valid name is saved and trimmed. Names that are too short, too long, or contain disallowed characters are rejected with a validation error and nothing changes.
Step 10H.6 — Server: start a new company
- Add a "new company" endpoint per decision 0.5.56, in one transaction with the company row lock. Delete ships, pilots, bays, discovered locations, boards, accepted contracts, dispatches, upgrades, goals, and loan state; then create the starting state with the same code path as guest creation.
- Scheduled arrival jobs for deleted dispatches must do nothing when they fire.
- Test: A mid-game player who starts a new company ends up with exactly the guest starting state (tutorial on, loaner and avatar at Earth, starting credits, Earth and Moon discovered) and a different world seed. Their old dispatches' arrival jobs run without error and change nothing. The player's backup code still restores this player.
Step 10H.7 — Client: rename and new company flows
- Company name is editable in place with inline validation.
- "Start a new company" opens a confirmation that explains everything will be lost and requires typing the current company name to enable the button. After success, the app goes to the tutorial start (Contracts with the intro card).
- Test: Component test: the confirm button stays disabled until the exact company name is typed; confirming calls the endpoint and navigates to the tutorial start.
Step 10H.8 — Server: backup code and restore
- Add endpoints: "get or create backup code" (returns the existing code only at creation time; afterwards the player can regenerate it, which shows the new code once), and "restore with code" (unauthenticated; on success, signs this device into the matching player).
- Store only a hash of the code. Rate-limit restore attempts.
- Test: A generated code restores the same player on a second session, and both sessions see the same state. Regenerating invalidates the old code. A wrong code fails with a generic error. Exceeding the attempt limit returns a rate-limit error. The database never contains the plain code.
Step 10H.9 — Client: backup and restore flows
- "Back up company" shows the code in large, grouped text with a Copy button and the line "Keep this somewhere safe. Anyone with this code can open your company." If a code already exists, offer "Generate a new code" with a warning that the old one stops working.
- "Restore a company" appears in Settings and on the start screen (under "Start your company"). Entering a code over a company that has progress past the tutorial shows a warning: "This device's current company will be left behind. Back it up first if you want to keep it."
- After a successful restore, the app reloads player state and goes to HQ.
- Test: Component test: the code displays grouped and Copy writes it to the clipboard; the restore warning appears only when the current company is past the tutorial; a successful restore navigates to HQ; a failed restore shows the error without leaving the screen.
Step 10H.10 — Client: About and debug info
- Show the game version and build (from the build), and a "Copy debug info" button that copies: version, build, player id, current server time, server clock offset, and current screen.
- Test: Component test: the version renders; Copy writes a text block containing all listed fields.
Step 10H.11 — Client and server: developer tools (non-production only)
- Developer section actions: advance the clock by 10 minutes or 1 hour (using the existing test-only clock-offset endpoint, decision 0.5.18), add 10,000 credits, and finish all flights now (advances the clock to the latest arrival).
- Add a test-only "add credits" endpoint registered only in non-production mode, like the clock-offset endpoint.
- Test: In development mode, each action changes state as described. In production mode, the add-credits and clock-offset endpoints return not-found and the Developer section doesn't render.
Step 10H.12 — Plan amendments and regression
- Apply the amendments in §6 to
implementation-plan.md. - Run the full suite.
- Test: CI is green. Manual check: back up a mid-game company, restore it in a private browser window and confirm the same state; then start a new company on one device and confirm the other device sees the new company after refresh.
6. Amendments to implementation-plan.md
| Step | Change |
|---|---|
| 0.3 | Add "account linking (email, Apple, Google sign-in)" to deferred. |
| 0.5 | Add decisions 0.5.53–0.5.58. |
| 4.2 | Route catalog gains: rename company, new company, get/regenerate backup code, restore with code, and the non-production add-credits endpoint. |
| 5.3 | Store the backup code hash and company name. |
| 8.1 | Header gains the Settings gear. |
| 8.4 | Start screen gains "Restore a company". |
| 11.2 | Settings that need the server are disabled while offline; display and help settings still work. |
| 12.x | End-to-end tests may use "Start a new company" and the developer tools to reset and fast-forward. |
7. Out of scope
Account sign-up or sign-in of any kind, push notification settings, sound and music settings (there is no audio yet), language selection, multiple company save slots, cloud export/import of save files, and anything else in implementation-plan.md §0.3.