Clear auth store when exiting demo session to prevent unauthorized page redirect.
## Problem
When users clicked "Salir" (Exit) from the demo session, they were redirected to the unauthorized page (`/unauthorized`) instead of the demo landing page (`/demo`).
## Root Cause
The `handleExpiration()` function in DemoBanner.tsx was clearing localStorage and navigating to `/demo`, but was NOT clearing the auth store. This created an inconsistent state:
- `isDemoMode = false` (localStorage cleared)
- `demoSessionId = null` (localStorage cleared)
- `isAuthenticated = true` (auth store NOT cleared - still has demo user)
The `useHasAccess()` hook checks:
```typescript
return isAuthenticated || (isDemoMode && !!demoSessionId);
```
After clearing localStorage but not auth:
- `isAuthenticated = true` but the demo session is invalid
- `isDemoMode = false` and `demoSessionId = null`
- Result: `useHasAccess()` returns `false`
When navigating to `/demo`, the ProtectedRoute checked access and found it was `false`, redirecting to `/unauthorized`.
## Solution
Call `logout()` on the auth store before navigating to clear the demo user session completely. This ensures:
- Auth store is cleared (`isAuthenticated = false`)
- User is properly logged out from demo session
- Navigation to `/demo` succeeds without authentication check
## Additional Improvements
- Also clear `virtual_tenant_id` and `subscription_tier` from localStorage
- Updated comment to clarify navigation intent
## Files Changed
- frontend/src/components/layout/DemoBanner/DemoBanner.tsx:73-74
- Added auth store logout before navigation
- Added clearing of virtual_tenant_id and subscription_tier
- Updated comment for clarity
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Prevent loadUserTenants from being called too early for demo sessions by excluding demo mode from the authenticated user auto-load logic.
## Problem
In enterprise demo sessions, loadUserTenants() was being called BEFORE child tenants were created, resulting in only the parent tenant (1 tenant) being returned instead of all 6 tenants (parent + 5 children).
Timeline of the race condition:
- 15:37:20: Session created, parent tenant cloning started
- 15:37:21: loadUserTenants() called by first useEffect → returned 1 tenant ❌
- 15:37:22: Child tenants created (5 tenants)
- 15:38:03: Session status changed to 'ready'
The first useEffect (for authenticated users) triggered immediately when isAuthenticated became true, calling loadUserTenants() at 15:37:21. This happened BEFORE the session polling logic in the second useEffect could wait for status='ready' and BEFORE child tenants were created.
## Solution
Added `!isDemoMode` condition to the first useEffect that auto-loads tenants for authenticated users. This ensures demo sessions use only the special initialization logic with session status polling (second useEffect), which waits for the session to be fully ready before loading tenants.
## Files Changed
- frontend/src/stores/useTenantInitializer.ts:61
- Added `&& !isDemoMode` to prevent early tenant loading for demo users
- Added dependency `isDemoMode` to useEffect dependency array
- Updated comment to clarify demo users have separate initialization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implemented polling mechanism to wait for demo session to be fully ready
before attempting to load tenant list.
## The Problem:
Frontend was calling GET /tenants/user/demo-user/tenants immediately after
session creation, but tenant cloning is asynchronous and takes 5-10 seconds.
This caused the API to return empty array [] even though it returned 200 OK.
## The Solution:
Added pollSessionStatus() function that:
1. Polls /api/v1/demo-sessions/{session_id}/status every 1 second
2. Waits for status to become 'ready' (max 30 seconds)
3. Only loads tenants after session is confirmed ready
4. Logs detailed status updates for debugging
## Flow (Before):
User clicks demo → Session created → API called immediately → Empty []
## Flow (After):
User clicks demo → Session created → Poll status (1s interval) →
Status: initializing → cloning_data → ready → Load tenants → Success!
## Benefits:
✅ No more empty tenant lists due to timing
✅ Clear console logs showing progress
✅ Handles session failures gracefully
✅ Timeout protection (30 seconds max)
✅ Works for both enterprise (6 tenants) and professional (1 tenant)
## Console Output Example:
⏳ Session status poll 1/30: initializing
⏳ Session status poll 2/30: cloning_data
⏳ Session status poll 8/30: ready
✅ Demo session is ready!
🔄 Loading available tenants for enterprise demo...
📋 Loaded available tenants: 6
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit refactors the demo session architecture to consolidate all demo
configuration data into the fixture files, removing redundant metadata files.
## Changes Made:
### 1. Data Consolidation
- **Removed**: `shared/demo/metadata/demo_users.json`
- **Removed**: `shared/demo/metadata/tenant_configs.json`
- **Updated**: Merged all user data into `02-auth.json` files
- **Updated**: Merged all tenant config data into `01-tenant.json` files
### 2. Enterprise Parent Tenant Updates
- Updated owner name to "Director" (matching auth fixtures)
- Added description field matching tenant_configs.json
- Added `base_tenant_id` to all child tenant entries
- Now includes all 5 child locations (Madrid, Barcelona, Valencia, Seville, Bilbao)
### 3. Professional Tenant Updates
- Added description field from tenant_configs.json
- Ensured consistency with auth fixtures
### 4. Code Updates
- **services/tenant/app/api/internal_demo.py**:
- Fixed child tenant staff members to use enterprise parent users
- Changed from professional staff IDs to enterprise staff IDs (Laura López, José Martínez, Francisco Moreno)
- **services/demo_session/app/core/config.py**:
- Updated DEMO_ACCOUNTS configuration with all 5 child outlets
- Updated enterprise tenant name and email to match fixtures
- Added descriptions for all child locations
- **gateway/app/middleware/demo_middleware.py**:
- Updated comments to reference fixture files as source of truth
- Clarified that owner IDs come from 01-tenant.json files
- **frontend/src/stores/useTenantInitializer.ts**:
- Updated tenant names and descriptions to match fixture files
- Added comments linking to source fixture files
## Benefits:
1. **Single Source of Truth**: All demo data now lives in fixture files
2. **Consistency**: No more sync issues between metadata and fixtures
3. **Maintainability**: Easier to update demo data (one place per tenant type)
4. **Clarity**: Clear separation between template data (fixtures) and runtime config
## Enterprise Demo Fix:
The enterprise owner is now correctly added as a member of all child tenants, fixing
the issue where the tenant switcher didn't show parent/child tenants and the
establishments page didn't load tenants for the demo enterprise user.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Standardize demo account type naming from inconsistent variants to clean names:
- individual_bakery, professional_bakery → professional
- central_baker, enterprise_chain → enterprise
This eliminates naming confusion that was causing bugs in the demo session
initialization, particularly for enterprise demo tenants where different
parts of the system used different names for the same concept.
Changes:
- Updated source of truth in demo_session config
- Updated all backend services (middleware, cloning, orchestration)
- Updated frontend types, pages, and stores
- Updated demo session models and schemas
- Removed all backward compatibility code as requested
Related to: Enterprise demo session access fix
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
1. **Fix "Sin Plan" (No Production Planned)**:
- Updated BASE_REFERENCE_DATE from Nov 25 to Nov 27 to match current date
- Production batches were being filtered out because they were dated for Nov 25
- The get_todays_batches() method filters for batches scheduled TODAY
2. **Fix "Ver razonamiento" Button Not Opening Modal**:
- Changed handleOpenReasoning() to always emit 'reasoning:show' event
- Previous logic tried to navigate to PO/batch detail pages instead
- Now keeps user on dashboard and shows reasoning modal inline
- Passes all metadata (action_id, po_id, batch_id, reasoning) in event
This ensures production progress shows correctly and users can view
AI reasoning without leaving the dashboard.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>