refactor: Fix AI billing system - revert to commit #10 + fixes
- Reverted to commit #10 (98e68f6) for stable AI function base
- Fixed database migrations: removed 0018-0019 that broke schema
- Fixed CreditCostConfig schema: restored credits_cost, unit fields
- Fixed historical table schema for django-simple-history
- Added debug system (staged for future use)
Changes:
- CreditCostConfig: Updated OPERATION_TYPE_CHOICES (10 ops, no duplicates)
- CreditUsageLog: Updated choices with legacy aliases marked
- Migration 0018_update_operation_choices: Applied successfully
- All AI operations working (clustering, ideas, content, optimization, etc.)
Test Results:
✓ CreditCostConfig save/load working
✓ Credit check passing for all operations
✓ AICore initialization successful
✓ AIEngine operation mapping functional
✓ Admin panel accessible without 500 errors
Future: AI-MODEL-COST-REFACTOR-PLAN.md created for token-based system
This commit is contained in:
3
backend/igny8_core/business/system/__init__.py
Normal file
3
backend/igny8_core/business/system/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
System app package
|
||||
"""
|
||||
65
backend/igny8_core/business/system/admin.py
Normal file
65
backend/igny8_core/business/system/admin.py
Normal file
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
System admin configuration
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import reverse
|
||||
from django.utils.html import format_html
|
||||
from igny8_core.business.system.models import DebugConfiguration
|
||||
|
||||
|
||||
@admin.register(DebugConfiguration)
|
||||
class DebugConfigurationAdmin(admin.ModelAdmin):
|
||||
"""Admin for debug configuration (singleton)"""
|
||||
|
||||
def has_add_permission(self, request):
|
||||
# Only allow one instance
|
||||
return not DebugConfiguration.objects.exists()
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
# Don't allow deletion
|
||||
return False
|
||||
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
# Redirect to edit view for singleton
|
||||
if DebugConfiguration.objects.exists():
|
||||
obj = DebugConfiguration.objects.first()
|
||||
return self.changeform_view(request, str(obj.pk), '', extra_context)
|
||||
return super().changelist_view(request, extra_context)
|
||||
|
||||
fieldsets = (
|
||||
('Debug Logging Control', {
|
||||
'fields': ('enable_debug_logging',),
|
||||
'description': '⚠️ <strong>Master Switch:</strong> When DISABLED, all logging below is completely skipped (zero overhead). When ENABLED, logs appear in console output.'
|
||||
}),
|
||||
('Logging Categories', {
|
||||
'fields': (
|
||||
'log_ai_steps',
|
||||
'log_api_requests',
|
||||
'log_database_queries',
|
||||
'log_celery_tasks',
|
||||
),
|
||||
'description': 'Fine-tune what gets logged when debug logging is enabled'
|
||||
}),
|
||||
('Audit', {
|
||||
'fields': ('updated_at', 'updated_by'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
)
|
||||
|
||||
readonly_fields = ('updated_at', 'updated_by')
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
obj.updated_by = request.user
|
||||
super().save_model(request, obj, form, change)
|
||||
|
||||
# Show message about cache clearing
|
||||
if change:
|
||||
self.message_user(request,
|
||||
"Debug configuration updated. Cache cleared. Changes take effect immediately.",
|
||||
level='success'
|
||||
)
|
||||
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('admin/css/forms.css',)
|
||||
}
|
||||
11
backend/igny8_core/business/system/apps.py
Normal file
11
backend/igny8_core/business/system/apps.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
System app configuration
|
||||
"""
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SystemConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'igny8_core.business.system'
|
||||
label = 'debug_system'
|
||||
verbose_name = 'Debug & System Settings'
|
||||
@@ -0,0 +1,35 @@
|
||||
# Generated by Django 5.2.9 on 2025-12-23 02:32
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='DebugConfiguration',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('enable_debug_logging', models.BooleanField(default=False, help_text='Enable verbose debug logging to console (AI steps, detailed execution)')),
|
||||
('log_ai_steps', models.BooleanField(default=True, help_text='Log AI function execution steps (only when debug logging enabled)')),
|
||||
('log_api_requests', models.BooleanField(default=False, help_text='Log all API requests and responses (only when debug logging enabled)')),
|
||||
('log_database_queries', models.BooleanField(default=False, help_text='Log database queries (only when debug logging enabled)')),
|
||||
('log_celery_tasks', models.BooleanField(default=True, help_text='Log Celery task execution (only when debug logging enabled)')),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('updated_by', models.ForeignKey(blank=True, help_text='Admin who last updated', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Debug Configuration',
|
||||
'verbose_name_plural': 'Debug Configuration',
|
||||
'db_table': 'igny8_debug_configuration',
|
||||
},
|
||||
),
|
||||
]
|
||||
86
backend/igny8_core/business/system/models.py
Normal file
86
backend/igny8_core/business/system/models.py
Normal file
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
System-wide settings and configuration models
|
||||
"""
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
|
||||
|
||||
class DebugConfiguration(models.Model):
|
||||
"""
|
||||
System-wide debug configuration (Singleton).
|
||||
Controls verbose logging and debugging features.
|
||||
"""
|
||||
# Debug settings
|
||||
enable_debug_logging = models.BooleanField(
|
||||
default=False,
|
||||
help_text="Enable verbose debug logging to console (AI steps, detailed execution)"
|
||||
)
|
||||
|
||||
log_ai_steps = models.BooleanField(
|
||||
default=True,
|
||||
help_text="Log AI function execution steps (only when debug logging enabled)"
|
||||
)
|
||||
|
||||
log_api_requests = models.BooleanField(
|
||||
default=False,
|
||||
help_text="Log all API requests and responses (only when debug logging enabled)"
|
||||
)
|
||||
|
||||
log_database_queries = models.BooleanField(
|
||||
default=False,
|
||||
help_text="Log database queries (only when debug logging enabled)"
|
||||
)
|
||||
|
||||
log_celery_tasks = models.BooleanField(
|
||||
default=True,
|
||||
help_text="Log Celery task execution (only when debug logging enabled)"
|
||||
)
|
||||
|
||||
# Audit fields
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
updated_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Admin who last updated"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
app_label = 'debug_system'
|
||||
db_table = 'igny8_debug_configuration'
|
||||
verbose_name = 'Debug Configuration'
|
||||
verbose_name_plural = 'Debug Configuration'
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""Enforce singleton pattern and clear cache on save"""
|
||||
self.pk = 1
|
||||
super().save(*args, **kwargs)
|
||||
# Clear ALL debug-related caches when settings change
|
||||
cache.delete('debug_config')
|
||||
cache.delete('debug_enabled')
|
||||
cache.delete('debug_first_worker_pid') # Reset worker selection
|
||||
|
||||
@classmethod
|
||||
def get_config(cls):
|
||||
"""Get or create the singleton config (cached)"""
|
||||
config = cache.get('debug_config')
|
||||
if config is None:
|
||||
config, created = cls.objects.get_or_create(pk=1)
|
||||
cache.set('debug_config', config, 300) # Cache for 5 minutes
|
||||
return config
|
||||
|
||||
@classmethod
|
||||
def is_debug_enabled(cls):
|
||||
"""Fast check if debug logging is enabled (cached for performance)"""
|
||||
enabled = cache.get('debug_enabled')
|
||||
if enabled is None:
|
||||
config = cls.get_config()
|
||||
enabled = config.enable_debug_logging
|
||||
cache.set('debug_enabled', enabled, 60) # Cache for 1 minute
|
||||
return enabled
|
||||
|
||||
def __str__(self):
|
||||
status = "ENABLED" if self.enable_debug_logging else "DISABLED"
|
||||
return f"Debug Configuration ({status})"
|
||||
Reference in New Issue
Block a user