Files
bakery-ia/FIXES_SUMMARY.md
2025-12-17 13:03:52 +01:00

18 KiB

Enterprise Demo Fixes Summary

Date: 2025-12-17 Issue: Child tenants not visible in multi-tenant menu & Distribution data not displaying

Problems Identified

1. Child Tenant Visibility Issue

Root Cause: Child tenants were being created with the wrong owner_id.

Location: services/tenant/app/api/internal_demo.py:620

Problem Details:

  • Child tenants were hardcoded to use the professional demo owner ID: c1a2b3c4-d5e6-47a8-b9c0-d1e2f3a4b5c6
  • This is INCORRECT for enterprise demos
  • The enterprise parent tenant uses owner ID: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7
  • Because of the mismatch, when the enterprise parent owner logged in, they could only see the parent tenant
  • The child tenants belonged to a different owner and were not visible in the tenant switcher

Impact:

  • Parent tenant owner could NOT see child tenants in the multi-tenant menu
  • Child tenants existed in the database but were inaccessible
  • Enterprise demo was non-functional for testing multi-location features

2. Distribution Data File Not Found for Child Tenants

Root Cause: Distribution service was trying to load non-existent distribution files for child tenants.

Location: services/distribution/app/api/internal_demo.py:148

Problem Details:

  • When cloning data for enterprise_child tenants, the code tried to load: shared/demo/fixtures/enterprise/children/C0000000-0000-4000-a000-000000000001/12-distribution.json
  • These files don't exist because child outlets are delivery destinations, not distribution hubs
  • Distribution is managed centrally by the parent tenant
  • This caused the demo session cloning to fail with FileNotFoundError

Error Message:

FileNotFoundError: Seed data file not found:
/app/shared/demo/fixtures/enterprise/children/C0000000-0000-4000-a000-000000000001/12-distribution.json

Impact:

  • Demo session cloning failed for enterprise demos
  • Child tenant creation was incomplete
  • Distribution page showed no data

3. Shipment Model Field Mismatch

Root Cause: Distribution cloning code tried to create Shipment with fields that don't exist in the model.

Location: services/distribution/app/api/internal_demo.py:283

Problem Details:

  • Fixture contains items field (list of products being shipped)
  • Fixture contains estimated_delivery_time field
  • Shipment model doesn't have these fields
  • Model only has: actual_delivery_time, delivery_notes, etc.
  • This caused TypeError when creating Shipment objects

Error Message:

TypeError: 'items' is an invalid keyword argument for Shipment

Impact:

  • Distribution data cloning failed completely
  • No routes or shipments were created
  • Distribution page was empty even after successful child tenant creation

Fixes Applied

Fix 1: Child Tenant Owner ID Correction

File Modified: services/tenant/app/api/internal_demo.py

Changes Made:

  1. Added parent tenant lookup (Lines 599-614):

    # Get parent tenant to retrieve the correct owner_id
    parent_result = await db.execute(select(Tenant).where(Tenant.id == parent_uuid))
    parent_tenant = parent_result.scalars().first()
    
    if not parent_tenant:
        logger.error("Parent tenant not found", parent_tenant_id=parent_tenant_id)
        return {...}
    
    # Use the parent's owner_id for the child tenant (enterprise demo owner)
    parent_owner_id = parent_tenant.owner_id
    
  2. Updated child tenant creation (Line 637):

    # Owner ID - MUST match the parent tenant owner (enterprise demo owner)
    # This ensures the parent owner can see and access child tenants
    owner_id=parent_owner_id
    
  3. Updated TenantMember creation (Line 711):

    # Use the parent's owner_id (already retrieved above)
    # This ensures consistency between tenant.owner_id and TenantMember records
    child_owner_member = TenantMember(
        tenant_id=virtual_uuid,
        user_id=parent_owner_id,  # Changed from hardcoded UUID
        role="owner",
        ...
    )
    
  4. Enhanced logging (Line 764):

    logger.info(
        "Child outlet created successfully",
        ...
        owner_id=str(parent_owner_id),  # Added for debugging
        ...
    )
    

Fix 2: Distribution Data Loading for Child Tenants

File Modified: services/distribution/app/api/internal_demo.py

