1552 lines
49 KiB
Markdown
1552 lines
49 KiB
Markdown
# 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
|
|
|
|
7. **UserAdmin Popup Styling** - User edit form in popup used default Django styling
|
|
- Changed `UserAdmin` to inherit from both `BaseUserAdmin` and `ModelAdmin`
|
|
- Multiple inheritance preserves Django user functionality + Unfold styling
|
|
- Popups now use Unfold templates with modern icons and widgets
|
|
|
|
**✅ 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 popups and forms use Unfold styling
|
|
- 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 with zero custom CSS
|
|
2. **Consistent Styling** - All admin pages, popups, and forms use Unfold templates
|
|
3. **Custom Admin Site** - Igny8AdminSite with logical grouping (maintained)
|
|
4. **Multi-Tenancy Support** - AccountAdminMixin and SiteSectorAdminMixin
|
|
5. **Payment Approval Workflow** - Comprehensive payment approval system
|
|
6. **Custom Actions** - API key generation, payment approval/rejection
|
|
7. **Field Customization** - Custom fieldsets and readonly fields
|
|
|
|
### ⚠️ Issues Remaining
|
|
|
|
#### 1. **Sidebar Menu Organization**
|
|
- ✅ Current get_app_list() structure works
|
|
- Missing PlanLimitUsage model (needs to be added to admin)
|
|
- Some empty groups appearing (site_building models don't exist)
|
|
- Need to clean up model groupings
|
|
|
|
#### 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 Clean Up Sidebar Menu Organization
|
|
|
|
**Problem:** site_building models referenced but don't exist, causing confusion. Some empty groups appearing.
|
|
|
|
**Action:**
|
|
|
|
1. **Remove non-existent site_building models** from `backend/igny8_core/admin/site.py` custom_groups:
|
|
- BusinessType
|
|
- AudienceProfile
|
|
- BrandPersonality
|
|
- HeroImageryDirection
|
|
|
|
2. **Add missing PlanLimitUsage model** to Billing group:
|
|
```python
|
|
'Billing & Accounts': {
|
|
'models': [
|
|
('igny8_core_auth', 'Plan'),
|
|
('billing', 'PlanLimitUsage'), # ADD THIS
|
|
('igny8_core_auth', 'Account'),
|
|
# ... rest of models
|
|
],
|
|
},
|
|
```
|
|
|
|
3. **Verify all referenced models exist** - check that each model in custom_groups is actually registered
|
|
|
|
**Files to modify:**
|
|
- `/data/app/igny8/backend/igny8_core/admin/site.py`
|
|
- Verify PlanLimitUsage is registered in admin
|
|
|
|
### 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 Test Admin Configuration
|
|
|
|
**Action:** After cleanup, verify:
|
|
- All sidebar groups display correctly
|
|
- No 404 errors when clicking model links
|
|
- All registered models appear in appropriate groups
|
|
- No empty groups in sidebar
|
|
|
|
---
|
|
|
|
## 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>
|
|
|
|
<!-- Unfold will automatically style these using its Tailwind-based theme -->
|
|
<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">{{ accounts.active }}</span>
|
|
<span class="metric-label">Active</span>
|
|
</div>
|
|
<div class="metric">
|
|
<span class="metric-value">{{ 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">{{ 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">{{ billing.pending_payments }}</span>
|
|
<span class="metric-label">Pending Approvals</span>
|
|
<a href="{% url 'admin:billing_payment_changelist' %}?status=pending_approval">
|
|
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">{{ automation.running }}</span>
|
|
<span class="metric-label">Running Now</span>
|
|
</div>
|
|
<div class="metric">
|
|
<span class="metric-value">{{ 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">
|
|
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">{{ 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">
|
|
Review
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
```
|
|
|
|
**Note:** Unfold automatically provides styling via Tailwind CSS. No custom CSS needed - use Unfold's utility classes if customization is required.
|
|
|
|
**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'
|
|
|
|
# Use Unfold badge classes instead of inline styles
|
|
if score >= 80:
|
|
badge_class = 'success'
|
|
elif score >= 60:
|
|
badge_class = 'warning'
|
|
else:
|
|
badge_class = 'danger'
|
|
|
|
return format_html(
|
|
'<span class="badge badge-{}">{}</span>',
|
|
badge_class, 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-message">{{ alert.message }}</span>
|
|
<a href="{{ alert.url }}" class="alert-action">{{ alert.action }}</a>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
```
|
|
|
|
**Note:** Use Unfold's alert styling classes. No custom CSS or emoji icons needed.
|
|
|
|
---
|
|
|
|
## 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
|
|
|
|
### ✅ Phase 0: Foundation (COMPLETED - Dec 14, 2025)
|
|
|
|
- [x] Install and configure Unfold theme
|
|
- [x] Fix all admin classes to inherit from Unfold ModelAdmin
|
|
- [x] Fix UserAdmin popup styling (multiple inheritance)
|
|
- [x] Configure UNFOLD settings in settings.py
|
|
- [x] Update middleware and INSTALLED_APPS
|
|
- [x] Test all containers running
|
|
|
|
### Phase 1: Configuration Cleanup (Week 1) - IN PROGRESS
|
|
|
|
- [x] Fix UserAdmin popup styling
|
|
- [ ] Remove unused site_building models from admin site config
|
|
- [ ] Remove duplicate model registrations (keep modules/ versions)
|
|
- [ ] Add PlanLimitUsage to Billing & Accounts group
|
|
- [ ] Verify all model links work
|
|
- [ ] Test admin configuration
|
|
|
|
### Phase 2: Bulk Operations & Export (Week 2-3) - NOT STARTED
|
|
|
|
- [ ] 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
|
|
|
|
### ✅ Phase 3: Monitoring & Dashboards (COMPLETED - Dec 14, 2025)
|
|
|
|
- [x] Install django-celery-results
|
|
- [x] Configure Celery to use django-db backend
|
|
- [x] Create CeleryTaskResultAdmin with colored status
|
|
- [x] Create CeleryGroupResultAdmin with colored status
|
|
- [x] Add retry_failed_tasks action
|
|
- [x] Add clear_old_tasks action
|
|
- [x] Create admin_dashboard view function
|
|
- [x] Create dashboard.html template with metrics
|
|
- [x] Add dashboard route to admin site URLs
|
|
- [x] Redirect admin index to dashboard
|
|
- [x] Add health_indicator to Account admin
|
|
- [x] Add health_details to Account admin
|
|
- [x] Create AdminAlerts utility class
|
|
- [x] Add alerts section to dashboard template
|
|
- [x] Fix execution_time format_html issue
|
|
- [x] Test dashboard metrics accuracy
|
|
- [x] Test alert system functionality
|
|
- [x] Verify all Celery admin pages work (200 status)
|
|
|
|
### ✅ Phase 4: Analytics & Reporting (COMPLETED - Dec 15, 2025)
|
|
|
|
- [x] Create reports.py module
|
|
- [x] Implement revenue_report view
|
|
- [x] Implement usage_report view
|
|
- [x] Implement content_report view
|
|
- [x] Implement data_quality_report view
|
|
- [x] Create report templates (revenue, usage, content, data_quality)
|
|
- [x] Add chart.js for visualizations
|
|
- [x] Add report routes to admin site URLs
|
|
- [x] Add report links to admin sidebar navigation
|
|
- [x] Create report permission checks
|
|
- [ ] Test all reports with real data (operational task)
|
|
- [ ] Optimize report queries for performance (operational task)
|
|
|
|
### ✅ Phase 5: Advanced Features (COMPLETED - Dec 15, 2025)
|
|
|
|
- [x] Enable list_editable for Tasks and Keywords
|
|
- [x] django-simple-history already installed
|
|
- [x] Add HistoricalRecords to Payment model
|
|
- [x] Add HistoricalRecords to Account model
|
|
- [x] Add HistoricalRecords to CreditCostConfig model
|
|
- [x] Run migrations for history tables
|
|
- [x] Update admins to use SimpleHistoryAdmin
|
|
- [x] Create create_admin_groups management command
|
|
- [x] Define permission groups (Content Manager, Billing Admin, Support Agent)
|
|
- [x] Assign permissions to groups
|
|
- [ ] Test permission restrictions (operational task)
|
|
- [ ] Document permission group usage (operational task)
|
|
|
|
---
|
|
|
|
## Technical Requirements
|
|
|
|
### Python Packages
|
|
|
|
```txt
|
|
# Already installed:
|
|
django-unfold==0.73.1 # Modern admin theme (✅ INSTALLED)
|
|
django-import-export==3.3.1 # CSV/Excel import/export (✅ INSTALLED)
|
|
django-celery-results==2.5.1 # Celery monitoring (✅ INSTALLED)
|
|
django-simple-history==3.4.0 # Audit trail (✅ INSTALLED)
|
|
|
|
# No additional packages needed for styling - Unfold handles everything
|
|
```
|
|
|
|
### Settings Configuration
|
|
|
|
```python
|
|
# backend/igny8_core/settings.py
|
|
# ✅ Already configured properly
|
|
|
|
INSTALLED_APPS = [
|
|
'unfold', # ✅ Already installed - Must be before django.contrib.admin
|
|
'unfold.contrib.filters', # ✅ Already installed
|
|
'unfold.contrib.import_export', # ✅ Already installed
|
|
'unfold.contrib.simple_history', # ✅ Already installed
|
|
'igny8_core.admin.apps.Igny8AdminConfig',
|
|
# ... rest of apps
|
|
'import_export', # ✅ Already installed
|
|
'django_celery_results', # ✅ Already installed
|
|
'simple_history', # ✅ Already installed
|
|
]
|
|
|
|
# Celery Results - ✅ Already configured
|
|
CELERY_RESULT_BACKEND = 'django-db'
|
|
CELERY_CACHE_BACKEND = 'django-cache'
|
|
|
|
# History Middleware - ✅ Already configured
|
|
MIDDLEWARE = [
|
|
# ... existing middleware
|
|
'simple_history.middleware.HistoryRequestMiddleware',
|
|
]
|
|
|
|
# Import/Export Settings
|
|
IMPORT_EXPORT_USE_TRANSACTIONS = True
|
|
|
|
# UNFOLD configuration - ✅ Already configured in settings.py
|
|
```
|
|
|
|
### Database Migrations
|
|
|
|
```bash
|
|
# Already completed - no additional migrations needed for Unfold
|
|
# Unfold uses Django's existing admin tables
|
|
|
|
# For future features:
|
|
# python manage.py migrate django_celery_results # When adding Celery monitoring
|
|
# python manage.py migrate simple_history # When adding history to models
|
|
```
|
|
|
|
### 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. **Unfold Issues (unlikely):** Already stable and working
|
|
- Unfold is well-tested and production-ready
|
|
- No custom styling to break
|
|
- All standard Django admin features work
|
|
|
|
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:** 2-4 weeks with 1-2 developers (reduced since styling is already complete via Unfold)
|
|
|
|
**Priority:** 🔴 High - Critical for efficient operations at scale
|
|
|
|
**Dependencies:** Should be implemented after Plan Management (#2) is complete
|
|
|
|
|
|
|