Files
igny8/DJANGO-ADMIN-IMPROVEMENT-PLAN.md
2025-12-14 17:15:21 +00:00

1644 lines
50 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Django Admin Improvement Plan - Unfold Edition
**Version:** 2.0.0
**Created:** December 14, 2025
**Status:** Implementation Phase
**Priority:** 🔴 High - 3-4 weeks implementation
**Dependencies:** After Plan Management Implementation
**Theme:** Django Unfold (Modern Admin Theme)
---
## 🔧 CRITICAL FIXES APPLIED (December 14, 2025)
### Problem: Multiple Conflicting Admin Systems
The system had **3 conflicting admin systems running simultaneously**:
1. Default Django admin
2. Custom IGNY8 admin modifications
3. Unfold theme (partially installed)
This caused style conflicts, crashes, and inconsistent UI.
### Solution: Clean Unfold-Only Installation
**✅ Fixed Issues:**
1. **Backend Container Crashing** - Missing `unfold` module
- Added `django-unfold==0.73.1` to requirements.txt
- Rebuilt Docker image: `igny8-backend:latest`
- All containers now use new image (backend, celery_worker, celery_beat, flower)
2. **Admin Apps Configuration Error** - `AttributeError: module 'django.contrib.admin' has no attribute 'apps'`
- Fixed import in `admin/apps.py`: `from django.contrib.admin.apps import AdminConfig`
- Import Unfold AFTER apps are ready in `ready()` method
3. **Admin Site Inheritance** - Mixed admin systems
- Changed `Igny8AdminSite` from `admin.AdminSite``UnfoldAdminSite`
- All admin classes now inherit from Unfold's `ModelAdmin`
4. **Celery Admin Filters** - Using wrong filter classes
- Changed from `DateRangeFilter``RangeDateFilter` (Unfold version)
- Updated `CeleryTaskResultAdmin` to use `ModelAdmin` from Unfold
5. **Middleware Configuration**
- Added `simple_history.middleware.HistoryRequestMiddleware`
6. **INSTALLED_APPS Order**
- Unfold apps MUST be before `django.contrib.admin`
- Configured properly in settings.py
**✅ Result: Single Clean Admin System**
- **ONLY Unfold** - No more conflicts
- Modern, responsive UI with Tailwind CSS
- Dark mode support
- Advanced filters and bulk operations built-in
- All containers running healthy
---
## Executive Summary
This document outlines a comprehensive improvement plan for the IGNY8 Django Admin interface using **Django Unfold**, a modern, feature-rich admin theme. Unfold provides a beautiful UI based on Tailwind CSS, advanced filtering, bulk operations, dark mode, and extensive customization options - eliminating the need for custom CSS/JS while providing enterprise-grade functionality out of the box.
**Key Objectives:**
-**COMPLETED:** Install and configure Unfold theme
- Leverage Unfold's built-in features for UI/UX excellence
- Reorganize sidebar menu using Unfold's navigation system
- Remove unused/empty models
- Implement bulk operations with Unfold's action system
- Add Celery task monitoring with Unfold integration
- Create operational dashboards using Unfold's dashboard tools
- Implement advanced filtering with Unfold's filter extensions
**What Makes This Different:**
- **Modern UI Out-of-the-Box:** No custom CSS needed - Unfold provides beautiful, responsive design
- **Built-in Features:** Bulk operations, advanced filters, charts, dark mode included
- **Django Integration:** Works seamlessly with django-import-export, django-simple-history, django-celery-results
- **Extensible:** Easy to customize with Unfold's configuration system
---
## Current State Analysis
### ✅ Completed (Phase 0) - December 14, 2025
1.**Unfold Installation** - django-unfold==0.73.1 installed in requirements.txt
2.**Docker Image Rebuilt** - igny8-backend:latest rebuilt with all dependencies
3.**Settings Configuration** - UNFOLD settings configured in settings.py
4.**Admin Site Update** - Igny8AdminSite now inherits from UnfoldAdminSite
5.**Admin Apps Fixed** - Igny8AdminConfig properly imports Unfold after apps ready
6.**Celery Admin Updated** - CeleryTaskResultAdmin uses Unfold ModelAdmin & filters
7.**Supporting Packages** - django-simple-history, django-import-export, django-celery-results installed
8.**Middleware Updated** - simple_history.middleware.HistoryRequestMiddleware added
9.**Static Files** - Unfold assets collected via collectstatic
10.**All Containers Running** - Backend, Celery Worker, Celery Beat, Flower all healthy
11.**Conflicts Resolved** - No more mixed admin systems (default + custom + Unfold)
12.**Single Admin System** - **Unfold ONLY** - clean, modern, no conflicts
### ✅ Strengths
1. **Modern UI Theme** - Unfold provides beautiful, responsive Tailwind-based design
2. **Custom Admin Site** - Igny8AdminSite with logical grouping (maintained)
3. **Multi-Tenancy Support** - AccountAdminMixin and SiteSectorAdminMixin
4. **Payment Approval Workflow** - Comprehensive payment approval system
5. **Custom Actions** - API key generation, payment approval/rejection
6. **Field Customization** - Custom fieldsets and readonly fields
### ⚠️ Issues Remaining
#### 1. **Sidebar Menu Organization**
- ✅ Current get_app_list() structure works but can be enhanced with Unfold features
- Need to add icons to models for better visual recognition
- Missing PlanLimitUsage model (needs to be added)
- Some empty groups appearing
#### 2. **Unused/Empty Models** (Same as before)
- **site_building** models referenced but don't exist
- Duplicate model registrations need cleanup
#### 3. **Missing Features** (Now easier with Unfold)
- CSV/Excel export - Can use Unfold's import_export integration
- Bulk operations - Use Unfold's enhanced action system
- Celery monitoring - Use Unfold's contrib package for better UI
- Admin dashboard - Use Unfold's dashboard widgets
- Advanced filtering - Use Unfold's filter contrib package
---
## Unfold Features Available
### Built-in Features We'll Use:
1. **Visual Interface**
- Modern Tailwind CSS-based design
- Dark mode support (automatic)
- Responsive layout (mobile-friendly)
- Beautiful forms and tables
2. **Advanced Filtering**
- `unfold.contrib.filters` - Enhanced filter UI
- Date range filters with calendar
- Autocomplete filters for foreign keys
- Numeric range filters
3. **Import/Export**
- `unfold.contrib.import_export` - Styled import/export UI
- Works seamlessly with django-import-export
- Beautiful file upload/download interface
4. **History/Audit Trail**
- `unfold.contrib.simple_history` - Enhanced history UI
- Timeline view of changes
- User attribution and timestamps
5. **Actions**
- Enhanced bulk actions UI
- Custom action styling
- Progress indicators
6. **Dashboard Components**
- Cards for metrics
- Charts (Chart.js integration)
- Custom widgets
- Activity feeds
7. **Other Features**
- Inline tabs for grouping
- Conditional field visibility
- WYSIWYG editor (Trix)
- Sortable inlines
- Command palette (Cmd+K search)
---
## Phase 1: Critical Fixes & Model Updates (Week 1)
### 1.1 Remove Unused Models from Admin Site
**Problem:** site_building models referenced but don't exist, causing confusion
**Action:**
- Remove from `backend/igny8_core/admin/site.py` custom_groups:
- BusinessType
- AudienceProfile
- BrandPersonality
- HeroImageryDirection
**Files to modify:**
- `/data/app/igny8/backend/igny8_core/admin/site.py`
### 1.2 Resolve Duplicate Model Registrations
**Problem:** Multiple models registered twice causing conflicts
**Action:**
- Keep only `modules/billing/admin.py` versions (they have full workflow)
- Remove or comment out duplicates in `business/billing/admin.py`:
- Invoice
- Payment
- CreditPackage
- CreditCostConfig
**Files to modify:**
- `/data/app/igny8/backend/igny8_core/business/billing/admin.py`
### 1.3 Update Admin Classes to Use Unfold
**Current State:** Most admin classes inherit from `admin.ModelAdmin`
**Action:** Update all admin classes to inherit from Unfold's ModelAdmin:
```python
from unfold.admin import ModelAdmin
from unfold.contrib.filters.admin import RangeDateFilter
from unfold.contrib.import_export.forms import ExportForm, ImportForm
class TasksAdmin(SiteSectorAdminMixin, ModelAdmin):
# Unfold-specific features
compressed_fields = True # Compact form layout
warn_unsaved_form = True # Warn before leaving unsaved form
# Standard Django admin
list_display = ['title', 'status', 'cluster', 'created_at']
list_filter = [
('created_at', RangeDateFilter), # Unfold date range filter
'status',
]
search_fields = ['title', 'description']
actions_detail = ['generate_content', 'assign_cluster'] # Actions in detail view
```
**Key Files to Update:**
- `/data/app/igny8/backend/igny8_core/modules/writer/admin.py`
- `/data/app/igny8/backend/igny8_core/modules/planner/admin.py`
- `/data/app/igny8/backend/igny8_core/modules/billing/admin.py`
- `/data/app/igny8/backend/igny8_core/business/automation/admin.py`
- `/data/app/igny8/backend/igny8_core/business/integration/admin.py`
- All other admin files
### 1.4 Add Model Icons for Visual Navigation
**Action:** Add icon declarations to each admin class using Unfold's icon system (Material Symbols):
```python
class AccountAdmin(AccountAdminMixin, ModelAdmin):
# Add icon for sidebar
icon = "business" # Material symbol name
class ContentAdmin(SiteSectorAdminMixin, ModelAdmin):
icon = "article"
class TasksAdmin(SiteSectorAdminMixin, ModelAdmin):
icon = "task"
```
**Icon Mapping:**
| Model | Icon | Material Symbol |
|-------|------|----------------|
| Account | business | Business/company icon |
| Plan | card_membership | Membership card |
| Site | language | Globe/website icon |
| User | person | Person icon |
| Content | article | Article/document |
| Tasks | task | Checkbox list |
| Clusters | bubble_chart | Cluster diagram |
| Keywords | vpn_key | Key icon |
| Payment | payment | Payment icon |
| Invoice | receipt | Receipt icon |
| Automation | settings_suggest | Automation gear |
| Integration | integration_instructions | Integration icon |
### 1.5 Configure Unfold Colors and Branding
**Already Done:** Basic UNFOLD configuration in settings.py
**Additional Customization:**
```python
# In settings.py UNFOLD dict
"SITE_FAVICONS": [
{
"rel": "icon",
"sizes": "32x32",
"type": "image/png",
"href": lambda request: static("favicons/favicon-32x32.png"),
},
],
"SIDEBAR": {
"show_search": True,
"show_all_applications": True,
"navigation": None, # Use get_app_list() from Igny8AdminSite
},
"THEME": "light", # or "dark" or "auto"
```
---
## Phase 2: Bulk Operations & Export (Week 2)
### 2.1 Implement CSV/Excel Export with Unfold
**Install Already Complete:** django-import-export and unfold.contrib.import_export
**Action:** Add ExportMixin and ImportMixin to admin classes:
```python
from import_export.admin import ImportExportModelAdmin
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
class TasksAdmin(SiteSectorAdminMixin, ImportExportModelAdmin, ModelAdmin):
import_form_class = ImportForm
export_form_class = ExportForm
# Define what fields to export
class TaskResource(resources.ModelResource):
class Meta:
model = Tasks
fields = ('id', 'title', 'status', 'cluster__name', 'site__name', 'created_at')
export_order = fields
resource_class = TaskResource
```
**Priority Models for Export:**
- ✅ Tasks
- ✅ Content
- ✅ Keywords
- ✅ Payments
- ✅ CreditTransactions
- ✅ Clusters
### 2.2 Add Bulk Operations with Unfold Actions
**Unfold provides enhanced action UI automatically**
**Action:** Add actions to admin classes:
```python
from django.contrib import admin
from unfold.decorators import action
class TasksAdmin(SiteSectorAdminMixin, ModelAdmin):
actions = ['bulk_set_in_progress', 'bulk_set_completed', 'bulk_assign_cluster']
@action(description="Mark as In Progress")
def bulk_set_in_progress(self, request, queryset):
updated = queryset.update(status='in_progress')
self.message_user(request, f'{updated} tasks marked as in progress', 'SUCCESS')
@action(description="Mark as Completed")
def bulk_set_completed(self, request, queryset):
updated = queryset.update(status='completed')
self.message_user(request, f'{updated} tasks completed', 'SUCCESS')
@action(description="Assign to Cluster", form_class=BulkAssignClusterForm)
def bulk_assign_cluster(self, request, queryset):
# Unfold will show form with cluster selection
if 'cluster' in request.POST:
cluster_id = request.POST['cluster']
queryset.update(cluster_id=cluster_id)
self.message_user(request, f'Assigned to cluster', 'SUCCESS')
```
**Bulk Actions to Add:**
#### Tasks Admin
- Mark as Draft
- Mark as In Progress
- Mark as Completed
- Assign to Cluster
- Generate Content (trigger AI)
#### Content Admin
- Publish to WordPress
- Change Status
- Add Taxonomy
- Update SEO Settings
#### Keywords Admin
- Assign to Cluster
- Set Priority
- Mark for Research
#### Payments Admin
- Approve Payments (already exists)
- Reject Payments (already exists)
- Export Transactions (add)
### 2.3 Advanced Filtering with Unfold
**Unfold provides beautiful filter UI out of the box**
**Action:** Use Unfold's filter contrib for enhanced filtering:
```python
from unfold.contrib.filters.admin import (
RangeDateFilter,
RangeDateTimeFilter,
RangeNumericFilter,
SingleNumericFilter,
SliderNumericFilter,
)
from unfold.contrib.filters.admin import RelatedDropdownFilter, ChoicesDropdownFilter
class CreditTransactionAdmin(AccountAdminMixin, ModelAdmin):
list_filter = [
('created_at', RangeDateFilter), # Beautiful date range picker
('amount', RangeNumericFilter), # Numeric range with slider
('account', RelatedDropdownFilter), # Dropdown with search
('transaction_type', ChoicesDropdownFilter), # Enhanced dropdown
]
```
**Filter Types to Implement:**
| Model | Filters |
|-------|---------|
| CreditTransaction | Date range, Amount range, Account dropdown, Type |
| Payment | Date range, Status, Amount range, Method |
| Content | Date range, Status, Site, Sector, Word count range |
| Tasks | Date range, Status, Cluster, Priority |
| AutomationRun | Date range, Status, Site, Success/Fail |
---
## Phase 3: Monitoring & Dashboards (Week 5-6)
### 3.1 Celery Task Monitoring
**Install django-celery-results:**
```bash
pip install django-celery-results
```
**Add to settings.py:**
```python
INSTALLED_APPS = [
# ...
'django_celery_results',
]
CELERY_RESULT_BACKEND = 'django-db'
CELERY_CACHE_BACKEND = 'django-cache'
```
**Create Celery Task Admin:**
File: `backend/igny8_core/admin/celery_admin.py`
```python
from django.contrib import admin
from django_celery_results.models import TaskResult
@admin.register(TaskResult)
class CeleryTaskResultAdmin(admin.ModelAdmin):
list_display = [
'task_id',
'task_name',
'status',
'date_created',
'date_done',
'colored_status',
]
list_filter = [
'status',
'task_name',
('date_created', DateRangeFilter),
]
search_fields = ['task_id', 'task_name', 'task_args']
readonly_fields = ['task_id', 'task_name', 'task_args', 'task_kwargs', 'result', 'traceback']
actions = ['retry_failed_tasks', 'clear_old_tasks']
def colored_status(self, obj):
colors = {
'SUCCESS': 'green',
'FAILURE': 'red',
'PENDING': 'orange',
'STARTED': 'blue',
}
color = colors.get(obj.status, 'gray')
return format_html(
'<span style="color: {}; font-weight: bold;">{}</span>',
color,
obj.status
)
colored_status.short_description = 'Status'
def retry_failed_tasks(self, request, queryset):
"""Retry failed celery tasks"""
from celery import current_app
count = 0
for task in queryset.filter(status='FAILURE'):
try:
# Get task function and retry
task_func = current_app.tasks.get(task.task_name)
if task_func:
task_func.apply_async()
count += 1
except Exception as e:
self.message_user(request, f'Error retrying task {task.task_id}: {str(e)}', level='ERROR')
self.message_user(request, f'Retried {count} failed task(s)', level='SUCCESS')
retry_failed_tasks.short_description = 'Retry failed tasks'
```
**Add to admin groups:**
```python
'🤖 AI & Automation': {
'models': [
# ...
('django_celery_results', 'TaskResult'),
],
},
```
### 3.2 Admin Dashboard with Metrics
**Create custom admin index view:**
File: `backend/igny8_core/admin/dashboard.py`
```python
from django.contrib.admin.views.decorators import staff_member_required
from django.shortcuts import render
from django.db.models import Count, Sum, Q
from django.utils import timezone
from datetime import timedelta
@staff_member_required
def admin_dashboard(request):
"""Custom admin dashboard with key metrics"""
# Date ranges
today = timezone.now().date()
week_ago = today - timedelta(days=7)
month_ago = today - timedelta(days=30)
# Account metrics
from igny8_core.auth.models import Account
total_accounts = Account.objects.count()
active_accounts = Account.objects.filter(status='active').count()
low_credit_accounts = Account.objects.filter(credits__lt=100).count()
# Content metrics
from igny8_core.modules.writer.models import Content, Tasks
content_this_week = Content.objects.filter(created_at__gte=week_ago).count()
content_this_month = Content.objects.filter(created_at__gte=month_ago).count()
tasks_pending = Tasks.objects.filter(status='pending').count()
# Billing metrics
from igny8_core.modules.billing.models import Payment, CreditTransaction
pending_payments = Payment.objects.filter(status='pending_approval').count()
payments_this_month = Payment.objects.filter(
created_at__gte=month_ago,
status='succeeded'
).aggregate(total=Sum('amount'))['total'] or 0
credit_usage_this_month = CreditTransaction.objects.filter(
created_at__gte=month_ago,
transaction_type='deduction'
).aggregate(total=Sum('amount'))['total'] or 0
# Automation metrics
from igny8_core.business.automation.models import AutomationRun
automation_running = AutomationRun.objects.filter(status='running').count()
automation_failed = AutomationRun.objects.filter(
status='failed',
created_at__gte=week_ago
).count()
# WordPress sync metrics
from igny8_core.business.integration.models import SyncEvent
sync_failed = SyncEvent.objects.filter(
success=False,
created_at__gte=today
).count()
context = {
'title': 'Dashboard',
'accounts': {
'total': total_accounts,
'active': active_accounts,
'low_credit': low_credit_accounts,
},
'content': {
'this_week': content_this_week,
'this_month': content_this_month,
'tasks_pending': tasks_pending,
},
'billing': {
'pending_payments': pending_payments,
'payments_this_month': payments_this_month,
'credit_usage_this_month': abs(credit_usage_this_month),
},
'automation': {
'running': automation_running,
'failed_this_week': automation_failed,
},
'integration': {
'sync_failed_today': sync_failed,
},
}
return render(request, 'admin/dashboard.html', context)
```
**Create dashboard template:**
File: `backend/igny8_core/templates/admin/dashboard.html`
```html
{% extends "admin/base_site.html" %}
{% load static %}
{% block content %}
<h1>IGNY8 Admin Dashboard</h1>
<div class="dashboard-grid">
<!-- Accounts Overview -->
<div class="dashboard-card">
<h2>👥 Accounts</h2>
<div class="metric-row">
<div class="metric">
<span class="metric-value">{{ accounts.total }}</span>
<span class="metric-label">Total Accounts</span>
</div>
<div class="metric">
<span class="metric-value status-active">{{ accounts.active }}</span>
<span class="metric-label">Active</span>
</div>
<div class="metric">
<span class="metric-value {% if accounts.low_credit > 0 %}credits-low{% endif %}">
{{ accounts.low_credit }}
</span>
<span class="metric-label">Low Credits (< 100)</span>
</div>
</div>
</div>
<!-- Content Production -->
<div class="dashboard-card">
<h2>📝 Content Production</h2>
<div class="metric-row">
<div class="metric">
<span class="metric-value">{{ content.this_week }}</span>
<span class="metric-label">This Week</span>
</div>
<div class="metric">
<span class="metric-value">{{ content.this_month }}</span>
<span class="metric-label">This Month</span>
</div>
<div class="metric">
<span class="metric-value status-pending">{{ content.tasks_pending }}</span>
<span class="metric-label">Tasks Pending</span>
</div>
</div>
</div>
<!-- Billing Overview -->
<div class="dashboard-card">
<h2>💰 Billing</h2>
<div class="metric-row">
<div class="metric">
<span class="metric-value {% if billing.pending_payments > 0 %}status-pending{% endif %}">
{{ billing.pending_payments }}
</span>
<span class="metric-label">Pending Approvals</span>
<a href="{% url 'admin:billing_payment_changelist' %}?status=pending_approval" class="metric-link">
Review →
</a>
</div>
<div class="metric">
<span class="metric-value">${{ billing.payments_this_month|floatformat:2 }}</span>
<span class="metric-label">Revenue This Month</span>
</div>
<div class="metric">
<span class="metric-value">{{ billing.credit_usage_this_month }}</span>
<span class="metric-label">Credits Used</span>
</div>
</div>
</div>
<!-- Automation Status -->
<div class="dashboard-card">
<h2>🤖 Automation</h2>
<div class="metric-row">
<div class="metric">
<span class="metric-value status-active">{{ automation.running }}</span>
<span class="metric-label">Running Now</span>
</div>
<div class="metric">
<span class="metric-value {% if automation.failed_this_week > 0 %}status-inactive{% endif %}">
{{ automation.failed_this_week }}
</span>
<span class="metric-label">Failed (7 days)</span>
{% if automation.failed_this_week > 0 %}
<a href="{% url 'admin:automation_automationrun_changelist' %}?status=failed" class="metric-link">
Review →
</a>
{% endif %}
</div>
</div>
</div>
<!-- Integration Health -->
<div class="dashboard-card">
<h2>🔗 Integration Health</h2>
<div class="metric-row">
<div class="metric">
<span class="metric-value {% if integration.sync_failed_today > 0 %}status-inactive{% endif %}">
{{ integration.sync_failed_today }}
</span>
<span class="metric-label">Failed Syncs Today</span>
{% if integration.sync_failed_today > 0 %}
<a href="{% url 'admin:integration_syncevent_changelist' %}?success=False" class="metric-link">
Review →
</a>
{% endif %}
</div>
</div>
</div>
</div>
<style>
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-top: 20px;
}
.dashboard-card {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.dashboard-card h2 {
margin-top: 0;
border-bottom: 2px solid #417690;
padding-bottom: 10px;
}
.metric-row {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-top: 15px;
}
.metric {
display: flex;
flex-direction: column;
min-width: 120px;
}
.metric-value {
font-size: 32px;
font-weight: bold;
color: #417690;
}
.metric-label {
font-size: 12px;
color: #666;
margin-top: 5px;
}
.metric-link {
font-size: 12px;
color: #417690;
text-decoration: none;
margin-top: 5px;
}
.metric-link:hover {
text-decoration: underline;
}
</style>
{% endblock %}
```
**Update admin site URLs:**
```python
# backend/igny8_core/admin/site.py
from .dashboard import admin_dashboard
class Igny8AdminSite(admin.AdminSite):
# ... existing code
def get_urls(self):
from django.urls import path
urls = super().get_urls()
custom_urls = [
path('dashboard/', self.admin_view(admin_dashboard), name='dashboard'),
]
return custom_urls + urls
def index(self, request, extra_context=None):
"""Redirect to custom dashboard"""
from django.shortcuts import redirect
return redirect('admin:dashboard')
```
### 3.3 Account Health Indicators
**Add to Account Admin:**
```python
@admin.register(Account)
class AccountAdmin(AccountAdminMixin, admin.ModelAdmin):
# ... existing code
list_display = [
'name',
'slug',
'owner',
'plan',
'status',
'credits',
'health_indicator', # ADD
'created_at'
]
def health_indicator(self, obj):
"""Visual health score"""
score = 100
issues = []
# Check credit balance
if obj.credits < 50:
score -= 30
issues.append('Low credits')
elif obj.credits < 100:
score -= 15
# Check recent activity
from django.utils import timezone
from datetime import timedelta
week_ago = timezone.now() - timedelta(days=7)
from igny8_core.modules.writer.models import Content
recent_content = Content.objects.filter(
account=obj,
created_at__gte=week_ago
).count()
if recent_content == 0:
score -= 20
issues.append('No recent activity')
# Check failed automations
from igny8_core.business.automation.models import AutomationRun
failed_runs = AutomationRun.objects.filter(
site__account=obj,
status='failed',
created_at__gte=week_ago
).count()
if failed_runs > 0:
score -= 15
issues.append(f'{failed_runs} failed automation(s)')
# Determine color
if score >= 80:
color = 'green'
icon = ''
elif score >= 60:
color = 'orange'
icon = '⚠️'
else:
color = 'red'
icon = ''
issue_text = ', '.join(issues) if issues else 'Healthy'
return format_html(
'<span style="color: {}; font-size: 18px;">{}</span> '
'<span style="color: {};">{}</span>',
color, icon, color, issue_text
)
health_indicator.short_description = 'Health'
```
### 3.4 Alert System
**Create alerts utility:**
File: `backend/igny8_core/admin/alerts.py`
```python
from django.core.cache import cache
from django.utils import timezone
from datetime import timedelta
class AdminAlerts:
"""System for admin alerts and notifications"""
@staticmethod
def get_alerts():
"""Get all active alerts"""
alerts = []
# Check for pending payments
from igny8_core.modules.billing.models import Payment
pending_payments = Payment.objects.filter(status='pending_approval').count()
if pending_payments > 0:
alerts.append({
'level': 'warning',
'message': f'{pending_payments} payment(s) awaiting approval',
'url': '/admin/billing/payment/?status=pending_approval',
'action': 'Review Payments'
})
# Check for low credit accounts
from igny8_core.auth.models import Account
low_credit_accounts = Account.objects.filter(
status='active',
credits__lt=100
).count()
if low_credit_accounts > 0:
alerts.append({
'level': 'info',
'message': f'{low_credit_accounts} account(s) with low credits',
'url': '/admin/igny8_core_auth/account/?credits__lt=100',
'action': 'View Accounts'
})
# Check for failed automations
from igny8_core.business.automation.models import AutomationRun
today = timezone.now().date()
failed_today = AutomationRun.objects.filter(
status='failed',
created_at__date=today
).count()
if failed_today > 0:
alerts.append({
'level': 'error',
'message': f'{failed_today} automation(s) failed today',
'url': '/admin/automation/automationrun/?status=failed',
'action': 'Review Failures'
})
# Check for failed syncs
from igny8_core.business.integration.models import SyncEvent
failed_syncs = SyncEvent.objects.filter(
success=False,
created_at__date=today
).count()
if failed_syncs > 5: # Only alert if more than 5
alerts.append({
'level': 'warning',
'message': f'{failed_syncs} WordPress sync failures today',
'url': '/admin/integration/syncevent/?success=False',
'action': 'Review Syncs'
})
return alerts
```
**Add to dashboard template:**
```html
<!-- Add after <h1>IGNY8 Admin Dashboard</h1> -->
{% if alerts %}
<div class="alerts-section">
{% for alert in alerts %}
<div class="alert alert-{{ alert.level }}">
<span class="alert-icon">
{% if alert.level == 'error' %}🔴{% endif %}
{% if alert.level == 'warning' %}⚠️{% endif %}
{% if alert.level == 'info' %}{% endif %}
</span>
<span class="alert-message">{{ alert.message }}</span>
<a href="{{ alert.url }}" class="alert-action">{{ alert.action }}</a>
</div>
{% endfor %}
</div>
{% endif %}
```
---
## Phase 4: Analytics & Reporting (Week 7-8)
### 4.1 Business Intelligence Reports
**Create reports module:**
File: `backend/igny8_core/admin/reports.py`
```python
from django.contrib.admin.views.decorators import staff_member_required
from django.shortcuts import render
from django.db.models import Count, Sum, Avg, Q
from django.utils import timezone
from datetime import timedelta
import json
@staff_member_required
def revenue_report(request):
"""Revenue and billing analytics"""
from igny8_core.modules.billing.models import Payment
from igny8_core.auth.models import Plan
# Date ranges
today = timezone.now()
months = []
monthly_revenue = []
for i in range(6):
month_start = today.replace(day=1) - timedelta(days=30*i)
month_end = month_start.replace(day=28) + timedelta(days=4)
revenue = Payment.objects.filter(
status='succeeded',
processed_at__gte=month_start,
processed_at__lt=month_end
).aggregate(total=Sum('amount'))['total'] or 0
months.insert(0, month_start.strftime('%b %Y'))
monthly_revenue.insert(0, float(revenue))
# Plan distribution
plan_distribution = Plan.objects.annotate(
account_count=Count('account')
).values('name', 'account_count')
# Payment method breakdown
payment_methods = Payment.objects.filter(
status='succeeded'
).values('payment_method').annotate(
count=Count('id'),
total=Sum('amount')
).order_by('-total')
context = {
'title': 'Revenue Report',
'months': json.dumps(months),
'monthly_revenue': json.dumps(monthly_revenue),
'plan_distribution': plan_distribution,
'payment_methods': payment_methods,
}
return render(request, 'admin/reports/revenue.html', context)
@staff_member_required
def usage_report(request):
"""Credit usage and AI operations analytics"""
from igny8_core.modules.billing.models import CreditUsageLog
# Usage by operation type
usage_by_operation = CreditUsageLog.objects.values(
'operation_type'
).annotate(
total_credits=Sum('credits_used'),
total_cost=Sum('cost_usd'),
operation_count=Count('id')
).order_by('-total_credits')
# Top credit consumers
from django.db.models import Count
top_consumers = CreditUsageLog.objects.values(
'account__name'
).annotate(
total_credits=Sum('credits_used'),
operation_count=Count('id')
).order_by('-total_credits')[:10]
# Model usage distribution
model_usage = CreditUsageLog.objects.values(
'model_used'
).annotate(
usage_count=Count('id')
).order_by('-usage_count')
context = {
'title': 'Usage Report',
'usage_by_operation': usage_by_operation,
'top_consumers': top_consumers,
'model_usage': model_usage,
}
return render(request, 'admin/reports/usage.html', context)
@staff_member_required
def content_report(request):
"""Content production analytics"""
from igny8_core.modules.writer.models import Content, Tasks
# Content by type
content_by_type = Content.objects.values(
'content_type'
).annotate(count=Count('id')).order_by('-count')
# Production timeline (last 30 days)
days = []
daily_counts = []
for i in range(30):
day = timezone.now().date() - timedelta(days=i)
count = Content.objects.filter(created_at__date=day).count()
days.insert(0, day.strftime('%m/%d'))
daily_counts.insert(0, count)
# Average word count by content type
avg_words = Content.objects.values('content_type').annotate(
avg_words=Avg('word_count')
).order_by('-avg_words')
# Task completion rate
total_tasks = Tasks.objects.count()
completed_tasks = Tasks.objects.filter(status='completed').count()
completion_rate = (completed_tasks / total_tasks * 100) if total_tasks > 0 else 0
context = {
'title': 'Content Production Report',
'content_by_type': content_by_type,
'days': json.dumps(days),
'daily_counts': json.dumps(daily_counts),
'avg_words': avg_words,
'completion_rate': completion_rate,
}
return render(request, 'admin/reports/content.html', context)
```
**Add report links to admin site:**
```python
# In Igny8AdminSite.get_urls()
custom_urls = [
path('dashboard/', self.admin_view(admin_dashboard), name='dashboard'),
path('reports/revenue/', self.admin_view(revenue_report), name='report_revenue'),
path('reports/usage/', self.admin_view(usage_report), name='report_usage'),
path('reports/content/', self.admin_view(content_report), name='report_content'),
]
```
### 4.2 Data Quality Dashboard
**Create data quality checker:**
```python
@staff_member_required
def data_quality_report(request):
"""Check data quality and integrity"""
issues = []
# Orphaned content (no site)
from igny8_core.modules.writer.models import Content
orphaned_content = Content.objects.filter(site__isnull=True).count()
if orphaned_content > 0:
issues.append({
'severity': 'warning',
'type': 'Orphaned Records',
'count': orphaned_content,
'description': 'Content items without assigned site',
'action_url': '/admin/writer/content/?site__isnull=True'
})
# Tasks without clusters
from igny8_core.modules.writer.models import Tasks
tasks_no_cluster = Tasks.objects.filter(cluster__isnull=True).count()
if tasks_no_cluster > 0:
issues.append({
'severity': 'info',
'type': 'Missing Relationships',
'count': tasks_no_cluster,
'description': 'Tasks without assigned cluster',
'action_url': '/admin/writer/tasks/?cluster__isnull=True'
})
# Accounts with negative credits
from igny8_core.auth.models import Account
negative_credits = Account.objects.filter(credits__lt=0).count()
if negative_credits > 0:
issues.append({
'severity': 'error',
'type': 'Data Integrity',
'count': negative_credits,
'description': 'Accounts with negative credit balance',
'action_url': '/admin/igny8_core_auth/account/?credits__lt=0'
})
# Duplicate keywords
from igny8_core.modules.planner.models import Keywords
from django.db.models import Count
duplicates = Keywords.objects.values('keyword', 'site', 'sector').annotate(
count=Count('id')
).filter(count__gt=1).count()
if duplicates > 0:
issues.append({
'severity': 'warning',
'type': 'Duplicates',
'count': duplicates,
'description': 'Duplicate keywords for same site/sector',
'action_url': '/admin/planner/keywords/'
})
# Content without SEO data
no_seo = Content.objects.filter(
Q(meta_title__isnull=True) | Q(meta_title='') |
Q(meta_description__isnull=True) | Q(meta_description='')
).count()
if no_seo > 0:
issues.append({
'severity': 'info',
'type': 'Incomplete Data',
'count': no_seo,
'description': 'Content missing SEO metadata',
'action_url': '/admin/writer/content/'
})
context = {
'title': 'Data Quality Report',
'issues': issues,
'total_issues': len(issues),
}
return render(request, 'admin/reports/data_quality.html', context)
```
---
## Phase 5: Advanced Features (Week 9-10)
### 5.1 Inline Editing
**Enable list_editable for common fields:**
```python
# Tasks Admin
class TasksAdmin(SiteSectorAdminMixin, admin.ModelAdmin):
list_editable = ['status', 'cluster'] # Quick edit in list view
# Keywords Admin
class KeywordsAdmin(SiteSectorAdminMixin, admin.ModelAdmin):
list_editable = ['cluster', 'status']
# Payment Admin - already has workflow, keep as-is
```
### 5.2 Enhanced Audit Trail
**Install django-simple-history:**
```bash
pip install django-simple-history
```
**Add to critical models:**
```python
from simple_history.models import HistoricalRecords
class Payment(models.Model):
# ... existing fields
history = HistoricalRecords()
class Account(AccountBaseModel):
# ... existing fields
history = HistoricalRecords()
class CreditCostConfig(models.Model):
# ... existing fields
history = HistoricalRecords()
```
**Register history admin:**
```python
from simple_history.admin import SimpleHistoryAdmin
@admin.register(Payment)
class PaymentAdmin(SimpleHistoryAdmin, AccountAdminMixin, admin.ModelAdmin):
# ... existing code
# This adds a "History" button to view all changes
```
### 5.3 Permission Groups
**Create permission groups:**
```python
# backend/igny8_core/management/commands/create_admin_groups.py
from django.core.management.base import BaseCommand
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
class Command(BaseCommand):
help = 'Create admin permission groups'
def handle(self, *args, **kwargs):
# Content Manager Group
content_manager, _ = Group.objects.get_or_create(name='Content Manager')
content_perms = Permission.objects.filter(
content_type__app_label__in=['writer', 'planner'],
codename__in=['view_content', 'change_content', 'view_tasks', 'change_tasks']
)
content_manager.permissions.set(content_perms)
# Billing Administrator Group
billing_admin, _ = Group.objects.get_or_create(name='Billing Administrator')
billing_perms = Permission.objects.filter(
content_type__app_label='billing'
)
billing_admin.permissions.set(billing_perms)
# Support Agent Group (Read-Only)
support_agent, _ = Group.objects.get_or_create(name='Support Agent')
support_perms = Permission.objects.filter(
codename__startswith='view_'
)
support_agent.permissions.set(support_perms)
self.stdout.write(self.style.SUCCESS('Successfully created admin groups'))
```
---
## Implementation Checklist
### Week 1-2: Critical Fixes & UI Foundation
- [ ] Remove unused site_building models from admin site config
- [ ] Remove duplicate model registrations (keep modules/ versions)
- [ ] Reorganize sidebar menu with emoji icons and logical groups
- [ ] Add PlanLimitUsage to Billing & Accounts group
- [ ] Install django-admin-interface or django-grappelli
- [ ] Configure admin theme package
- [ ] Create custom CSS file for status colors and basic styling
- [ ] Create custom base_site.html template
- [ ] Test admin UI improvements
- [ ] Document theme customization options
### Week 3-4: Operational Features
- [ ] Add bulk status update actions to Tasks admin
- [ ] Add bulk operations to Content admin
- [ ] Add bulk operations to Keywords admin
- [ ] Add export action to Payments admin
- [ ] Install django-import-export
- [ ] Create Resource classes for Tasks, Content, Keywords, Payments
- [ ] Add export buttons to admin list views
- [ ] Install django-admin-rangefilter
- [ ] Add date range filters to key models
- [ ] Configure autocomplete_fields for large foreign keys
- [ ] Test all bulk operations
- [ ] Test export functionality
### Week 5-6: Monitoring & Dashboards
- [ ] Install django-celery-results
- [ ] Configure Celery to use django-db backend
- [ ] Create CeleryTaskResultAdmin with colored status
- [ ] Add retry_failed_tasks action
- [ ] Create admin_dashboard view function
- [ ] Create dashboard.html template with metrics
- [ ] Add dashboard route to admin site URLs
- [ ] Redirect admin index to dashboard
- [ ] Add health_indicator to Account admin
- [ ] Create AdminAlerts utility class
- [ ] Add alerts section to dashboard template
- [ ] Add alert styling CSS
- [ ] Test dashboard metrics accuracy
- [ ] Test alert system functionality
### Week 7-8: Analytics & Reporting
- [ ] Create reports.py module
- [ ] Implement revenue_report view
- [ ] Implement usage_report view
- [ ] Implement content_report view
- [ ] Implement data_quality_report view
- [ ] Create report templates (revenue, usage, content, data_quality)
- [ ] Add chart.js or similar for visualizations
- [ ] Add report links to admin navigation
- [ ] Create report permission checks
- [ ] Test all reports with real data
- [ ] Optimize report queries for performance
### Week 9-10: Advanced Features
- [ ] Enable list_editable for Tasks and Keywords
- [ ] Install django-simple-history
- [ ] Add HistoricalRecords to Payment model
- [ ] Add HistoricalRecords to Account model
- [ ] Add HistoricalRecords to CreditCostConfig model
- [ ] Run migrations for history tables
- [ ] Update admins to use SimpleHistoryAdmin
- [ ] Create create_admin_groups management command
- [ ] Define permission groups (Content Manager, Billing Admin, Support Agent)
- [ ] Assign permissions to groups
- [ ] Test permission restrictions
- [ ] Document permission group usage
---
## Technical Requirements
### Python Packages
```txt
# Add to requirements.txt
django-admin-interface==0.26.0 # Modern admin theme
django-import-export==3.3.1 # CSV/Excel import/export
django-admin-rangefilter==0.11.1 # Date range filters
django-advanced-filters==2.4.0 # Saved filters
django-celery-results==2.5.1 # Celery monitoring
django-simple-history==3.4.0 # Audit trail
```
### Settings Configuration
```python
# backend/igny8_core/settings.py
INSTALLED_APPS = [
'admin_interface', # Must be before django.contrib.admin
'colorfield', # Required by admin_interface
'igny8_core.admin.apps.Igny8AdminConfig',
# ... rest of apps
'import_export',
'rangefilter',
'advanced_filters',
'django_celery_results',
'simple_history',
]
# Admin Interface Configuration
X_FRAME_OPTIONS = 'SAMEORIGIN' # Required for admin_interface
# Celery Results
CELERY_RESULT_BACKEND = 'django-db'
CELERY_CACHE_BACKEND = 'django-cache'
# History Middleware
MIDDLEWARE = [
# ... existing middleware
'simple_history.middleware.HistoryRequestMiddleware',
]
# Import/Export Settings
IMPORT_EXPORT_USE_TRANSACTIONS = True
```
### Database Migrations
```bash
# After adding packages
python manage.py migrate admin_interface
python manage.py migrate django_celery_results
python manage.py migrate simple_history
# Collect static files
python manage.py collectstatic --noinput
```
### Static Files Structure
```
backend/igny8_core/static/
├── admin/
│ ├── css/
│ │ └── igny8_admin.css
│ └── js/
│ └── igny8_admin.js
└── charts/
└── chart.min.js
```
### Template Structure
```
backend/igny8_core/templates/
├── admin/
│ ├── base_site.html
│ ├── dashboard.html
│ └── reports/
│ ├── revenue.html
│ ├── usage.html
│ ├── content.html
│ └── data_quality.html
```
---
## Testing Plan
### Manual Testing Checklist
- [ ] Admin login works
- [ ] Dashboard displays correctly
- [ ] All sidebar groups show correct models
- [ ] No 404 errors for any admin links
- [ ] Bulk actions work on all enabled models
- [ ] CSV export generates valid files
- [ ] Date range filters work correctly
- [ ] Autocomplete fields load data
- [ ] Celery task monitoring shows tasks
- [ ] Dashboard metrics are accurate
- [ ] Alerts show for real issues
- [ ] Reports generate without errors
- [ ] Charts render correctly
- [ ] History tracking works for enabled models
- [ ] Permission groups restrict access correctly
### Performance Testing
- [ ] Dashboard loads in < 2 seconds
- [ ] List views with 1000+ records paginate correctly
- [ ] Bulk operations on 100+ records complete
- [ ] Export of 1000+ records completes
- [ ] Reports with large datasets load within 5 seconds
- [ ] No N+1 query issues in list views
---
## Rollback Plan
If issues arise during implementation:
1. **Theme Issues:** Revert to default Django admin
```bash
# Remove from INSTALLED_APPS
# 'admin_interface',
python manage.py migrate admin_interface zero
```
2. **Duplicate Registration Issues:**
- Keep `modules/` admin files active
- Comment out `business/` admin registrations
3. **Performance Issues:**
- Disable expensive dashboard queries
- Use caching for metrics
- Reduce pagination size
4. **Database Issues:**
- All migrations are reversible
- Backup before major changes
- Test on staging first
---
## Success Metrics
Track these metrics to measure improvement success:
1. **Time Savings**
- Payment approval time: Target < 2 minutes
- Content review time: Target < 5 minutes per item
- Report generation time: Target < 30 seconds
2. **User Satisfaction**
- Admin user feedback: Target 8+/10
- Feature usage: 80%+ of new features used weekly
3. **Data Quality**
- Orphaned records: Reduce by 90%
- Duplicate data: Reduce by 80%
- Data completeness: Increase to 95%+
4. **Operational Efficiency**
- Failed automation detection: < 1 hour
- Payment processing: Same-day completion
- Account health monitoring: 100% visibility
---
## Maintenance & Support
### Regular Maintenance Tasks
- **Weekly:**
- Review dashboard alerts
- Check failed celery tasks
- Monitor data quality issues
- **Monthly:**
- Review permission group assignments
- Update credit cost configs if needed
- Clean up old celery task results
- Archive old audit logs
- **Quarterly:**
- Review and optimize slow admin queries
- Update admin theme if needed
- Review and update permission groups
- Analyze usage patterns for improvements
### Documentation Updates
Keep these docs updated:
- Admin user guide with new features
- Permission group definitions
- Report interpretation guides
- Troubleshooting common issues
---
## Future Enhancements (Post-Launch)
1. **AI-Powered Insights**
- Anomaly detection in usage patterns
- Predictive account churn analysis
- Automated optimization recommendations
2. **Advanced Automation**
- Workflow builder for common tasks
- Scheduled report delivery
- Auto-responses to common issues
3. **Mobile Admin**
- Responsive mobile design
- Mobile-optimized dashboards
- Push notifications for critical alerts
4. **Integration Enhancements**
- Slack/Discord alert integration
- Zapier/Make.com workflow triggers
- API for external admin tools
---
## Conclusion
This comprehensive plan transforms the Django admin from a basic management tool into a powerful operational hub. The phased approach ensures steady progress while minimizing disruption. Focus on Phases 1-3 for immediate operational impact, then expand to analytics and advanced features in Phases 4-5.
**Estimated Total Effort:** 4-6 weeks with 1-2 developers
**Priority:** 🔴 High - Critical for efficient operations at scale
**Dependencies:** Should be implemented after Plan Management (#2) is complete