docs(loyalty): record 2026-05-23 Test 3 + cooldown bug + routing investigation
Some checks failed
CI / ruff (push) Successful in 17s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has been cancelled

End-of-day update. Three things in this session:

- Test 3 (staff stamps/points at terminal) — all 6 sub-steps verified
  on prod, including the new cooldown rejection and its localised
  toast. Tests 1-3 now done; Tests 4-8 ahead.

- Cooldown bug (93ab072f) + localised toast (aa8ca594) — points-based
  programs were silently bypassing program.cooldown_minutes because
  points_service.earn_points wrote last_points_at but never read it.
  Mirror the stamp check + raise new PointsCooldownException with
  error_code POINTS_COOLDOWN. Then localise the terminal toast in
  en/fr/de/lb (new cooldown_wait_minutes key) and propagate
  error.details through the apiClient so the catch site can render
  {minutes}.

- Routing investigation (no fix yet, queued for post-walkthrough) —
  user hit a 404 on .../platforms/loyalty/store/fashionhub/dashboard
  on the subdomain. Diagnosed 4 distinct bugs from path-based→
  subdomain/custom-domain drift (Mount 1 broken, server redirect
  store.py:86, JS login.js:155, sidebar URL builder). Ran the full
  middleware suite (185 tests pass) — depth on inbound resolution,
  zero coverage on outbound URL construction; that's why the bugs
  slip through. Scoped a Redirect Trace tool on /admin/platform-debug
  + matching integration tests as the regression net.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-23 23:44:23 +02:00
parent aa8ca59493
commit 78621cb7bb

View File

@@ -222,6 +222,51 @@ subtitle conditional the same way as the title:
- **Test 3** — Staff stamps/points at the terminal (`/store/FASHIONHUB/loyalty/terminal`)
- Items #3 (Hetzner doc check), #4 (unit tests for the B1-F chain), #5 (prospecting `tasks/__init__.py` missing import), #6 (other-module email audit) still queued from the 2026-05-17 follow-up list.
## 2026-05-23 update — Test 3 done + cooldown bug + routing investigation
### Test 3 (staff stamps/points at terminal) — all 6 sub-steps verified
Lookup by card-number AND by email both work; phone + birthday show correctly on the card detail (B1-D regression check passed); points earning credits; cooldown rejection fires (after the fix below).
### Cooldown bug fixed (`93ab072f`)
`stamp_service.add_stamp` properly checks cooldown before crediting. The parallel `points_service.earn_points` wrote `card.last_points_at` but **never read it** — so the program's `cooldown_minutes` was silently ignored for points-based programs. Mirrored the stamp check in `points_service` after the row lock; added `PointsCooldownException` with error_code `POINTS_COOLDOWN`.
### Cooldown toast localised (`aa8ca594`)
After the cooldown fix shipped, the FR-locale toast still showed the raw English from the backend. Three small changes:
- `static/shared/js/api-client.js` — propagate `error.details` (alongside `errorCode`) so callers can render localised toasts.
- `loyalty-terminal.js:277` — in the transaction-dispatch catch, branch on `errorCode === 'POINTS_COOLDOWN' | 'STAMP_COOLDOWN'` and render `loyalty.store.terminal.cooldown_wait_minutes` with `{minutes}` from `error.details.cooldown_minutes`; toast type switches to `warning` since the rejection is soft.
- New `cooldown_wait_minutes` key in en/fr/de/lb under `loyalty.store.terminal.*`.
### Routing investigation — 4 distinct bugs in path/host handling (not yet fixed)
User hit a 404 on `https://fashionhub.rewardflow.lu/platforms/loyalty/store/fashionhub/dashboard` after login, then noticed several other oddities. Diagnostics found four distinct routing-implementation bugs, all from the same architectural drift (path-based dev → subdomain/custom-domain prod):
1. **Mount 1 store-resolution broken on subdomain**`/store/login` returns "Failed to load store information" even though the route is mounted at `main.py:449-458` and the host should resolve the store via middleware. Workaround: use Mount 2 `/store/{STORE_CODE}/login`.
2. **Server-side post-login redirect leaks dev prefix**`app/modules/tenancy/routes/pages/store.py:86` builds `/platforms/{platform_code}/store/{store_code}/dashboard` on a subdomain hit (should pick the `:88` branch). Same pattern as B1-B but for redirects.
3. **JS post-login redirect uses wrong heuristic**`app/modules/tenancy/static/store/js/login.js:155-158` treats "platform_code is set" as "we're in path-based mode" and prepends `/platforms/{code}/` always. Should check `window.location.pathname.startsWith('/platforms/')` instead.
4. **Sidebar URL builder uses code-bearing form on subdomain** — works (Mount 2 also matches) but inconsistent with the canonical platform-debug pattern; adds visible cruft to URLs.
### Why didn't tests catch this?
Ran the full middleware suite (185 tests, 29s, all green). Confirmed thorough coverage of **inbound** resolution (host → platform/store, request.state population). **Zero coverage on outbound URL construction** — no test asserts post-login Location header, sidebar URLs, or Mount 1 actually serving on subdomain. The bugs exist precisely because nothing red-flags them.
### Platform-debug enhancement scoped (not implemented)
User suggested enhancing `/admin/platform-debug` to test redirects. My scope: add a 5th panel called **"Redirect Trace"** alongside Platform Trace, Domain Health, Permissions Audit, Tenant Isolation. Auto-runs the 12-row (host × URL-pattern) matrix the page already enumerates, simulates each via `httpx.AsyncClient(transport=ASGITransport(app=app))`, asserts the redirect Location vs the expected canonical. The same backing endpoint becomes the harness for `tests/integration/test_redirect_trace.py` so the 4 routing bugs would surface in red.
### Status board delta
- Step 6 (web user-journey E2E tests) — Tests 1 ✅, 2 ✅, **3 ✅** done. Tests 48 ahead.
### Carry over for next session
- **Test 4** — Cross-store redemption at FASHIONOUTLET with the card from Tests 1-3
- **Routing pass** (after Test 8 finishes so we don't churn mid-walkthrough): fix the 4 routing bugs in one focused commit, add the RedirectTrace admin tool + the corresponding integration test, update hetzner doc + user-journeys doc Case 3 to match the canonical platform-debug pattern.
- Existing follow-ups still queued: Hetzner doc check, B1-F unit tests, prospecting `tasks/__init__.py` missing import, other-module email audit.
## Status board
| # | Pre-launch step | State | Notes |