Changes Made:

  1. Added early return for child tenants (Lines 147-166):
    elif demo_account_type == "enterprise_child":
        # Child outlets don't have their own distribution data
        # Distribution is managed centrally by the parent tenant
        # Child locations are delivery destinations, not distribution hubs
        logger.info(
            "Skipping distribution cloning for child outlet - distribution managed by parent",
            base_tenant_id=base_tenant_id,
            virtual_tenant_id=virtual_tenant_id,
            session_id=session_id
        )
        duration_ms = int((datetime.now(timezone.utc) - start_time).total_seconds() * 1000)
        return {
            "service": "distribution",
            "status": "completed",
            "records_cloned": 0,
            "duration_ms": duration_ms,
            "details": {
                "note": "Child outlets don't manage distribution - handled by parent tenant"
            }
        }
    

Rationale:

  • In an enterprise bakery setup, the central production facility (parent) manages all distribution
  • Retail outlets (children) are receiving locations, not distribution hubs
  • The parent's distribution.json already includes routes and shipments that reference child tenant locations
  • Attempting to load child-specific distribution files was architecturally incorrect

Fix 3: Shipment Field Compatibility

File Modified: services/distribution/app/api/internal_demo.py

Changes Made:

  1. Removed estimated_delivery_time field (Lines 261-267):

    # Note: The Shipment model doesn't have estimated_delivery_time
    # Only actual_delivery_time is stored
    actual_delivery_time = parse_date_field(
        shipment_data.get('actual_delivery_time'),
        session_time,
        "actual_delivery_time"
    )
    
  2. Stored items in delivery_notes (Lines 273-287):

    # Store items in delivery_notes as JSON for demo purposes
    # (In production, items would be in the linked purchase order)
    import json
    items_json = json.dumps(shipment_data.get('items', [])) if shipment_data.get('items') else None
    
    new_shipment = Shipment(
        ...
        total_weight_kg=shipment_data.get('total_weight_kg'),
        actual_delivery_time=actual_delivery_time,
        # Store items info in delivery_notes for demo display
        delivery_notes=f"{shipment_data.get('notes', '')}\nItems: {items_json}" if items_json else shipment_data.get('notes'),
        ...
    )
    

Rationale:

  • Shipment model represents delivery tracking, not content inventory
  • In production systems, shipment items are stored in the linked purchase order
  • For demo purposes, we store items as JSON in the delivery_notes field
  • This allows the demo to show what's being shipped without requiring full PO integration

How Data Flows in Enterprise Demo

User & Ownership Structure

Enterprise Demo Owner
├── ID: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7
├── Email: director@panaderiaartesana.es
├── Role: owner
│
├── Parent Tenant (Central Production)
│   ├── ID: 80000000-0000-4000-a000-000000000001 (template)
│   ├── Name: "Panadería Artesana España - Central"
│   ├── Type: parent
│   └── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7
│
└── Child Tenants (Retail Outlets)
    ├── Madrid - Salamanca
    │   ├── ID: A0000000-0000-4000-a000-000000000001 (template)
    │   ├── Type: child
    │   └── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7 ✅ (NOW CORRECT)
    │
    ├── Barcelona - Eixample
    │   ├── ID: B0000000-0000-4000-a000-000000000001
    │   └── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7 ✅
    │
    ├── Valencia - Ruzafa
    │   ├── ID: C0000000-0000-4000-a000-000000000001
    │   └── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7 ✅
    │
    ├── Seville - Triana
    │   ├── ID: D0000000-0000-4000-a000-000000000001
    │   └── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7 ✅
    │
    └── Bilbao - Casco Viejo
        ├── ID: E0000000-0000-4000-a000-000000000001
        └── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7 ✅

Tenant Loading Flow

  1. User logs into enterprise demo

    • Demo session created with demo_account_type: "enterprise"
    • Session ID stored in JWT token
  2. Frontend requests user tenants

    • Calls: GET /tenants/user/{user_id}/owned
    • Backend: services/tenant/app/api/tenant_operations.py:284
  3. Backend retrieves virtual tenants

    • Extracts demo_session_id from JWT
    • Calls: tenant_service.get_virtual_tenants_for_session(demo_session_id, "enterprise")
    • Query: SELECT * FROM tenants WHERE demo_session_id = ? AND owner_id = ?
    • Returns: Parent + All child tenants with matching owner_id
  4. Frontend displays in TenantSwitcher

    • Component: frontend/src/components/ui/TenantSwitcher.tsx
    • Shows all tenants where user is owner
    • Now includes all 6 tenants (1 parent + 5 children)

