14 KiB
Complete System Audit Report
Date: December 8, 2025
Scope: Full stack audit - Backend models, permissions, middleware, frontend, documentation
Status: 🔴 CRITICAL ISSUES FOUND
Executive Summary
Overall System State: 🔴 BROKEN
Your multi-tenancy system has 5 CRITICAL ISSUES that are causing widespread failures:
- Superuser Access Broken - Session auth blocked on API, no bypass logic working
- Permission System Contradictions - Multiple conflicting permission classes
- Missing Bypass Logic - Superuser/developer checks removed from critical paths
- Account Validation Too Strict - Blocks all users including system accounts
- Paid Plan Signup Missing - No path for users to subscribe to paid plans
Impact: Neither regular tenants NOR superusers can access the application.
Critical Issue #1: Superuser Access COMPLETELY BROKEN
Problem
Superusers cannot access the application at all due to conflicting middleware logic.
Root Cause
File: backend/igny8_core/auth/middleware.py:35-41
# Block superuser access via session on non-admin routes (JWT required)
auth_header = request.META.get('HTTP_AUTHORIZATION', '')
if request.user.is_superuser and not auth_header.startswith('Bearer '):
logout(request)
return JsonResponse(
{'success': False, 'error': 'Session authentication not allowed for API. Use JWT.'},
status=status.HTTP_403_FORBIDDEN,
)
This blocks ALL superuser access because:
- Superusers login via Django admin (session-based)
- Session cookies are sent to API automatically
- Middleware detects superuser + no JWT = LOGOUT + 403 error
- Even WITH JWT, there's no bypass logic downstream
Evidence
- Middleware forces JWT-only for superusers
- No JWT generation on login (traditional Django session auth)
- Permission classes have
is_superuserchecks BUT middleware blocks before reaching them - Admin panel uses session auth, but API rejects it
Impact
- Superusers cannot access ANY page in the app
- Developer account cannot debug issues
- System administration impossible
Critical Issue #2: Permission System Has CONTRADICTIONS
Problem
Three different permission modules with conflicting logic:
Module A: backend/igny8_core/auth/permissions.py
class IsOwnerOrAdmin(permissions.BasePermission):
def has_permission(self, request, view):
if getattr(user, "is_superuser", False):
return True # ✅ Superuser allowed
return user.role in ['owner', 'admin', 'developer']
Module B: backend/igny8_core/api/permissions.py
class HasTenantAccess(permissions.BasePermission):
def has_permission(self, request, view):
# NO superuser bypass ❌
# Regular users must have account access
if account:
return user_account == account
return False # Denies superusers without account match
Module C: backend/igny8_core/admin/base.py
class AccountAdminMixin:
def get_queryset(self, request):
if request.user.is_superuser or request.user.is_developer():
return qs # ✅ Bypass for superuser/developer
The Contradiction
- auth/permissions.py - Allows superuser bypass
- api/permissions.py - NO superuser bypass (strict tenant-only)
- admin/base.py - Allows superuser/developer bypass
- ViewSets - Use MIXED permission classes from different modules
Example of Broken ViewSet
File: backend/igny8_core/auth/views.py:144
class UsersViewSet(AccountModelViewSet):
permission_classes = [
IsAuthenticatedAndActive, # From api/permissions - no bypass
HasTenantAccess, # From api/permissions - no bypass
IsOwnerOrAdmin # From auth/permissions - has bypass
]
Result: Permission denied because HasTenantAccess (2nd check) fails before IsOwnerOrAdmin (3rd check) runs.
Impact
- Inconsistent behavior across endpoints
- Some endpoints work, some don't
- Debugging is impossible - which permission is denying?
Critical Issue #3: Account Validation TOO STRICT
Problem
Middleware validation blocks even system accounts and developers.
File: backend/igny8_core/auth/middleware.py:148-170 + auth/utils.py:133-195
def _validate_account_and_plan(self, request, user):
from .utils import validate_account_and_plan
is_valid, error_message, http_status = validate_account_and_plan(user)
if not is_valid:
return self._deny_request(request, error_message, http_status)
def validate_account_and_plan(user_or_account):
account = getattr(user_or_account, 'account', None)
if not account:
return (False, 'Account not configured', 403)
if account.status in ['suspended', 'cancelled']:
return (False, f'Account is {account.status}', 403)
plan = getattr(account, 'plan', None)
if not plan:
return (False, 'No subscription plan', 402)
if not plan.is_active:
return (False, 'Active subscription required', 402)
return (True, None, None)
The Problem
NO bypass for:
- Superusers (is_superuser=True)
- Developer role (role='developer')
- System accounts (aws-admin, default-account)
Even the developer account (dev@igny8.com) gets blocked if:
- Their account doesn't have a plan
- Their plan is inactive
- Their account status is suspended
Impact
- Cannot fix issues even with superuser access
- System accounts get blocked
- No emergency access path
Critical Issue #4: Missing Bypass Logic in Core Components
AccountModelViewSet - NO Bypass
File: backend/igny8_core/api/base.py:17-42
def get_queryset(self):
queryset = super().get_queryset()
if hasattr(queryset.model, 'account'):
# Filter by account
if account:
queryset = queryset.filter(account=account)
else:
return queryset.none() # ❌ Blocks everyone without account
Missing:
- No check for
is_superuser - No check for
role='developer' - No check for system accounts
HasTenantAccess Permission - NO Bypass
File: backend/igny8_core/api/permissions.py:23-52
class HasTenantAccess(permissions.BasePermission):
def has_permission(self, request, view):
# NO superuser bypass
if account:
return user_account == account
return False # ❌ Denies superusers
Impact
Every API endpoint using these base classes is broken for superusers.
Critical Issue #5: Paid Plan Signup Path MISSING
Problem
Marketing page shows paid plans ($89, $139, $229) but all signup buttons go to free trial.
File: tenancy-accounts-payments-still-have issues/PRICING-TO-PAID-SIGNUP-GAP.md
Gap Analysis
- ✅ Free trial signup works
- ❌ Paid plan signup does NOT exist
- ❌ No payment page
- ❌ No plan selection on signup
- ❌ No payment method collection
Missing Components
- Payment page UI (frontend)
- Plan parameter routing (/signup?plan=starter)
- Payment method selection
- Pending payment account creation
- Bank transfer confirmation flow
Models & Database State
✅ What's Working
-
Models are well-designed:
- Account, User, Plan, Subscription, Site, Sector
- Credit system (CreditTransaction, CreditUsageLog)
- Payment/Invoice models exist
- Proper relationships (ForeignKey, OneToOne)
-
Database has data:
- 5 plans (free, starter, growth, scale, enterprise)
- 8 accounts actively using system
- 280+ credit transactions
- Credit tracking working
-
Soft delete implemented:
- SoftDeletableModel base class
- Retention policies
- Restore functionality
❌ What's Broken
-
Missing field in Account model:
payment_methodfield defined in model but NOT in database (migration missing)
-
Subscription table empty:
- No subscriptions exist despite Subscription model
- Users operating on credits without subscription tracking
-
Payment system incomplete:
- Models exist but no data
- No payment gateway integration
- No invoice generation in use
Documentation Issues
Problem: Scattered & Contradictory
Three separate doc folders:
master-docs/- Structured, organized, but may be outdatedold-docs/- Legacy docs, unclear what's still validtenancy-accounts-payments-still-have issues/- Recent fixes, most accurate
Contradictions Found
- Superuser bypass: Docs say it exists, code shows it was removed
- Payment methods: Docs describe manual payment flow, but frontend doesn't implement it
- Plan allocation: Docs show complex fallback logic, implementation shows it was simplified
- Session auth: Docs don't mention JWT requirement for API
Missing from Docs
- Current state of superuser access (broken)
- Which permission module is canonical
- Middleware validation rules
- Account.payment_method migration status
Frontend Analysis
✅ Frontend Code Quality: GOOD
- Well-structured React/TypeScript
- Proper state management (Zustand)
- Error handling hooks exist
- API service layer organized
❌ Frontend Issues
- No paid plan signup page - Missing
/paymentroute - No error display for permission denied - Silent failures
- No JWT token generation - Still using session auth
- No superuser indicator - Users don't know why access is denied
ROOT CAUSE ANALYSIS
Timeline of What Happened
- Initially: Superuser had full bypass, everything worked
- Tenancy work started: Added strict tenant isolation
- Security concern: Removed some bypass logic to prevent session contamination
- Over-correction: Removed TOO MUCH bypass logic
- Now: Neither tenants nor superusers can access anything
The Core Problem
Attempted to fix security issue but broke fundamental access:
- Session contamination IS a real issue
- JWT-only for API IS correct approach
- BUT: Removed all bypass logic instead of fixing authentication method
- AND: Middleware blocks before permission classes can allow bypass
RECOMMENDATIONS
I have TWO OPTIONS for you:
Option 1: QUICK FIX (2-4 hours) ⚡
Restore superuser access immediately, patch critical flows
Pros:
- Fastest path to working system
- Superuser can access app today
- Tenant system keeps working
Cons:
- Technical debt remains
- Documentation still messy
- Some inconsistencies persist
What gets fixed:
- Add superuser bypass to middleware
- Add developer role bypass to HasTenantAccess
- Add system account bypass to AccountModelViewSet
- Generate JWT tokens on login
- Update frontend to use JWT
Estimated time: 2-4 hours
Effort: LOW
Risk: LOW
Option 2: PROPER REBUILD (2-3 days) 🏗️
Redesign tenancy system with clean architecture
Pros:
- Clean, maintainable code
- Consistent permission logic
- Proper documentation
- All flows working correctly
- Future-proof architecture
Cons:
- Takes 2-3 days
- Requires careful testing
- Must migrate existing data
What gets rebuilt:
- Unified permission system - One module, clear hierarchy
- Clean middleware - Proper bypass logic for all roles
- JWT authentication - Token generation + refresh
- Paid plan signup - Complete payment flow
- Consolidated docs - Single source of truth
- Account migration - Add missing payment_method field
- Subscription system - Link accounts to subscriptions
- Test suite - Cover all permission scenarios
Estimated time: 2-3 days
Effort: MEDIUM
Risk: MEDIUM (with proper testing)
MY RECOMMENDATION
Start with Option 1 (Quick Fix), then Option 2
Why:
- You need access NOW - can't wait 3 days
- Quick fix restores functionality in hours
- Then properly rebuild when system is accessible
- Less risk - incremental improvement
Action Plan:
- NOW: Quick fix (2-4 hours) - restore superuser access
- Tomorrow: Test all flows, document issues
- Next 2-3 days: Proper rebuild with clean architecture
- End result: Production-ready multi-tenancy system
Next Steps
Please confirm which option you want:
Option A: Quick fix now (I'll start immediately)
Option B: Full rebuild (2-3 days, but cleaner)
Option C: Quick fix now + full rebuild after (RECOMMENDED)
Once you confirm, I'll begin implementation with detailed progress updates.
File Inventory (Issues Found)
Backend Files with Issues
- ✅
/backend/igny8_core/auth/middleware.py- Blocks superusers - ✅
/backend/igny8_core/auth/utils.py- No bypass in validation - ✅
/backend/igny8_core/api/permissions.py- No superuser bypass - ✅
/backend/igny8_core/api/base.py- No bypass in queryset filter - ⚠️
/backend/igny8_core/auth/models.py- Missing payment_method migration - ✅
/backend/igny8_core/auth/views.py- Mixed permission classes
Frontend Files with Issues
- ⚠️
/frontend/src/services/api.ts- No JWT token handling - ❌
/frontend/src/pages/Payment.tsx- MISSING (paid signup) - ⚠️
/frontend/src/components/auth/SignUpForm.tsx- No plan parameter
Documentation Issues
- ⚠️
master-docs/- May be outdated - ⚠️
old-docs/- Unclear what's valid - ✅
tenancy-accounts-payments-still-have issues/- Most accurate
Legend:
- ✅ = Critical issue, must fix
- ⚠️ = Important but not blocking
- ❌ = Missing component
Conclusion
Your system has good architecture but broken implementation due to over-correction during security fixes. The models are solid, the database is working, but the permission/access layer is preventing anyone (including you) from using the app.
The good news: This is fixable in a few hours with targeted changes.
Waiting for your decision on which option to proceed with...