# COMPREHENSIVE REFACTORING PLAN: Frontend Admin Removal & Global Settings Architecture **Date**: December 20, 2025 **Status**: Detailed Implementation Plan **Priority**: HIGH - Architecture Refactoring --- ## PART 1: FRONTEND PAGES - COMPLETE INVENTORY & MIGRATION PLAN ### 1.1 ADMIN PAGES TO REMOVE (Frontend → Django Admin) #### Page 1: System Dashboard - **File**: `frontend/src/pages/admin/AdminSystemDashboard.tsx` - **Current Route**: `/admin/dashboard` - **APIs Called**: - `/v1/admin/billing/stats/` - System-wide billing statistics - **Data Displayed**: - Total users, active users - Credits issued vs used (30-day) - Top accounts by credits - Quick links to: Marketing site, App, Django admin, PgAdmin, FileManager, Portainer, Swagger, ReDoc, Gitea - **Actions**: Read-only dashboard - **Django Admin Equivalent**: ✅ YES - Custom dashboard already exists at `/admin/dashboard/` - **Migration Strategy**: ✅ **REMOVE FRONTEND** - Django admin dashboard already has similar functionality - **Status**: Ready to remove --- #### Page 2: All Accounts Management - **File**: `frontend/src/pages/admin/AdminAllAccountsPage.tsx` - **Current Route**: `/admin/accounts` - **APIs Called**: - `/v1/admin/accounts/` - List all accounts with search/filter - **Data Displayed**: - Account name, owner, plan, status, credits - Search by name/owner - Filter by status, plan - **Actions**: View accounts, search, filter - **Django Admin Equivalent**: ✅ YES - `/admin/igny8_core_auth/account/` - **Django Admin Features**: - List display with all fields - Search by name, owner email - Filter by status, plan, created date - Bulk actions (activate, suspend, soft delete, credit adjustment) - **180+ bulk actions** just implemented - **Migration Strategy**: ✅ **REMOVE FRONTEND** - Django admin is MORE powerful - **Status**: Ready to remove --- #### Page 3: Subscriptions Management - **File**: `frontend/src/pages/admin/AdminSubscriptionsPage.tsx` - **Current Route**: `/admin/subscriptions` - **APIs Called**: - `/v1/admin/subscriptions/` - List all subscriptions - `/v1/admin/subscriptions/{id}/activate/` - Activate subscription - `/v1/admin/subscriptions/{id}/cancel/` - Cancel subscription - **Data Displayed**: - Account name, plan, status, start/end date - Filter by status, plan - **Actions**: Activate, cancel subscriptions - **Django Admin Equivalent**: ✅ YES - `/admin/igny8_core_auth/subscription/` - **Django Admin Features**: - List with all fields - Filter by status, plan, account - Bulk actions: activate, cancel, renew, upgrade plan - Change history tracking - **Migration Strategy**: ✅ **REMOVE FRONTEND** - Django admin has same + more features - **Status**: Ready to remove --- #### Page 4: Account Limits Configuration - **File**: `frontend/src/pages/admin/AdminAccountLimitsPage.tsx` - **Current Route**: `/admin/account-limits` - **APIs Called**: ❌ NONE - Using mock data - **Data Displayed**: Mock list of accounts with limit overrides - **Actions**: None (placeholder UI) - **Django Admin Equivalent**: ⚠️ PARTIAL - Plan limits exist in Plan model, usage tracking in PlanLimitUsage - **Migration Strategy**: - ✅ **REMOVE FRONTEND** - Non-functional placeholder - ⚠️ **ADD TO DJANGO ADMIN** if needed: Create inline for account-specific limit overrides - **Status**: Remove (no functionality to preserve) --- #### Page 5: Admin Billing Overview - **File**: `frontend/src/pages/Admin/AdminBilling.tsx` - **Current Route**: `/admin/billing` - **APIs Called**: - `/v1/admin/billing/stats/` - Billing statistics - `/v1/admin/users/` - All users with credits - `/v1/admin/credit-costs/` - Credit cost configurations - `/v1/admin/users/{id}/adjust-credits/` - Adjust user credits - **Data Displayed**: - Billing stats (credits issued, used, revenue) - User list with credit balances - Credit cost configurations - **Actions**: - Adjust credits for any user (with reason) - View/edit credit costs - **Django Admin Equivalent**: ✅ YES - Multiple models - `/admin/igny8_core_auth/account/` - Account with credit adjustment actions - `/admin/billing/credittransaction/` - All transactions - `/admin/billing/creditcostconfig/` - Cost configurations - **Django Admin Features**: - Bulk credit adjustment on Account admin - Full transaction history - Edit credit costs directly - **Migration Strategy**: ✅ **REMOVE FRONTEND** - Django admin has all functionality - **Status**: Ready to remove --- #### Page 6: All Invoices - **File**: `frontend/src/pages/admin/AdminAllInvoicesPage.tsx` - **Current Route**: `/admin/invoices` - **APIs Called**: - `/v1/admin/invoices/` - List all invoices across accounts - **Data Displayed**: - Invoice number, account, amount, status, date - Search by account, invoice number - Filter by status - **Actions**: View invoices, search, filter - **Django Admin Equivalent**: ✅ YES - `/admin/billing/invoice/` - **Django Admin Features**: - List with all fields - Search by number, account - Filter by status, date range - Bulk actions: mark as paid/pending/cancelled, send reminders, apply late fees - **Migration Strategy**: ✅ **REMOVE FRONTEND** - Django admin superior - **Status**: Ready to remove --- #### Page 7: All Payments - **File**: `frontend/src/pages/admin/AdminAllPaymentsPage.tsx` - **Current Route**: `/admin/payments` - **APIs Called**: - `/v1/admin/payments/` - List all payments - `/v1/admin/payments/{id}/` - Payment details - **Data Displayed**: - Payment ID, account, amount, method, status, date - Search by account, transaction ID - Filter by status, method - **Actions**: View payments, search, filter - **Django Admin Equivalent**: ✅ YES - `/admin/billing/payment/` - **Django Admin Features**: - List with all fields - Search capabilities - Filter by status, method, date - Bulk actions: verify, mark failed, refund - **Migration Strategy**: ✅ **REMOVE FRONTEND** - Django admin has it - **Status**: Ready to remove --- #### Page 8: Payment Approval (Manual Payments) - **File**: `frontend/src/pages/admin/PaymentApprovalPage.tsx` - **Current Route**: `/admin/payments/approvals` - **APIs Called**: - `/v1/admin/payments/pending/` - Pending manual payments - `/v1/admin/payments/{id}/approve/` - Approve payment - `/v1/admin/payments/{id}/reject/` - Reject payment - **Data Displayed**: - Pending manual payments awaiting approval - Payment details, account info - **Actions**: Approve or reject manual payments - **Django Admin Equivalent**: ⚠️ PARTIAL - Payment model exists, but no specific approval workflow - **Migration Strategy**: - ✅ **REMOVE FRONTEND** - ⚠️ **ADD TO DJANGO ADMIN**: Add list filter for pending status + approve/reject actions - **Status**: Remove, add actions to Django admin Payment model --- #### Page 9: Credit Packages - **File**: `frontend/src/pages/admin/AdminCreditPackagesPage.tsx` - **Current Route**: `/admin/credit-packages` - **APIs Called**: - `/v1/admin/credit-packages/` - CRUD operations - **Data Displayed**: - Package name, credits, price, active status - **Actions**: Create, edit, delete, activate/deactivate packages - **Django Admin Equivalent**: ✅ YES - `/admin/billing/creditpackage/` - **Django Admin Features**: - Full CRUD - Import/export - Bulk activate/deactivate - **Migration Strategy**: ✅ **REMOVE FRONTEND** - Django admin sufficient - **Status**: Ready to remove --- #### Page 10: Credit Costs Configuration - **File**: `frontend/src/pages/Admin/AdminCreditCostsPage.tsx` - **Current Route**: `/admin/credit-costs` - **APIs Called**: - `/v1/admin/credit-costs/` - CRUD for credit costs - **Data Displayed**: - Operation type, cost in credits - All operations (keyword research, clustering, content gen, images, etc.) - **Actions**: Create, edit, delete cost configurations - **Django Admin Equivalent**: ✅ YES - `/admin/billing/creditcostconfig/` - **Django Admin Features**: - Full CRUD on cost configs - Organized by operation type - Bulk operations - **Migration Strategy**: ✅ **REMOVE FRONTEND** - Django admin has it - **Status**: Ready to remove --- #### Page 11: All Users - **File**: `frontend/src/pages/admin/AdminAllUsersPage.tsx` - **Current Route**: `/admin/users` - **APIs Called**: - `/v1/admin/users/` - List all users across accounts - **Data Displayed**: - Username, email, account, role, status - Search by name, email - Filter by role, account - **Actions**: View users, search, filter - **Django Admin Equivalent**: ✅ YES - `/admin/igny8_core_auth/user/` - **Django Admin Features**: - Comprehensive user management - Search by username, email, account - Filter by role, status, account - Bulk actions: activate, deactivate, assign groups, reset password, verify email - **Migration Strategy**: ✅ **REMOVE FRONTEND** - Django admin superior - **Status**: Ready to remove --- #### Page 12: Roles & Permissions - **File**: `frontend/src/pages/admin/AdminRolesPermissionsPage.tsx` - **Current Route**: `/admin/roles` - **APIs Called**: ❌ NONE - Mock data - **Data Displayed**: Mock list of roles with permissions - **Actions**: None (placeholder) - **Django Admin Equivalent**: ✅ YES - `/admin/auth/group/` and `/admin/auth/permission/` - **Django Admin Features**: - Full group (role) management - Permission assignment per group - User group assignments - **Migration Strategy**: ✅ **REMOVE FRONTEND** - Non-functional placeholder - **Status**: Remove (Django admin already handles this) --- #### Page 13: Activity Logs (Audit Trail) - **File**: `frontend/src/pages/admin/AdminActivityLogsPage.tsx` - **Current Route**: `/admin/activity-logs` - **APIs Called**: ❌ NONE - Mock data - **Data Displayed**: Mock audit logs - **Actions**: None (placeholder) - **Django Admin Equivalent**: ✅ YES - `/admin/admin/logentry/` - **Django Admin Features**: - Complete audit trail of all admin actions - Filter by user, action type, date - Search by object - **Migration Strategy**: ✅ **REMOVE FRONTEND** - Django admin has complete audit trail - **Status**: Remove (Django admin LogEntry is production-ready) --- #### Page 14: System Settings (Global Config) - **File**: `frontend/src/pages/admin/AdminSystemSettingsPage.tsx` - **Current Route**: `/admin/system-settings` - **APIs Called**: ❌ NONE - Mock data - **Data Displayed**: Mock system-wide settings - **Actions**: None (placeholder) - **Django Admin Equivalent**: ⚠️ PARTIAL - SystemSettings model exists - **Migration Strategy**: - ✅ **REMOVE FRONTEND** - Non-functional - ✅ **USE DJANGO ADMIN** - `/admin/system/systemsettings/` - **Status**: Remove, use Django admin --- #### Page 15: System Health Monitor - **File**: `frontend/src/pages/admin/AdminSystemHealthPage.tsx` - **Current Route**: `/settings/status` (also `/admin/system-health`) - **APIs Called**: ❌ NONE - Mock data - **Data Displayed**: Mock infrastructure health (DB, Redis, Celery, API) - **Actions**: None (placeholder) - **Django Admin Equivalent**: ❌ NO - Needs to be created - **Migration Strategy**: - ✅ **REMOVE FRONTEND** - ⚠️ **CREATE IN DJANGO ADMIN**: New monitoring page at `/admin/monitoring/system-health/` - **What to build**: Real health checks for database, Redis, Celery workers, API response times - **Status**: Remove, create new Django admin page --- #### Page 16: API Monitor - **File**: `frontend/src/pages/admin/AdminAPIMonitorPage.tsx` AND `frontend/src/pages/Settings/ApiMonitor.tsx` - **Current Route**: `/settings/api-monitor` - **APIs Called**: ❌ NONE - Frontend runs endpoint checks directly - **Data Displayed**: - 100+ API endpoint health checks - Response times, error rates - Status per endpoint group - **Actions**: Manual endpoint testing, real-time monitoring - **Django Admin Equivalent**: ❌ NO - Needs to be created - **Migration Strategy**: - ✅ **REMOVE FRONTEND** - ⚠️ **CREATE IN DJANGO ADMIN**: `/admin/monitoring/api-monitor/` - **What to build**: - Backend service to check API endpoints - Store results in database - Display status dashboard - Alert on failures - **Status**: Remove, create new Django admin page (complex - worth building) --- ### 1.2 SETTINGS PAGES ANALYSIS #### Page 17: Module Settings (Enable/Disable Modules) - **File**: `frontend/src/pages/Settings/Modules.tsx` - **Current Route**: `/settings/modules` - **APIs Called**: - `/v1/system/settings/modules/` - GET/PUT module enable settings - **Data Displayed**: Toggle switches for each module (Planner, Writer, Automation, etc.) - **Actions**: Enable/disable modules per account - **Who Needs This**: ✅ **ACCOUNT OWNERS** - This is account-specific configuration - **Django Admin Equivalent**: ✅ YES - `/admin/system/moduleenablesettings/` - **Migration Strategy**: ⚠️ **KEEP IN FRONTEND** - Normal users need this - **Status**: Keep (user-facing feature, not admin-only) --- #### Page 18: AI Settings - **File**: `frontend/src/pages/Settings/AI.tsx` - **Current Route**: `/settings/ai` - **APIs Called**: - `/v1/system/settings/ai/` - GET/PUT AI settings (models, prompts, etc.) - **Data Displayed**: - AI model selection (text, image) - Prompt customization - Temperature, tokens, etc. - **Actions**: Configure AI behavior per account - **Who Needs This**: ⚠️ **POWER USERS** - Account-specific AI config - **Current Issue**: ❌ Using aws-admin fallback for settings - **Migration Strategy**: - ⚠️ **REFACTOR** - Implement global + account override pattern - Keep in frontend but connect to proper global settings - **Status**: Keep, refactor backend --- #### Page 19: System Settings (Account-Level) - **File**: `frontend/src/pages/Settings/System.tsx` - **Current Route**: `/settings/system` - **APIs Called**: TBD - Check file - **Migration Strategy**: **AUDIT NEEDED** - Unclear if account-level or global --- #### Page 20: Debug Status - **File**: `frontend/src/pages/Settings/DebugStatus.tsx` - **Current Route**: `/settings/debug-status` - **APIs Called**: - Various debug endpoints (environment, config, cache status) - **Data Displayed**: System debug information, environment variables (masked), active settings - **Actions**: View debug info, clear caches - **Who Needs This**: ⚠️ **DEVELOPERS ONLY** - **Migration Strategy**: - ✅ **REMOVE FROM FRONTEND** - ⚠️ **CREATE IN DJANGO ADMIN**: `/admin/monitoring/debug-console/` - **Status**: Remove, move to Django admin --- #### Page 21-37: Other Settings Pages (Keep - User-Facing) - `/settings/account` - ✅ Keep (account info, team management) - `/settings/billing` - ✅ Keep (view own invoices, add payment methods) - `/settings/credits` - ✅ Keep (view credit balance, usage, buy more) - `/settings/integration` - ✅ Keep (WordPress site connections) - `/settings/users` - ✅ Keep (manage team members) - `/settings/sites` - ✅ Keep (manage sites/domains) - `/settings/publishing` - ✅ Keep (publishing settings per site) - `/settings/subscriptions` - ✅ Keep (view/manage own subscription) - `/settings/plans` - ✅ Keep (view available plans, upgrade) - `/settings/industries` - ✅ Keep (select industry for account) - `/settings/profile` - ✅ Keep (user profile settings) - `/settings/import-export` - ✅ Keep (data export for account) - `/settings/general` - ✅ Keep (general account preferences) **Status**: All KEEP - Normal user features --- ### 1.3 UI ELEMENTS PAGES (23 Pages) **Directory**: `frontend/src/pages/Settings/UiElements/` **Pages**: 1. Alerts 2. Avatars 3. Badges 4. Breadcrumb 5. Buttons 6. ButtonsGroup 7. Cards 8. Carousel 9. Dropdowns 10. Images 11. Links 12. List 13. Modals 14. Notifications 15. Pagination 16. Popovers 17. PricingTable 18. Progressbar 19. Ribbons 20. Spinners 21. Tabs 22. Tooltips 23. Videos **Purpose**: Design system showcase / component library documentation **Who Needs This**: - ❌ Not needed in production app - ✅ Useful for developers - ✅ Could be useful for marketing (show UI quality) **Migration Strategy**: - ✅ **REMOVE FROM MAIN APP** - ⚠️ **OPTIONAL**: Move to marketing site at `https://igny8.com/design-system` with `noindex` meta tag - **Alternative**: Create separate Storybook instance for component documentation **Status**: Remove from production app --- ## PART 2: SETTINGS ARCHITECTURE - DETAILED ANALYSIS ### 2.1 CURRENT DATABASE MODELS #### Integration Settings Model **File**: `backend/igny8_core/modules/system/models.py` ```python class IntegrationSettings(AccountBaseModel): integration_type = models.CharField(max_length=50) # openai, runware, gsc, image_generation config = models.JSONField(default=dict) # Stores API keys, settings is_active = models.BooleanField(default=True) # Foreign key to Account (inherited from AccountBaseModel) # account = models.ForeignKey(Account) ``` **Current Config Structure**: ```json { "openai_api_key": "sk-...", "openai_model": "gpt-4", "openai_temperature": 0.7, "openai_max_tokens": 4000, "dalle_api_key": "sk-...", "dalle_model": "dall-e-3", "dalle_size": "1024x1024", "dalle_quality": "standard", "dalle_style": "vivid", "anthropic_api_key": "sk-...", "anthropic_model": "claude-3-sonnet-20240229" } ``` **Issue**: ❌ Account-based, using aws-admin as fallback (confusing pattern) --- #### AI Prompts Model **File**: `backend/igny8_core/modules/system/models.py` ```python class AIPrompt(AccountBaseModel): prompt_type = models.CharField(max_length=50) # clustering, ideas, content_generation, etc. prompt_value = models.TextField() # Current prompt default_prompt = models.TextField() # Default (for reset) is_active = models.BooleanField(default=True) # unique_together = [['account', 'prompt_type']] ``` **Current Behavior**: - ✅ Has `default_prompt` field - Good! - ⚠️ Account-specific prompts - ❌ No global prompt library **Issue**: Need global library + account customization --- #### Author Profiles Model ```python class AuthorProfile(AccountBaseModel): name = models.CharField(max_length=255) description = models.TextField() tone = models.CharField(max_length=100) language = models.CharField(max_length=50, default='en') structure_template = models.JSONField(default=dict) is_active = models.BooleanField(default=True) ``` **Issue**: Account-based, no global library --- #### Content Strategies Model ```python class Strategy(AccountBaseModel): name = models.CharField(max_length=255) description = models.TextField() sector = models.ForeignKey(Sector) # Optional prompt_types = models.JSONField(default=list) section_logic = models.JSONField(default=dict) is_active = models.BooleanField(default=True) ``` **Issue**: Account-based, no global templates --- ### 2.2 PROPOSED SETTINGS ARCHITECTURE #### Category 1: TRULY GLOBAL (No Account Override Needed) | Setting | Current | Proposed | Reasoning | |---------|---------|----------|-----------| | **Credit Cost Config** | ✅ Global | ✅ Keep Global | System-wide pricing, no per-account override | | **Rate Limiting Rules** | ✅ Global (code) | ✅ Keep Global | System-wide throttling | | **Publishing Channels** | ✅ Global | ✅ Keep Global | Available platforms (WordPress, Ghost, etc.) | | **System Feature Flags** | ✅ Global | ✅ Keep Global | Enable/disable features platform-wide | **Implementation**: Already correct, no changes needed --- #### Category 2: GLOBAL DEFAULT + ACCOUNT OVERRIDE (Complex Pattern) ##### 2.2.1 AI Integration Settings (OpenAI, DALL-E, Anthropic) **Current**: ```python IntegrationSettings(AccountBaseModel): account = FK(Account) # Per-account, fallback to aws-admin integration_type = 'openai' config = {openai_api_key, openai_model, ...} ``` **Proposed - Two Models**: ```python # NEW: Global defaults (no account FK) class GlobalIntegrationSettings(models.Model): """Platform-wide default API keys and settings""" # OpenAI openai_api_key = EncryptedCharField(max_length=500) openai_model = models.CharField(max_length=100, default='gpt-4-turbo-preview') openai_temperature = models.FloatField(default=0.7) openai_max_tokens = models.IntegerField(default=4000) # DALL-E dalle_api_key = EncryptedCharField(max_length=500) dalle_model = models.CharField(max_length=100, default='dall-e-3') dalle_size = models.CharField(max_length=20, default='1024x1024') dalle_quality = models.CharField(max_length=20, default='standard') dalle_style = models.CharField(max_length=20, default='vivid') # Anthropic anthropic_api_key = EncryptedCharField(max_length=500) anthropic_model = models.CharField(max_length=100, default='claude-3-sonnet-20240229') # Metadata is_active = models.BooleanField(default=True) last_updated = models.DateTimeField(auto_now=True) updated_by = models.ForeignKey(User, null=True) class Meta: verbose_name = "Global Integration Settings" # Singleton pattern - only one row def save(self, *args, **kwargs): # Enforce singleton self.pk = 1 super().save(*args, **kwargs) @classmethod def get_instance(cls): obj, created = cls.objects.get_or_create(pk=1) return obj # MODIFIED: Account overrides (optional) class AccountIntegrationOverride(models.Model): """Optional per-account API key overrides""" account = models.OneToOneField(Account, on_delete=models.CASCADE, related_name='integration_override') use_own_keys = models.BooleanField(default=False, help_text="Use account's own API keys instead of global") # OpenAI overrides (null = use global) openai_api_key = EncryptedCharField(max_length=500, null=True, blank=True) openai_model = models.CharField(max_length=100, null=True, blank=True) openai_temperature = models.FloatField(null=True, blank=True) openai_max_tokens = models.IntegerField(null=True, blank=True) # DALL-E overrides dalle_api_key = EncryptedCharField(max_length=500, null=True, blank=True) dalle_model = models.CharField(max_length=100, null=True, blank=True) dalle_size = models.CharField(max_length=20, null=True, blank=True) dalle_quality = models.CharField(max_length=20, null=True, blank=True) dalle_style = models.CharField(max_length=20, null=True, blank=True) # Anthropic overrides anthropic_api_key = EncryptedCharField(max_length=500, null=True, blank=True) anthropic_model = models.CharField(max_length=100, null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def get_effective_openai_settings(self): """Get effective OpenAI settings (own or global)""" if self.use_own_keys and self.openai_api_key: return { 'api_key': self.openai_api_key, 'model': self.openai_model or GlobalIntegrationSettings.get_instance().openai_model, 'temperature': self.openai_temperature if self.openai_temperature is not None else GlobalIntegrationSettings.get_instance().openai_temperature, 'max_tokens': self.openai_max_tokens or GlobalIntegrationSettings.get_instance().openai_max_tokens, } else: # Use global global_settings = GlobalIntegrationSettings.get_instance() return { 'api_key': global_settings.openai_api_key, 'model': global_settings.openai_model, 'temperature': global_settings.openai_temperature, 'max_tokens': global_settings.openai_max_tokens, } def get_effective_dalle_settings(self): """Get effective DALL-E settings""" if self.use_own_keys and self.dalle_api_key: global_settings = GlobalIntegrationSettings.get_instance() return { 'api_key': self.dalle_api_key, 'model': self.dalle_model or global_settings.dalle_model, 'size': self.dalle_size or global_settings.dalle_size, 'quality': self.dalle_quality or global_settings.dalle_quality, 'style': self.dalle_style or global_settings.dalle_style, } else: global_settings = GlobalIntegrationSettings.get_instance() return { 'api_key': global_settings.dalle_api_key, 'model': global_settings.dalle_model, 'size': global_settings.dalle_size, 'quality': global_settings.dalle_quality, 'style': global_settings.dalle_style, } ``` **Updated Lookup Logic**: ```python # backend/igny8_core/ai/settings.py def get_openai_settings(account): """Get effective OpenAI settings for account""" try: override = AccountIntegrationOverride.objects.get(account=account) if override.use_own_keys: return override.get_effective_openai_settings() except AccountIntegrationOverride.DoesNotExist: pass # Use global settings global_settings = GlobalIntegrationSettings.get_instance() return { 'api_key': global_settings.openai_api_key, 'model': global_settings.openai_model, 'temperature': global_settings.openai_temperature, 'max_tokens': global_settings.openai_max_tokens, } def get_dalle_settings(account): """Get effective DALL-E settings for account""" try: override = AccountIntegrationOverride.objects.get(account=account) if override.use_own_keys: return override.get_effective_dalle_settings() except AccountIntegrationOverride.DoesNotExist: pass # Use global global_settings = GlobalIntegrationSettings.get_instance() return { 'api_key': global_settings.dalle_api_key, 'model': global_settings.dalle_model, 'size': global_settings.dalle_size, 'quality': global_settings.dalle_quality, 'style': global_settings.dalle_style, } ``` **Frontend Display**: ```typescript // For regular users in /settings/ai { "Using global AI settings": true, "Current model": "gpt-4-turbo-preview (global)", "Want to use your own API keys?": "Contact support" // Enterprise feature } // For enterprise accounts with override { "Using own API keys": true, "OpenAI API Key": "sk-...****", "Model": "gpt-4" (dropdown with all available models), "Temperature": 0.7 (slider), "Reset to global settings": (button) } ``` --- ##### 2.2.2 AI Prompts **Current**: ```python class AIPrompt(AccountBaseModel): account = FK(Account) # Per-account prompt_type = 'clustering' prompt_value = "Current prompt..." default_prompt = "Default prompt..." # ✅ Has this! ``` **Proposed - Add Global Library**: ```python # NEW: Global prompt library (no account) class GlobalAIPrompt(models.Model): """Platform-wide default prompts""" prompt_type = models.CharField(max_length=50, unique=True) prompt_value = models.TextField(help_text="Default prompt template") description = models.TextField(blank=True) variables = models.JSONField(default=list, help_text="List of variables like {keyword}, {industry}, etc.") is_active = models.BooleanField(default=True) version = models.IntegerField(default=1) last_updated = models.DateTimeField(auto_now=True) class Meta: verbose_name = "Global AI Prompt" ordering = ['prompt_type'] # KEEP: Account-specific customization class AIPrompt(AccountBaseModel): """Account-specific prompt customizations""" account = FK(Account) prompt_type = models.CharField(max_length=50) prompt_value = models.TextField() # Customized prompt is_customized = models.BooleanField(default=False, help_text="True if modified from global") # Remove default_prompt field (use global instead) # default_prompt = REMOVED def reset_to_global(self): """Reset prompt to global default""" global_prompt = GlobalAIPrompt.objects.get(prompt_type=self.prompt_type) self.prompt_value = global_prompt.prompt_value self.is_customized = False self.save() def get_effective_prompt(self): """Get the prompt to use (customized or global)""" if self.is_customized and self.prompt_value: return self.prompt_value else: # Use global try: global_prompt = GlobalAIPrompt.objects.get(prompt_type=self.prompt_type, is_active=True) return global_prompt.prompt_value except GlobalAIPrompt.DoesNotExist: return self.prompt_value # Fallback to stored value ``` **Lookup Logic**: ```python def get_prompt(account, prompt_type): """Get effective prompt for account""" try: account_prompt = AIPrompt.objects.get(account=account, prompt_type=prompt_type) if account_prompt.is_customized: return account_prompt.prompt_value except AIPrompt.DoesNotExist: pass # Use global global_prompt = GlobalAIPrompt.objects.get(prompt_type=prompt_type, is_active=True) return global_prompt.prompt_value ``` **User Experience**: ``` [Prompt Editor - Clustering] Default (Global): "Analyze the following keywords and group them into semantic clusters..." [Using global prompt] [Customize] OR (if customized): Your Custom Prompt: [Textarea with custom prompt] [Save] [Reset to Global Default] ``` --- ##### 2.2.3 Author Profiles **Proposed**: ```python # NEW: Global author profile library class GlobalAuthorProfile(models.Model): """Platform-wide author persona templates""" name = models.CharField(max_length=255, unique=True) description = models.TextField() tone = models.CharField(max_length=100) language = models.CharField(max_length=50, default='en') structure_template = models.JSONField(default=dict) is_active = models.BooleanField(default=True) category = models.CharField(max_length=50, choices=[ ('saas', 'SaaS/B2B'), ('ecommerce', 'E-commerce'), ('blog', 'Blog/Publishing'), ('technical', 'Technical'), ('creative', 'Creative'), ]) # KEEP: Account customization class AuthorProfile(AccountBaseModel): account = FK(Account) name = models.CharField(max_length=255) description = models.TextField() tone = models.CharField(max_length=100) language = models.CharField(max_length=50, default='en') structure_template = models.JSONField(default=dict) is_active = models.BooleanField(default=True) is_custom = models.BooleanField(default=False, help_text="True if created by user, not cloned from global") cloned_from = models.ForeignKey(GlobalAuthorProfile, null=True, blank=True, on_delete=models.SET_NULL) ``` **User Experience**: ``` [Author Profiles] Global Library (Available to All Accounts): - SaaS B2B Professional (tone: professional, formal) - E-commerce Product Descriptions (tone: persuasive, benefit-focused) - Blog Conversational (tone: casual, friendly) [Clone to My Account] My Custom Profiles: - Tech Startup Informal (cloned from SaaS B2B, customized) [Edit] [Delete] - Product Launch Hype (created from scratch) [Edit] [Delete] [Create New Profile] ``` --- ##### 2.2.4 Content Strategies **Similar to Author Profiles**: ```python # NEW: Global strategy templates class GlobalStrategy(models.Model): name = models.CharField(max_length=255, unique=True) description = models.TextField() prompt_types = models.JSONField(default=list) section_logic = models.JSONField(default=dict) is_active = models.BooleanField(default=True) category = models.CharField(max_length=50) # blog, ecommerce, saas, etc. # KEEP: Account strategies class Strategy(AccountBaseModel): account = FK(Account) name = models.CharField(max_length=255) description = models.TextField() sector = models.ForeignKey(Sector, null=True) prompt_types = models.JSONField(default=list) section_logic = models.JSONField(default=dict) is_active = models.BooleanField(default=True) is_custom = models.BooleanField(default=False) cloned_from = models.ForeignKey(GlobalStrategy, null=True) ``` --- ### 2.3 SETTINGS MIGRATION SUMMARY | Setting Type | Current Model | Proposed Change | Pattern | |--------------|---------------|-----------------|---------| | **OpenAI API Key** | `IntegrationSettings(account)` with aws-admin fallback | `GlobalIntegrationSettings` + `AccountIntegrationOverride` | Global + Optional Override | | **DALL-E Settings** | `IntegrationSettings(account)` with fallback | Same as OpenAI | Global + Optional Override | | **AI Model Selection** | `IntegrationSettings.config['openai_model']` | Multiple fields: text models, image models, embedding models | Global + Override per model type | | **Image Generation Settings** | `IntegrationSettings.config` | Separate fields for size, quality, style, steps, guidance | Global + Override | | **AI Prompts** | `AIPrompt(account)` with `default_prompt` field | `GlobalAIPrompt` + `AIPrompt(account)` with `is_customized` flag | Global Library + Account Custom | | **Author Profiles** | `AuthorProfile(account)` only | `GlobalAuthorProfile` + `AuthorProfile(account)` with `cloned_from` | Global Library + Account Clone/Custom | | **Content Strategies** | `Strategy(account)` only | `GlobalStrategy` + `Strategy(account)` with `cloned_from` | Global Library + Account Clone/Custom | | **Module Enable/Disable** | `ModuleEnableSettings(account)` | ✅ Keep as is | Per-Account Only | | **WordPress Integrations** | `SiteIntegration(account, site)` | ✅ Keep as is | Per-Account Only | | **Publishing Channels** | Global (correct) | ✅ Keep as is | Truly Global | | **Credit Costs** | Global (correct) | ✅ Keep as is | Truly Global | --- ## PART 3: FRONTEND CODE CLEANUP - COMPLETE AUDIT ### 3.1 FILES TO DELETE #### Admin Pages (16 files) ``` frontend/src/pages/admin/AdminSystemDashboard.tsx frontend/src/pages/admin/AdminAllAccountsPage.tsx frontend/src/pages/admin/AdminSubscriptionsPage.tsx frontend/src/pages/admin/AdminAccountLimitsPage.tsx frontend/src/pages/Admin/AdminBilling.tsx frontend/src/pages/admin/AdminAllInvoicesPage.tsx frontend/src/pages/admin/AdminAllPaymentsPage.tsx frontend/src/pages/admin/PaymentApprovalPage.tsx frontend/src/pages/admin/AdminCreditPackagesPage.tsx frontend/src/pages/Admin/AdminCreditCostsPage.tsx frontend/src/pages/admin/AdminAllUsersPage.tsx frontend/src/pages/admin/AdminRolesPermissionsPage.tsx frontend/src/pages/admin/AdminActivityLogsPage.tsx frontend/src/pages/admin/AdminSystemSettingsPage.tsx frontend/src/pages/admin/AdminSystemHealthPage.tsx frontend/src/pages/admin/AdminAPIMonitorPage.tsx ``` #### Settings Pages to Remove (3 files) ``` frontend/src/pages/Settings/ApiMonitor.tsx frontend/src/pages/Settings/DebugStatus.tsx frontend/src/pages/Settings/MasterStatus.tsx (if exists) ``` #### UI Elements Pages (23 files) ``` frontend/src/pages/Settings/UiElements/Alerts.tsx frontend/src/pages/Settings/UiElements/Avatars.tsx ... (all 23 files) ``` #### Components to Delete ``` frontend/src/components/auth/AdminGuard.tsx frontend/src/components/sidebar/ApiStatusIndicator.tsx (move logic to Django) frontend/src/components/debug/ResourceDebugOverlay.tsx frontend/src/components/debug/ResourceDebugToggle.tsx ``` **Total Files to Delete**: ~45 files --- ### 3.2 CODE TO MODIFY #### File: frontend/src/layout/AppSidebar.tsx **Remove**: ```typescript // Line 46-52: Remove isAwsAdminAccount check const isAwsAdminAccount = Boolean( user?.account?.slug === 'aws-admin' || user?.account?.slug === 'default-account' || user?.account?.slug === 'default' || user?.role === 'developer' ); // Lines 258-355: Remove entire adminSection const adminSection: MenuSection = useMemo(() => ({ label: "ADMIN", items: [...] }), []); // Line 360: Remove admin section from allSections const allSections = useMemo(() => { const baseSections = menuSections.map(...); if (isAwsAdminAccount) { // ← REMOVE THIS CHECK return [...baseSections, adminSection]; } return baseSections; }, [menuSections, isAwsAdminAccount, adminSection]); ``` **Result**: Sidebar becomes pure user interface --- #### File: frontend/src/components/auth/ProtectedRoute.tsx **Remove**: ```typescript // Line 127: Remove isPrivileged check const isPrivileged = user?.role === 'developer' || user?.is_superuser; // Any code using isPrivileged variable ``` --- #### File: frontend/src/services/api.ts **Remove**: ```typescript // Lines 640-641, 788-789, 1011-1012, 1169-1170 // Remove comments about admin/developer overrides // Always add site_id if there's an active site (even for admin/developer) // The backend will respect it appropriately - admin/developer can still see all sites // Remove any conditional logic that checks for admin/developer ``` --- #### File: frontend/src/routes.tsx **Remove Routes**: ```typescript // Remove all /admin/* routes { path: '/admin/dashboard', element: }, { path: '/admin/accounts', element: }, // ... all admin routes // Remove /ui-elements/* routes { path: '/ui-elements/alerts', element: }, // ... all 23 UI element routes // Remove some /settings routes { path: '/settings/api-monitor', element: }, { path: '/settings/debug-status', element: }, ``` --- ### 3.3 BACKEND CODE TO MODIFY #### Remove API Endpoints (No Longer Needed) **File**: `backend/igny8_core/api/urls.py` or similar **Remove**: ```python # Admin endpoints that duplicate Django admin path('admin/accounts/', views.admin_accounts), # Django admin has this path('admin/subscriptions/', views.admin_subscriptions), path('admin/users/', views.admin_users), path('admin/billing/stats/', views.admin_billing_stats), # etc. ``` **Keep**: ```python # User-facing endpoints path('billing/credits/balance/', ...), # Users need this path('system/settings/modules/', ...), # Users need this # etc. ``` --- #### Remove Permission Class **File**: `backend/igny8_core/api/permissions.py` **Remove**: ```python class IsSystemAccountOrDeveloper(permissions.BasePermission): """No longer needed - no admin-only frontend endpoints""" pass ``` --- #### Update Settings Lookup Logic **File**: `backend/igny8_core/ai/settings.py` **Replace**: ```python # BEFORE def get_openai_settings(account): settings = IntegrationSettings.objects.filter(account=account).first() if not settings: # Fallback to aws-admin (WRONG!) aws = Account.objects.filter(slug='aws-admin').first() settings = IntegrationSettings.objects.filter(account=aws).first() return settings # AFTER def get_openai_settings(account): # Check for account override try: override = AccountIntegrationOverride.objects.get(account=account) if override.use_own_keys: return override.get_effective_openai_settings() except AccountIntegrationOverride.DoesNotExist: pass # Use global settings return GlobalIntegrationSettings.get_instance().get_openai_settings() ``` --- ## PART 4: DJANGO ADMIN ENHANCEMENTS ### 4.1 NEW PAGES TO CREATE #### Page 1: System Health Monitor **File**: `backend/igny8_core/admin/monitoring.py` ```python from django.contrib.admin.views.decorators import staff_member_required from django.shortcuts import render from django.db import connection import redis from celery import Celery @staff_member_required def system_health_dashboard(request): """ System infrastructure health monitoring """ context = {} # Database Check try: with connection.cursor() as cursor: cursor.execute("SELECT 1") context['database'] = { 'status': 'healthy', 'message': 'Database connection OK' } except Exception as e: context['database'] = { 'status': 'error', 'message': str(e) } # Redis Check try: r = redis.Redis(host='redis', port=6379, db=0) r.ping() context['redis'] = { 'status': 'healthy', 'message': 'Redis connection OK' } except Exception as e: context['redis'] = { 'status': 'error', 'message': str(e) } # Celery Workers Check try: app = Celery('igny8_core') inspect = app.control.inspect() active = inspect.active() context['celery'] = { 'status': 'healthy' if active else 'warning', 'workers': len(active) if active else 0, 'message': f'{len(active)} workers active' if active else 'No workers' } except Exception as e: context['celery'] = { 'status': 'error', 'message': str(e) } return render(request, 'admin/monitoring/system_health.html', context) ``` **Template**: `backend/igny8_core/templates/admin/monitoring/system_health.html` --- #### Page 2: API Monitor **File**: `backend/igny8_core/admin/monitoring.py` ```python @staff_member_required def api_monitor_dashboard(request): """ API endpoint health monitoring """ # Define endpoint groups to check endpoint_groups = [ { 'name': 'Authentication', 'endpoints': [ {'path': '/v1/auth/login/', 'method': 'POST'}, {'path': '/v1/auth/me/', 'method': 'GET'}, ] }, { 'name': 'Planner Module', 'endpoints': [ {'path': '/v1/planner/keywords/', 'method': 'GET'}, {'path': '/v1/planner/clusters/', 'method': 'GET'}, ] }, # ... more groups ] # Check each endpoint results = [] for group in endpoint_groups: group_results = [] for endpoint in group['endpoints']: # Make internal API call status = check_endpoint(endpoint['path'], endpoint['method']) group_results.append({ 'path': endpoint['path'], 'method': endpoint['method'], 'status': status['status'], 'response_time': status['response_time'], }) results.append({ 'name': group['name'], 'endpoints': group_results }) context = {'results': results} return render(request, 'admin/monitoring/api_monitor.html', context) def check_endpoint(path, method): """Check endpoint health""" import requests import time start = time.time() try: if method == 'GET': response = requests.get(f'http://localhost:8010{path}', timeout=5) else: response = requests.post(f'http://localhost:8010{path}', timeout=5) elapsed = (time.time() - start) * 1000 # ms return { 'status': 'healthy' if response.status_code < 400 else 'error', 'response_time': round(elapsed, 2), 'status_code': response.status_code, } except Exception as e: return { 'status': 'error', 'response_time': None, 'error': str(e), } ``` --- #### Page 3: Debug Console **File**: `backend/igny8_core/admin/monitoring.py` ```python @staff_member_required def debug_console(request): """ System debug information """ from django.conf import settings import os context = { 'environment': { 'DEBUG': settings.DEBUG, 'ENVIRONMENT': os.getenv('ENVIRONMENT', 'unknown'), 'DJANGO_SETTINGS_MODULE': os.getenv('DJANGO_SETTINGS_MODULE'), }, 'database': { 'ENGINE': settings.DATABASES['default']['ENGINE'], 'NAME': settings.DATABASES['default']['NAME'], 'HOST': settings.DATABASES['default']['HOST'], }, 'cache': { 'BACKEND': settings.CACHES['default']['BACKEND'], 'LOCATION': settings.CACHES['default']['LOCATION'], }, 'celery': { 'BROKER_URL': settings.CELERY_BROKER_URL, 'RESULT_BACKEND': settings.CELERY_RESULT_BACKEND, }, } return render(request, 'admin/monitoring/debug_console.html', context) ``` --- ### 4.2 UPDATE DJANGO ADMIN SITE **File**: `backend/igny8_core/admin/site.py` ```python def get_urls(self): """Add custom monitoring URLs""" from django.urls import path from .monitoring import ( system_health_dashboard, api_monitor_dashboard, debug_console ) urls = super().get_urls() custom_urls = [ # Existing path('dashboard/', self.admin_view(admin_dashboard), name='dashboard'), # NEW: Monitoring path('monitoring/system-health/', self.admin_view(system_health_dashboard), name='monitoring_system_health'), path('monitoring/api-monitor/', self.admin_view(api_monitor_dashboard), name='monitoring_api_monitor'), path('monitoring/debug-console/', self.admin_view(debug_console), name='monitoring_debug_console'), ] return custom_urls + urls ``` --- ### 4.3 ADD PAYMENT APPROVAL ACTIONS **File**: `backend/igny8_core/modules/billing/admin.py` ```python class PaymentAdmin(ExportMixin, Igny8ModelAdmin): list_display = ['id', 'account', 'amount', 'status', 'method', 'created_at'] list_filter = ['status', 'method', 'created_at'] search_fields = ['account__name', 'transaction_id'] actions = [ 'bulk_approve_payments', 'bulk_reject_payments', # ... existing actions ] def bulk_approve_payments(self, request, queryset): """Approve pending manual payments""" pending = queryset.filter(status='pending', method='manual') count = 0 for payment in pending: payment.status = 'completed' payment.approved_by = request.user payment.approved_at = timezone.now() payment.save() count += 1 # Credit the account payment.account.credits += payment.amount_credits payment.account.save() # Create credit transaction CreditTransaction.objects.create( account=payment.account, amount=payment.amount_credits, transaction_type='purchase', description=f'Manual payment approved: {payment.transaction_id}', created_by=request.user ) self.message_user(request, f'{count} payment(s) approved.') bulk_approve_payments.short_description = "Approve selected pending payments" def bulk_reject_payments(self, request, queryset): """Reject pending manual payments""" pending = queryset.filter(status='pending', method='manual') count = pending.update(status='failed') self.message_user(request, f'{count} payment(s) rejected.') bulk_reject_payments.short_description = "Reject selected pending payments" ``` --- ## PART 5: IMPLEMENTATION PHASES ### Phase 1: Backend Settings Refactor (Week 1-2) **Tasks**: 1. ✅ Create `GlobalIntegrationSettings` model 2. ✅ Create `AccountIntegrationOverride` model 3. ✅ Create `GlobalAIPrompt` model 4. ✅ Update `AIPrompt` model (add `is_customized`) 5. ✅ Create `GlobalAuthorProfile` model 6. ✅ Update `AuthorProfile` (add `cloned_from`) 7. ✅ Create `GlobalStrategy` model 8. ✅ Update `Strategy` (add `cloned_from`) 9. ✅ Create migrations 10. ✅ Create data migration to move aws-admin settings to global 11. ✅ Update `ai/settings.py` lookup logic 12. ✅ Update all API views using settings 13. ✅ Test thoroughly **Deliverables**: - New models in production - Settings lookup working correctly - All existing functionality preserved --- ### Phase 2: Django Admin Enhancements (Week 2-3) **Tasks**: 1. ✅ Create `admin/monitoring.py` 2. ✅ Build system health dashboard 3. ✅ Build API monitor dashboard 4. ✅ Build debug console 5. ✅ Add monitoring URLs to admin site 6. ✅ Create templates for monitoring pages 7. ✅ Add payment approval actions to Payment admin 8. ✅ Test all new Django admin features **Deliverables**: - 3 new monitoring pages in Django admin - Payment approval workflow functional --- ### Phase 3: Frontend Cleanup (Week 3-4) **Tasks**: 1. ✅ Delete 16 admin page files 2. ✅ Delete 3 settings page files (api-monitor, debug-status) 3. ✅ Delete 23 UI elements page files 4. ✅ Delete AdminGuard component 5. ✅ Delete ApiStatusIndicator component 6. ✅ Remove admin section from AppSidebar 7. ✅ Remove isAwsAdminAccount checks 8. ✅ Remove isPrivileged checks from ProtectedRoute 9. ✅ Clean up api.ts comments 10. ✅ Remove admin routes from routes.tsx 11. ✅ Test all user-facing features still work 12. ✅ Verify no broken links **Deliverables**: - ~45 files deleted - Frontend code cleaned - All user features functional --- ### Phase 4: Backend API Cleanup (Week 4) **Tasks**: 1. ✅ Remove admin-only API endpoints (duplicating Django admin) 2. ✅ Remove `IsSystemAccountOrDeveloper` permission class 3. ✅ Update settings API to use global + override pattern 4. ✅ Remove aws-admin fallback logic everywhere 5. ✅ Test all remaining API endpoints 6. ✅ Update API documentation **Deliverables**: - Cleaner API codebase - No frontend admin dependencies --- ### Phase 5: Testing & Documentation (Week 4) **Tasks**: 1. ✅ End-to-end testing of all user features 2. ✅ Test Django admin monitoring pages 3. ✅ Test global + override settings pattern 4. ✅ Verify no regressions 5. ✅ Update documentation 6. ✅ Train team on new architecture **Deliverables**: - All tests passing - Documentation updated - Team trained --- ## PART 6: VERIFICATION CHECKLIST ### 6.1 Settings Verification - [ ] Global OpenAI settings work for all accounts - [ ] Account can override OpenAI with own key - [ ] Global DALL-E settings work - [ ] Account can override DALL-E settings - [ ] Global prompts accessible to all accounts - [ ] Account can customize prompts - [ ] Account can reset prompts to global default - [ ] Global author profiles clonable by accounts - [ ] Global strategies clonable by accounts ### 6.2 Frontend Verification - [ ] No admin routes accessible in frontend - [ ] Sidebar has no admin section - [ ] All user settings pages still work - [ ] Module enable/disable works - [ ] WordPress integrations work - [ ] No broken links - [ ] No console errors about missing routes ### 6.3 Django Admin Verification - [ ] System health monitor functional - [ ] API monitor functional - [ ] Debug console functional - [ ] Payment approval actions work - [ ] All existing admin models still work - [ ] Bulk actions still work ### 6.4 Backend Verification - [ ] AI operations use correct settings (global or override) - [ ] No aws-admin fallback logic remaining - [ ] Settings API returns global + override info - [ ] All endpoints functional - [ ] No permission errors --- ## PART 7: ROLLBACK PLAN If issues occur during migration: 1. **Phase 1 Rollback**: - Keep new models but don't use them - Restore old settings lookup logic 2. **Phase 2 Rollback**: - Remove monitoring pages from Django admin URLs 3. **Phase 3 Rollback**: - Git revert frontend file deletions - Restore admin routes 4. **Phase 4 Rollback**: - Restore API endpoints - Restore permission classes --- ## SUMMARY ### Pages Being Removed from Frontend: 42 Pages **Admin Pages**: 16 **Monitoring Pages**: 3 **UI Elements Pages**: 23 ### Pages Being Created in Django Admin: 3 Pages **Monitoring Pages**: System Health, API Monitor, Debug Console ### Settings Being Refactored: 7 Categories 1. OpenAI API settings (global + override) 2. DALL-E/image settings (global + override) 3. Anthropic settings (global + override) 4. AI Prompts (global library + account custom) 5. Author Profiles (global library + account clone) 6. Content Strategies (global library + account clone) 7. Module enable settings (keep as account-specific) ### Code Cleanup: 5 Areas 1. Frontend admin components (delete) 2. Frontend admin routes (delete) 3. Backend admin-only APIs (delete) 4. Permission classes (simplify) 5. Settings fallback logic (replace with global) --- **Status**: ✅ COMPREHENSIVE PLAN COMPLETE **Timeline**: 4 weeks for full implementation **Risk**: LOW - Well-defined changes **Benefit**: HIGH - Cleaner, more secure, easier to maintain --- *End of Comprehensive Plan*