- Add pessimistic locking (SELECT FOR UPDATE) on card write operations
to prevent race conditions in stamp_service and points_service
- Replace 16 console.log/error/warn calls with LogConfig.createLogger()
in 3 storefront JS files (dashboard, history, enroll)
- Delete all stale lu.json locale files across 8 modules (lb is the
correct ISO 639-1 code for Luxembourgish)
- Update architecture rules and docs to reference lb.json not lu.json
- Add production-readiness.md report for loyalty module
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded English strings across all 22 templates, 10 JS files,
and 4 locale files (en/fr/de/lb) with ~300 translation keys per language.
Uses server-side _() for Jinja2 templates and I18n.t() for JS toast
messages and dynamic Alpine.js expressions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix Google Wallet class creation: add required issuerName field (merchant name),
programLogo with default logo fallback, hexBackgroundColor default
- Add default loyalty logo assets (200px + 512px) for programs without custom logos
- Smart retry: skip retries on 400/401/403/404 client errors (not transient)
- Fix enrollment success page: use sessionStorage for wallet URLs instead of
authenticated API call (self-enrolled customers have no session)
- Hide wallet section on success page when no wallet URLs available
- Wire up T&C modal on enrollment page with program.terms_text
- Add startup validation for Google/Apple Wallet configs in lifespan
- Add admin wallet status dashboard endpoint and UI (moved to service layer)
- Fix Apple Wallet push notifications with real APNs HTTP/2 implementation
- Fix docs: correct enrollment URLs (port, path segments, /v1 prefix)
- Fix test assertion: !loyalty-enroll! → !enrollment!
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align Alpine.js base component naming with storefront terminology.
Updated across all storefront JS, templates, and documentation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix storefront enabled_modules always empty (page_context overwrote computed
set with empty default via extra_context)
- Fix storefront loyalty JS using store's data() instead of shopLayoutData()
- Remove defer from storefront loyalty scripts to prevent Alpine race condition
- Fix enrollment field name mismatch (customer_email → email) in both store
and storefront JS
- Add self-enrollment customer creation (resolve_customer_id with
create_if_missing) including hashed_password and customer_number
- Fix card list showing "Unknown" — add customer_name/email to CardResponse
- Add GET /cards/{card_id} detail endpoint for store card detail page
- Fix enroll-success.html using data() instead of shopLayoutData()
- Fix enrollment redirect reading response.card_number instead of
response.card.card_number
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>