Files
igny8/tenancy-accounts-payments-still-have issues/CURRENT-STATE-CONTEXT.md
alorig affa783a4f docs
2025-12-08 14:57:26 +05:00

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 Email 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):

  1. IsAuthenticatedAndActive - Basic auth check
  2. HasTenantAccess - Ensures user belongs to account
  3. IsViewerOrAbove - viewer, editor, admin, owner
  4. IsEditorOrAbove - editor, admin, owner
  5. IsAdminOrOwner - admin, owner only
  6. IsSystemAccountOrDeveloper - System accounts or developer role

Auth Permissions (auth/permissions.py):

  1. IsOwnerOrAdmin - owner, admin, developer
  2. IsEditorOrAbove - editor, admin, owner, developer
  3. IsViewerOrAbove - All authenticated users
  4. AccountPermission - User must belong to account

Role Hierarchy (Ascending Power)

  1. viewer - Read-only access
  2. editor - Can create/edit content
  3. admin - Can manage content, view billing
  4. owner - Full account control
  5. developer - Super admin, bypasses filters
  6. system_bot - Automation only

Critical Findings for Implementation

What's Ready

  1. Plans are configured and active
  2. Account-Plan relationship works
  3. User-Account relationship works
  4. Site-Account tenancy isolation works
  5. Credit system fully functional
  6. Soft delete implemented

What's Missing

  1. payment_method field - Doesn't exist in DB (needs migration 0007)
  2. Subscription records - None exist (payment system not in use)
  3. external_payment_id - Doesn't exist (needs migration)
  4. stripe_subscription_id nullability - Currently required & unique

⚠️ What Needs Attention

  1. Free trial plan - Can use existing 'free' (100 credits) OR create 'free-trial' (2000 credits)
  2. Registration credit seeding - Currently NOT happening (accounts created with 0 credits unless manually set)
  3. Account status - 'pending_payment' not in STATUS_CHOICES yet
  4. 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

  1. Plan → Account (1:many) - Plan defines limits
  2. Account → User (1:many) - Users belong to accounts
  3. Account → Site (1:many) - Sites isolated by account
  4. Site → Sector (1:many) - Sectors belong to sites
  5. 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

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)

  1. Run: docker exec igny8_backend python manage.py create_free_trial_plan
  2. Verify plan created
  3. Test signup flow

Next Phase (Payment System)

  1. Create migration 0007_add_payment_method_fields
  2. Run migration
  3. Update serializers to include payment_method
  4. Implement bank transfer confirmation endpoint
  5. Update API key authentication to validate account
  6. 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:

  1. Finds Site by wp_api_key
  2. Gets account from site
  3. Gets user from account (prefers owner)
  4. Sets request.account = account
  5. Sets request.site = site
  6. 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

  1. 0001_initial - Created all base models (Plan, Account, User, Site, Sector, Subscription, Industry, etc.)
  2. 0002_add_wp_api_key_to_site - Added Site.wp_api_key for WordPress integration
  3. 0003_add_sync_event_model - Sync tracking
  4. 0004_add_invoice_payment_models - Invoice models (likely in billing app)
  5. 0005_account_owner_nullable - Made Account.owner nullable
  6. 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)

  1. Backend changes made (serializer updated)
  2. Frontend changes made (plan selection removed)
  3. Management command created
  4. Need to run: python manage.py create_free_trial_plan
  5. Then test: Signup flow should work

For Payment System (Phase 1+)

  1. Create migration 0007 for payment_method fields
  2. Update Account and Subscription models
  3. Update serializers to expose new fields
  4. Create bank transfer confirmation endpoint
  5. Fix API key authentication validation
  6. Fix throttling to be per-account
  7. Add comprehensive tests

For Production Deployment

  1. Run create_free_trial_plan command
  2. Test signup creates accounts with 2000 credits
  3. Verify redirect to /sites works
  4. Monitor for any errors
  5. Rollback plan ready if issues

File Reference Index

Models

Key Services

Authentication

Permissions


This document provides complete context for 100% accurate implementation when the time comes.