diff --git a/DECISIONS.md b/DECISIONS.md index 0794fc3..e1774e0 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1033,3 +1033,8 @@ Implementation decisions not spelled out in `memory-bank/implementation-plan.md` - **CR-001's text is amended in place** where the CR asks (goal 4, the deal, the modal, and the "hire first pilot" target now "buy a second ship"), with a note of what changed, so its history stays readable. - **The manual check was scripted** (`cr010-smoke.mjs`); its numbers confirm the deduction order: (1118 − 230) × 0.25 = 222 to the pilot, then 30 % of the remaining 896 (268, rounded down) to the lender, 628 credited. + +## CR-011 — Settings Screen and Company Backup (Phase 10K) + +- **Renumbered on arrival:** titled "CR-008 … Phase 10H"; CR-008 to CR-010 and Phases 10H–10J already exist, so it is **CR-011**, done as **Phase 10K** (its 10H.n are 10K.n). +- **Decisions** 0.5.53–0.5.58 are recorded as **0.5.71–0.5.76**; "account linking" is added to §0.3 (deferred). diff --git a/memory-bank/change-requests/CR-011-settings-backup.md b/memory-bank/change-requests/CR-011-settings-backup.md new file mode 100644 index 0000000..4c7a782 --- /dev/null +++ b/memory-bank/change-requests/CR-011-settings-backup.md @@ -0,0 +1,127 @@ +# 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.md` for schema or API changes and `progress.md` after 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. + +### 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. diff --git a/memory-bank/implementation-plan.md b/memory-bank/implementation-plan.md index 5a382ad..91acd66 100644 --- a/memory-bank/implementation-plan.md +++ b/memory-bank/implementation-plan.md @@ -36,7 +36,7 @@ This plan covers the **base game only**: the core loop of taking contracts, disp ### 0.3 Explicitly deferred (do NOT build) -Random events, reputation, fuel price variation, throttle setting, multi-leg routes, recurring bay rent, pilot salaries over time, pilot poaching, automation/standing routes, interstellar, push notifications, Capacitor builds, Hardened landing class, Venus/Io, Fragile/Urgent/Fuel-efficiency skills, social features, monetization. +Random events, reputation, fuel price variation, throttle setting, multi-leg routes, recurring bay rent, pilot salaries over time, pilot poaching, automation/standing routes, interstellar, push notifications, Capacitor builds, Hardened landing class, Venus/Io, Fragile/Urgent/Fuel-efficiency skills, social features, monetization, account linking (email, Apple, Google sign-in) *(CR-011)*. ### 0.4 Glossary @@ -126,6 +126,12 @@ These answer the pre-build review. Log each one in `DECISIONS.md` as it is imple 68. **Courier to Mars** (CR-009). A Courier with maxed fuel tanks can reach Mars at and around closest approach, but not at Mars's farthest distance. Base and lower-level Couriers still can't reach Mars at all. 69. **Deduction order** (CR-010). On resolution: pilot pay is taken from the payout first; loan repayment (0.5.32) is calculated on what remains. 70. **Veteran pilot** (CR-010). Accepting the deal also creates the veteran (CR-010 §2): at Earth, unassigned, level 2 with Heavy Cargo 1. The veteran is a normal hired pilot in every respect except how they were acquired. +71. **No accounts yet** (CR-011). Players remain guests. Account linking (email, Apple, Google) stays deferred (§0.3). +72. **Backup code** (CR-011). 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. +73. **Several devices** (CR-011). More than one device may be signed into the same player at once; the server is authoritative, so this is safe. +74. **New company** (CR-011). 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. +75. **Company name** (CR-011). Players can rename their company: 3–32 characters, letters, digits, spaces, and basic punctuation, trimmed. The default name is generated from the world seed. +76. **Display preferences** (CR-011). 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. --- @@ -604,6 +610,12 @@ Steps 10J.1–10J.7 are specified in `memory-bank/change-requests/CR-010-veteran --- +## Phase 10K — Settings Screen and Company Backup (CR-011) + +Steps 10K.1–10K.12 are specified in `memory-bank/change-requests/CR-011-settings-backup.md` §5 (written there as 10H.1–10H.12), with its §6 amendments. Done after Phase 10J and before Phase 11; stop for review at the end. + +--- + ## Phase 11 — PWA ### Step 11.1 — Installable PWA diff --git a/memory-bank/progress.md b/memory-bank/progress.md index 90ad95b..3a794a7 100644 --- a/memory-bank/progress.md +++ b/memory-bank/progress.md @@ -247,3 +247,20 @@ Spec: `memory-bank/change-requests/CR-010-veteran-pilot-profit-share.md` (receiv - [x] **Step 10J.5 — Client: deal modal and pilot card.** The deal modal says Halvorsen's pilot comes with the business and lists "Pilot: …and Rosa Kell. Halvorsen's pilot for twelve years." (from content). The veteran's Pilots card shows the bio line under the name. Test: `veteran-ui.test.tsx`. - [x] **Step 10J.6 — Client: pilot share in dispatch and summaries.** The dispatch sheet shows "Pilot share" between Fuel and Net profit for hired pilots (sim `pilotShare`), none for the avatar; net profit is payout − fuel − share. API `ResolutionSummary.pilotPay` (from the stored resolution); the away summary shows "[share] pilot share to [pilot]" when above zero. Test: `pilot-share.test.tsx`. - [x] **Step 10J.7 — Plan amendments and regression.** CR-010 §6 amendments: plan steps 2.1, 3.17, 9.5 and 12.1 (the 30–45 minute target is now the second ship), and CR-001 Steps 10A.5, 10A.8, 10A.13 and its §2 targets (decisions 0.5.12, 0.5.69–70 were set with the CR). Typecheck, lint, full suite with coverage (828 tests) and the web build are green. Scripted manual check against a live server (scratchpad `cr010-smoke.mjs`): after the deal Rosa Kell is at Earth, unassigned, level 2, Heavy Cargo 1; the avatar rests at Earth after six trips; swapped crews; Rosa flies a 20 t Machine Parts job needing Heavy Cargo 1 (the avatar has 0): payout 1118, fuel 230, pilot share 222, loan repayment 268, credits 628; goal 4 ready. **Phase 10J complete — stopped for review.** + +## Phase 10K — Settings Screen and Company Backup (CR-011) + +Spec: `memory-bank/change-requests/CR-011-settings-backup.md` (received as "CR-008 … Phase 10H"). New decisions recorded as plan §0.5.71–0.5.76. + +- [ ] Step 10K.1 — Client: device preferences store +- [ ] Step 10K.2 — Client: settings screen and entry point +- [ ] Step 10K.3 — Client: display options applied everywhere +- [ ] Step 10K.4 — Client: reset map view and show tips again +- [ ] Step 10K.5 — Server: rename company +- [ ] Step 10K.6 — Server: start a new company +- [ ] Step 10K.7 — Client: rename and new company flows +- [ ] Step 10K.8 — Server: backup code and restore +- [ ] Step 10K.9 — Client: backup and restore flows +- [ ] Step 10K.10 — Client: About and debug info +- [ ] Step 10K.11 — Client and server: developer tools (non-production only) +- [ ] Step 10K.12 — Plan amendments and regression