1616 lines
52 KiB
Markdown
1616 lines
52 KiB
Markdown
# 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: <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**:
|
|
```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*
|