Distribution Data Flow

  1. Demo session cloning

    • Orchestrator calls distribution service: POST /internal/demo/clone
    • Loads fixture: shared/demo/fixtures/enterprise/parent/12-distribution.json
  2. Distribution data includes

    • Delivery routes with route_sequence (stops at multiple locations)
    • Shipments linked to child tenants
    • All dates use BASE_TS markers for session-relative times
  3. Frontend queries distribution

    • Calls: GET /tenants/{tenant_id}/distribution/routes?date={date}
    • Calls: GET /tenants/{tenant_id}/distribution/shipments?date={date}
    • Service: frontend/src/api/hooks/useEnterpriseDashboard.ts:307

Testing Instructions

1. Restart Services

After applying the fixes, you need to restart the affected services:

# Restart tenant service (Fix 1: child tenant owner_id)
kubectl rollout restart deployment tenant-service -n bakery-ia

# Restart distribution service (Fix 2: skip child distribution loading)
kubectl rollout restart deployment distribution-service -n bakery-ia

# Or restart all services at once
./kubernetes_restart.sh

2. Create New Enterprise Demo Session

Important: You must create a NEW demo session to test the fix. Existing sessions have already created child tenants with the wrong owner_id.

# Navigate to frontend
cd frontend

# Start development server if not running
npm run dev

# Open browser to demo page
# http://localhost:3000/demo

3. Test Child Tenant Visibility

  1. Click "Try Enterprise Demo" button
  2. Wait for demo session to initialize
  3. After redirect to dashboard, look for the tenant switcher in the top-left
  4. Click on the tenant switcher dropdown
  5. Expected Result: You should see 6 organizations:
    • Panadería Artesana España - Central (parent)
    • Madrid - Salamanca (child)
    • Barcelona - Eixample (child)
    • Valencia - Ruzafa (child)
    • Seville - Triana (child)
    • Bilbao - Casco Viejo (child)

4. Test Distribution Page

  1. From the enterprise dashboard, navigate to "Distribution"
  2. Check if routes and shipments are displayed
  3. Expected Result: You should see:
    • Active routes count
    • Pending deliveries count
    • Distribution map with route visualization
    • List of routes in the "Rutas" tab

5. Verify Database (Optional)

If you have database access:

-- Check child tenant owner_ids
SELECT
    id,
    name,
    tenant_type,
    owner_id,
    demo_session_id
FROM tenants
WHERE tenant_type = 'child'
    AND is_demo = true
ORDER BY created_at DESC
LIMIT 10;

-- Should show owner_id = 'd2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7' for all child tenants

Troubleshooting

Child Tenants Still Not Visible

  1. Verify you created a NEW demo session after deploying the fix

    • Old sessions have child tenants with wrong owner_id
    • Solution: Create a new demo session
  2. Check logs for child tenant creation

    kubectl logs -f deployment/tenant-service -n bakery-ia | grep "Child outlet created"
    
    • Should show: owner_id=d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7
  3. Verify demo session ID in JWT

    • Open browser DevTools > Application > Storage > Local Storage
    • Check if demo_session_id is present in token
    • Should match the session_id in database

Distribution Data Not Showing

  1. Check date parameter

    • Distribution page defaults to today's date
    • Demo data uses BASE_TS (session creation time)
    • Routes might be scheduled for BASE_TS + 2h, BASE_TS + 3h, etc.
    • Solution: Try querying without date filter or use session date
  2. Verify distribution data was cloned

    kubectl logs -f deployment/demo-session-service -n bakery-ia | grep "distribution"
    
    • Should show: "Distribution data cloning completed"
    • Should show: records_cloned > 0
  3. Check backend endpoint

    # Get tenant ID from tenant switcher
    TENANT_ID="your-virtual-tenant-id"
    
    # Query routes directly
    curl -H "Authorization: Bearer YOUR_TOKEN" \
      "http://localhost:8000/tenants/${TENANT_ID}/distribution/routes"
    
  4. Check browser console for errors

    • Open DevTools > Console
    • Look for API errors or failed requests
    • Check Network tab for distribution API calls

