20 KiB
Current Database State & Context Analysis
READ-ONLY Documentation for Future Implementation
Generated: 2025-12-08
Method: Docker exec query via check_current_state.py
Purpose: Understand existing state before making changes
Existing Plans in Database
| ID | Slug | Name | Price/Month | Credits | Max Sites | Max Users | Active |
|---|---|---|---|---|---|---|---|
| 1 | free | Free Plan | $0 | 100 | 1 | 1 | ✅ |
| 2 | starter | Starter | $89 | 1,000 | 1 | 2 | ✅ |
| 4 | growth | Growth | $139 | 2,000 | 3 | 3 | ✅ |
| 5 | scale | Scale | $229 | 4,000 | 5 | 5 | ✅ |
| 6 | enterprise | Enterprise Plan | $0 | 10,000 | 20 | 10,000 | ✅ |
Plan Features
- Free: No features array (empty)
- Starter: ai_writer, image_gen
- Growth: ai_writer, image_gen, auto_publish
- Scale: ai_writer, image_gen, auto_publish, custom_prompts
- Enterprise: ai_writer, image_gen, auto_publish, custom_prompts, unlimited
Key Observation
✅ Free plan already exists with 100 credits
- Could use this for free trial signup
- OR create separate 'free-trial' plan with more credits (e.g., 2000)
Existing Accounts (Sample)
| ID | Slug | Name | Owner | Plan | Credits | Status |
|---|---|---|---|---|---|---|
| 29 | home-g8 | Home G8 | admin@homeg8.com | starter | 8,000 | active |
| 14 | scale-account | Scale Account | scale@igny8.com | scale | 8,000 | active |
| 5 | aws-admin | AWS Admin | dev@igny8.com | enterprise | 454 | active |
| 28 | auto-remote | Auto Remote | auto+remote0003@example.com | enterprise | 0 | trial |
| 30 | tacbit | TacBit | payments@tacbit.net | free | 100 | trial |
Total Accounts: 8
Account Observations
- ✅ Account → Plan relationship working
- ✅ Account → Owner (User) relationship working
- ✅ Credits are being tracked and used (aws-admin has 454 remaining)
- ✅ Status field supports: active, trial, suspended, cancelled
- ❌ payment_method field does NOT exist in database yet
- ❌ billing_ fields exist but not used*
Existing Users & Roles
| ID | Role | Account | Superuser | |
|---|---|---|---|---|
| 3 | dev@igny8.com | developer | aws-admin | ✅ Yes |
| 43 | scale@igny8.com | owner | scale-account | No |
| 53 | tacbit.com@gmail.com | owner | salman-raza-sadiq | No |
| 57 | admin@homeg8.com | owner | home-g8 | No |
| 58 | payments@tacbit.net | owner | tacbit | No |
Total Users: 8
User Role Distribution
- 1 developer (superuser)
- 7 owners
- 0 admins
- 0 editors
- 0 viewers
User → Account Relationship
✅ All users have accounts assigned
- User.account is ForeignKey to Account (nullable)
- Account.owner is ForeignKey to User
- Bidirectional relationship working correctly
Existing Sites
| ID | Slug | Name | Account | Industry | Active | Sectors |
|---|---|---|---|---|---|---|
| 19 | tester-site | tester site | home-g8 | Healthcare & Medical | ✅ | 1 |
| 18 | new-site | new site | scale-account | Healthcare & Medical | ✅ | 1 |
| 16 | massagers-mart | Massagers Mart | aws-admin | Healthcare & Medical | ✅ | 3 |
| 5 | home-garden-site | Home & Garden Site | aws-admin | Home & Garden | ✅ | 5 |
Total Sites: 4
Site → Account Relationship
Site model:
- account: ForeignKey (db_column='tenant_id', on_delete=CASCADE)
- industry: ForeignKey (to Industry, optional)
✅ All sites belong to accounts ✅ Sites have industries assigned ✅ Sectors are properly linked to sites
Subscriptions
Status: ❌ NO SUBSCRIPTIONS EXIST IN DATABASE
Implications
- Subscription model exists in code but not used in production
- Payment system not implemented yet
- Users are operating on credits without subscription tracking
- This confirms need for payment_method fields
Credit Transactions
Total Transactions: 280
Sample (Latest 5):
| Account | Type | Amount | Balance After | Description |
|---|---|---|---|---|
| aws-admin | deduction | -2 | 454 | image_prompt_extraction |
| aws-admin | deduction | -2 | 456 | image_prompt_extraction |
| aws-admin | deduction | -2 | 458 | image_prompt_extraction |
Credit System Status
✅ Credit tracking is working
- CreditTransaction records all operations
- Deductions are logged
- Balance tracking is accurate
- Operations: clustering, idea_generation, content_generation, image_prompt_extraction, etc.
Model Field Analysis
Account Model (Current Database Fields)
Has:
- id, name, slug, owner, plan, credits, status
- stripe_customer_id (exists but not used)
- billing_email, billing_address_* (exists but not used)
- Soft delete fields: is_deleted, deleted_at, deleted_by, restore_until
- deletion_retention_days
Missing:
- ❌ payment_method (needs migration)
- ❌ Any payment tracking beyond stripe_customer_id
Subscription Model (Current Database Fields)
Has:
- id, account (OneToOne), status
- stripe_subscription_id (unique, NOT nullable currently)
- current_period_start, current_period_end
- cancel_at_period_end
Missing:
- ❌ payment_method (needs migration)
- ❌ external_payment_id (needs migration)
- stripe_subscription_id should be nullable (needs migration)
Site Model
Has:
- account (ForeignKey with db_column='tenant_id')
- industry (ForeignKey, optional)
- All standard fields (name, slug, domain, etc.)
- WordPress integration fields (wp_url, wp_username, wp_app_password)
- ✅ wp_api_key (added in migration 0002)
Permission System Analysis
Permission Classes (from code)
API Permissions (api/permissions.py):
IsAuthenticatedAndActive- Basic auth checkHasTenantAccess- Ensures user belongs to accountIsViewerOrAbove- viewer, editor, admin, ownerIsEditorOrAbove- editor, admin, ownerIsAdminOrOwner- admin, owner onlyIsSystemAccountOrDeveloper- System accounts or developer role
Auth Permissions (auth/permissions.py):
IsOwnerOrAdmin- owner, admin, developerIsEditorOrAbove- editor, admin, owner, developerIsViewerOrAbove- All authenticated usersAccountPermission- User must belong to account
Role Hierarchy (Ascending Power)
- viewer - Read-only access
- editor - Can create/edit content
- admin - Can manage content, view billing
- owner - Full account control
- developer - Super admin, bypasses filters
- system_bot - Automation only
Critical Findings for Implementation
✅ What's Ready
- Plans are configured and active
- Account-Plan relationship works
- User-Account relationship works
- Site-Account tenancy isolation works
- Credit system fully functional
- Soft delete implemented
❌ What's Missing
- payment_method field - Doesn't exist in DB (needs migration 0007)
- Subscription records - None exist (payment system not in use)
- external_payment_id - Doesn't exist (needs migration)
- stripe_subscription_id nullability - Currently required & unique
⚠️ What Needs Attention
- Free trial plan - Can use existing 'free' (100 credits) OR create 'free-trial' (2000 credits)
- Registration credit seeding - Currently NOT happening (accounts created with 0 credits unless manually set)
- Account status - 'pending_payment' not in STATUS_CHOICES yet
- API key validation - No account/plan check in APIKeyAuthentication
Database Schema State
Current Migration: 0006_soft_delete_and_retention
Applied migrations:
- 0001_initial - Base models
- 0002_add_wp_api_key_to_site - WordPress integration
- 0003_add_sync_event_model - Sync events
- 0004_add_invoice_payment_models - Invoice/payment (but not used)
- 0005_account_owner_nullable - Made owner nullable
- 0006_soft_delete_and_retention - Soft delete support
Next migration: 0007_add_payment_method_fields (planned)
Relationships Map
Plan (1) ←──────── (many) Account
↓
credits (IntegerField)
status (CharField)
↓
Account (1) ──────→ (many) User
│ ↓
│ role (CharField)
│ account (ForeignKey, nullable)
│
└──────→ (many) Site
↓
account (ForeignKey, db_column='tenant_id')
industry (ForeignKey, optional)
↓
(many) Sector
↓
account (ForeignKey, auto-set from site)
site (ForeignKey)
industry_sector (ForeignKey to IndustrySector)
Key Relationships
- Plan → Account (1:many) - Plan defines limits
- Account → User (1:many) - Users belong to accounts
- Account → Site (1:many) - Sites isolated by account
- Site → Sector (1:many) - Sectors belong to sites
- Account → Subscription (1:1) - Optional, not used yet
Implementation Strategy Based on Current State
Option A: Use Existing 'free' Plan
Pros:
- Already exists
- No need to create new plan
- Simple
Cons:
- Only 100 credits (might be too low for trial)
- Would need to update included_credits
Option B: Create 'free-trial' Plan (RECOMMENDED)
Pros:
- Separate from 'free' plan
- Can give more credits (2000)
- Clear distinction between free tier and trial
- Can set trial-specific limits
Cons:
- Requires creating new plan
RECOMMENDATION: Create free-trial plan with 2000 credits
Changes Already Made (DO NOT UNDO)
✅ backend/igny8_core/auth/serializers.py:276
- Updated RegisterSerializer.create() to:
- Auto-assign 'free-trial' plan (falls back to 'free')
- Seed credits from plan.get_effective_credits_per_month()
- Set account.status = 'trial'
- Create CreditTransaction for initial credits
✅ frontend/src/components/auth/SignUpForm.tsx
- Removed plan loading and selection UI
- Changed to "Start Your Free Trial" heading
- Removed plan_id from registration call
- Redirect to /sites instead of /account/plans
✅ backend/igny8_core/auth/management/commands/create_free_trial_plan.py
- Command to create free-trial plan
Required Actions Before Going Live
Immediate (Before Testing Signup)
- ✅ Run:
docker exec igny8_backend python manage.py create_free_trial_plan - Verify plan created
- Test signup flow
Next Phase (Payment System)
- Create migration 0007_add_payment_method_fields
- Run migration
- Update serializers to include payment_method
- Implement bank transfer confirmation endpoint
- Update API key authentication to validate account
- Fix throttling to be per-account
Account Status Flow
Current Valid Statuses
STATUS_CHOICES = [
('active', 'Active'), # Paid account
('suspended', 'Suspended'), # Payment failed
('trial', 'Trial'), # Free trial
('cancelled', 'Cancelled'), # User cancelled
]
Needed Status
- 'pending_payment' - For bank transfer awaiting confirmation
Status Transitions
NEW USER → Registration
↓
status = 'trial'
credits = plan.included_credits
↓
USING APP
↓
Upgrade/Pay → status = 'active'
OR
Trial Expires → status = 'suspended'
OR
Cancels → status = 'cancelled'
Credit Flow Analysis
Current Flow (from transactions)
Account created
→ credits = 0 (DEFAULT - PROBLEM!)
→ User manually adds credits OR
→ Credits never seeded
AI Operation
→ CreditService.check_credits() (BEFORE call)
→ AICore.run_ai_request()
→ CreditService.deduct_credits_for_operation() (AFTER call)
→ CreditTransaction created
Fixed Flow (After serializer changes)
Registration
→ Account created with credits = plan.get_effective_credits_per_month()
→ CreditTransaction logged for initial credits
→ User has credits immediately
AI Operation
→ Same as before (already working)
Site <-> Account Relationship
Database Structure
-- Sites table
CREATE TABLE igny8_sites (
id BIGINT PRIMARY KEY,
name VARCHAR(255),
slug VARCHAR(255),
tenant_id BIGINT REFERENCES igny8_tenants(id), -- Account FK
industry_id BIGINT REFERENCES igny8_industries(id),
is_active BOOLEAN DEFAULT TRUE,
status VARCHAR(20) DEFAULT 'active',
...
)
-- Unique constraint: (account, slug)
-- Meaning: Slug must be unique within an account
Current Sites Data
- 4 sites exist
- All have valid account references
- All sites have industries
- Sectors properly linked (1-5 sectors per site)
Site Access Control
From User.get_accessible_sites():
# Owner/Admin/Developer: All sites in account
# Editor/Viewer: Only sites in SiteUserAccess
Permissions in Practice
ViewSet Permission Combinations
Example: SiteViewSet
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess, IsEditorOrAbove]
Means: User must be authenticated AND belong to account AND have editor+ role
Example: PlanViewSet
permission_classes = [permissions.AllowAny]
Means: Public endpoint, no auth required
Current Auth Flow
Request → AccountContextMiddleware
→ Checks JWT/session
→ Sets request.account from token
→ Validates account exists
→ Validates plan is active
→ Blocks if suspended/cancelled
↓
ViewSet Permission Classes
→ Check user authentication
→ Check tenant access
→ Check role requirements
↓
ViewSet get_queryset()
→ Filter by request.account
→ Return only user's data
API Key Authentication Current State
From APIKeyAuthentication.authenticate()
Current behavior:
- Finds Site by wp_api_key
- Gets account from site
- Gets user from account (prefers owner)
- Sets request.account = account
- Sets request.site = site
- Returns (user, api_key)
PROBLEM:
- ❌ No validation of account.status
- ❌ No validation of account.plan
- WordPress bridge can access even if account suspended
Fix needed: Add validation call after line 122:
from igny8_core.auth.utils import validate_account_and_plan
is_valid, error_message, http_status = validate_account_and_plan(account)
if not is_valid:
raise AuthenticationFailed(error_message)
Throttling Current State
From DebugScopedRateThrottle
Current behavior (line 46):
authenticated_bypass = True # ALL authenticated users bypass
PROBLEM:
- ❌ No per-account throttling
- ❌ Any authenticated user can make unlimited requests
- ❌ DoS risk from single tenant
Fix needed:
- Remove blanket bypass
- Add
get_cache_key()method to key by account.id - Only bypass in DEBUG mode
Credit System Integration
Credit Operations Map
# From CreditService and AIEngine
'clustering': Fixed cost (per cluster operation)
'idea_generation': Per idea
'content_generation': Per 100 words
'image_generation': Per image
'image_prompt_extraction': Fixed cost
Current Credit Costs (from constants)
- Needs to be verified in CreditCostConfig table
- Fallback to CREDIT_COSTS constants
Credit Check Flow (from AIEngine)
# Line 213-235 in ai/engine.py
1. Calculate estimated cost
2. CreditService.check_credits(account, operation_type, amount)
3. If insufficient → raise InsufficientCreditsError (NO AI call made)
4. If sufficient → Proceed with AI call
5. After success → CreditService.deduct_credits_for_operation()
✅ Credit pre-check already working!
Migration History
Applied Migrations
- 0001_initial - Created all base models (Plan, Account, User, Site, Sector, Subscription, Industry, etc.)
- 0002_add_wp_api_key_to_site - Added Site.wp_api_key for WordPress integration
- 0003_add_sync_event_model - Sync tracking
- 0004_add_invoice_payment_models - Invoice models (likely in billing app)
- 0005_account_owner_nullable - Made Account.owner nullable
- 0006_soft_delete_and_retention - Added soft delete fields
Next Migration (Planned)
0007_add_payment_method_fields
- Add Account.payment_method
- Add Subscription.payment_method
- Add Subscription.external_payment_id
- Make Subscription.stripe_subscription_id nullable
- Add 'pending_payment' to Account.STATUS_CHOICES
System Account Logic
System Account Slugs (from code)
# Account.is_system_account()
SYSTEM_SLUGS = ['aws-admin', 'default-account', 'default']
Current system account: aws-admin (id: 5)
- Owner: dev@igny8.com (developer role, superuser)
- Plan: enterprise (10,000 credits)
- Used for development and testing
System Account Usage
- Has 454 credits remaining (from 10,000)
- 280+ credit transactions
- 2 sites (massagers-mart, home-garden-site)
- Active and working
Registration Flow (Current vs Fixed)
BEFORE (Current in production)
POST /api/v1/auth/register/
→ RegisterSerializer.create()
→ Get/assign plan (free or cheapest)
→ Create User
→ Create Account with plan
→ account.credits = 0 (DEFAULT - WRONG!)
→ No CreditTransaction created
→ Return user with 0 credits
AFTER (With my changes)
POST /api/v1/auth/register/
→ RegisterSerializer.create()
→ Force free-trial plan
→ Create User
→ Create Account with:
• plan = free-trial
• credits = 2000 (from plan)
• status = 'trial'
→ CreditTransaction created
→ Return user with 2000 credits ready to use
Conclusion & Recommendations
For Free Trial Signup (Immediate)
- ✅ Backend changes made (serializer updated)
- ✅ Frontend changes made (plan selection removed)
- ✅ Management command created
- ⏳ Need to run:
python manage.py create_free_trial_plan - ⏳ Then test: Signup flow should work
For Payment System (Phase 1+)
- Create migration 0007 for payment_method fields
- Update Account and Subscription models
- Update serializers to expose new fields
- Create bank transfer confirmation endpoint
- Fix API key authentication validation
- Fix throttling to be per-account
- Add comprehensive tests
For Production Deployment
- Run create_free_trial_plan command
- Test signup creates accounts with 2000 credits
- Verify redirect to /sites works
- Monitor for any errors
- Rollback plan ready if issues
File Reference Index
Models
- Plan:
backend/igny8_core/auth/models.py:129 - Account:
backend/igny8_core/auth/models.py:56 - Subscription:
backend/igny8_core/auth/models.py:192 - User:
backend/igny8_core/auth/models.py:562 - Site:
backend/igny8_core/auth/models.py:223 - Sector:
backend/igny8_core/auth/models.py:433
Key Services
- CreditService:
backend/igny8_core/business/billing/services/credit_service.py:12 - AIEngine:
backend/igny8_core/ai/engine.py:14
Authentication
- Middleware:
backend/igny8_core/auth/middleware.py:19 - API Key Auth:
backend/igny8_core/api/authentication.py:87 - JWT Auth:
backend/igny8_core/api/authentication.py:21
Permissions
- API Permissions:
backend/igny8_core/api/permissions.py - Auth Permissions:
backend/igny8_core/auth/permissions.py
This document provides complete context for 100% accurate implementation when the time comes.