docs(loyalty): record 2026-05-29 Test 5.0 i18n sweep + FR/DE email accents
All checks were successful
CI / ruff (push) Successful in 19s
CI / pytest (push) Successful in 2h48m44s
CI / validate (push) Successful in 33s
CI / dependency-scanning (push) Successful in 34s
CI / docs (push) Successful in 55s
CI / deploy (push) Successful in 1m52s

Five-issue triage shipped as four commits today: storefront i18n sweep
(10a99f98), FR password_reset accents + store-name signature
(b463c6bf), DE password_reset umlauts (36fd3781), Alpine x-text quoting
fix (1bade6e6), plus a seed-script sys.path fix (213a6053) hit during
the prod reseed. Test 5.0 (forgot-password end-to-end on FR) verified
end-of-day; Test 5 proper (login + dashboard + history) blocks on
recreating the prod api container tomorrow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-29 00:17:49 +02:00
parent 213a60533c
commit acbe2eff1a

View File

@@ -329,6 +329,106 @@ start, so the first session where the user can actually invoke it as
prospecting `tasks/__init__.py` missing import, other-module email
audit.
## 2026-05-29 update — Test 5.0 storefront i18n sweep + FR/DE email accents
### Test 5.0 (forgot-password) surfaced 5 distinct issues, all fixed
The user retried Test 5 with the `478c3a9c` JSON-body fix in place. The
forgot-password POST succeeded, but five downstream issues showed up in
one walk-through. Triaged analysis-first per user request before
batching the fix, then shipped as four commits.
| # | Where | Fix |
|---|---|---|
| 1 | API `forgot-password` handler | Read `request.state.language` first; fall back to `customer.preferred_language` (which is now backfilled at loyalty self-enrollment for both new and returning customers so future emails respect storefront locale). |
| 2A | `customers/storefront/reset-password.html` icons | Replaced `$icon('x-mark' / 'spinner' / 'check')` with inline SVGs (matches `forgot-password.html` convention; standalone templates don't load `icons.js`). |
| 2B | Same template — full i18n | Added `lang` attribute, swapped every hardcoded string for `_()` (22 new `auth.*` keys × 4 locales), added language selector, threaded JS validation strings via `window.__resetPasswordI18n`. |
| 3 | login + forgot + reset CTAs | Renamed `auth.continue_shopping``auth.back_to_home` (loyalty storefronts have no catalog). 4-locale rename. |
| 5 | `/account/dashboard`, `/profile`, `/addresses` body | i18n sweep across all three customer-area templates (~80 new `customers.storefront.pages.{dashboard,profile,addresses}.*` keys × 4 locales). |
Issue 4 (login looked "strangely in FR" after the broken reset page) was
NOT a bug — login.html was correctly translated all along; the contrast
with the broken reset page just made it look weird.
### FR + DE password_reset email body restored to native orthography
The seeded FR template body had every accent stripped (`Envoye`, `recu`,
`demande`, `equipe`, `Reinitialiser`, etc.). Same pattern in DE
(`zurucksetzen`, `Schaltflache`, `lauft`, `konnen`, `Grussen`).
Both templates now read natively. As a bonus, signatures on all 4 locales
were changed from generic ("L'équipe" / "The Team" / "Das Team" /
"D'Team") to `{{ store_name }}`-interpolated ("L'équipe Fashion Hub" /
"The Fashion Hub Team" / etc.) using the auto-injected `store_name`
branding variable from `EmailService.get_branding`.
The seeder is idempotent (upserts on `(code, language)`), so re-running
`scripts/seed/seed_email_templates_core.py` updates existing rows in
place — no DB wipe needed.
### Alpine quoting bug surfaced and fixed downstream
The customer-dashboard unread-message line crashed Alpine with
`"expected expression, got '}'"` because the original sweep emitted
`{{ _('...')|tojson }}` directly inside `x-text="..."` — the JSON's
double quotes broke out of the double-quoted HTML attribute. Fix moved
the singular/plural strings onto `window.__accountDashboardI18n` and
referenced them by global path from `x-text`. The nested
`x-data="{ unreadCount: 0 }"` scope can't see the parent component's
`i18n` property, but `window.*` is always reachable.
The other auth templates using `|tojson` (language-selector blocks)
escape it via single-quoted outer attributes (`x-data='...'`), so the
collision was unique to the new dashboard code.
### Seed-script path bug surfaced during the prod reseed
`scripts/seed/seed_email_templates_core.py` had
`Path(__file__).parent.parent` which resolves to `scripts/`, not the
project root, so `from app.core.database import get_db` failed with
`ModuleNotFoundError: No module named 'app'`. The loyalty sibling had
`parent.parent.parent` already (correct). Fixed to match. The canonical
deploy command in `docs/deployment/hetzner-server-setup.md:549` sets
`PYTHONPATH=/app` and would have masked the bug anyway, but defence in
depth is cheap.
### Status board delta
- Step 6 (web user-journey E2E tests) — Tests 1 ✅, 2 ✅, 3 ✅, 4 ✅,
**5.0 ✅** (forgot-password end-to-end on FR, including email
reception and accent correctness). Test 5 itself (login + dashboard +
history) is the next concrete step, gated on recreating the prod
`api` container to serve the i18n-swept HTML.
### Carry over for next session
1. **Recreate the prod `api` container** first thing tomorrow:
`docker compose --profile full up -d --force-recreate api`. The
Alpine fix (`1bade6e6`) is in the image built today but the
long-running container is still on the old image, so the dashboard
still throws the `x-text` error end-of-day. Verify the dashboard
renders cleanly after recreate.
2. **Continue Test 5** from step 5.1 (login as customer) → 5.2
(`/account/loyalty` dashboard, expect 168 pts) → 5.3
(`/account/loyalty/history`, expect cross-store transaction list).
3. **Static asset cache-busting gaps** (new item raised by user): the
`?v=<commit-sha>` system from the 2026-05-18 cache-busting work is
in place, but some JS/CSS still load without the `?v=` query param.
Audit which files miss it (likely standalone templates that bypass
the `static_v()` / `url_for` helpers). The `FE-024` arch rule was
supposed to guard this — check whether it's firing on these gaps.
4. **DE/LB email template quality sweep** — other DE templates likely
have the same missing-umlaut pattern as `password_reset`
(signup_welcome, order_confirmation, team_invite, etc.; ~11 codes ×
4 locales). LB has inconsistent accents too. Worth a single pass
with a native-speaker review.
5. **Transaction categories permissions audit** (carried from
2026-05-24).
6. **Routing pass** (carried — after Test 8).
7. **Existing backlog** (carried): Hetzner doc check, B1-F unit tests,
prospecting `tasks/__init__.py` missing import, other-module email
audit.
## Status board
| # | Pre-launch step | State | Notes |