532 lines
18 KiB
Markdown
532 lines
18 KiB
Markdown
# 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):
|
|
```python
|
|
# 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):
|
|
```python
|
|
# 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):
|
|
```python
|
|
# 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):
|
|
```python
|
|
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):
|
|
```python
|
|
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):
|
|
```python
|
|
# 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):
|
|
```python
|
|
# 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:
|
|
|
|
```bash
|
|
# 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.
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```sql
|
|
-- 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**
|
|
```bash
|
|
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**
|
|
```bash
|
|
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**
|
|
```bash
|
|
# 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
|
|
|
|
- [x] Child tenant owner_id now matches parent tenant owner_id
|
|
- [x] Child tenants include demo_session_id for session-based queries
|
|
- [x] TenantMember records use consistent owner_id
|
|
- [x] Distribution fixture exists with proper structure
|
|
- [x] Distribution API endpoints are correctly implemented
|
|
- [x] Frontend hooks properly call distribution API
|
|
- [x] Distribution cloning skips child tenants (they don't manage distribution)
|
|
- [x] FileNotFoundError for child distribution files is resolved
|
|
- [x] Shipment model field compatibility issues resolved
|
|
- [x] Items data stored in delivery_notes for demo display
|
|
|
|
## Next Steps
|
|
|
|
1. **Deploy Fixes**
|
|
```bash
|
|
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**
|
|
```bash
|
|
# 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:
|
|
```json
|
|
{
|
|
"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
|
|
```bash
|
|
# 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)
|