From 60263b468258080ffcaa4c45facf47b9aca33b66 Mon Sep 17 00:00:00 2001 From: "IGNY8 VPS (Salman)" Date: Sat, 13 Dec 2025 22:12:25 +0000 Subject: [PATCH] phase 1 partial --- DJANGO-ADMIN-IMPROVEMENT-PLAN.md | 1624 +++++++++++++++++ backend/igny8_core/admin/site.py | 127 +- backend/igny8_core/business/billing/admin.py | 144 +- .../static/admin/css/igny8_admin.css | 290 +++ .../igny8_core/templates/admin/base_site.html | 19 + 5 files changed, 2012 insertions(+), 192 deletions(-) create mode 100644 DJANGO-ADMIN-IMPROVEMENT-PLAN.md create mode 100644 backend/igny8_core/static/admin/css/igny8_admin.css create mode 100644 backend/igny8_core/templates/admin/base_site.html diff --git a/DJANGO-ADMIN-IMPROVEMENT-PLAN.md b/DJANGO-ADMIN-IMPROVEMENT-PLAN.md new file mode 100644 index 00000000..b08c8869 --- /dev/null +++ b/DJANGO-ADMIN-IMPROVEMENT-PLAN.md @@ -0,0 +1,1624 @@ +# Django Admin Improvement Plan + +**Version:** 1.0.0 +**Created:** December 13, 2025 +**Status:** Planning Phase +**Priority:** 🔴 High - 4-6 weeks implementation +**Dependencies:** After Plan Management Implementation + +--- + +## Executive Summary + +This document outlines a comprehensive improvement plan for the IGNY8 Django Admin interface to transform it from a basic management tool into a powerful operational command center. The plan addresses UI/UX deficiencies, operational inefficiencies, missing monitoring capabilities, and organizational improvements. + +**Key Objectives:** +- Enhance UI styling and user experience +- Reorganize sidebar menu for logical grouping +- Remove unused/empty models +- Add bulk operations and data export +- Implement Celery task monitoring +- Create operational dashboards +- Improve search and filtering capabilities + +--- + +## Current State Analysis + +### ✅ Strengths + +1. **Custom Admin Site** - Igny8AdminSite with logical grouping +2. **Multi-Tenancy Support** - AccountAdminMixin and SiteSectorAdminMixin +3. **Payment Approval Workflow** - Comprehensive payment approval system +4. **Custom Actions** - API key generation, payment approval/rejection +5. **Field Customization** - Custom fieldsets and readonly fields + +### âš ī¸ Issues Identified + +#### 1. **UI/UX Problems** +- No custom styling - uses default Django admin theme +- Basic, dated appearance +- Poor mobile responsiveness +- No dashboard widgets or charts +- Limited visual feedback for actions +- No color coding for statuses + +#### 2. **Sidebar Menu Organization** +- Some groups have unclear purpose +- "Payments" group separated from "Billing & Tenancy" +- Missing PlanLimitUsage model (needs to be added) +- Some empty groups appearing +- Inconsistent naming conventions + +#### 3. **Unused/Empty Models** +- **site_building** models referenced but don't exist: + - BusinessType + - AudienceProfile + - BrandPersonality + - HeroImageryDirection +- Duplicate model registrations: + - Invoice registered in both `business/billing/admin.py` and `modules/billing/admin.py` + - Payment registered twice (with comment noting one shouldn't be used) + - CreditPackage registered twice + - CreditCostConfig registered twice + +#### 4. **Missing Features** +- No CSV/Excel export functionality +- Limited bulk operations (only 3 actions total) +- No Celery task monitoring interface +- No admin dashboard with metrics +- No data quality indicators +- No audit trail beyond basic LogEntry +- No advanced filtering (date ranges, etc.) + +#### 5. **Operational Gaps** +- No at-risk account alerts +- No low credit warnings +- No failed automation alerts +- No WordPress sync status dashboard +- No performance metrics tracking + +--- + +## Phase 1: Critical Fixes & UI Foundation (Week 1-2) + +### 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 Reorganize Sidebar Menu Groups + +**Current Groups:** +1. Billing & Tenancy +2. Sites & Users +3. Global Reference Data +4. Planner +5. Writer Module +6. Thinker Module +7. System Configuration +8. Payments (separate!) +9. Integrations & Sync +10. Publishing +11. Optimization +12. Django Internals + +**Proposed Reorganization:** + +```python +'💰 Billing & Accounts': { + 'models': [ + ('igny8_core_auth', 'Plan'), + ('billing', 'PlanLimitUsage'), # ADD THIS + ('igny8_core_auth', 'Account'), + ('igny8_core_auth', 'Subscription'), + ('billing', 'Invoice'), + ('billing', 'Payment'), + ('billing', 'CreditTransaction'), + ('billing', 'CreditUsageLog'), + ('billing', 'CreditPackage'), + ('billing', 'PaymentMethodConfig'), + ('billing', 'AccountPaymentMethod'), + ('billing', 'CreditCostConfig'), + ], +}, +'đŸ‘Ĩ Sites & Users': { + 'models': [ + ('igny8_core_auth', 'Site'), + ('igny8_core_auth', 'Sector'), + ('igny8_core_auth', 'User'), + ('igny8_core_auth', 'SiteUserAccess'), + ('igny8_core_auth', 'PasswordResetToken'), + ], +}, +'📚 Content Management': { + 'models': [ + ('writer', 'Content'), + ('writer', 'Tasks'), + ('writer', 'Images'), + ('writer', 'ContentTaxonomy'), + ('writer', 'ContentAttribute'), + ('writer', 'ContentTaxonomyRelation'), + ('writer', 'ContentClusterMap'), + ], +}, +'đŸŽ¯ Planning & Strategy': { + 'models': [ + ('planner', 'Clusters'), + ('planner', 'Keywords'), + ('planner', 'ContentIdeas'), + ('system', 'Strategy'), + ], +}, +'🔗 Integrations & Publishing': { + 'models': [ + ('integration', 'SiteIntegration'), + ('integration', 'SyncEvent'), + ('publishing', 'PublishingRecord'), + ('publishing', 'DeploymentRecord'), + ], +}, +'🤖 AI & Automation': { + 'models': [ + ('ai', 'AITaskLog'), + ('system', 'AIPrompt'), + ('automation', 'AutomationConfig'), + ('automation', 'AutomationRun'), + ('optimization', 'OptimizationTask'), + ], +}, +'🌍 Global Reference Data': { + 'models': [ + ('igny8_core_auth', 'Industry'), + ('igny8_core_auth', 'IndustrySector'), + ('igny8_core_auth', 'SeedKeyword'), + ], +}, +'âš™ī¸ System Configuration': { + 'models': [ + ('system', 'IntegrationSettings'), + ('system', 'AuthorProfile'), + ('system', 'SystemSettings'), + ('system', 'AccountSettings'), + ('system', 'UserSettings'), + ('system', 'ModuleSettings'), + ('system', 'AISettings'), + ('system', 'ModuleEnableSettings'), + ('system', 'SystemLog'), + ('system', 'SystemStatus'), + ], +}, +'🔧 Django System': { + 'models': [ + ('admin', 'LogEntry'), + ('auth', 'Group'), + ('auth', 'Permission'), + ('contenttypes', 'ContentType'), + ('sessions', 'Session'), + ], +}, +``` + +**Benefits:** +- Logical grouping by functionality +- Emoji icons for quick visual recognition +- Combined Billing & Payments into one group +- Separated Content Management from Planning +- Grouped AI, Automation, and Optimization together +- Clearer hierarchy and easier navigation + +### 1.4 Install Django Admin Enhancement Packages + +**Packages to install:** + +```bash +# UI Enhancement +pip install django-admin-interface # Modern, customizable theme +# OR +pip install django-grappelli # Alternative mature theme + +# Functionality +pip install django-import-export # CSV/Excel import/export +pip install django-admin-rangefilter # Date range filters +pip install django-advanced-filters # Save filter combinations +pip install django-admin-autocomplete-filter # Better autocomplete +``` + +**Configuration needed:** +- Add to INSTALLED_APPS +- Configure static files +- Run collectstatic +- Apply migrations if needed + +### 1.5 Basic UI Styling Improvements + +**Without packages (quick wins):** + +Create custom CSS file: `backend/igny8_core/static/admin/css/igny8_admin.css` + +```css +/* Status badges */ +.status-active { color: #28a745; font-weight: bold; } +.status-inactive { color: #dc3545; } +.status-pending { color: #ffc107; } + +/* Credit indicators */ +.credits-low { color: #dc3545; font-weight: bold; } +.credits-medium { color: #ffc107; } +.credits-high { color: #28a745; } + +/* Quick action buttons */ +.admin-action-button { + padding: 5px 15px; + border-radius: 4px; + cursor: pointer; + text-decoration: none; + display: inline-block; + margin: 2px; +} + +/* List view enhancements */ +.django-admin-index tr:hover { + background-color: #f8f9fa; +} +``` + +Add custom template: `backend/igny8_core/templates/admin/base_site.html` + +```html +{% extends "admin/base.html" %} +{% load static %} + +{% block title %}{{ title }} | IGNY8 Admin{% endblock %} + +{% block branding %} +

