fix: store menu 404, logger crash, platform detection, and sidebar UX
All checks were successful
CI / ruff (push) Successful in 12s
CI / pytest (push) Successful in 46m12s
CI / validate (push) Successful in 24s
CI / dependency-scanning (push) Successful in 29s
CI / docs (push) Successful in 38s
CI / deploy (push) Successful in 50s

- Fix store menu API URL (/store/menu/render/store, not /store/core/...)
- Fix storeLog/merchantLog fallback to console object instead of console.log
- Embed platform_id/platform_code in store JWT from URL context at login
- Use token_platform_id in store menu endpoint with DB fallback for old tokens
- Add "Menu unavailable" warning in sidebar fallback for all three frontends
- Standardize admin section default to all-open (consistent with store/merchant)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-23 13:53:31 +01:00
parent 506171503d
commit 2fc157d7b2
8 changed files with 33 additions and 9 deletions

View File

@@ -95,8 +95,10 @@ async def get_rendered_store_menu(
# Get the store from the JWT token's store context
store = store_service.get_store_by_id(db, current_user.token_store_id)
# Resolve the store's platform via service layer
platform_id = menu_service.get_store_primary_platform_id(db, store.id)
# Platform from JWT (set at login from URL context), fall back to DB for old tokens
platform_id = current_user.token_platform_id
if platform_id is None:
platform_id = menu_service.get_store_primary_platform_id(db, store.id)
# Get filtered menu with platform visibility and store_code interpolation
menu = menu_service.get_menu_for_rendering(

View File

@@ -214,7 +214,7 @@ function data() {
// Initialize openSections for new sections (default: first section open)
if (this.openSections[section.id] === undefined) {
// Default: first section open, rest closed
this.openSections[section.id] = (sections.indexOf(section) === 0);
this.openSections[section.id] = true;
}
}
console.debug('Menu config loaded:', this.visibleMenuItems.size, 'items');

View File

@@ -5,7 +5,7 @@
*/
// Use centralized logger (guarded: log-config.js loads with defer, so it may not be ready yet)
const merchantLog = (window.LogConfig && window.LogConfig.log) || console.log;
const merchantLog = (window.LogConfig && window.LogConfig.log) || console;
console.log('[MERCHANT INIT-ALPINE] Loading...');

View File

@@ -5,7 +5,7 @@
*/
// Use centralized logger (guarded: log-config.js loads with defer, so it may not be ready yet)
const storeLog = (window.LogConfig && window.LogConfig.log) || console.log;
const storeLog = (window.LogConfig && window.LogConfig.log) || console;
console.log('[STORE INIT-ALPINE] Loading...');
@@ -129,7 +129,7 @@ function data() {
this.menuLoading = true;
try {
this.menuData = await apiClient.get('/store/core/menu/render/store');
this.menuData = await apiClient.get('/store/menu/render/store');
// Initialize section open state from response
for (const section of (this.menuData?.sections || [])) {
if (this.openSections[section.id] === undefined) {

View File

@@ -27,6 +27,7 @@ from app.modules.tenancy.models.user_password_reset_token import (
UserPasswordResetToken, # noqa: API-007
)
from app.modules.tenancy.services.user_auth_service import user_auth_service
from middleware.platform_context import get_current_platform
from middleware.store_context import get_current_store
from models.schema.auth import LogoutResponse, StoreUserResponse, UserContext, UserLogin
@@ -110,12 +111,19 @@ def store_login(
f"for store {store.store_code} as {store_role}"
)
# Get platform from URL context (middleware-detected)
platform = get_current_platform(request)
platform_id = platform.id if platform else None
platform_code = platform.code if platform else None
# Create store-scoped access token with store information
token_data = auth_service.auth_manager.create_access_token(
user=user,
store_id=store.id,
store_code=store.store_code,
store_role=store_role,
platform_id=platform_id,
platform_code=platform_code,
)
# Set HTTP-only cookie for browser navigation

View File

@@ -88,7 +88,11 @@
</a>
</li>
</ul>
<p class="px-6 py-3 text-xs text-gray-400">Loading menu...</p>
<div class="px-6 mt-4">
<p class="text-xs text-gray-400 dark:text-gray-500">
Menu unavailable. Showing default items only.
</p>
</div>
</div>
</div>
{% endmacro %}

View File

@@ -86,7 +86,7 @@
</template>
</div>
<!-- Fallback: static dashboard link (if menu API fails) -->
<!-- Fallback: static dashboard link + warning (if menu API fails) -->
<div x-show="!menuLoading && !menuData" x-cloak>
<ul class="mt-6">
<li class="relative px-6 py-3">
@@ -99,6 +99,11 @@
</a>
</li>
</ul>
<div class="px-6 mt-4">
<p class="text-xs text-gray-400 dark:text-gray-500">
Menu unavailable. Showing default items only.
</p>
</div>
</div>
</div>
{% endmacro %}

View File

@@ -86,7 +86,7 @@
</template>
</div>
<!-- Fallback: static dashboard link (if menu API fails) -->
<!-- Fallback: static dashboard link + warning (if menu API fails) -->
<div x-show="!menuLoading && !menuData" x-cloak>
<ul class="mt-6">
<li class="relative px-6 py-3">
@@ -99,6 +99,11 @@
</a>
</li>
</ul>
<div class="px-6 mt-4">
<p class="text-xs text-gray-400 dark:text-gray-500">
Menu unavailable. Showing default items only.
</p>
</div>
</div>
<!-- Quick Actions (static, outside dynamic menu) -->