Files
igny8/final-tenancy-accounts-payments/CURRENT-STATE-CONTEXT.md
IGNY8 VPS (Salman) 7483de6aba asda
2025-12-08 06:40:06 +00:00

675 lines
20 KiB
Markdown

# 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`](backend/igny8_core/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`](backend/igny8_core/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
### 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`](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`](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`](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
```python
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
```sql
-- 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()`](backend/igny8_core/auth/models.py:618):
```python
# Owner/Admin/Developer: All sites in account
# Editor/Viewer: Only sites in SiteUserAccess
```
---
## Permissions in Practice
### ViewSet Permission Combinations
**Example: SiteViewSet**
```python
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess, IsEditorOrAbove]
```
Means: User must be authenticated AND belong to account AND have editor+ role
**Example: PlanViewSet**
```python
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()`](backend/igny8_core/api/authentication.py:92)
**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:
```python
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`](backend/igny8_core/api/throttles.py:12)
**Current behavior (line 46):**
```python
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
```python
# 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)
```python
# 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)
```python
# 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
- Plan: [`backend/igny8_core/auth/models.py:129`](backend/igny8_core/auth/models.py:129)
- Account: [`backend/igny8_core/auth/models.py:56`](backend/igny8_core/auth/models.py:56)
- Subscription: [`backend/igny8_core/auth/models.py:192`](backend/igny8_core/auth/models.py:192)
- User: [`backend/igny8_core/auth/models.py:562`](backend/igny8_core/auth/models.py:562)
- Site: [`backend/igny8_core/auth/models.py:223`](backend/igny8_core/auth/models.py:223)
- Sector: [`backend/igny8_core/auth/models.py:433`](backend/igny8_core/auth/models.py:433)
### Key Services
- CreditService: [`backend/igny8_core/business/billing/services/credit_service.py:12`](backend/igny8_core/business/billing/services/credit_service.py:12)
- AIEngine: [`backend/igny8_core/ai/engine.py:14`](backend/igny8_core/ai/engine.py:14)
### Authentication
- Middleware: [`backend/igny8_core/auth/middleware.py:19`](backend/igny8_core/auth/middleware.py:19)
- API Key Auth: [`backend/igny8_core/api/authentication.py:87`](backend/igny8_core/api/authentication.py:87)
- JWT Auth: [`backend/igny8_core/api/authentication.py:21`](backend/igny8_core/api/authentication.py:21)
### Permissions
- API Permissions: [`backend/igny8_core/api/permissions.py`](backend/igny8_core/api/permissions.py)
- Auth Permissions: [`backend/igny8_core/auth/permissions.py`](backend/igny8_core/auth/permissions.py)
---
**This document provides complete context for 100% accurate implementation when the time comes.**