From 388e27e30919940e5bba8067a1ba3853fe08cd22 Mon Sep 17 00:00:00 2001 From: Urtzi Alfaro Date: Wed, 17 Dec 2025 16:16:00 +0100 Subject: [PATCH] Fix timing issue: Poll demo session status before loading tenants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- frontend/src/stores/useTenantInitializer.ts | 78 ++++++++++++++++----- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/frontend/src/stores/useTenantInitializer.ts b/frontend/src/stores/useTenantInitializer.ts index 02be35c2..24aab966 100644 --- a/frontend/src/stores/useTenantInitializer.ts +++ b/frontend/src/stores/useTenantInitializer.ts @@ -131,26 +131,68 @@ export const useTenantInitializer = () => { console.log('✅ [TenantInitializer] Set API client tenant ID:', virtualTenantId); }); - // For enterprise demos, load the actual tenant list to show child tenants + // For enterprise demos, wait for session to be ready, then load tenants if (demoAccountType === 'enterprise') { - console.log('🔄 [TenantInitializer] Loading available tenants for enterprise demo...'); - // Use a mock user ID for demo mode - const mockUserId = 'demo-user'; - - // Import tenant service and load user tenants - import('../api/services/tenant').then(({ TenantService }) => { - const tenantService = new TenantService(); - tenantService.getUserTenants(mockUserId) - .then(tenants => { - console.log('📋 [TenantInitializer] Loaded available tenants:', tenants.length); - // Update the tenant store with available tenants - import('../stores/tenant.store').then(({ useTenantStore }) => { - useTenantStore.getState().setAvailableTenants(tenants); - }); - }) - .catch(error => { - console.error('❌ [TenantInitializer] Failed to load available tenants:', error); + console.log('🔄 [TenantInitializer] Waiting for enterprise demo session to be ready...'); + + // Poll session status until ready + const pollSessionStatus = async (sessionId: string, maxAttempts = 30) => { + for (let attempt = 1; attempt <= maxAttempts; attempt++) { + try { + const response = await fetch(`/api/v1/demo-sessions/${sessionId}/status`); + if (response.ok) { + const status = await response.json(); + console.log(`⏳ [TenantInitializer] Session status poll ${attempt}/${maxAttempts}:`, status.status); + + if (status.status === 'ready') { + console.log('✅ [TenantInitializer] Demo session is ready!'); + return true; + } else if (status.status === 'failed') { + console.error('❌ [TenantInitializer] Demo session failed:', status); + return false; + } + // Status is 'initializing' or 'cloning_data' - continue polling + } + } catch (error) { + console.warn(`⚠️ [TenantInitializer] Status poll ${attempt} failed:`, error); + } + + // Wait 1 second before next poll (except on last attempt) + if (attempt < maxAttempts) { + await new Promise(resolve => setTimeout(resolve, 1000)); + } + } + + console.error('❌ [TenantInitializer] Session readiness timeout after 30 seconds'); + return false; + }; + + // Wait for session to be ready, then load tenants + pollSessionStatus(demoSessionId).then(isReady => { + if (isReady) { + console.log('🔄 [TenantInitializer] Loading available tenants for enterprise demo...'); + const mockUserId = 'demo-user'; + + import('../api/services/tenant').then(({ TenantService }) => { + const tenantService = new TenantService(); + tenantService.getUserTenants(mockUserId) + .then(tenants => { + console.log('📋 [TenantInitializer] Loaded available tenants:', tenants.length); + if (tenants.length === 0) { + console.warn('⚠️ [TenantInitializer] Session ready but no tenants found - possible sync issue'); + } + // Update the tenant store with available tenants + import('../stores/tenant.store').then(({ useTenantStore }) => { + useTenantStore.getState().setAvailableTenants(tenants); + }); + }) + .catch(error => { + console.error('❌ [TenantInitializer] Failed to load available tenants:', error); + }); }); + } else { + console.error('❌ [TenantInitializer] Cannot load tenants - session not ready'); + } }); } }