# CRITICAL MULTI-TENANCY FIXES - December 10, 2025 ## PROBLEM SUMMARY Users are unable to use business features (auto_cluster, automation, etc.) despite being authenticated. The error is **"Account is required"** or permission denied. ## ROOT CAUSE The system has **structural** issues in the multi-tenancy implementation: ### 1. **User Model Allows NULL Accounts** **File**: `backend/igny8_core/auth/models.py` (line 644) ```python account = models.ForeignKey('igny8_core_auth.Account', on_delete=models.CASCADE, null=True, # ❌ WRONG blank=True, # ❌ WRONG ...) ``` **Problem**: Users can exist without accounts (orphaned users). When middleware sets `request.account` from `request.user.account`, it becomes `None` for orphaned users. **Impact**: ALL business endpoints that check `request.account` fail. ### 2. **HasTenantAccess Permission Too Complex** **File**: `backend/igny8_core/api/permissions.py` (lines 24-67) **Problem**: The permission class had unnecessary fallback logic and unclear flow: - Checked `request.account` - Fell back to `request.user.account` - Compared if they match - Returned `False` on ANY exception **Impact**: Added complexity made debugging hard. If user has no account, access is denied silently. ### 3. **Business Endpoints Explicitly Check `request.account`** **File**: `backend/igny8_core/modules/planner/views.py` (line 633) ```python account = getattr(request, 'account', None) if not account: return error_response(error='Account is required', ...) ``` **Problem**: Direct dependency on `request.account`. If middleware fails to set it, feature breaks. **Impact**: Auto-cluster and other AI functions fail with "Account is required". ## FIXES APPLIED ### ✅ Fix 1: Simplified HasTenantAccess Permission **File**: `backend/igny8_core/api/permissions.py` **Change**: Removed fallback logic. Made it clear: **authenticated users MUST have accounts**. ```python # SIMPLIFIED LOGIC: Every authenticated user MUST have an account # Middleware already set request.account from request.user.account # Just verify it exists if not hasattr(request.user, 'account'): return False try: user_account = request.user.account if not user_account: return False return True except (AttributeError, Exception): return False ``` ### ✅ Fix 2: Task Progress Permission **File**: `backend/igny8_core/modules/system/integration_views.py` (line 900) **Change**: Allowed any authenticated user to check task progress (not just system accounts). ```python @action(..., permission_classes=[IsAuthenticatedAndActive]) def task_progress(self, request, task_id=None): ``` ### ✅ Fix 3: AI Settings Fallback **File**: `backend/igny8_core/ai/settings.py` **Change**: Added fallback to system account (aws-admin) for OpenAI settings when user account doesn't have them configured. ### ✅ Fix 4: Error Response Parameter **File**: `backend/igny8_core/modules/planner/views.py` **Change**: Fixed `error_response()` call - changed invalid `extra_data` parameter to `debug_info`. ## REQUIRED ACTIONS ### 🔴 CRITICAL: Fix Orphaned Users 1. **Run the fix script**: ```bash cd /data/app/igny8/backend python3 fix_orphaned_users.py ``` 2. **The script will**: - Find users with `account = NULL` - Create accounts for them OR delete them - Report results ### 🔴 CRITICAL: Make Account Field Required After fixing orphaned users, update the User model: **File**: `backend/igny8_core/auth/models.py` (line 644) **Change**: ```python # BEFORE account = models.ForeignKey(..., null=True, blank=True, ...) # AFTER account = models.ForeignKey(..., null=False, blank=False, ...) ``` **Then create and run migration**: ```bash cd /data/app/igny8/backend python3 manage.py makemigrations python3 manage.py migrate ``` ## VERIFICATION After fixes, verify: 1. **Check no orphaned users**: ```bash cd /data/app/igny8/backend python3 manage.py shell -c " from igny8_core.auth.models import User orphaned = User.objects.filter(account__isnull=True).count() print(f'Orphaned users: {orphaned}') " ``` Expected: `Orphaned users: 0` 2. **Test auto-cluster**: - Login as normal user - Select 5+ keywords - Click "Auto Cluster" - Should work without "Account is required" error 3. **Test task progress**: - Start any AI function - Progress modal should show real-time updates - No "403 Forbidden" errors ## ARCHITECTURE PRINCIPLES ESTABLISHED 1. **NO NULL ACCOUNTS**: Every user MUST have an account. Period. 2. **NO FALLBACKS**: If `request.user.account` is None, it's a data integrity issue, not a code issue. 3. **CLEAR FLOW**: - User registers → Account created → User.account set - User logs in → Middleware sets request.account from user.account - Permission checks → Verify request.user.account exists - Business logic → Use request.account directly 4. **FAIL FAST**: Don't hide errors with fallbacks. If account is missing, raise error. ## FILES MODIFIED 1. `backend/igny8_core/api/permissions.py` - Simplified HasTenantAccess 2. `backend/igny8_core/modules/system/integration_views.py` - Fixed task_progress permission 3. `backend/igny8_core/ai/settings.py` - Added system account fallback for AI settings 4. `backend/igny8_core/modules/planner/views.py` - Fixed error_response call ## FILES CREATED 1. `backend/fix_orphaned_users.py` - Script to fix orphaned users 2. `MULTI-TENANCY-FIXES-DEC-2025.md` - This document ## NEXT STEPS 1. ✅ Run orphaned users fix script 2. ✅ Make User.account field required (migration) 3. ✅ Test all business features 4. ✅ Update documentation to reflect "no fallbacks" principle 5. ✅ Add database constraints to prevent orphaned users --- **Date**: December 10, 2025 **Status**: FIXES APPLIED - VERIFICATION PENDING **Priority**: CRITICAL