docs(loyalty): record 2026-05-29 Test 5.0 i18n sweep + FR/DE email accents
All checks were successful
All checks were successful
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:
@@ -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 |
|
||||
|
||||
Reference in New Issue
Block a user