52 KiB
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.tsxANDfrontend/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:
- Alerts
- Avatars
- Badges
- Breadcrumb
- Buttons
- ButtonsGroup
- Cards
- Carousel
- Dropdowns
- Images
- Links
- List
- Modals
- Notifications
- Pagination
- Popovers
- PricingTable
- Progressbar
- Ribbons
- Spinners
- Tabs
- Tooltips
- 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-systemwithnoindexmeta 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
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:
{
"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
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_promptfield - Good! - ⚠️ Account-specific prompts
- ❌ No global prompt library
Issue: Need global library + account customization
Author Profiles Model
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
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:
IntegrationSettings(AccountBaseModel):
account = FK(Account) # Per-account, fallback to aws-admin
integration_type = 'openai'
config = {openai_api_key, openai_model, ...}
Proposed - Two Models:
# 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:
# 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:
// 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:
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:
# 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:
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:
# 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:
# 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:
// 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:
// 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:
// 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:
// Remove all /admin/* routes
{ path: '/admin/dashboard', element: <AdminSystemDashboard /> },
{ path: '/admin/accounts', element: <AdminAllAccountsPage /> },
// ... all admin routes
// Remove /ui-elements/* routes
{ path: '/ui-elements/alerts', element: <Alerts /> },
// ... all 23 UI element routes
// Remove some /settings routes
{ path: '/settings/api-monitor', element: <ApiMonitor /> },
{ path: '/settings/debug-status', element: <DebugStatus /> },
3.3 BACKEND CODE TO MODIFY
Remove API Endpoints (No Longer Needed)
File: backend/igny8_core/api/urls.py or similar
Remove:
# 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:
# 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:
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:
# 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
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
@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
@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
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
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:
- ✅ Create
GlobalIntegrationSettingsmodel - ✅ Create
AccountIntegrationOverridemodel - ✅ Create
GlobalAIPromptmodel - ✅ Update
AIPromptmodel (addis_customized) - ✅ Create
GlobalAuthorProfilemodel - ✅ Update
AuthorProfile(addcloned_from) - ✅ Create
GlobalStrategymodel - ✅ Update
Strategy(addcloned_from) - ✅ Create migrations
- ✅ Create data migration to move aws-admin settings to global
- ✅ Update
ai/settings.pylookup logic - ✅ Update all API views using settings
- ✅ Test thoroughly
Deliverables:
- New models in production
- Settings lookup working correctly
- All existing functionality preserved
Phase 2: Django Admin Enhancements (Week 2-3)
Tasks:
- ✅ Create
admin/monitoring.py - ✅ Build system health dashboard
- ✅ Build API monitor dashboard
- ✅ Build debug console
- ✅ Add monitoring URLs to admin site
- ✅ Create templates for monitoring pages
- ✅ Add payment approval actions to Payment admin
- ✅ 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:
- ✅ Delete 16 admin page files
- ✅ Delete 3 settings page files (api-monitor, debug-status)
- ✅ Delete 23 UI elements page files
- ✅ Delete AdminGuard component
- ✅ Delete ApiStatusIndicator component
- ✅ Remove admin section from AppSidebar
- ✅ Remove isAwsAdminAccount checks
- ✅ Remove isPrivileged checks from ProtectedRoute
- ✅ Clean up api.ts comments
- ✅ Remove admin routes from routes.tsx
- ✅ Test all user-facing features still work
- ✅ Verify no broken links
Deliverables:
- ~45 files deleted
- Frontend code cleaned
- All user features functional
Phase 4: Backend API Cleanup (Week 4)
Tasks:
- ✅ Remove admin-only API endpoints (duplicating Django admin)
- ✅ Remove
IsSystemAccountOrDeveloperpermission class - ✅ Update settings API to use global + override pattern
- ✅ Remove aws-admin fallback logic everywhere
- ✅ Test all remaining API endpoints
- ✅ Update API documentation
Deliverables:
- Cleaner API codebase
- No frontend admin dependencies
Phase 5: Testing & Documentation (Week 4)
Tasks:
- ✅ End-to-end testing of all user features
- ✅ Test Django admin monitoring pages
- ✅ Test global + override settings pattern
- ✅ Verify no regressions
- ✅ Update documentation
- ✅ 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:
-
Phase 1 Rollback:
- Keep new models but don't use them
- Restore old settings lookup logic
-
Phase 2 Rollback:
- Remove monitoring pages from Django admin URLs
-
Phase 3 Rollback:
- Git revert frontend file deletions
- Restore admin routes
-
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
- OpenAI API settings (global + override)
- DALL-E/image settings (global + override)
- Anthropic settings (global + override)
- AI Prompts (global library + account custom)
- Author Profiles (global library + account clone)
- Content Strategies (global library + account clone)
- Module enable settings (keep as account-specific)
Code Cleanup: 5 Areas
- Frontend admin components (delete)
- Frontend admin routes (delete)
- Backend admin-only APIs (delete)
- Permission classes (simplify)
- 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