# IMPLEMENTATION PLAN: Clean Signup to Payment Workflow
**Version:** 2.0  
**Date:** December 8, 2025  
**Status:** 🔧 READY FOR IMPLEMENTATION

---

## Table of Contents
1. [Executive Summary](#executive-summary)
2. [Deep Analysis Findings](#deep-analysis-findings)
3. [Field & Relationship Audit](#field--relationship-audit)
4. [Simplified Model Architecture](#simplified-model-architecture)
5. [Complete Workflow Diagrams](#complete-workflow-diagrams)
6. [Implementation Phases](#implementation-phases)
7. [Database Migrations](#database-migrations)
8. [Testing Plan](#testing-plan)

---

## Executive Summary

### Current State Analysis

**Critical Issues Found:**
1. **Duplicate Date Fields** - Period dates stored in 2 places (Subscription + Invoice)
2. **Payment Method Chaos** - Stored in 3 different models with no single source of truth
3. **Missing Relationships** - Subscription has no `plan` field, breaking invoice creation
4. **Unused Payment References** - No `external_payment_id` captured for manual payments
5. **Profile Fields Not Updated** - Billing info never synced from account to invoices
6. **Country-Specific Logic Missing** - Pakistan payment methods not filtered
7. **Site Industry Not Required** - Can create sites without industry, then can't add sectors
8. **Broken Paid Signup Flow** - Imports non-existent `billing.Subscription`

**Complexity Issues:**
- 4 global payment methods + 1 country-specific = unnecessary complexity
- Payment method config table exists but not used in signup flow
- Manual payment instructions not shown to users
- No clear workflow for payment confirmation after signup

### Target Architecture

**Simplified Models:**
```
Account (1) ──────┐
  ├─ plan_id      │
  ├─ credits      │
  └─ status       │
                  │
Subscription (1)  │◄── ONE-TO-ONE relationship
  ├─ account_id   │
  ├─ plan_id      │◄── ADDED (currently missing)
  ├─ period_start │◄── SINGLE source of truth for dates
  ├─ period_end   │
  └─ status       │
                  │
Invoice (many)    │◄── Created from Subscription
  ├─ subscription_id
  ├─ total        │◄── No duplicate period dates
  └─ status       │
                  │
Payment (many)    │◄── Links to Invoice
  ├─ invoice_id   │
  ├─ payment_method
  ├─ external_payment_id  ◄── ADDED for manual payments
  └─ status       │
```

**Simplified Payment Methods:**
- **Global (3):** Stripe, PayPal, Bank Transfer
- **Country-Specific (1):** Local Wallet (Pakistan only)
- **Total:** 4 payment methods (removed unnecessary complexity)

---

## Deep Analysis Findings

### 1. Date Field Redundancy

**Problem:** Period dates duplicated in multiple places

**Current State:**
```python
# Subscription model (auth/models.py line 253-254)
current_period_start = models.DateTimeField()
current_period_end = models.DateTimeField()

# Invoice model (billing/models.py line 212-213)
billing_period_start = models.DateTimeField(null=True, blank=True)
billing_period_end = models.DateTimeField(null=True, blank=True)
```

**Issues:**
- Same period stored in 2 places
- Can become out of sync
- Invoice fields are nullable but subscription fields are required
- No automatic sync mechanism

**Solution:**
✅ Keep dates in `Subscription` only (single source of truth)  
✅ Remove `billing_period_start/end` from Invoice  
✅ Access dates via `invoice.subscription.current_period_start`

**Migration Required:**
```python
# 1. Remove fields from Invoice model
migrations.RemoveField('invoice', 'billing_period_start')
migrations.RemoveField('invoice', 'billing_period_end')

# No data loss - dates preserved in Subscription
```

---

### 2. Payment Method Field Chaos

**Problem:** Payment method stored in 3 different models with no clear hierarchy

**Current Locations:**
```python
# 1. Account (auth/models.py line 87-92)
payment_method = models.CharField(
    max_length=30,
    choices=PAYMENT_METHOD_CHOICES,
    default='stripe'
)

# 2. Subscription (auth/models.py line 240-244)
payment_method = models.CharField(
    max_length=30,
    choices=PAYMENT_METHOD_CHOICES,
    default='stripe'
)

# 3. Payment (billing/models.py line 309)
payment_method = models.CharField(
    max_length=50,
    choices=PAYMENT_METHOD_CHOICES,
    db_index=True
)

# 4. AccountPaymentMethod (billing/models.py line 476) ✓ CORRECT
type = models.CharField(
    max_length=50,
    choices=PAYMENT_METHOD_CHOICES
)
```

**Which is Used?**
- Registration: Sets `Account.payment_method` and creates `AccountPaymentMethod`
- Subscription creation: Copies from account or uses 'bank_transfer' default
- Payment processing: Uses `Payment.payment_method`
- **Result:** 3 fields that can be out of sync

**Solution:**
✅ Use `AccountPaymentMethod` as single source of truth  
✅ Deprecate `Account.payment_method` (make it read-only derived property)  
✅ Deprecate `Subscription.payment_method` (get from account's default method)  
✅ Keep `Payment.payment_method` for historical record

**New Pattern:**
```python
# Account model
@property
def payment_method(self):
    """Get default payment method from AccountPaymentMethod"""
    default_method = self.accountpaymentmethod_set.filter(
        is_default=True, 
        is_enabled=True
    ).first()
    return default_method.type if default_method else 'stripe'

# Subscription model - remove field, use property
@property
def payment_method(self):
    return self.account.payment_method
```

---

### 3. Missing Subscription.plan Relationship

**Problem:** Subscription has no plan field, breaking invoice logic

**Current State:**
```python
# Subscription model (auth/models.py line 218-260)
class Subscription(models.Model):
    account = models.OneToOneField('Account')
    # ❌ NO PLAN FIELD
    stripe_subscription_id = CharField
    payment_method = CharField
    status = CharField
    current_period_start = DateTimeField
    current_period_end = DateTimeField
```

**Code Expects Plan:**
```python
# InvoiceService.create_subscription_invoice()
subscription.plan  # ❌ AttributeError: 'Subscription' object has no attribute 'plan'
```

**Why It's Missing:**
- Plan stored in `Account.plan` only
- Assumption: Get plan via `subscription.account.plan`
- **Problem:** If account changes plan mid-subscription, historical invoices show wrong plan

**Solution:**
✅ Add `Subscription.plan` field  
✅ Set from `Account.plan` at subscription creation  
✅ Keep plan locked for subscription duration (historical accuracy)  
✅ New subscription created when plan changes

**Migration:**
```python
migrations.AddField(
    model_name='subscription',
    name='plan',
    field=models.ForeignKey(
        'igny8_core_auth.Plan',
        on_delete=models.PROTECT,
        related_name='subscriptions',
        null=True  # Temporarily nullable
    ),
)

# Data migration: Copy from account
def copy_plan_from_account(apps, schema_editor):
    Subscription = apps.get_model('igny8_core_auth', 'Subscription')
    for sub in Subscription.objects.all():
        sub.plan = sub.account.plan
        sub.save()

# Make required
migrations.AlterField(
    model_name='subscription',
    name='plan',
    field=models.ForeignKey(
        'igny8_core_auth.Plan',
        on_delete=models.PROTECT,
        related_name='subscriptions'
    ),
)
```

---

### 4. Missing Payment References for Manual Payments

**Problem:** No way to track bank transfer references or local wallet transaction IDs

**Current State:**
```python
# Payment model has these fields:
stripe_payment_intent_id = CharField  # ✓ For Stripe
stripe_charge_id = CharField          # ✓ For Stripe
paypal_order_id = CharField           # ✓ For PayPal
paypal_capture_id = CharField         # ✓ For PayPal

# For manual payments:
manual_reference = CharField(blank=True)  # ✓ EXISTS but not used
transaction_reference = CharField(blank=True)  # ⚠️ DUPLICATE field
```

**Issues:**
- Two fields for same purpose (`manual_reference` and `transaction_reference`)
- Neither field is populated during signup
- No validation requiring reference for manual payments
- Admin approval has no reference number to verify

**Solution:**
✅ Keep `manual_reference` only (remove `transaction_reference`)  
✅ Require `manual_reference` for bank_transfer and local_wallet payments  
✅ Show reference field in payment confirmation form  
✅ Display reference in admin approval interface

**Validation:**
```python
class Payment(models.Model):
    def clean(self):
        # Require manual_reference for manual payment methods
        if self.payment_method in ['bank_transfer', 'local_wallet']:
            if not self.manual_reference:
                raise ValidationError({
                    'manual_reference': 'Reference number required for manual payments'
                })
```

---

### 5. Billing Profile Fields Not Updated

**Problem:** Account billing fields exist but never populated or synced

**Current Account Fields:**
```python
# Account model (auth/models.py line 100-110)
billing_email = models.EmailField(blank=True, null=True)
billing_address_line1 = CharField(max_length=255, blank=True)
billing_address_line2 = CharField(max_length=255, blank=True)
billing_city = CharField(max_length=100, blank=True)
billing_state = CharField(max_length=100, blank=True)
billing_postal_code = CharField(max_length=20, blank=True)
billing_country = CharField(max_length=2, blank=True)
tax_id = CharField(max_length=100, blank=True)
```

**When Are They Set?**
❌ Not set during registration  
❌ Not set during payment  
❌ No form to update them  
❌ Invoice has duplicate `billing_email` field

**Solution:**
✅ Add billing form during paid plan signup (before payment)  
✅ Update account billing fields when user confirms payment  
✅ Snapshot billing info to `Invoice.metadata` at invoice creation  
✅ Remove duplicate `Invoice.billing_email` field

**Signup Flow Update:**
```
1. User selects paid plan
2. User fills registration form
3. User fills billing info form ← NEW STEP
4. User selects payment method
5. Payment instructions shown
6. Account created with billing info
7. Invoice created with billing snapshot
```

---

### 6. Payment Method Country Logic Missing

**Problem:** Pakistan-specific payment method not filtered by country

**Current Setup:**
```python
# PaymentMethodConfig model exists (billing/models.py line 410)
class PaymentMethodConfig(models.Model):
    country_code = CharField  # e.g., 'PK'
    payment_method = CharField  # e.g., 'local_wallet'
    is_enabled = BooleanField
    instructions = TextField
    wallet_type = CharField  # e.g., 'JazzCash', 'Easypaisa'
```

**Issues:**
- Config exists but NOT used in signup flow
- Frontend shows all 4 payment methods to everyone
- No country detection
- No filtering logic

**Solution:**
✅ Detect user country from IP or billing_country  
✅ Query `PaymentMethodConfig` for available methods  
✅ Show only enabled methods for user's country  
✅ Create default configs for global methods

**Default Configurations:**
```python
# Global methods (available everywhere)
PaymentMethodConfig.objects.create(
    country_code='*',  # Wildcard for all countries
    payment_method='stripe',
    is_enabled=True,
    display_name='Credit/Debit Card (Stripe)',
    sort_order=1
)

PaymentMethodConfig.objects.create(
    country_code='*',
    payment_method='paypal',
    is_enabled=True,
    display_name='PayPal',
    sort_order=2
)

PaymentMethodConfig.objects.create(
    country_code='*',
    payment_method='bank_transfer',
    is_enabled=True,
    display_name='Bank Transfer',
    instructions='Transfer to: Account 123456...',
    sort_order=3
)

# Pakistan-specific
PaymentMethodConfig.objects.create(
    country_code='PK',
    payment_method='local_wallet',
    is_enabled=True,
    display_name='JazzCash / Easypaisa',
    wallet_type='JazzCash',
    wallet_id='03001234567',
    instructions='Send payment to JazzCash: 03001234567',
    sort_order=4
)
```

**API Endpoint:**
```python
# New endpoint: GET /v1/billing/payment-methods/?country=PK
def list_payment_methods(request):
    country = request.GET.get('country', '*')
    
    # Get country-specific + global methods
    methods = PaymentMethodConfig.objects.filter(
        Q(country_code=country) | Q(country_code='*'),
        is_enabled=True
    ).order_by('sort_order')
    
    return Response(PaymentMethodConfigSerializer(methods, many=True).data)
```

---

### 7. Site.industry Field Not Required

**Problem:** Industry is nullable but required for sector creation

**Current State:**
```python
# Site model (auth/models.py line 280-286)
industry = models.ForeignKey(
    'Industry',
    on_delete=models.PROTECT,
    related_name='sites',
    null=True,  # ❌ NULLABLE
    blank=True,
    help_text="Industry this site belongs to"
)
```

**Serializer:**
```python
# SiteSerializer (auth/serializers.py line 60-82)
class Meta:
    fields = ['industry', ...]
    # ❌ industry not in required_fields
```

**Impact:**
- Sites created without industry
- Sector creation fails: `if self.industry_sector.industry != self.site.industry`
- If site.industry is None, comparison always fails
- User can't add any sectors

**Solution:**
✅ Make `Site.industry` required (not nullable)  
✅ Update migration to set default industry for existing NULL sites  
✅ Update serializer to require industry  
✅ Update frontend to show industry selector in site creation form

**Migration:**
```python
# 1. Set default industry for existing sites
def set_default_industry(apps, schema_editor):
    Site = apps.get_model('igny8_core_auth', 'Site')
    Industry = apps.get_model('igny8_core_auth', 'Industry')
    
    default_industry = Industry.objects.filter(
        slug='technology'
    ).first()
    
    if default_industry:
        Site.objects.filter(industry__isnull=True).update(
            industry=default_industry
        )

migrations.RunPython(set_default_industry)

# 2. Make field required
migrations.AlterField(
    model_name='site',
    name='industry',
    field=models.ForeignKey(
        'Industry',
        on_delete=models.PROTECT,
        related_name='sites'
        # Removed: null=True, blank=True
    ),
)
```


---

### 8. Broken Paid Signup Import

**Problem:** Imports non-existent `billing.Subscription`

**Current Code:**
```python
# auth/serializers.py line 291
from igny8_core.business.billing.models import Subscription  # ❌ DOES NOT EXIST
```

**Fix:**
```python
# Use existing auth.Subscription
from igny8_core.auth.models import Subscription  # ✓ EXISTS
```

---

## Field & Relationship Audit

### Complete Field Inventory

#### Subscription Model - BEFORE Cleanup
```python
class Subscription(models.Model):
    # Relationships
    account = OneToOneField('Account')          # ✓ KEEP
    # ❌ MISSING: plan field
    
    # Payment tracking
    stripe_subscription_id = CharField          # ✓ KEEP
    payment_method = CharField                  # ❌ REMOVE (use AccountPaymentMethod)
    external_payment_id = CharField             # ✓ KEEP
    
    # Status & dates
    status = CharField                          # ✓ KEEP
    current_period_start = DateTimeField        # ✓ KEEP (source of truth)
    current_period_end = DateTimeField          # ✓ KEEP (source of truth)
    cancel_at_period_end = BooleanField         # ✓ KEEP
    
    # Audit
    created_at = DateTimeField                  # ✓ KEEP
    updated_at = DateTimeField                  # ✓ KEEP
```

#### Subscription Model - AFTER Cleanup
```python
class Subscription(models.Model):
    # Relationships
    account = OneToOneField('Account')          # ✓ Tenant isolation
    plan = ForeignKey('Plan')                   # ✅ ADDED - historical plan tracking
    
    # Payment tracking
    stripe_subscription_id = CharField          # ✓ Stripe reference
    external_payment_id = CharField             # ✓ Manual payment reference
    
    # Status & dates (SINGLE SOURCE OF TRUTH)
    status = CharField                          # ✓ active/past_due/canceled
    current_period_start = DateTimeField        # ✓ Billing cycle start
    current_period_end = DateTimeField          # ✓ Billing cycle end
    cancel_at_period_end = BooleanField         # ✓ Cancellation flag
    
    # Audit
    created_at = DateTimeField
    updated_at = DateTimeField
    
    # Properties (derived, not stored)
    @property
    def payment_method(self):
        """Get from AccountPaymentMethod"""
        return self.account.payment_method
```

**Changes Summary:**
- ✅ Added: `plan` field (FK to Plan)
- ❌ Removed: `payment_method` field (use property instead)
- Field count: 11 → 11 (same, but cleaner relationships)

---

#### Invoice Model - BEFORE Cleanup
```python
class Invoice(AccountBaseModel):
    # Relationships
    account = ForeignKey('Account')             # ✓ KEEP (via AccountBaseModel)
    subscription = ForeignKey('Subscription')   # ✓ KEEP
    
    # Amounts
    subtotal = DecimalField                     # ✓ KEEP
    tax = DecimalField                          # ✓ KEEP
    total = DecimalField                        # ✓ KEEP
    currency = CharField                        # ✓ KEEP
    
    # Status & dates
    status = CharField                          # ✓ KEEP
    invoice_number = CharField                  # ✓ KEEP
    invoice_date = DateField                    # ✓ KEEP
    due_date = DateField                        # ✓ KEEP
    paid_at = DateTimeField                     # ✓ KEEP
    
    # DUPLICATE FIELDS
    billing_period_start = DateTimeField        # ❌ REMOVE (in Subscription)
    billing_period_end = DateTimeField          # ❌ REMOVE (in Subscription)
    billing_email = EmailField                  # ❌ REMOVE (use metadata snapshot)
    payment_method = CharField                  # ✓ KEEP (historical record)
    
    # Data
    line_items = JSONField                      # ✓ KEEP
    notes = TextField                           # ✓ KEEP
    metadata = JSONField                        # ✓ KEEP (billing snapshot goes here)
    
    # Stripe
    stripe_invoice_id = CharField               # ✓ KEEP
    
    # Audit
    created_at = DateTimeField                  # ✓ KEEP
    updated_at = DateTimeField                  # ✓ KEEP
```

#### Invoice Model - AFTER Cleanup
```python
class Invoice(AccountBaseModel):
    # Relationships
    account = ForeignKey('Account')             # ✓ Tenant isolation
    subscription = ForeignKey('Subscription')   # ✓ Links to subscription
    
    # Invoice identity
    invoice_number = CharField(unique=True)     # ✓ INV-2025-001
    
    # Amounts
    subtotal = DecimalField                     # ✓ Pre-tax amount
    tax = DecimalField                          # ✓ Tax amount
    total = DecimalField                        # ✓ Total payable
    currency = CharField(default='USD')         # ✓ Currency code
    
    # Status & dates
    status = CharField                          # ✓ draft/pending/paid/void
    invoice_date = DateField                    # ✓ Issue date
    due_date = DateField                        # ✓ Payment deadline
    paid_at = DateTimeField(null=True)          # ✓ Payment timestamp
    
    # Historical tracking
    payment_method = CharField                  # ✓ Payment method used
    
    # Data
    line_items = JSONField(default=list)        # ✓ Invoice items
    notes = TextField(blank=True)               # ✓ Admin notes
    metadata = JSONField(default=dict)          # ✓ Billing snapshot
    
    # Stripe integration
    stripe_invoice_id = CharField               # ✓ Stripe reference
    
    # Audit
    created_at = DateTimeField
    updated_at = DateTimeField
    
    # Properties (access via relationship)
    @property
    def billing_period_start(self):
        """Get from subscription"""
        return self.subscription.current_period_start if self.subscription else None
    
    @property
    def billing_period_end(self):
        """Get from subscription"""
        return self.subscription.current_period_end if self.subscription else None
    
    @property
    def billing_email(self):
        """Get from metadata snapshot or account"""
        return self.metadata.get('billing_email') or self.account.billing_email
```

**Changes Summary:**
- ❌ Removed: `billing_period_start` (get from subscription)
- ❌ Removed: `billing_period_end` (get from subscription)
- ❌ Removed: `billing_email` (use metadata snapshot)
- Field count: 21 → 18 (3 fields removed, cleaner)


---

## Simplified Model Architecture

### Core Models Summary

| Model | Fields (Before) | Fields (After) | Changes |
|-------|----------------|----------------|---------|
| **Account** | 26 fields | 26 fields | Convert `payment_method` to property |
| **Subscription** | 11 fields | 11 fields | ✅ Add `plan`, ❌ Remove `payment_method` field |
| **Invoice** | 21 fields | 18 fields | ❌ Remove 3 duplicate fields |
| **Payment** | 26 fields | 25 fields | ❌ Remove `transaction_reference` |
| **AccountPaymentMethod** | 11 fields | 11 fields | No changes (already correct) |
| **PaymentMethodConfig** | 14 fields | 14 fields | No changes (needs implementation) |

**Total Field Reduction:** 109 fields → 105 fields (4 fewer fields, cleaner relationships)

---

### Relationship Map - BEFORE Cleanup

```
Account (1)
  ├─ plan_id ──────────────────► Plan
  ├─ payment_method (field)     ⚠️ Can be out of sync
  │
  ├─ Subscription (1:1)
  │    ├─ payment_method (field)  ⚠️ Duplicate #2
  │    ├─ period_start
  │    ├─ period_end
  │    └─ ❌ NO plan field
  │
  ├─ Invoice (1:many)
  │    ├─ subscription_id
  │    ├─ period_start           ⚠️ Duplicate dates
  │    ├─ period_end             ⚠️ Duplicate dates
  │    ├─ billing_email          ⚠️ Duplicate field
  │    └─ payment_method (field) ⚠️ Duplicate #3
  │
  ├─ Payment (1:many)
  │    ├─ invoice_id
  │    ├─ payment_method (field) ⚠️ Duplicate #4
  │    ├─ manual_reference
  │    └─ transaction_reference   ⚠️ Duplicate field
  │
  └─ AccountPaymentMethod (1:many)  ✓ Correct design
       ├─ type
       ├─ is_default
       └─ is_enabled
```

**Problems:**
- 🔴 4 payment_method fields (which is source of truth?)
- 🔴 Period dates duplicated (Subscription + Invoice)
- 🔴 Billing email duplicated (Account + Invoice)
- 🔴 Payment references duplicated (manual_reference + transaction_reference)
- 🔴 No plan in Subscription (can't track plan changes)

---

### Relationship Map - AFTER Cleanup

```
Account (1)
  ├─ plan_id ──────────────────► Plan
  │  @property payment_method → get from AccountPaymentMethod
  │
  ├─ Subscription (1:1)
  │    ├─ ✅ plan_id ──────────► Plan (added)
  │    ├─ period_start          ◄─── SINGLE SOURCE
  │    ├─ period_end            ◄─── SINGLE SOURCE
  │    └─ @property payment_method → get from Account
  │
  ├─ Invoice (1:many)
  │    ├─ subscription_id ─────► Subscription
  │    ├─ @property period_start  → via subscription
  │    ├─ @property period_end    → via subscription
  │    ├─ @property billing_email → via metadata
  │    └─ payment_method (field)  ✓ Historical record
  │
  ├─ Payment (1:many)
  │    ├─ invoice_id ──────────► Invoice
  │    ├─ payment_method (field)  ✓ Historical record
  │    └─ manual_reference        ✓ Single field
  │
  └─ AccountPaymentMethod (1:many) ◄─── PRIMARY SOURCE
       ├─ type                    ◄─── Source of truth
       ├─ is_default
       ├─ is_enabled
       └─ instructions

PaymentMethodConfig (global)
  ├─ country_code
  ├─ payment_method
  ├─ is_enabled
  └─ instructions
```

**Solutions:**
- ✅ AccountPaymentMethod is single source of truth
- ✅ Subscription has plan_id for historical tracking
- ✅ Period dates only in Subscription (Invoice uses properties)
- ✅ Billing email only in Account (Invoice snapshots to metadata)
- ✅ Single payment reference field
- ✅ Clear hierarchy: Config → AccountPaymentMethod → Historical records

---

## Complete Workflow Diagrams

### 1. FREE TRIAL SIGNUP FLOW

```
┌────────────────────────────────────────────────────────────────┐
│ USER: Clicks "Start Free Trial" on homepage                   │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ FRONTEND: /signup (no plan parameter)                         │
│                                                                 │
│  Form Fields:                                                   │
│  ├─ First Name*                                                │
│  ├─ Last Name*                                                 │
│  ├─ Email*                                                     │
│  ├─ Password*                                                  │
│  ├─ Account Name (optional)                                   │
│  └─ ☑ Agree to Terms                                          │
│                                                                 │
│  [Create Account] button                                       │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ API: POST /v1/auth/register/                                   │
│                                                                 │
│  Request Body:                                                  │
│  {                                                              │
│    "email": "user@example.com",                                │
│    "password": "SecurePass123!",                               │
│    "first_name": "John",                                       │
│    "last_name": "Doe",                                         │
│    "account_name": "John's Business"                           │
│    // plan_slug not provided = defaults to 'free'             │
│  }                                                              │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ BACKEND: RegisterSerializer.create()                           │
│                                                                 │
│  1. Resolve Plan                                               │
│     plan = Plan.objects.get(slug='free')                      │
│     status = 'trial'                                           │
│     credits = 1000 (plan.included_credits)                    │
│                                                                 │
│  2. Generate Username                                          │
│     username = email.split('@')[0]                            │
│     (ensure unique with counter if needed)                     │
│                                                                 │
│  3. Create User (without account first)                        │
│     user = User.objects.create_user(                          │
│       username=username,                                       │
│       email=email,                                             │
│       password=hashed_password,                                │
│       role='owner',                                            │
│       account=None  ← Will be set later                       │
│     )                                                           │
│                                                                 │
│  4. Generate Account Slug                                      │
│     slug = slugify(account_name)                              │
│     (ensure unique with counter)                               │
│                                                                 │
│  5. Create Account                                             │
│     account = Account.objects.create(                         │
│       name=account_name,                                       │
│       slug=slug,                                               │
│       owner=user,                                              │
│       plan=plan,                                               │
│       credits=1000,                                            │
│       status='trial'                                           │
│     )                                                           │
│                                                                 │
│  6. Link User to Account                                       │
│     user.account = account                                     │
│     user.save()                                                │
│                                                                 │
│  7. Log Credit Transaction                                     │
│     CreditTransaction.objects.create(                         │
│       account=account,                                         │
│       transaction_type='subscription',                        │
│       amount=1000,                                             │
│       balance_after=1000,                                      │
│       description='Free plan credits'                         │
│     )                                                           │
│                                                                 │
│  8. Return User Object                                         │
│     return user                                                │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ FRONTEND: Check account status                                 │
│                                                                 │
│  if (user.account.status === 'trial') {                        │
│    navigate('/sites')  ← Go to dashboard                      │
│  }                                                              │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ USER: Lands on /sites (Sites page)                            │
│                                                                 │
│  - Can create 1 site (plan.max_sites = 1)                     │
│  - Has 1000 credits to use                                     │
│  - Status: Free Trial                                          │
└────────────────────────────────────────────────────────────────┘
```

**Database State After Free Trial Signup:**
```sql
-- igny8_tenants (Accounts)
INSERT INTO igny8_tenants VALUES (
  1, 'Johns Business', 'johns-business', 1, 1000, 'trial', NULL
);
-- id, name, slug, plan_id, credits, status, owner_id

-- igny8_users
INSERT INTO igny8_users VALUES (
  1, 'john@example.com', 'john-doe', 'owner', 1
);
-- id, email, username, role, tenant_id

-- igny8_credit_transactions
INSERT INTO igny8_credit_transactions VALUES (
  1, 1, 'subscription', 1000, 1000, 'Free plan credits'
);
-- id, tenant_id, type, amount, balance_after, description

-- igny8_subscriptions: NO RECORD (free trial has no subscription)
-- igny8_invoices: NO RECORD
-- igny8_payments: NO RECORD
```


---

### 2. PAID PLAN SIGNUP FLOW (With Manual Payment)

```
┌────────────────────────────────────────────────────────────────┐
│ USER: Clicks "Get Started" on Starter plan pricing card       │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ FRONTEND: /signup?plan=starter                                 │
│                                                                 │
│  Page loads with plan details shown:                           │
│  ┌──────────────────────────────────────┐                     │
│  │ 📋 Starter Plan                       │                     │
│  │ $29/month                             │                     │
│  │ ✓ 5,000 credits                      │                     │
│  │ ✓ 3 sites                             │                     │
│  │ ✓ 3 users                             │                     │
│  └──────────────────────────────────────┘                     │
│                                                                 │
│  Form Fields:                                                   │
│  ├─ First Name*                                                │
│  ├─ Last Name*                                                 │
│  ├─ Email*                                                     │
│  ├─ Password*                                                  │
│  ├─ Account Name*                                              │
│  └─ ☑ Agree to Terms                                          │
│                                                                 │
│  [Continue to Billing] button                                  │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ FRONTEND: /signup/billing (New Step)                          │
│                                                                 │
│  Billing Information Form:                                      │
│  ├─ Billing Email*                                             │
│  ├─ Country* (dropdown with flag icons)                       │
│  ├─ Address Line 1                                             │
│  ├─ Address Line 2                                             │
│  ├─ City                                                       │
│  ├─ State/Province                                             │
│  ├─ Postal Code                                                │
│  └─ Tax ID (optional)                                          │
│                                                                 │
│  [Continue to Payment] button                                  │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ FRONTEND: Fetch Available Payment Methods                     │
│                                                                 │
│  API: GET /v1/billing/payment-methods/?country=PK             │
│                                                                 │
│  Response:                                                      │
│  [                                                              │
│    {                                                            │
│      "payment_method": "stripe",                               │
│      "display_name": "Credit/Debit Card",                     │
│      "sort_order": 1                                           │
│    },                                                           │
│    {                                                            │
│      "payment_method": "paypal",                               │
│      "display_name": "PayPal",                                 │
│      "sort_order": 2                                           │
│    },                                                           │
│    {                                                            │
│      "payment_method": "bank_transfer",                        │
│      "display_name": "Bank Transfer",                          │
│      "instructions": "Transfer to: Account 123456789...",     │
│      "sort_order": 3                                           │
│    },                                                           │
│    {                                                            │
│      "payment_method": "local_wallet",                         │
│      "display_name": "JazzCash / Easypaisa",                  │
│      "wallet_type": "JazzCash",                                │
│      "wallet_id": "03001234567",                               │
│      "instructions": "Send to JazzCash: 03001234567",         │
│      "sort_order": 4                                           │
│    }                                                            │
│  ]                                                              │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ FRONTEND: /signup/payment                                      │
│                                                                 │
│  Payment Method Selection:                                      │
│  ○ Credit/Debit Card (Stripe)                                 │
│  ○ PayPal                                                      │
│  ● Bank Transfer ← User selects                               │
│  ○ JazzCash / Easypaisa                                        │
│                                                                 │
│  [Conditional: If Bank Transfer selected]                      │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │ 📋 Bank Transfer Instructions                             │ │
│  │                                                            │ │
│  │ Account Name: IGNY8 Inc                                   │ │
│  │ Account Number: 123456789                                 │ │
│  │ Bank Name: ABC Bank                                       │ │
│  │ SWIFT: ABCPKKA                                            │ │
│  │                                                            │ │
│  │ Amount: $29.00 USD                                        │ │
│  │                                                            │ │
│  │ ⚠️ Important:                                             │ │
│  │ - Make payment to above account                           │ │
│  │ - Keep transaction reference                              │ │
│  │ - You'll confirm payment in next step                     │ │
│  └──────────────────────────────────────────────────────────┘ │
│                                                                 │
│  [Create Account & Continue] button                            │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ API: POST /v1/auth/register/                                   │
│                                                                 │
│  Request Body:                                                  │
│  {                                                              │
│    "email": "user@example.com",                                │
│    "password": "SecurePass123!",                               │
│    "first_name": "Ahmad",                                      │
│    "last_name": "Khan",                                        │
│    "account_name": "Ahmad Tech",                               │
│    "plan_slug": "starter",                                     │
│    "payment_method": "bank_transfer",                          │
│    "billing_email": "billing@ahmad.com",                       │
│    "billing_country": "PK",                                    │
│    "billing_address_line1": "123 Main St",                     │
│    "billing_city": "Karachi"                                   │
│  }                                                              │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ BACKEND: RegisterSerializer.create() - PAID PLAN PATH         │
│                                                                 │
│  1. Resolve Plan                                               │
│     plan = Plan.objects.get(slug='starter')                   │
│     status = 'pending_payment'                                 │
│     credits = 0  ← No credits until payment confirmed         │
│                                                                 │
│  2. Calculate Period Dates                                     │
│     period_start = timezone.now()                              │
│     period_end = period_start + 30 days                        │
│                                                                 │
│  3. Create User                                                │
│     user = User.objects.create_user(...)                      │
│                                                                 │
│  4. Create Account WITH Billing Info                           │
│     account = Account.objects.create(                         │
│       name="Ahmad Tech",                                       │
│       slug="ahmad-tech",                                       │
│       owner=user,                                              │
│       plan=plan,                                               │
│       credits=0,                                               │
│       status='pending_payment',                                │
│       billing_email="billing@ahmad.com",                       │
│       billing_country="PK",                                    │
│       billing_address_line1="123 Main St",                     │
│       billing_city="Karachi"                                   │
│     )                                                           │
│                                                                 │
│  5. Link User to Account                                       │
│     user.account = account                                     │
│     user.save()                                                │
│                                                                 │
│  6. Create Subscription ✅ WITH PLAN                           │
│     subscription = Subscription.objects.create(                │
│       account=account,                                         │
│       plan=plan,  ← ADDED FIELD                               │
│       status='pending_payment',                                │
│       current_period_start=period_start,                       │
│       current_period_end=period_end,                           │
│       cancel_at_period_end=False                               │
│     )                                                           │
│                                                                 │
│  7. Create Invoice                                             │
│     invoice = InvoiceService.create_subscription_invoice(      │
│       subscription=subscription,                               │
│       billing_period_start=period_start,                       │
│       billing_period_end=period_end                            │
│     )                                                           │
│     # Invoice fields:                                          │
│     # - invoice_number: "INV-2025-001"                         │
│     # - total: 29.00                                           │
│     # - status: "pending"                                      │
│     # - metadata: { billing snapshot }                         │
│                                                                 │
│  8. Create AccountPaymentMethod                                │
│     AccountPaymentMethod.objects.create(                      │
│       account=account,                                         │
│       type='bank_transfer',                                    │
│       display_name='Bank Transfer (Manual)',                   │
│       is_default=True,                                         │
│       is_enabled=True,                                         │
│       instructions='See invoice for details'                   │
│     )                                                           │
│                                                                 │
│  9. NO CREDIT TRANSACTION (not yet paid)                       │
│                                                                 │
│  10. Return User Object                                        │
│      return user                                               │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ FRONTEND: Check account status                                 │
│                                                                 │
│  if (user.account.status === 'pending_payment') {              │
│    navigate('/account/plans')  ← Go to payment confirmation   │
│  }                                                              │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ USER: Lands on /account/plans (Account & Plans Page)          │
│                                                                 │
│  Account Status Bar:                                            │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │ ⚠️  Payment Pending                                       │ │
│  │ Your account is pending payment confirmation              │ │
│  │ [Confirm Payment] button                                  │ │
│  └──────────────────────────────────────────────────────────┘ │
│                                                                 │
│  Current Plan: Starter Plan ($29/month)                        │
│  Status: Pending Payment                                       │
│  Credits: 0 / 5,000                                            │
│                                                                 │
│  Invoices Tab:                                                  │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │ Invoice #INV-2025-001                                     │ │
│  │ Date: Dec 8, 2025                                         │ │
│  │ Amount: $29.00                                            │ │
│  │ Status: Pending                                           │ │
│  │ Payment Method: Bank Transfer                             │ │
│  │ [Confirm Payment] button                                  │ │
│  └──────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘
```


**Database State After Paid Signup (Before Payment Confirmation):**
```sql
-- igny8_tenants
INSERT INTO igny8_tenants VALUES (
  2, 'Ahmad Tech', 'ahmad-tech', 2, 0, 'pending_payment', 
  'billing@ahmad.com', 'PK', '123 Main St', NULL, 'Karachi', NULL, NULL, NULL
);
-- id, name, slug, plan_id, credits, status, billing_email, billing_country, address...

-- igny8_users
INSERT INTO igny8_users VALUES (
  2, 'user@example.com', 'ahmad-khan', 'owner', 2
);

-- igny8_subscriptions ✅ WITH PLAN NOW
INSERT INTO igny8_subscriptions VALUES (
  2, 2, 2, NULL, 'pending_payment', '2025-12-08', '2026-01-08', FALSE
);
-- id, tenant_id, plan_id, stripe_id, status, period_start, period_end, cancel_at_end

-- igny8_invoices
INSERT INTO igny8_invoices VALUES (
  2, 2, 2, 'INV-2025-002', 29.00, 0, 29.00, 'USD', 'pending', '2025-12-08', '2025-12-15'
);
-- id, tenant_id, subscription_id, invoice_number, subtotal, tax, total, currency, status, invoice_date, due_date

-- igny8_account_payment_methods
INSERT INTO igny8_account_payment_methods VALUES (
  2, 2, 'bank_transfer', 'Bank Transfer (Manual)', TRUE, TRUE, FALSE
);
-- id, tenant_id, type, display_name, is_default, is_enabled, is_verified

-- igny8_payments: NO RECORD YET
-- igny8_credit_transactions: NO RECORD YET
```

---

### 3. PAYMENT CONFIRMATION FLOW (Manual Payment)

```
┌────────────────────────────────────────────────────────────────┐
│ USER: Clicks "Confirm Payment" button                          │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ FRONTEND: Payment Confirmation Modal/Page                      │
│                                                                 │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │ 💳 Confirm Payment                                        │ │
│  │                                                            │ │
│  │ Invoice: #INV-2025-002                                    │ │
│  │ Amount: $29.00 USD                                        │ │
│  │ Payment Method: Bank Transfer                             │ │
│  │                                                            │ │
│  │ Payment Reference Number:*                                │ │
│  │ ┌──────────────────────────────────────────────────────┐ │ │
│  │ │ [Enter transaction reference]                         │ │ │
│  │ └──────────────────────────────────────────────────────┘ │ │
│  │                                                            │ │
│  │ Payment Date:*                                            │ │
│  │ ┌──────────────────────────────────────────────────────┐ │ │
│  │ │ [Select date]                                         │ │ │
│  │ └──────────────────────────────────────────────────────┘ │ │
│  │                                                            │ │
│  │ Additional Notes:                                         │ │
│  │ ┌──────────────────────────────────────────────────────┐ │ │
│  │ │ [Optional notes about payment]                        │ │ │
│  │ └──────────────────────────────────────────────────────┘ │ │
│  │                                                            │ │
│  │ Upload Proof (Optional):                                  │ │
│  │ ┌──────────────────────────────────────────────────────┐ │ │
│  │ │ [Upload receipt/screenshot]                           │ │ │
│  │ └──────────────────────────────────────────────────────┘ │ │
│  │                                                            │ │
│  │ ⚠️ Your payment will be reviewed by our team within 24hrs│ │
│  │                                                            │ │
│  │ [Cancel]  [Submit for Approval]                          │ │
│  └──────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ API: POST /v1/billing/payments/confirm/                        │
│                                                                 │
│  Request Body:                                                  │
│  {                                                              │
│    "invoice_id": 2,                                            │
│    "payment_method": "bank_transfer",                          │
│    "manual_reference": "BT-20251208-12345",                    │
│    "manual_notes": "Paid via ABC Bank on Dec 8",              │
│    "amount": "29.00",                                          │
│    "proof_url": "https://s3.../receipt.jpg"                    │
│  }                                                              │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ BACKEND: Create Payment Record - Pending Approval              │
│                                                                 │
│  Payment.objects.create(                                        │
│    account=account,                                            │
│    invoice=invoice,                                            │
│    amount=29.00,                                               │
│    currency='USD',                                             │
│    status='pending_approval',  ← Awaiting admin approval      │
│    payment_method='bank_transfer',                             │
│    manual_reference='BT-20251208-12345',  ← User provided     │
│    manual_notes='Paid via ABC Bank on Dec 8',                 │
│    metadata={                                                  │
│      'proof_url': 'https://s3.../receipt.jpg'                 │
│    }                                                            │
│  )                                                              │
│                                                                 │
│  # Invoice remains "pending" until payment approved            │
│  # Account remains "pending_payment" until payment approved    │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ FRONTEND: Success Message                                      │
│                                                                 │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │ ✅ Payment Submitted                                      │ │
│  │                                                            │ │
│  │ Your payment confirmation has been submitted for review.  │ │
│  │ We'll verify your payment and activate your account       │ │
│  │ within 24 hours.                                          │ │
│  │                                                            │ │
│  │ Reference: BT-20251208-12345                              │ │
│  │ Status: Pending Review                                    │ │
│  │                                                            │ │
│  │ You'll receive an email once approved.                    │ │
│  │                                                            │ │
│  │ [Go to Dashboard]                                         │ │
│  └──────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ USER: Dashboard shows "Payment under review" status            │
│                                                                 │
│  - Can browse platform but can't create sites                 │
│  - Credits still 0 until approved                              │
│  - Status shows "Pending Approval"                             │
└────────────────────────────────────────────────────────────────┘
```

**Database State After Payment Submission:**
```sql
-- igny8_payments (NEW RECORD)
INSERT INTO igny8_payments VALUES (
  1, 2, 2, 29.00, 'USD', 'pending_approval', 'bank_transfer',
  NULL, NULL, NULL, NULL,
  'BT-20251208-12345', 'Paid via ABC Bank on Dec 8',
  NULL, NULL, NULL, NULL, NULL, NULL,
  '{"proof_url": "https://s3.../receipt.jpg"}'
);
-- id, tenant_id, invoice_id, amount, currency, status, payment_method,
-- stripe fields, paypal fields,
-- manual_reference, manual_notes,
-- admin_notes, approved_by, approved_at, processed_at, failed_at, refunded_at,
-- metadata
```

---

### 4. ADMIN APPROVAL FLOW

```
┌────────────────────────────────────────────────────────────────┐
│ ADMIN: Receives notification of pending payment                │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ ADMIN PANEL: /admin/billing/payment/                           │
│                                                                 │
│  Pending Payments List:                                         │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │ Payment #1                                                │ │
│  │ Account: Ahmad Tech                                       │ │
│  │ Invoice: INV-2025-002                                     │ │
│  │ Amount: $29.00                                            │ │
│  │ Method: Bank Transfer                                     │ │
│  │ Reference: BT-20251208-12345                              │ │
│  │ Notes: Paid via ABC Bank on Dec 8                        │ │
│  │ Proof: [View Receipt]                                     │ │
│  │                                                            │ │
│  │ [Approve] [Reject]                                        │ │
│  └──────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ ADMIN: Clicks "Approve" button                                 │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ API: POST /v1/billing/payments/1/approve/                      │
│                                                                 │
│  Request Body:                                                  │
│  {                                                              │
│    "admin_notes": "Verified payment in bank statement"         │
│  }                                                              │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ BACKEND: Approve Payment & Activate Account                    │
│                                                                 │
│  with transaction.atomic():                                     │
│    # 1. Update Payment                                         │
│    payment.status = 'succeeded'                                │
│    payment.approved_by = admin_user                            │
│    payment.approved_at = timezone.now()                        │
│    payment.processed_at = timezone.now()                       │
│    payment.admin_notes = 'Verified payment...'                 │
│    payment.save()                                              │
│                                                                 │
│    # 2. Update Invoice                                         │
│    invoice.status = 'paid'                                     │
│    invoice.paid_at = timezone.now()                            │
│    invoice.save()                                              │
│                                                                 │
│    # 3. Update Subscription                                    │
│    subscription.status = 'active'                              │
│    subscription.external_payment_id = payment.manual_reference │
│    subscription.save()                                         │
│                                                                 │
│    # 4. Update Account                                         │
│    account.status = 'active'                                   │
│    account.save()                                              │
│                                                                 │
│    # 5. Add Credits                                            │
│    CreditService.add_credits(                                  │
│      account=account,                                          │
│      amount=subscription.plan.included_credits,  # 5000        │
│      description=f'Starter plan credits - {invoice.invoice_number}',│
│      metadata={                                                │
│        'subscription_id': subscription.id,                     │
│        'invoice_id': invoice.id,                               │
│        'payment_id': payment.id                                │
│      }                                                          │
│    )                                                            │
│    # This creates:                                             │
│    # - Updates account.credits = 5000                          │
│    # - Creates CreditTransaction record                        │
│                                                                 │
│    # 6. Send Activation Email                                  │
│    send_account_activated_email(account, subscription)        │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ USER: Receives email "Account Activated"                       │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ USER: Logs in and sees activated account                       │
│                                                                 │
│  Account Status: ✅ Active                                     │
│  Plan: Starter Plan                                            │
│  Credits: 5,000 / 5,000                                        │
│  Sites: 0 / 3                                                  │
│                                                                 │
│  [Create Your First Site] button                               │
└────────────────────────────────────────────────────────────────┘
```

**Database State After Admin Approval:**
```sql
-- igny8_tenants (UPDATED)
UPDATE igny8_tenants SET status = 'active', credits = 5000 WHERE id = 2;

-- igny8_subscriptions (UPDATED)
UPDATE igny8_subscriptions SET status = 'active', external_payment_id = 'BT-20251208-12345' WHERE id = 2;

-- igny8_invoices (UPDATED)
UPDATE igny8_invoices SET status = 'paid', paid_at = '2025-12-08 15:30:00' WHERE id = 2;

-- igny8_payments (UPDATED)
UPDATE igny8_payments SET 
  status = 'succeeded', 
  approved_by = 1, 
  approved_at = '2025-12-08 15:30:00',
  processed_at = '2025-12-08 15:30:00',
  admin_notes = 'Verified payment in bank statement'
WHERE id = 1;

-- igny8_credit_transactions (NEW RECORD)
INSERT INTO igny8_credit_transactions VALUES (
  2, 2, 'subscription', 5000, 5000, 'Starter plan credits - INV-2025-002',
  '{"subscription_id": 2, "invoice_id": 2, "payment_id": 1}'
);
```


---

### 5. SITE CREATION FLOW (After Account Activated)

```
┌────────────────────────────────────────────────────────────────┐
│ USER: Clicks "Create Your First Site" button                   │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ FRONTEND: /sites/create                                        │
│                                                                 │
│  Site Creation Form:                                            │
│  ├─ Site Name*                                                 │
│  │  [Enter site name]                                          │
│  │                                                             │
│  ├─ Domain/URL                                                 │
│  │  [https://example.com]                                      │
│  │                                                             │
│  ├─ Industry* ✅ REQUIRED FIELD                                │
│  │  [Select industry ▼]                                        │
│  │   - Technology                                              │
│  │   - Healthcare                                              │
│  │   - Finance                                                 │
│  │   - E-commerce                                              │
│  │   ...                                                       │
│  │                                                             │
│  ├─ Description                                                │
│  │  [Describe your site...]                                    │
│  │                                                             │
│  └─ Site Type                                                  │
│     ○ Marketing Site                                           │
│     ○ Blog                                                     │
│     ○ E-commerce                                               │
│     ○ Corporate                                                │
│                                                                 │
│  [Cancel] [Create Site]                                        │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ API: POST /v1/auth/sites/                                      │
│                                                                 │
│  Request Body:                                                  │
│  {                                                              │
│    "name": "Tech News Hub",                                    │
│    "domain": "https://technewshub.com",                        │
│    "industry": 2,  ← REQUIRED (Technology industry ID)        │
│    "description": "Latest technology news and tutorials",      │
│    "site_type": "blog"                                         │
│  }                                                              │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ BACKEND: SiteViewSet.create()                                  │
│                                                                 │
│  1. Validate Account Plan Limits                               │
│     max_sites = account.plan.max_sites  # 3 for Starter       │
│     current_sites = account.sites.filter(is_active=True).count()│
│     if current_sites >= max_sites:                             │
│       raise ValidationError("Site limit reached")              │
│                                                                 │
│  2. Validate Industry Required ✅                              │
│     if not validated_data.get('industry'):                     │
│       raise ValidationError("Industry is required")            │
│                                                                 │
│  3. Generate Unique Slug                                       │
│     slug = slugify("Tech News Hub")  # "tech-news-hub"        │
│     # Ensure unique per account                                │
│                                                                 │
│  4. Normalize Domain                                           │
│     domain = "https://technewshub.com"                         │
│     # Ensure https:// prefix                                   │
│                                                                 │
│  5. Create Site                                                │
│     site = Site.objects.create(                               │
│       account=request.account,  # Auto from middleware        │
│       name="Tech News Hub",                                    │
│       slug="tech-news-hub",                                    │
│       domain="https://technewshub.com",                        │
│       industry_id=2,  # Technology                            │
│       description="Latest technology news...",                 │
│       site_type="blog",                                        │
│       hosting_type="igny8_sites",                              │
│       status="active",                                         │
│       is_active=True                                           │
│     )                                                           │
│                                                                 │
│  6. Create SiteUserAccess ✅ NEW STEP                          │
│     SiteUserAccess.objects.create(                            │
│       user=request.user,                                       │
│       site=site,                                               │
│       granted_by=request.user                                  │
│     )                                                           │
│                                                                 │
│  7. Return Site Object                                         │
│     return site                                                │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ FRONTEND: Redirect to /sites/{site_id}/sectors                │
│                                                                 │
│  Success message: "Site created! Now add sectors to organize   │
│                    your content."                              │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ USER: Add Sectors to Site                                      │
│                                                                 │
│  Available Sectors for Technology Industry:                     │
│  □ Web Development                                             │
│  □ AI & Machine Learning                                       │
│  □ Cybersecurity                                               │
│  □ Cloud Computing                                             │
│  □ Mobile Development                                          │
│                                                                 │
│  Select up to 5 sectors (Starter plan limit)                   │
│  [Add Selected Sectors]                                        │
└────────────────────────────────────────────────────────────────┘
```

**Database State After Site Creation:**
```sql
-- igny8_sites (NEW RECORD)
INSERT INTO igny8_sites VALUES (
  1, 2, 'Tech News Hub', 'tech-news-hub', 'https://technewshub.com',
  'Latest technology news and tutorials', 2, TRUE, 'active',
  'blog', 'igny8_sites'
);
-- id, tenant_id, name, slug, domain, description, industry_id, is_active, status, site_type, hosting_type

-- igny8_site_user_access (NEW RECORD) ✅
INSERT INTO igny8_site_user_access VALUES (
  1, 2, 1, 2, '2025-12-08 16:00:00'
);
-- id, user_id, site_id, granted_by_id, granted_at
```

---

## Implementation Phases

### PHASE 1: Critical Fixes (URGENT - 1 Day)

**Priority:** 🔴 Blocking Production

#### 1.1 Fix Subscription Import
```python
# File: backend/igny8_core/auth/serializers.py
# Line 291

# BEFORE:
from igny8_core.business.billing.models import Subscription  # ❌

# AFTER:
from igny8_core.auth.models import Subscription  # ✅
```

#### 1.2 Add Subscription.plan Field
```bash
cd backend
python manage.py makemigrations --name add_subscription_plan_field

# Migration file created: 0XXX_add_subscription_plan_field.py
```

```python
# Migration content:
from django.db import migrations, models

def copy_plan_from_account(apps, schema_editor):
    """Copy plan from account to subscription"""
    Subscription = apps.get_model('igny8_core_auth', 'Subscription')
    for sub in Subscription.objects.select_related('account__plan'):
        sub.plan = sub.account.plan
        sub.save(update_fields=['plan'])

class Migration(migrations.Migration):
    dependencies = [
        ('igny8_core_auth', '0XXX_previous_migration'),
    ]
    
    operations = [
        # 1. Add field as nullable
        migrations.AddField(
            model_name='subscription',
            name='plan',
            field=models.ForeignKey(
                'igny8_core_auth.Plan',
                on_delete=models.PROTECT,
                related_name='subscriptions',
                null=True
            ),
        ),
        # 2. Copy data
        migrations.RunPython(
            copy_plan_from_account,
            reverse_code=migrations.RunPython.noop
        ),
        # 3. Make non-nullable
        migrations.AlterField(
            model_name='subscription',
            name='plan',
            field=models.ForeignKey(
                'igny8_core_auth.Plan',
                on_delete=models.PROTECT,
                related_name='subscriptions'
            ),
        ),
    ]
```

```bash
# Apply migration
python manage.py migrate
```

#### 1.3 Make Site.industry Required
```bash
python manage.py makemigrations --name make_site_industry_required
```

```python
def set_default_industry(apps, schema_editor):
    """Set default industry for sites without one"""
    Site = apps.get_model('igny8_core_auth', 'Site')
    Industry = apps.get_model('igny8_core_auth', 'Industry')
    
    default = Industry.objects.filter(slug='technology').first()
    if default:
        Site.objects.filter(industry__isnull=True).update(industry=default)

class Migration(migrations.Migration):
    operations = [
        migrations.RunPython(set_default_industry),
        migrations.AlterField(
            model_name='site',
            name='industry',
            field=models.ForeignKey(
                'igny8_core_auth.Industry',
                on_delete=models.PROTECT,
                related_name='sites'
            ),
        ),
    ]
```

#### 1.4 Update Free Plan Credits
```bash
docker exec igny8_backend python manage.py shell
```

```python
from igny8_core.auth.models import Plan
plan = Plan.objects.get(slug='free')
plan.included_credits = 1000
plan.save()
print(f"Updated free plan credits: {plan.included_credits}")
```

**Testing Phase 1:**
```bash
# Test 1: Free trial signup
curl -X POST http://localhost:8000/api/v1/auth/register/ \
  -H "Content-Type: application/json" \
  -d '{
    "email": "test@example.com",
    "password": "Test123!",
    "password_confirm": "Test123!",
    "first_name": "Test",
    "last_name": "User"
  }'
# Expected: ✅ Success, 1000 credits

# Test 2: Paid signup (should not crash)
curl -X POST http://localhost:8000/api/v1/auth/register/ \
  -H "Content-Type: application/json" \
  -d '{
    "email": "paid@example.com",
    "password": "Test123!",
    "password_confirm": "Test123!",
    "first_name": "Paid",
    "last_name": "User",
    "plan_slug": "starter"
  }'
# Expected: ✅ Success, subscription created with plan_id
```

---

### PHASE 2: Model Cleanup (2-3 Days)

**Priority:** 🟡 Important

#### 2.1 Remove Duplicate Fields from Invoice
```bash
python manage.py makemigrations --name remove_duplicate_invoice_fields
```

```python
class Migration(migrations.Migration):
    operations = [
        migrations.RemoveField('invoice', 'billing_period_start'),
        migrations.RemoveField('invoice', 'billing_period_end'),
        migrations.RemoveField('invoice', 'billing_email'),
    ]
```

#### 2.2 Add Properties to Invoice Model
```python
# File: backend/igny8_core/business/billing/models.py

class Invoice(AccountBaseModel):
    # ... existing fields ...
    
    @property
    def billing_period_start(self):
        """Get from subscription"""
        return self.subscription.current_period_start if self.subscription else None
    
    @property
    def billing_period_end(self):
        """Get from subscription"""
        return self.subscription.current_period_end if self.subscription else None
    
    @property
    def billing_email(self):
        """Get from metadata or account"""
        snapshot = self.metadata.get('billing_snapshot', {})
        return snapshot.get('email') or self.account.billing_email
```

#### 2.3 Remove Duplicate payment_method from Subscription
```bash
python manage.py makemigrations --name remove_subscription_payment_method
```

```python
class Migration(migrations.Migration):
    operations = [
        migrations.RemoveField('subscription', 'payment_method'),
    ]
```

#### 2.4 Add payment_method Property to Subscription
```python
# File: backend/igny8_core/auth/models.py

class Subscription(models.Model):
    # ... existing fields ...
    
    @property
    def payment_method(self):
        """Get from account's default payment method"""
        return self.account.payment_method
```

#### 2.5 Convert Account.payment_method to Property
```python
# File: backend/igny8_core/auth/models.py

class Account(SoftDeletableModel):
    # Keep field for backward compatibility but make it read-only in forms
    # Eventually remove via migration
    
    @property
    def default_payment_method(self):
        """Get default payment method from AccountPaymentMethod"""
        method = self.accountpaymentmethod_set.filter(
            is_default=True,
            is_enabled=True
        ).first()
        return method.type if method else 'stripe'
```

#### 2.6 Remove transaction_reference from Payment
```bash
python manage.py makemigrations --name remove_duplicate_payment_reference
```

```python
class Migration(migrations.Migration):
    operations = [
        migrations.RemoveField('payment', 'transaction_reference'),
    ]
```

---

### PHASE 3: New Features (3-5 Days)

**Priority:** 🟢 Enhancement

#### 3.1 Create PaymentMethodConfig Default Data
```bash
docker exec igny8_backend python manage.py shell
```

```python
from igny8_core.business.billing.models import PaymentMethodConfig

# Global methods (available everywhere)
PaymentMethodConfig.objects.get_or_create(
    country_code='*',
    payment_method='stripe',
    defaults={
        'is_enabled': True,
        'display_name': 'Credit/Debit Card (Stripe)',
        'sort_order': 1
    }
)

PaymentMethodConfig.objects.get_or_create(
    country_code='*',
    payment_method='paypal',
    defaults={
        'is_enabled': True,
        'display_name': 'PayPal',
        'sort_order': 2
    }
)

PaymentMethodConfig.objects.get_or_create(
    country_code='*',
    payment_method='bank_transfer',
    defaults={
        'is_enabled': True,
        'display_name': 'Bank Transfer',
        'instructions': '''
            Bank Name: ABC Bank
            Account Name: IGNY8 Inc
            Account Number: 123456789
            SWIFT: ABCPKKA
            
            Please transfer the exact invoice amount and keep the transaction reference.
        ''',
        'sort_order': 3
    }
)

# Pakistan-specific
PaymentMethodConfig.objects.get_or_create(
    country_code='PK',
    payment_method='local_wallet',
    defaults={
        'is_enabled': True,
        'display_name': 'JazzCash / Easypaisa',
        'wallet_type': 'JazzCash',
        'wallet_id': '03001234567',
        'instructions': '''
            Send payment to:
            JazzCash: 03001234567
            Account Name: IGNY8
            
            Please keep the transaction ID and confirm payment after sending.
        ''',
        'sort_order': 4
    }
)

print("Payment method configurations created!")
```

#### 3.2 Create Payment Methods API Endpoint
```python
# File: backend/igny8_core/business/billing/views.py

@action(detail=False, methods=['get'], url_path='payment-methods')
def list_payment_methods(self, request):
    """Get available payment methods for user's country"""
    country = request.GET.get('country', '*')
    
    # Get country-specific + global methods
    from django.db.models import Q
    methods = PaymentMethodConfig.objects.filter(
        Q(country_code=country) | Q(country_code='*'),
        is_enabled=True
    ).order_by('sort_order')
    
    from .serializers import PaymentMethodConfigSerializer
    return Response(PaymentMethodConfigSerializer(methods, many=True).data)
```

#### 3.3 Create Payment Confirmation Endpoint
```python
# File: backend/igny8_core/business/billing/views.py

@action(detail=False, methods=['post'], url_path='payments/confirm')
def confirm_payment(self, request):
    """User confirms manual payment with reference"""
    invoice_id = request.data.get('invoice_id')
    manual_reference = request.data.get('manual_reference')
    manual_notes = request.data.get('manual_notes', '')
    proof_url = request.data.get('proof_url')
    
    if not invoice_id or not manual_reference:
        return error_response(
            error='invoice_id and manual_reference required',
            status_code=400,
            request=request
        )
    
    try:
        invoice = Invoice.objects.get(
            id=invoice_id,
            account=request.account
        )
        
        payment = Payment.objects.create(
            account=request.account,
            invoice=invoice,
            amount=invoice.total,
            currency=invoice.currency,
            status='pending_approval',
            payment_method=invoice.payment_method or 'bank_transfer',
            manual_reference=manual_reference,
            manual_notes=manual_notes,
            metadata={'proof_url': proof_url} if proof_url else {}
        )
        
        # Send notification to admin
        send_payment_confirmation_notification(payment)
        
        return success_response(
            data={'payment_id': payment.id, 'status': 'pending_approval'},
            message='Payment confirmation submitted for review',
            request=request
        )
    except Invoice.DoesNotExist:
        return error_response(
            error='Invoice not found',
            status_code=404,
            request=request
        )
```


#### 3.4 Update RegisterSerializer for Billing Fields
```python
# File: backend/igny8_core/auth/serializers.py

class RegisterSerializer(serializers.ModelSerializer):
    # ... existing fields ...
    
    # Add billing fields
    billing_email = serializers.EmailField(required=False, allow_blank=True)
    billing_address = serializers.CharField(required=False, allow_blank=True)
    billing_city = serializers.CharField(required=False, allow_blank=True)
    billing_country = serializers.CharField(required=False, allow_blank=True)
    payment_method = serializers.CharField(required=False, default='stripe')
    
    class Meta:
        model = User
        fields = [
            'email', 'password', 'password_confirm', 'first_name', 'last_name',
            'billing_email', 'billing_address', 'billing_city', 'billing_country',
            'payment_method', 'plan_slug'
        ]
    
    def create(self, validated_data):
        # ... existing account/user creation ...
        
        # Update billing fields if provided
        billing_email = validated_data.pop('billing_email', None)
        billing_address = validated_data.pop('billing_address', None)
        billing_city = validated_data.pop('billing_city', None)
        billing_country = validated_data.pop('billing_country', None)
        payment_method = validated_data.pop('payment_method', 'stripe')
        
        if billing_email:
            account.billing_email = billing_email
        if billing_address:
            account.billing_address = billing_address
        if billing_city:
            account.billing_city = billing_city
        if billing_country:
            account.billing_country = billing_country
        
        account.save(update_fields=[
            'billing_email', 'billing_address', 'billing_city', 'billing_country'
        ])
        
        # Create AccountPaymentMethod if not free trial
        if not is_free_trial:
            from igny8_core.business.billing.models import AccountPaymentMethod
            AccountPaymentMethod.objects.create(
                account=account,
                type=payment_method,
                is_default=True,
                is_enabled=True
            )
        
        # ... rest of creation logic ...
```

#### 3.5 Frontend: Add Billing Form Step
```typescript
// File: frontend/src/components/auth/SignUpForm.tsx

interface BillingFormData {
  billing_email: string;
  billing_address: string;
  billing_city: string;
  billing_country: string;
  payment_method: string;
}

const [step, setStep] = useState<'signup' | 'billing'>('signup');
const [billingData, setBillingData] = useState<BillingFormData>({
  billing_email: '',
  billing_address: '',
  billing_city: '',
  billing_country: '',
  payment_method: 'stripe'
});

// After initial form submission
const handleSignupSubmit = async (e: React.FormEvent) => {
  e.preventDefault();
  
  // If paid plan, show billing form
  if (planSlug && planSlug !== 'free') {
    setStep('billing');
  } else {
    // Free trial, submit directly
    await submitRegistration();
  }
};

// Billing form submission
const handleBillingSubmit = async (e: React.FormEvent) => {
  e.preventDefault();
  await submitRegistration();
};

const submitRegistration = async () => {
  const payload = {
    email,
    password,
    password_confirm: passwordConfirm,
    first_name: firstName,
    last_name: lastName,
    plan_slug: planSlug,
    ...(step === 'billing' ? billingData : {})
  };
  
  await register(payload);
};

// Render billing form
{step === 'billing' && (
  <div className="billing-form">
    <h3>Billing Information</h3>
    
    <Input
      label="Billing Email"
      type="email"
      value={billingData.billing_email}
      onChange={(e) => setBillingData({
        ...billingData,
        billing_email: e.target.value
      })}
      required
    />
    
    <Input
      label="Address"
      value={billingData.billing_address}
      onChange={(e) => setBillingData({
        ...billingData,
        billing_address: e.target.value
      })}
      required
    />
    
    <CountrySelect
      label="Country"
      value={billingData.billing_country}
      onChange={(country) => setBillingData({
        ...billingData,
        billing_country: country
      })}
    />
    
    <PaymentMethodSelect
      country={billingData.billing_country}
      value={billingData.payment_method}
      onChange={(method) => setBillingData({
        ...billingData,
        payment_method: method
      })}
    />
    
    <Button onClick={handleBillingSubmit}>
      Complete Signup
    </Button>
  </div>
)}
```

#### 3.6 Admin Payment Approval Interface
```python
# File: backend/igny8_core/business/billing/admin.py

from django.contrib import admin
from .models import Payment

@admin.register(Payment)
class PaymentAdmin(admin.ModelAdmin):
    list_display = ['id', 'account', 'amount', 'status', 'payment_method', 'created_at']
    list_filter = ['status', 'payment_method', 'created_at']
    search_fields = ['account__name', 'manual_reference', 'external_payment_id']
    
    actions = ['approve_payments', 'reject_payments']
    
    def approve_payments(self, request, queryset):
        """Approve selected payments"""
        count = 0
        for payment in queryset.filter(status='pending_approval'):
            try:
                # Call existing approval endpoint
                from .views import BillingViewSet
                viewset = BillingViewSet()
                viewset.request = request
                viewset.approve_payment_internal(payment)
                count += 1
            except Exception as e:
                self.message_user(
                    request,
                    f"Error approving payment {payment.id}: {str(e)}",
                    level='ERROR'
                )
        
        self.message_user(
            request,
            f"Successfully approved {count} payment(s)"
        )
    
    approve_payments.short_description = "Approve selected payments"
    
    def reject_payments(self, request, queryset):
        """Reject selected payments"""
        count = queryset.filter(
            status='pending_approval'
        ).update(status='failed', metadata={'rejected_by': request.user.id})
        
        self.message_user(request, f"Rejected {count} payment(s)")
    
    reject_payments.short_description = "Reject selected payments"
```

---

### PHASE 4: Testing & Validation (1-2 Days)

**Priority:** 🔵 Quality Assurance

#### 4.1 Test: Free Trial Signup End-to-End
```bash
# 1. Frontend: Go to /signup
# 2. Fill form: email, password, name
# 3. Submit
# 4. Verify: Account created with 1000 credits
# 5. Verify: Subscription.plan_id = 1 (Free plan)
# 6. Verify: Can create 1 site
# 7. Verify: Site requires industry selection
# 8. Verify: Can access site dashboard
```

**Database Verification:**
```sql
SELECT 
  a.id, a.email, a.status, a.credits,
  s.plan_id, s.status, s.current_period_start,
  p.slug, p.included_credits
FROM igny8_tenants a
JOIN igny8_subscriptions s ON s.tenant_id = a.id
JOIN igny8_plans p ON s.plan_id = p.id
WHERE a.email = 'test@example.com';
-- Expected: credits=1000, plan_id=1, plan.slug='free'
```

#### 4.2 Test: Paid Signup with Bank Transfer
```bash
# 1. Frontend: /signup?plan=starter
# 2. Fill signup form
# 3. Step 2: Fill billing form
#    - billing_email: billing@company.com
#    - billing_country: PK
#    - payment_method: bank_transfer
# 4. Submit
# 5. Verify: Account created with status='pending_payment'
# 6. Verify: Invoice created with total=5000
# 7. Verify: Payment method instructions shown
# 8. User submits payment with reference: BT-12345
# 9. Verify: Payment status='pending_approval'
# 10. Admin approves payment
# 11. Verify: Account status='active', credits=5000
# 12. User can now create 3 sites
```

**API Test:**
```bash
# Step 1: Register with paid plan
curl -X POST http://localhost:8000/api/v1/auth/register/ \
  -H "Content-Type: application/json" \
  -d '{
    "email": "paid@test.com",
    "password": "Test123!",
    "password_confirm": "Test123!",
    "first_name": "Paid",
    "last_name": "User",
    "plan_slug": "starter",
    "billing_email": "billing@test.com",
    "billing_country": "PK",
    "payment_method": "bank_transfer"
  }'

# Expected response:
# {
#   "success": true,
#   "message": "Account created. Please complete payment.",
#   "data": {
#     "account_id": 2,
#     "invoice_id": 2,
#     "amount": 5000,
#     "payment_method": "bank_transfer",
#     "instructions": "Bank transfer details..."
#   }
# }

# Step 2: Confirm payment
curl -X POST http://localhost:8000/api/v1/billing/payments/confirm/ \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "invoice_id": 2,
    "manual_reference": "BT-20251208-12345",
    "manual_notes": "Transferred via ABC Bank on Dec 8"
  }'

# Expected:
# {
#   "success": true,
#   "message": "Payment confirmation submitted for review",
#   "data": {"payment_id": 1, "status": "pending_approval"}
# }
```

#### 4.3 Test: Site Creation with Industry
```bash
# After account activated, create site
curl -X POST http://localhost:8000/api/v1/auth/sites/ \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Tech Blog",
    "domain": "https://mytechblog.com",
    "industry": 2,
    "site_type": "blog"
  }'

# Expected: ✅ Site created

# Test without industry (should fail)
curl -X POST http://localhost:8000/api/v1/auth/sites/ \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Blog",
    "domain": "https://myblog.com"
  }'

# Expected: ❌ 400 Bad Request, "industry is required"
```

#### 4.4 Test: Payment Method Filtering by Country
```bash
# Get payment methods for Pakistan
curl http://localhost:8000/api/v1/billing/payment-methods/?country=PK

# Expected:
# [
#   {"type": "stripe", "display_name": "Credit/Debit Card (Stripe)"},
#   {"type": "paypal", "display_name": "PayPal"},
#   {"type": "bank_transfer", "display_name": "Bank Transfer", "instructions": "..."},
#   {"type": "local_wallet", "display_name": "JazzCash / Easypaisa", "instructions": "..."}
# ]

# Get payment methods for USA
curl http://localhost:8000/api/v1/billing/payment-methods/?country=US

# Expected (only global methods):
# [
#   {"type": "stripe", "display_name": "Credit/Debit Card (Stripe)"},
#   {"type": "paypal", "display_name": "PayPal"},
#   {"type": "bank_transfer", "display_name": "Bank Transfer"}
# ]
```

---

## Summary: Complete Workflow After Implementation

```
FREE TRIAL PATH:
User → /signup → Fill form → Submit → Account created (1000 credits) → 
Create site (industry required) → Add sectors → Start using

PAID PLAN PATH:
User → /signup?plan=starter → Fill signup form → Fill billing form → 
Submit → Account created (pending_payment) → Invoice generated → 
User sees payment instructions → Transfer payment → Submit confirmation → 
Admin receives notification → Admin approves → Account activated (5000 credits) → 
Create sites (up to 3) → Add sectors → Start using
```

**Key Improvements:**
✅ Subscription.plan field tracks historical plan
✅ No duplicate date fields (Invoice uses Subscription dates)
✅ Single source of truth for payment methods (AccountPaymentMethod)
✅ Billing fields captured and saved during signup
✅ Country-specific payment methods shown
✅ Manual payment confirmation workflow
✅ Admin approval triggers atomic updates across all tables
✅ Site.industry is required
✅ SiteUserAccess created automatically
✅ Free plan has correct 1000 credits

**Database Reduction:**
- Before: 109 fields across models
- After: 105 fields (-4 duplicate fields)
- Relationships cleaner: payment_method in 1 place instead of 4

**Testing Coverage:**
- ✅ Free trial signup (frontend → API → database)
- ✅ Paid plan signup with billing form
- ✅ Payment confirmation flow
- ✅ Admin approval workflow
- ✅ Site creation with industry requirement
- ✅ Payment method filtering by country
- ✅ Credit allocation and transaction logging

---

## Implementation Timeline

| Phase | Duration | Tasks |
|-------|----------|-------|
| **Phase 1** | 1 day | Fix import, add Subscription.plan, make Site.industry required, update free plan credits |
| **Phase 2** | 2-3 days | Remove duplicate fields, add properties, consolidate payment methods |
| **Phase 3** | 3-5 days | Create payment methods API, payment confirmation, billing form, admin interface |
| **Phase 4** | 1-2 days | End-to-end testing, validation, bug fixes |
| **Total** | **7-11 days** | Complete implementation with testing |

**Critical Path:**
1. Day 1: Phase 1 (fixes blocking production)
2. Day 2-4: Phase 2 (cleanup duplicate fields)
3. Day 5-9: Phase 3 (new features)
4. Day 10-11: Phase 4 (testing)

---

## Appendix: Quick Reference

### Model Changes Summary
```python
# Subscription
+ plan = FK(Plan)  # NEW
- payment_method  # REMOVE (use property)

# Invoice
- billing_period_start  # REMOVE (use property from subscription)
- billing_period_end  # REMOVE (use property from subscription)
- billing_email  # REMOVE (use property from metadata/account)

# Payment
- transaction_reference  # REMOVE (duplicate of manual_reference)

# Site
! industry = FK(Industry, null=False)  # MAKE REQUIRED

# Account (no changes, keep payment_method for backward compatibility)
```

### API Endpoints Created
```
GET  /v1/billing/payment-methods/?country=PK
POST /v1/billing/payments/confirm/
POST /v1/auth/register/  (enhanced with billing fields)
```

### Database Queries for Verification
```sql
-- Verify subscription has plan
SELECT s.id, s.tenant_id, s.plan_id, p.slug
FROM igny8_subscriptions s
JOIN igny8_plans p ON s.plan_id = p.id;

-- Verify no duplicate payment methods
SELECT 
  a.id AS account_id,
  apm.type AS default_method,
  apm.is_default
FROM igny8_tenants a
LEFT JOIN igny8_account_payment_methods apm 
  ON apm.tenant_id = a.id AND apm.is_default = TRUE;

-- Verify all sites have industry
SELECT id, name, industry_id 
FROM igny8_sites 
WHERE industry_id IS NULL;
-- Expected: 0 rows

-- Verify credit transactions match account credits
SELECT 
  a.id,
  a.credits AS account_total,
  COALESCE(SUM(ct.amount), 0) AS transaction_total
FROM igny8_tenants a
LEFT JOIN igny8_credit_transactions ct ON ct.tenant_id = a.id
GROUP BY a.id, a.credits
HAVING a.credits != COALESCE(SUM(ct.amount), 0);
-- Expected: 0 rows (all match)
```