+ + IGNY8 Administration + +

+{% endblock %} + +{% block extrastyle %} + {{ block.super }} + +{% endblock %} +``` + +--- + +## Phase 2: Operational Features (Week 3-4) + +### 2.1 Add Bulk Operations + +**Priority Models for Bulk Actions:** + +#### Tasks Admin +```python +actions = [ + 'bulk_set_status_draft', + 'bulk_set_status_in_progress', + 'bulk_set_status_completed', + 'bulk_assign_cluster', + 'bulk_generate_content', + 'bulk_export_csv', +] +``` + +#### Content Admin +```python +actions = [ + 'bulk_publish_to_wordpress', + 'bulk_set_status', + 'bulk_add_taxonomy', + 'bulk_export_with_seo', +] +``` + +#### Keywords Admin +```python +actions = [ + 'bulk_assign_cluster', + 'bulk_set_priority', + 'bulk_export_csv', +] +``` + +#### Payments Admin (already has some) +```python +actions = [ + 'approve_payments', + 'reject_payments', + 'export_transactions', # ADD +] +``` + +### 2.2 Implement CSV Export + +**Install django-import-export:** + +Add to each admin class: + +```python +from import_export.admin import ExportMixin + +class TasksAdmin(ExportMixin, SiteSectorAdminMixin, admin.ModelAdmin): + resource_class = TaskResource # Define export fields + # ... existing code +``` + +**Create Resource classes for key models:** +- TaskResource +- ContentResource +- KeywordsResource +- CreditTransactionResource +- PaymentResource + +### 2.3 Advanced Filtering + +**Add date range filters:** + +```python +from rangefilter.filters import DateRangeFilter + +class CreditTransactionAdmin(AccountAdminMixin, admin.ModelAdmin): + list_filter = [ + 'transaction_type', + ('created_at', DateRangeFilter), + 'account', + ] +``` + +**Add autocomplete filters for large datasets:** + +```python +class TasksAdmin(SiteSectorAdminMixin, admin.ModelAdmin): + autocomplete_fields = ['site', 'sector', 'cluster'] + search_fields = ['title', 'description'] +``` + +--- + +## 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( + '{}', + 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 %} +

IGNY8 Admin Dashboard

+ +
+ +
+

đŸ‘Ĩ Accounts

+
+
+ {{ accounts.total }} + Total Accounts +
+
+ {{ accounts.active }} + Active +
+
+ + {{ accounts.low_credit }} + + Low Credits (< 100) +
+
+
+ + +
+

📝 Content Production

+
+
+ {{ content.this_week }} + This Week +
+
+ {{ content.this_month }} + This Month +
+
+ {{ content.tasks_pending }} + Tasks Pending +
+
+
+ + +
+

💰 Billing

+
+
+ + {{ billing.pending_payments }} + + Pending Approvals + + Review → + +
+
+ ${{ billing.payments_this_month|floatformat:2 }} + Revenue This Month +
+
+ {{ billing.credit_usage_this_month }} + Credits Used +
+
+
+ + +
+

🤖 Automation

+
+
+ {{ automation.running }} + Running Now +
+
+ + {{ automation.failed_this_week }} + + Failed (7 days) + {% if automation.failed_this_week > 0 %} + + Review → + + {% endif %} +
+
+
+ + +
+

🔗 Integration Health

+
+
+ + {{ integration.sync_failed_today }} + + Failed Syncs Today + {% if integration.sync_failed_today > 0 %} + + Review → + + {% endif %} +
+
+
+
+ + +{% 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( + '{} ' + '{}', + 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 + +{% if alerts %} +
+ {% for alert in alerts %} +
+ + {% if alert.level == 'error' %}🔴{% endif %} + {% if alert.level == 'warning' %}âš ī¸{% endif %} + {% if alert.level == 'info' %}â„šī¸{% endif %} + + {{ alert.message }} + {{ alert.action }} +
+ {% endfor %} +
+{% 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 + + + diff --git a/backend/igny8_core/admin/site.py b/backend/igny8_core/admin/site.py index b046d37d..4feb7d76 100644 --- a/backend/igny8_core/admin/site.py +++ b/backend/igny8_core/admin/site.py @@ -23,57 +23,42 @@ class Igny8AdminSite(admin.AdminSite): def get_app_list(self, request): """ - Customize the app list to organize models into proper groups + Customize the app list to organize models into logical groups """ # Get the default app list app_dict = self._build_app_dict(request) # Define our custom groups with their models (using object_name) + # Organized by business function with emoji icons for visual recognition custom_groups = { - 'Billing & Tenancy': { + '💰 Billing & Accounts': { 'models': [ ('igny8_core_auth', 'Plan'), ('igny8_core_auth', 'Account'), ('igny8_core_auth', 'Subscription'), - ('billing', 'CreditTransaction'), - ('billing', 'CreditUsageLog'), ('billing', 'Invoice'), ('billing', 'Payment'), + ('billing', 'CreditTransaction'), + ('billing', 'CreditUsageLog'), ('billing', 'CreditPackage'), + ('billing', 'PaymentMethodConfig'), + ('billing', 'AccountPaymentMethod'), ('billing', 'CreditCostConfig'), ], }, - 'Sites & Users': { + 'đŸ‘Ĩ Sites & Users': { 'models': [ ('igny8_core_auth', 'Site'), + ('igny8_core_auth', 'Sector'), ('igny8_core_auth', 'User'), ('igny8_core_auth', 'SiteUserAccess'), ('igny8_core_auth', 'PasswordResetToken'), - ('igny8_core_auth', 'Sector'), ], }, - 'Global Reference Data': { + '📚 Content Management': { 'models': [ - ('igny8_core_auth', 'Industry'), - ('igny8_core_auth', 'IndustrySector'), - ('igny8_core_auth', 'SeedKeyword'), - ('site_building', 'BusinessType'), - ('site_building', 'AudienceProfile'), - ('site_building', 'BrandPersonality'), - ('site_building', 'HeroImageryDirection'), - ], - }, - 'Planner': { - 'models': [ - ('planner', 'Keywords'), - ('planner', 'Clusters'), - ('planner', 'ContentIdeas'), - ], - }, - 'Writer Module': { - 'models': [ - ('writer', 'Tasks'), ('writer', 'Content'), + ('writer', 'Tasks'), ('writer', 'Images'), ('writer', 'ContentTaxonomy'), ('writer', 'ContentAttribute'), @@ -81,54 +66,53 @@ class Igny8AdminSite(admin.AdminSite): ('writer', 'ContentClusterMap'), ], }, - 'Thinker Module': { + 'đŸŽ¯ Planning & Strategy': { 'models': [ - ('system', 'AIPrompt'), - ('system', 'AuthorProfile'), + ('planner', 'Clusters'), + ('planner', 'Keywords'), + ('planner', 'ContentIdeas'), ('system', 'Strategy'), - ('ai', 'AITaskLog'), ], }, - 'System Configuration': { + '🔗 Integrations & Publishing': { + 'models': [ + ('integration', 'SiteIntegration'), + ('integration', 'SyncEvent'), + ('publishing', 'PublishingRecord'), + ('publishing', 'DeploymentRecord'), + ], + }, + '🤖 AI & Automation': { + 'models': [ + ('ai', 'AITaskLog'), + ('system', 'AIPrompt'), + ('automation', 'AutomationConfig'), + ('automation', 'AutomationRun'), + ('optimization', 'OptimizationTask'), + ], + }, + '🌍 Global Reference Data': { + 'models': [ + ('igny8_core_auth', 'Industry'), + ('igny8_core_auth', 'IndustrySector'), + ('igny8_core_auth', 'SeedKeyword'), + ], + }, + 'âš™ī¸ System Configuration': { 'models': [ ('system', 'IntegrationSettings'), - ('system', 'SystemLog'), - ('system', 'SystemStatus'), + ('system', 'AuthorProfile'), ('system', 'SystemSettings'), ('system', 'AccountSettings'), ('system', 'UserSettings'), ('system', 'ModuleSettings'), ('system', 'AISettings'), ('system', 'ModuleEnableSettings'), - # Automation config lives under the automation app - include here - ('automation', 'AutomationConfig'), - ('automation', 'AutomationRun'), + ('system', 'SystemLog'), + ('system', 'SystemStatus'), ], }, - 'Payments': { - 'models': [ - ('billing', 'PaymentMethodConfig'), - ('billing', 'AccountPaymentMethod'), - ], - }, - 'Integrations & Sync': { - 'models': [ - ('integration', 'SiteIntegration'), - ('integration', 'SyncEvent'), - ], - }, - 'Publishing': { - 'models': [ - ('publishing', 'PublishingRecord'), - ('publishing', 'DeploymentRecord'), - ], - }, - 'Optimization': { - 'models': [ - ('optimization', 'OptimizationTask'), - ], - }, - 'Django Internals': { + '🔧 Django System': { 'models': [ ('admin', 'LogEntry'), ('auth', 'Group'), @@ -159,7 +143,7 @@ class Igny8AdminSite(admin.AdminSite): if group_models: app_list.append({ 'name': group_name, - 'app_label': group_name.lower().replace(' ', '_').replace('&', ''), + 'app_label': group_name.lower().replace(' ', '_').replace('&', '').replace('emoji', ''), 'app_url': None, 'has_module_perms': True, 'models': group_models, @@ -167,18 +151,15 @@ class Igny8AdminSite(admin.AdminSite): # Sort the app list by our custom order order = [ - 'Billing & Tenancy', - 'Sites & Users', - 'Global Reference Data', - 'Planner', - 'Writer Module', - 'Thinker Module', - 'System Configuration', - 'Payments', - 'Integrations & Sync', - 'Publishing', - 'Optimization', - 'Django Internals', + '💰 Billing & Accounts', + 'đŸ‘Ĩ Sites & Users', + '📚 Content Management', + 'đŸŽ¯ Planning & Strategy', + '🔗 Integrations & Publishing', + '🤖 AI & Automation', + '🌍 Global Reference Data', + 'âš™ī¸ System Configuration', + '🔧 Django System', ] app_list.sort(key=lambda x: order.index(x['name']) if x['name'] in order else 999) diff --git a/backend/igny8_core/business/billing/admin.py b/backend/igny8_core/business/billing/admin.py index f2f0864a..b92780f0 100644 --- a/backend/igny8_core/business/billing/admin.py +++ b/backend/igny8_core/business/billing/admin.py @@ -1,5 +1,8 @@ """ Billing Business Logic Admin + +NOTE: Most billing models are registered in modules/billing/admin.py +with full workflow functionality. This file contains legacy/minimal registrations. """ from django.contrib import admin from django.utils.html import format_html @@ -14,133 +17,36 @@ from .models import ( ) -@admin.register(CreditCostConfig) -class CreditCostConfigAdmin(admin.ModelAdmin): - list_display = [ - 'operation_type', - 'display_name', - 'credits_cost_display', - 'unit', - 'is_active', - 'cost_change_indicator', - 'updated_at', - 'updated_by' - ] - - list_filter = ['is_active', 'unit', 'updated_at'] - search_fields = ['operation_type', 'display_name', 'description'] - - fieldsets = ( - ('Operation', { - 'fields': ('operation_type', 'display_name', 'description') - }), - ('Cost Configuration', { - 'fields': ('credits_cost', 'unit', 'is_active') - }), - ('Audit Trail', { - 'fields': ('previous_cost', 'updated_by', 'created_at', 'updated_at'), - 'classes': ('collapse',) - }), - ) - - readonly_fields = ['created_at', 'updated_at', 'previous_cost'] - - def credits_cost_display(self, obj): - """Show cost with color coding""" - if obj.credits_cost >= 20: - color = 'red' - elif obj.credits_cost >= 10: - color = 'orange' - else: - color = 'green' - return format_html( - '{} credits', - color, - obj.credits_cost - ) - credits_cost_display.short_description = 'Cost' - - def cost_change_indicator(self, obj): - """Show if cost changed recently""" - if obj.previous_cost is not None: - if obj.credits_cost > obj.previous_cost: - icon = '📈' # Increased - color = 'red' - elif obj.credits_cost < obj.previous_cost: - icon = '📉' # Decreased - color = 'green' - else: - icon = 'âžĄī¸' # Same - color = 'gray' - - return format_html( - '{} ({} → {})', - icon, - color, - obj.previous_cost, - obj.credits_cost - ) - return '—' - cost_change_indicator.short_description = 'Recent Change' - - def save_model(self, request, obj, form, change): - """Track who made the change""" - obj.updated_by = request.user - super().save_model(request, obj, form, change) +# CreditCostConfig - DUPLICATE - Registered in modules/billing/admin.py with better features +# Commenting out to avoid conflicts +# @admin.register(CreditCostConfig) +# class CreditCostConfigAdmin(admin.ModelAdmin): +# ...existing implementation... -@admin.register(Invoice) -class InvoiceAdmin(AccountAdminMixin, admin.ModelAdmin): - list_display = [ - 'invoice_number', - 'account', - 'status', - 'total', - 'currency', - 'invoice_date', - 'due_date', - 'subscription', - ] - list_filter = ['status', 'currency', 'invoice_date', 'account'] - search_fields = ['invoice_number', 'account__name', 'subscription__id'] - readonly_fields = ['created_at', 'updated_at'] +# Invoice - DUPLICATE - Registered in modules/billing/admin.py +# Commenting out to avoid conflicts +# @admin.register(Invoice) +# class InvoiceAdmin(AccountAdminMixin, admin.ModelAdmin): +# ...existing implementation... -@admin.register(Payment) -class PaymentAdmin(AccountAdminMixin, admin.ModelAdmin): - \"\"\" - Payment admin - DO NOT USE. - Use the Payment admin in modules/billing/admin.py which has approval workflow actions. - This is kept for backward compatibility only. - \"\"\" - list_display = [ - 'id', - 'invoice', - 'account', - 'payment_method', - 'status', - 'amount', - 'currency', - 'processed_at', - ] - list_filter = ['status', 'payment_method', 'currency', 'created_at'] - search_fields = ['invoice__invoice_number', 'account__name', 'stripe_payment_intent_id', 'paypal_order_id'] - readonly_fields = ['created_at', 'updated_at'] - - def has_add_permission(self, request):\n return False # Prevent creating payments here - \n def has_delete_permission(self, request, obj=None):\n return False # Prevent deleting payments here +# Payment - DUPLICATE - Registered in modules/billing/admin.py with full approval workflow +# Commenting out to avoid conflicts +# @admin.register(Payment) +# class PaymentAdmin(AccountAdminMixin, admin.ModelAdmin): +# ...existing implementation... -@admin.register(CreditPackage) -class CreditPackageAdmin(admin.ModelAdmin): - list_display = ['name', 'slug', 'credits', 'price', 'discount_percentage', 'is_active', 'is_featured', 'sort_order'] - list_filter = ['is_active', 'is_featured'] - search_fields = ['name', 'slug'] - readonly_fields = ['created_at', 'updated_at'] +# CreditPackage - DUPLICATE - Registered in modules/billing/admin.py +# Commenting out to avoid conflicts +# @admin.register(CreditPackage) +# class CreditPackageAdmin(admin.ModelAdmin): +# ...existing implementation... -# PaymentMethodConfig admin is in modules/billing/admin.py - do not duplicate -# @admin.register(PaymentMethodConfig) +# PaymentMethodConfig and AccountPaymentMethod are kept here as they're not duplicated +# or have minimal implementations that don't conflict @admin.register(AccountPaymentMethod) class AccountPaymentMethodAdmin(admin.ModelAdmin): diff --git a/backend/igny8_core/static/admin/css/igny8_admin.css b/backend/igny8_core/static/admin/css/igny8_admin.css new file mode 100644 index 00000000..f0726f32 --- /dev/null +++ b/backend/igny8_core/static/admin/css/igny8_admin.css @@ -0,0 +1,290 @@ +/* IGNY8 Custom Admin Styles */ + +/* Status badges */ +.status-active { + color: #28a745 !important; + font-weight: bold; +} + +.status-inactive { + color: #dc3545 !important; +} + +.status-pending { + color: #ffc107 !important; + font-weight: bold; +} + +.status-succeeded, .status-completed { + color: #28a745 !important; +} + +.status-failed, .status-error { + color: #dc3545 !important; +} + +/* Credit indicators */ +.credits-low { + color: #dc3545 !important; + font-weight: bold; +} + +.credits-medium { + color: #ffc107 !important; +} + +.credits-high { + color: #28a745 !important; +} + +/* Quick action buttons */ +.admin-action-button { + padding: 5px 15px; + border-radius: 4px; + cursor: pointer; + text-decoration: none; + display: inline-block; + margin: 2px; + background-color: #417690; + color: white; + border: none; +} + +.admin-action-button:hover { + background-color: #305d75; + color: white; + text-decoration: none; +} + +/* List view enhancements */ +#content-main table tr:hover { + background-color: #f8f9fa !important; +} + +/* Improve sidebar menu appearance */ +#content-related h3 { + background: #417690; + color: white; + padding: 10px; + border-radius: 4px 4px 0 0; +} + +/* Better form field spacing */ +.form-row { + padding: 10px; +} + +/* Highlight required fields */ +.required label:after { + content: " *"; + color: #dc3545; +} + +/* Success messages */ +.success, .messagelist .success { + background-color: #d4edda !important; + border-color: #c3e6cb !important; + color: #155724 !important; +} + +/* Warning messages */ +.warning, .messagelist .warning { + background-color: #fff3cd !important; + border-color: #ffeaa7 !important; + color: #856404 !important; +} + +/* Error messages */ +.error, .messagelist .error { + background-color: #f8d7da !important; + border-color: #f5c6cb !important; + color: #721c24 !important; +} + +/* Improve table readability */ +#result_list tbody tr:nth-child(odd) { + background-color: #f9f9f9; +} + +#result_list tbody tr:nth-child(even) { + background-color: #ffffff; +} + +/* Better button styling */ +.button, input[type=submit], input[type=button], .submit-row input { + background: #417690 !important; + color: white !important; + border: none !important; + padding: 10px 15px !important; + border-radius: 4px !important; + cursor: pointer !important; +} + +.button:hover, input[type=submit]:hover, input[type=button]:hover { + background: #305d75 !important; +} + +/* Delete button styling */ +.deletelink, .deletelink-box a { + background: #dc3545 !important; +} + +.deletelink:hover, .deletelink-box a:hover { + background: #c82333 !important; +} + +/* Improve filter sidebar */ +#changelist-filter h2 { + background: #417690; + color: white; + padding: 8px 10px; + margin-bottom: 0; +} + +#changelist-filter h3 { + font-weight: bold; + margin-top: 15px; + padding-bottom: 5px; + border-bottom: 1px solid #ddd; +} + +/* Better pagination */ +.paginator { + font-size: 14px; + padding: 10px; + background: #f8f9fa; + border-radius: 4px; +} + +.paginator a { + padding: 5px 10px; + margin: 0 2px; + background: white; + border: 1px solid #ddd; + border-radius: 3px; +} + +.paginator a:hover { + background: #417690; + color: white; + text-decoration: none; +} + +/* Responsive improvements */ +@media (max-width: 768px) { + #content-main { + padding: 10px; + } + + .module table { + font-size: 12px; + } +} + +/* Admin header improvements */ +#header { + background: #417690; + color: white; +} + +#header a:link, #header a:visited { + color: white; +} + +#branding h1 { + color: white; +} + +/* Fieldset legend styling */ +fieldset.module h2 { + background: #417690; + color: white; + padding: 8px 10px; + border-radius: 4px 4px 0 0; +} + +/* Inline forms */ +.inline-group { + border: 1px solid #ddd; + border-radius: 4px; + margin-bottom: 20px; +} + +.inline-group .tabular { + overflow-x: auto; +} + +/* Help text styling */ +.help { + font-size: 12px; + color: #666; + display: block; + margin-top: 5px; +} + +/* Dashboard widget styling */ +.dashboard-card { + background: white; + border: 1px solid #ddd; + border-radius: 8px; + padding: 20px; + margin: 10px 0; + 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 { + display: inline-block; + margin: 10px 20px 10px 0; +} + +.metric-value { + font-size: 32px; + font-weight: bold; + color: #417690; + display: block; +} + +.metric-label { + font-size: 12px; + color: #666; + display: block; + margin-top: 5px; +} + +/* Alert styling */ +.alert { + padding: 15px; + margin: 10px 0; + border-radius: 4px; + border-left: 4px solid; +} + +.alert-error { + background-color: #f8d7da; + border-left-color: #dc3545; + color: #721c24; +} + +.alert-warning { + background-color: #fff3cd; + border-left-color: #ffc107; + color: #856404; +} + +.alert-info { + background-color: #d1ecf1; + border-left-color: #17a2b8; + color: #0c5460; +} + +.alert-success { + background-color: #d4edda; + border-left-color: #28a745; + color: #155724; +} diff --git a/backend/igny8_core/templates/admin/base_site.html b/backend/igny8_core/templates/admin/base_site.html new file mode 100644 index 00000000..1446add4 --- /dev/null +++ b/backend/igny8_core/templates/admin/base_site.html @@ -0,0 +1,19 @@ +{% extends "admin/base.html" %} +{% load static %} + +{% block title %}{{ title }} | IGNY8 Admin{% endblock %} + +{% block branding %} +

+ + 🚀 IGNY8 Administration + +

+{% endblock %} + +{% block extrastyle %} + {{ block.super }} + +{% endblock %} + +{% block nav-global %}{% endblock %}