Files Changed

  1. services/tenant/app/api/internal_demo.py

    • Lines 599-614: Added parent tenant lookup
    • Line 637: Fixed child tenant owner_id
    • Line 711: Fixed TenantMember owner_id
    • Line 764: Enhanced logging
  2. services/distribution/app/api/internal_demo.py

    • Lines 147-166: Skip distribution cloning for child tenants
    • Lines 261-267: Removed unsupported estimated_delivery_time field
    • Lines 273-292: Fixed items field issue (model doesn't support it)
    • Stored items data in delivery_notes field for demo display
    • Added clear logging explaining why child tenants don't get distribution data

Verification Checklist

  • Child tenant owner_id now matches parent tenant owner_id
  • Child tenants include demo_session_id for session-based queries
  • TenantMember records use consistent owner_id
  • Distribution fixture exists with proper structure
  • Distribution API endpoints are correctly implemented
  • Frontend hooks properly call distribution API
  • Distribution cloning skips child tenants (they don't manage distribution)
  • FileNotFoundError for child distribution files is resolved
  • Shipment model field compatibility issues resolved
  • Items data stored in delivery_notes for demo display

Next Steps

  1. Deploy Fixes

    kubectl rollout restart deployment tenant-service -n bakery-ia
    kubectl rollout restart deployment distribution-service -n bakery-ia
    
  2. Create New Demo Session

    • Must be a new session, old sessions have wrong data
  3. Test Multi-Tenant Menu

    • Verify all 6 tenants visible
    • Test switching between tenants
  4. Test Distribution Page

    • Check if data displays
    • If not, investigate date filtering
  5. Monitor Logs

    # Watch tenant service logs
    kubectl logs -f deployment/tenant-service -n bakery-ia
    
    # Watch distribution service logs
    kubectl logs -f deployment/distribution-service -n bakery-ia
    

Additional Notes

Why This Fix Works

The tenant visibility is controlled by the owner_id field. When a user logs in and requests their tenants:

  1. Backend extracts user_id from JWT: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7
  2. Queries database: SELECT * FROM tenants WHERE owner_id = ? AND demo_session_id = ?
  3. Previously: Parent had correct owner_id, children had wrong owner_id → Only parent returned
  4. Now: Parent AND children have same owner_id → All tenants returned

Distribution Data Structure

The distribution fixture creates a realistic enterprise distribution scenario:

  • Routes: Delivery routes from central production to retail outlets
  • Shipments: Individual shipments assigned to routes
  • Child References: Shipments reference child_tenant_id for destination tracking
  • Time Offsets: Uses BASE_TS + offset for realistic scheduling

Example:

{
  "route_number": "MAD-BCN-001",
  "route_date": "BASE_TS + 2h",  // 2 hours after session creation
  "route_sequence": [
    {"stop_number": 1, "location_id": "parent-id"},
    {"stop_number": 2, "location_id": "child-A-id"},
    {"stop_number": 3, "location_id": "child-B-id"}
  ]
}

This creates a distribution network where:

  • Central production (parent) produces goods
  • Distribution routes deliver to retail outlets (children)
  • Shipments track individual deliveries
  • All entities are linked for network-wide visibility

Summary of All Changes

Services Modified

  1. tenant-service - Fixed child tenant owner_id
  2. distribution-service - Fixed child cloning + shipment fields

Database Impact

  • Child tenants created in new sessions will have correct owner_id
  • Distribution routes and shipments will be created successfully
  • No migration needed (only affects new demo sessions)

Deployment Commands

# Restart affected services
kubectl rollout restart deployment tenant-service -n bakery-ia
kubectl rollout restart deployment distribution-service -n bakery-ia

# Verify deployments
kubectl rollout status deployment tenant-service -n bakery-ia
kubectl rollout status deployment distribution-service -n bakery-ia

Testing Checklist

  • Create new enterprise demo session
  • Verify 6 tenants visible in tenant switcher
  • Switch between parent and child tenants
  • Navigate to Distribution page on parent tenant
  • Verify routes and shipments are displayed
  • Check demo session logs for errors

Fix Status: ALL FIXES COMPLETED Testing Status: PENDING USER VERIFICATION Production Ready: YES (after testing)