- Add merchant loyalty overview route and template (was 404)
- Fix store loyalty route paths to match menu URLs (/{store_code}/loyalty/...)
- Add loyalty rewards card to storefront account dashboard
- Fix merchant overview to resolve merchant via get_merchant_for_current_user_page
- Fix store login to use store's primary platform for JWT token (interim fix)
- Fix apiClient to attach status/errorCode to thrown errors (fixes error.status
checks in 12+ JS files — loyalty settings, terminal, email templates, etc.)
- Hide "Add Product" sidebar button when catalog module is not enabled
- Add proposal doc for proper platform detection in store login flow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3.3 KiB
Store Login: JWT Token Gets Wrong Platform
Status: Open — needs design review on fallback strategy Date: 2026-02-24
Problem
When a user logs in to a store via /platforms/loyalty/store/FASHIONHUB/login, the JWT token should encode platform_id=3 (loyalty). Instead, it gets platform_id=2 (main). This causes the store sidebar menu to show the wrong modules — e.g., analytics (from "main") appears while loyalty (from "loyalty") is missing.
Root Cause Chain
- User visits
http://localhost:8000/platforms/loyalty/store/FASHIONHUB/login - PlatformContextMiddleware detects
loyaltyand rewrites path to/store/FASHIONHUB/login— correct - Login page renders with loyalty platform context — correct
- JavaScript
login.jsPOSTs toapiClient.post('/store/auth/login', ...)which resolves to/api/v1/store/auth/login— no platform prefix - PlatformContextMiddleware sees
/api/v1/store/auth/login, doesn't match/platforms/*, defaults to "main" platform - Store auth endpoint calls
get_current_platform(request)→ gets "main" (id=2) instead of "loyalty" (id=3) - Token encodes
platform_id=2, all subsequent menu/API calls use the wrong platform
The Referer-based platform extraction in the middleware (middleware/platform_context.py lines 359-374) only handles /api/v1/storefront/ paths, not /api/v1/store/ paths.
Why is_primary Is Wrong
A store can be subscribed to multiple platforms. The platform should be determined by the login URL context (which platform the user navigated from), not by a database default. Using is_primary would always pick the same platform regardless of how the user accessed the store.
Key Constraint
- Production: One domain per platform (e.g.,
omsflow.lufor OMS,loyaltyflow.lufor loyalty). Store subdomains:fashionhub.omsflow.lu. Premium domains:fashionhub.lu. - Development: Path-based:
/platforms/{code}/store/{store_code}/login - A store can be on multiple platforms and should show different menus depending on which platform URL the user logged in from.
Current Workaround
app/modules/tenancy/routes/api/store_auth.py currently uses is_primary to resolve the platform from the store's store_platforms table. This works for single-platform stores but breaks for multi-platform stores.
Files Involved
| File | Role |
|---|---|
middleware/platform_context.py |
Platform detection from URL/domain — doesn't cover /api/v1/store/ paths |
middleware/store_context.py |
Store detection from URL/domain |
app/modules/tenancy/routes/api/store_auth.py |
Store login endpoint — creates JWT with platform_id |
app/modules/tenancy/static/store/js/login.js |
Frontend login — POSTs to /api/v1/store/auth/login |
static/shared/js/api-client.js |
API client — base URL is /api/v1 (no platform prefix) |
models/schema/auth.py |
UserLogin schema — currently has store_code but not platform_code |
app/modules/core/routes/api/store_menu.py |
Menu API — reads token_platform_id from JWT |
Open Questions
- What should the fallback strategy be when platform can't be determined from the login context?
- Should the solution also handle storefront customer login (which has the same issue)?
- Should the Referer-based detection in
platform_context.pybe extended to cover/api/v1/store/paths as a complementary fix?