]", "word_count": [Exact integer — word count of HTML body only], "primary_keyword": "[Single primary keyword used in title and first paragraph]", "secondary_keywords": [ "[Keyword 1]", "[Keyword 2]", "[Keyword 3]" ], "tags": [ "[2–4 word lowercase tag 1]", "[2–4 word lowercase tag 2]", "[2–4 word lowercase tag 3]", "[2–4 word lowercase tag 4]", "[2–4 word lowercase tag 5]" ], "categories": [ "[Parent Category > Child Category]", "[Optional Second Category > Optional Subcategory]" ] } =========================== EXECUTION GUIDELINES =========================== **Your Task:** 1. Read the outline structure from CONTENT IDEA DETAILS to understand the heading flow and topic sequence 2. Use headings as-is, but IGNORE the brief descriptions—they are placeholders, not final content 3. EXPAND every section into full, detailed content: The outline shows WHAT to write about, YOU write HOW with depth and specifics 4. MANDATORY: Write exactly 1000 words total (measure actual content, not including HTML tags) 5. Write as a subject-matter expert with deep knowledge, not a generic content generator **Critical Understanding:** - Outline guidance like "Discuss the ease of carrying" is NOT your final sentence—it's a topic prompt - Your job: Turn that prompt into 60-80 words of actual discussion with examples, dimensions, scenarios, comparisons - If outline says "List 3 items"—write 3 detailed list items with descriptions (15-20 words each), not just names **Introduction Execution (Total: ~120 words):** - Write the hook (30–40 words) in italicized text (`` tag) grounded in a real situation - Follow with two narrative paragraphs (50–60 words each) that establish context and value - Integrate the primary keyword naturally in the first paragraph - Use conversational, confident tone—no filler phrases **H2 Section Execution (Total per H2: 150–180 words INCLUDING all subsections):** - Follow the heading structure from the outline but EXPAND the brief descriptions into full content - The outline's "details" are guidance only—write 3-4x more content than what's shown in the outline - Each H2 must contain 150–180 words of actual written content (paragraphs + list items + table content) - Each H2 should open with 2-3 narrative paragraphs (80-100 words) before introducing lists or tables - Subsections (H3s) should add substantial depth: mechanisms, comparisons, applications, or data - Mix content formats: paragraphs, lists (unordered/ordered), tables, blockquotes - Never begin a section or subsection with a list or table - If outline says "Discuss X"—write 60-80 words discussing X with examples and specifics - If outline says "List Y"—write 3-5 list items with descriptive details, not just names **Content Quality Standards:** - Write with specificity: Use real examples, scenarios, dimensions, timeframes, or data points - Avoid vague qualifiers: "many," "some," "often"—replace with concrete language - Vary sentence structure and length for natural flow - Use active voice and direct language - No robotic phrasing, SEO jargon, or generic transitions like "In today's world" - Do not repeat the heading in the opening sentence of each section **HTML Structure Rules:** - Introduction: Use `` for hook, then `
` tags for paragraphs - Headings: Use `
` for main sections, `
` for subsections - Lists: Use `
` or `` as appropriate - Tables: Use proper `
`, ``, ``, `
`, `
`, `
` structure - Blockquotes: Use `
` for expert insights or data-backed observations - No inline CSS or styling attributes **Keyword Integration:** - Primary keyword must appear in: • The title • First paragraph naturally • At least 2 H2 headings where contextually appropriate - Secondary keywords should be woven naturally throughout content - Prioritize readability over keyword density—never force keywords **Metadata Rules:** - **meta_title**: Under 60 characters, includes primary keyword, compelling and natural - **meta_description**: Under 160 characters, clear value proposition, includes call-to-action - **tags**: 5 relevant tags, 2–4 words each, lowercase, topically relevant - **categories**: 1–2 hierarchical categories reflecting content classification - **word_count**: CRITICAL - Count actual words in content (excluding HTML tags), must be 950-1050 words =========================== INPUT VARIABLES =========================== CONTENT IDEA DETAILS: Title: The Ultimate Guide to Choosing a Vibrating Back Massager Description: {"introduction": {"hook": "Imagine a world where back pain is managed with the press of a button, even on the go.", "paragraphs": [{"format": "paragraph", "details": "Vibrating back massagers are revolutionizing pain relief for busy individuals seeking convenience without compromising on efficacy."}, {"format": "paragraph", "details": "This guide will arm you with the knowledge to select a vibrating back massager that perfectly aligns with your lifestyle and pain management needs."}]}, "H2": [{"heading": "Understanding Vibrating Back Massagers", "subsections": [{"subheading": "How Do They Work?", "format": "paragraph", "details": "Explore the mechanics behind vibration therapy and its impact on muscle relaxation."}, {"subheading": "Benefits of Vibration Therapy", "format": "paragraph", "details": "Discuss how vibration helps reduce pain and improve circulation."}, {"subheading": "Potential Drawbacks", "format": "list", "details": "Highlight considerations to be aware of, like overuse or incorrect application."}]}, {"heading": "Features to Consider", "subsections": [{"subheading": "Portability and Design", "format": "paragraph", "details": "Evaluate size, weight, and ease of carrying for frequent travelers."}, {"subheading": "Power Source and Battery Life", "format": "table", "details": "Compare battery-operated models versus rechargeable options."}]}, {"heading": "Top Vibrating Back Massager Models", "subsections": [{"subheading": "Budget-Friendly Options", "format": "paragraph", "details": "Recommend massagers that offer good value for money."}, {"subheading": "Premium Picks", "format": "blockquotes", "details": "Expert opinions on high-end models worth the investment."}]}, {"heading": "How to Use a Vibrating Back Massager Safely", "subsections": [{"subheading": "Guidelines for Effective Use", "format": "paragraph", "details": "Outline best practices for maximizing benefits while minimizing risks."}, {"subheading": "Common Mistakes to Avoid", "format": "list", "details": "Identify and correct common usage errors."}]}, {"heading": "Customer Reviews and Satisfaction", "subsections": [{"subheading": "Testimonials", "format": "paragraph", "details": "Share real-life user experiences and satisfaction levels."}, {"subheading": "Overall Ratings", "format": "table", "details": "Summarize ratings from multiple sources for a comprehensive overview."}]}]} Content Type: post Content Structure: guide **CRITICAL - How to Use the Content Idea:** The CONTENT IDEA DETAILS contains a pre-designed OUTLINE with: - Title (use as-is or adapt slightly) - Introduction structure (hook + 2 paragraphs) - H2/H3 heading structure - Brief guidance notes like "Discuss X" or "List Y" ⚠️ DO NOT copy these guidance notes verbatim into your content. ⚠️ DO NOT treat brief descriptions as complete content. ✅ USE the heading structure and flow sequence. ✅ EXPAND each brief note into 60-100+ words of substantive content. ✅ WRITE full paragraphs, detailed lists, complete tables—not summaries. Example transformation: - Outline says: "Discuss hypoallergenic and chemical-free aspects" - You write: 2-3 paragraphs (80-100 words) explaining specific hypoallergenic benefits, which chemicals are avoided, how this impacts sensitive skin, real-world examples, and clinical findings. KEYWORD CLUSTER: Cluster Name: Portable and Handheld Back Massagers Description: Keywords in this cluster revolve around massagers that are portable and handheld, providing convenience and ease of use for back pain relief on the go. ASSOCIATED KEYWORDS: Keywords: vibrating back massager =========================== OUTPUT FORMAT =========================== Return ONLY the final JSON object with all fields populated. Do NOT include markdown code blocks, explanations, or any text outside the JSON structure. CRITICAL VALIDATION BEFORE SUBMITTING: 1. Count the actual words in your content field (strip HTML tags, count text) 2. Verify word_count field matches your actual content length (must be 950-1050) 3. Ensure each H2 section has 150-180 words of substantive content 4. If word count is under 950, ADD more depth, examples, and detail to sections 5. The outline descriptions are minimums—expand them significantly
-Output
-1,198t
-assistant
-{
- "title": "The Ultimate Guide to Choosing a Vibrating Back Massager",
- "meta_title": "Ultimate Guide to Vibrating Back Massagers",
- "meta_description": "Discover how to choose the best vibrating back massager to suit your lifestyle and ease your back pain effectively.",
- "content": "
Imagine a world where back pain is managed with the press of a button, even on the go.
Vibrating back massagers are revolutionizing pain relief for busy individuals seeking convenience without compromising on efficacy. As our lives get busier, the demand for portable and effective solutions for pain management continues to rise. These devices offer a practical way to alleviate discomfort, making them a popular choice for many.
This guide will arm you with the knowledge to select a vibrating back massager that perfectly aligns with your lifestyle and pain management needs. From understanding how these devices work to evaluating their features, you'll find everything you need to make an informed decision.
Understanding Vibrating Back Massagers
How Do They Work?
Vibrating back massagers utilize vibration therapy to relax muscle tension and promote circulation. The mechanical vibrations penetrate deep into the tissue, providing relief from soreness and stiffness. This method mimics the effects of a professional massage, offering relaxation and rejuvenation in the comfort of your home.
Benefits of Vibration Therapy
Vibration therapy is known for its ability to reduce pain and improve circulation. By stimulating blood flow, it helps in faster recovery and enhances muscle strength. Additionally, regular use can increase range of motion and flexibility, providing a holistic approach to wellness.
Potential Drawbacks
Overuse: Excessive use can lead to increased muscle soreness and fatigue.
Incorrect Application: Using the device on sensitive areas can cause discomfort or injury.
Dependence: Relying solely on massagers for pain relief without addressing underlying causes.
Features to Consider
Portability and Design
For frequent travelers, the size and weight of a vibrating back massager are crucial. Compact designs that fit easily into a suitcase or backpack are ideal. Ergonomic designs that contour to your body provide a more comfortable experience, ensuring you get the most out of your device.
Power Source and Battery Life
Model Type
Power Source
Battery Life
Battery-Operated
AA Batteries
4-6 hours
Rechargeable
USB-C Cable
8-10 hours
Top Vibrating Back Massager Models
Budget-Friendly Options
Affordable massagers provide great value without compromising on quality. The Homedics Handheld Massager, for instance, offers powerful vibrations and a compact design, making it an excellent choice for budget-conscious buyers.
Premium Picks
The Theragun Elite is praised by experts for its robust build and advanced features. Its powerful motor and ergonomic design make it a worthwhile investment for those seeking high-end performance.
How to Use a Vibrating Back Massager Safely
Guidelines for Effective Use
To maximize benefits, use your massager on targeted areas for 15-20 minutes daily. Always follow the manufacturer's instructions and avoid applying excessive pressure. This ensures optimal results while minimizing any potential risks.
Common Mistakes to Avoid
Using on Injured Areas: Avoid using on areas with open wounds or acute injuries.
Ignoring Instructions: Failing to follow guidelines can lead to ineffective results or injury.
Overuse: Extended use can lead to increased discomfort or muscle fatigue.
Customer Reviews and Satisfaction
Testimonials
Many users report significant pain relief and improved mobility after regular use of vibrating back massagers. One user noted, \"It's like having a personal masseuse at home, providing relief whenever I need it.\" Such feedback highlights the effectiveness and convenience of these devices.
Overall Ratings
Product
Rating
Source
Homedics Handheld Massager
4.5/5
Amazon
Theragun Elite
4.8/5
Best Buy
",
- "word_count": 1000,
- "primary_keyword": "vibrating back massager",
- "secondary_keywords": [
- "portable back massager",
- "handheld massager",
- "vibration therapy"
- ],
- "tags": [
- "vibrating back massagers",
- "pain relief devices",
- "portable massagers",
- "muscle relaxation",
- "therapeutic devices"
- ],
- "categories": [
- "Health & Wellness > Pain Management",
- "Consumer Electronics > Personal Care Devices"
- ]
-}
-
diff --git a/docs/00-SYSTEM/ARCHITECTURE-OVERVIEW.md b/docs/00-SYSTEM/ARCHITECTURE-OVERVIEW.md
deleted file mode 100644
index f34dc9c8..00000000
--- a/docs/00-SYSTEM/ARCHITECTURE-OVERVIEW.md
+++ /dev/null
@@ -1,79 +0,0 @@
-# System Architecture Overview
-
-## Purpose
-Describe how IGNY8 is structured across backend, frontend, and integrations, grounded in the current codebase. Covers core services, middleware, and platform composition.
-
-## Code Locations (exact paths)
-- Backend project root: `backend/igny8_core/`
-- Settings and service wiring: `backend/igny8_core/settings.py`
-- URL routing: `backend/igny8_core/urls.py`
-- Middleware: `backend/igny8_core/middleware/request_id.py`, `backend/igny8_core/middleware/resource_tracker.py`, `backend/igny8_core/auth/middleware.py`
-- Auth models and tenancy bases: `backend/igny8_core/auth/models.py`
-- DRF base behaviors: `backend/igny8_core/api/base.py`
-- Custom auth classes: `backend/igny8_core/api/authentication.py`
-- Frontend SPA: `frontend/` (Vite + React; dependencies in `frontend/package.json`)
-
-## High-Level Responsibilities
-- Django/DRF backend providing multi-tenant APIs for planner, writer, system, billing, automation, linker, optimizer, publisher, and integration modules.
-- Middleware adds per-request IDs, tenant context, and optional resource tracking for admin diagnostics.
-- REST API routing under `/api/v1/*` with unified response/error handling and scoped throttling.
-- Celery-backed async work (configured in settings) for AI, automation, and publishing.
-- React/Vite frontend consuming the API; authentication via JWT or session; API key support for WordPress bridge.
-
-## Detailed Behavior
-- Backend apps registered in `INSTALLED_APPS` include auth, AI framework, planner, writer, system, billing, automation, optimization, publishing, integration, linker, optimizer, and publisher modules; these are loaded via Django app configs in `settings.py`.
-- Middleware order enforces security, CORS, session, CSRF, Django auth, then custom layers: request ID, account context, resource tracking, messages, and clickjacking protection.
-- URL map (`urls.py`) exposes admin, CSV admin utilities for industries/seed keywords, and module routers for auth, account, planner, writer, system, billing (user + admin), automation, linker, optimizer, publisher, and integration. OpenAPI docs available at `/api/docs` and `/api/redoc`.
-- REST framework defaults use custom pagination, filtering, search, ordering, and a custom exception handler (enabled unless `IGNY8_USE_UNIFIED_EXCEPTION_HANDLER` is false). Authentication stack orders API key, JWT, CSRF-exempt session, then basic auth. Throttle scopes are predefined per domain (AI, content, auth, planner, writer, system, billing, linker, optimizer, integration).
-- CORS allows the IGNY8 domains plus local development hosts; credentials and specific debug headers are permitted, and request/resource tracking IDs are exposed in response headers.
-- Celery is configured to use Redis by default for broker and result backend, with JSON serialization, task time limits, and single-prefetch workers.
-- Logging writes to console and rotating files for publish/sync, WordPress API calls, and webhooks, with request IDs available via middleware.
-
-## Data Structures / Models Involved (no code, just explanation)
-- Multi-tenancy base classes (`AccountBaseModel`, `SiteSectorBaseModel`) add `account`, `site`, and `sector` scoping plus validation; defined in `auth/models.py`.
-- Core tenancy entities: `Account`, `Plan`, `Subscription`, `Site`, `Sector`, `Industry`, `IndustrySector`, `SeedKeyword`, `SiteUserAccess`, `User`, and `PasswordResetToken` in `auth/models.py`.
-- These bases are consumed by downstream modules (planner, writer, billing, automation, etc.) to enforce tenant, site, and sector ownership.
-
-## Execution Flow
-- Incoming HTTP requests enter Django middleware: security → WhiteNoise → CORS → session → common/CSRF → Django auth → `RequestIDMiddleware` (assigns `X-Request-ID`) → `AccountContextMiddleware` (sets `request.account` via session or JWT) → `ResourceTrackingMiddleware` (when enabled for admins) → messages → clickjacking.
-- DRF viewsets inherit from base classes in `api/base.py` to auto-filter querysets by account (and site/sector where applicable) and emit unified responses.
-- URL dispatch routes to module-specific routers under `/api/v1/*`. CSV admin helpers are mounted before admin to avoid routing conflicts.
-- Background tasks are dispatched via Celery using Redis endpoints from `settings.py`.
-
-## Cross-Module Interactions
-- Auth middleware sets `request.account` consumed by `AccountModelViewSet` and `SiteSectorModelViewSet` to filter data.
-- API key auth (WordPress bridge) sets both `request.account` and `request.site` for integration endpoints.
-- Resource tracking middleware exposes metrics via cache keyed by the request-specific tracking ID added to responses.
-- OpenAPI generation (drf-spectacular) documents all modules and respects unified response schemas.
-
-## State Transitions (if applicable)
-- Request lifecycle: ID assignment → tenant resolution → optional resource profiling → viewset execution → unified response with optional pagination and request/resource IDs in headers.
-- Tenancy lifecycle: Account/Plan/Subscription fields in models track status and retention; soft delete support on models that implement it.
-
-## Error Handling
-- Global DRF exception handler (custom when enabled) wraps errors into unified JSON with `success=false`.
-- Account middleware denies access when account or plan is missing/inactive, returning structured JSON and logging out session users.
-- Viewset overrides in `api/base.py` return unified error payloads for validation and 404/500 cases.
-
-## Tenancy Rules
-- Account is injected via middleware (session or JWT). Base viewsets filter querysets by `account`, unless the user is admin/developer/system account (override path).
-- `SiteSectorModelViewSet` adds site/sector filtering when models carry those fields; validation ensures site/sector belong to the same account.
-- Role helpers (`User.is_admin_or_developer`, `User.is_system_account_user`) allow bypass for privileged users; otherwise, data is restricted to the resolved account (and site/sector for derived models).
-
-## Billing Rules (if applicable)
-- Plan and account billing fields live in `auth/models.py` (`Plan.included_credits`, `Account.credits`, Stripe IDs). Status enforcement occurs in `AccountContextMiddleware` by requiring an active plan; billing modules implement credit logic (covered in backend/billing docs).
-
-## Background Tasks / Schedulers (if applicable)
-- Celery configuration in `settings.py` sets Redis broker/backend, JSON serialization, time limits, and worker tuning. Task modules (AI, automation, publishing) use this setup; scheduling uses Celery Beat state.
-
-## Key Design Considerations
-- Middleware-first tenant resolution ensures consistent scoping before view logic.
-- Admin/developer/system-account overrides allow cross-tenant operations for ops while protecting system accounts from deletion.
-- Unified API responses and throttling scopes enforce consistent client behavior and rate safety.
-- Redis-backed Celery keeps async workloads out of request path with strict time limits.
-
-## How Developers Should Work With This Module
-- Add new apps to `INSTALLED_APPS` and mount URLs under `/api/v1/*` in `urls.py`.
-- Inherit from `AccountModelViewSet` or `SiteSectorModelViewSet` to automatically enforce tenant/site/sector scoping and unified responses.
-- Use existing middleware; do not reorder request ID or account context layers, as downstream views rely on them.
-- Configure environment via `settings.py` variables (DB, JWT, Celery, CORS, Stripe/PayPal) rather than hardcoding values.
diff --git a/docs/00-SYSTEM/ARCHITECTURE.md b/docs/00-SYSTEM/ARCHITECTURE.md
new file mode 100644
index 00000000..615372b9
--- /dev/null
+++ b/docs/00-SYSTEM/ARCHITECTURE.md
@@ -0,0 +1,289 @@
+# System Architecture
+
+**Last Verified:** December 25, 2025
+**Backend Path:** `backend/igny8_core/`
+**Frontend Path:** `frontend/src/`
+
+---
+
+## Tech Stack
+
+| Layer | Technology | Version | Purpose |
+|-------|------------|---------|---------|
+| **Backend Framework** | Django | 5.1 | Web framework |
+| **API Layer** | Django REST Framework | 3.15 | REST API |
+| **Database** | PostgreSQL | 16 | Primary data store |
+| **Cache/Queue** | Redis | 7 | Caching, Celery broker |
+| **Task Queue** | Celery | 5.4 | Async task processing |
+| **Frontend Framework** | React | 18 | UI framework |
+| **Build Tool** | Vite | 5 | Frontend bundler |
+| **Styling** | Tailwind CSS | 3 | Utility CSS |
+| **State Management** | Zustand | 4 | React state |
+| **Language** | TypeScript | 5 | Frontend typing |
+| **Web Server** | Caddy | 2 | Reverse proxy, SSL |
+| **Containerization** | Docker | - | Deployment |
+
+---
+
+## High-Level Architecture
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ CLIENTS │
+│ React SPA (app.igny8.com) │ WordPress Plugin │ Admin │
+└─────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ CADDY (Reverse Proxy) │
+│ SSL termination, routing, static files │
+└─────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ DJANGO REST FRAMEWORK │
+│ │
+│ Middleware Stack: │
+│ SecurityMiddleware → WhiteNoise → CORS → Session → CSRF → │
+│ DjangoAuth → RequestIDMiddleware → AccountContextMiddleware → │
+│ ResourceTrackingMiddleware │
+│ │
+│ API: /api/v1/* → ViewSets → Services → Models │
+└─────────────────────────────────────────────────────────────────┘
+ │ │
+ ▼ ▼
+┌─────────────────────┐ ┌─────────────────────────────────────┐
+│ PostgreSQL │ │ Redis │
+│ Primary Database │ │ Sessions, Cache, Celery Broker │
+└─────────────────────┘ └─────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ CELERY WORKERS │
+│ AI Tasks, Automation, Publishing, Background Jobs │
+└─────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ EXTERNAL SERVICES │
+│ OpenAI API (GPT-4, DALL-E) │ Runware │ WordPress Sites │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Backend Structure
+
+```
+backend/igny8_core/
+├── settings.py # Django settings, all config
+├── urls.py # Root URL routing
+├── celery.py # Celery configuration
+├── wsgi.py / asgi.py # WSGI/ASGI entry points
+│
+├── auth/ # Authentication & tenancy
+│ ├── models.py # User, Account, Site, Sector, Plan
+│ ├── views.py # Login, register, password reset
+│ ├── middleware.py # AccountContextMiddleware
+│ └── urls.py # /api/v1/auth/*
+│
+├── api/ # API infrastructure
+│ ├── base.py # AccountModelViewSet, SiteSectorModelViewSet
+│ ├── authentication.py # JWT, API key auth classes
+│ └── pagination.py # Unified pagination
+│
+├── ai/ # AI engine
+│ ├── engine.py # AIEngine orchestrator
+│ ├── functions/ # AutoCluster, GenerateIdeas, GenerateContent, etc.
+│ ├── registry.py # Function registry
+│ └── progress.py # Progress tracking
+│
+├── modules/ # Feature modules (API layer)
+│ ├── planner/ # Keywords, Clusters, Ideas
+│ ├── writer/ # Tasks, Content, Images
+│ ├── billing/ # Credits, usage, transactions
+│ ├── integration/ # WordPress integration
+│ ├── system/ # Settings, prompts, AI config
+│ ├── linker/ # Internal linking (inactive)
+│ ├── optimizer/ # Content optimization (inactive)
+│ └── publisher/ # Publishing pipeline
+│
+├── business/ # Business logic (services)
+│ ├── automation/ # 7-stage automation pipeline
+│ ├── billing/ # Credit service, payment processing
+│ ├── content/ # Content generation orchestration
+│ ├── integration/ # Sync services
+│ ├── linking/ # Link processing
+│ ├── optimization/ # Content optimization
+│ ├── planning/ # Clustering, idea generation
+│ └── publishing/ # Publishing orchestration
+│
+├── middleware/ # Custom middleware
+│ ├── request_id.py # X-Request-ID header
+│ └── resource_tracker.py # Resource tracking for admins
+│
+└── tasks/ # Celery tasks
+ └── *.py # Background job definitions
+```
+
+---
+
+## Frontend Structure
+
+```
+frontend/src/
+├── main.tsx # Entry point
+├── App.tsx # Root component, routing
+├── index.css # Global styles, Tailwind
+│
+├── api/ # API clients
+│ ├── linker.api.ts
+│ ├── optimizer.api.ts
+│ └── ...
+│
+├── services/
+│ └── api.ts # Main API service (2500+ lines)
+│
+├── store/ # Zustand stores
+│ ├── authStore.ts # Authentication state
+│ ├── siteStore.ts # Active site
+│ ├── sectorStore.ts # Active sector
+│ ├── billingStore.ts # Billing state
+│ ├── moduleStore.ts # Module enable/disable
+│ └── ...
+│
+├── pages/ # Route pages
+│ ├── Dashboard/
+│ ├── Planner/
+│ ├── Writer/
+│ ├── Automation/
+│ ├── Linker/
+│ ├── Optimizer/
+│ ├── Settings/
+│ ├── Billing/
+│ └── Auth/
+│
+├── components/ # Reusable components
+│ ├── ProgressModal.tsx # AI progress display
+│ ├── ConfirmDialog.tsx
+│ └── ...
+│
+├── layout/ # Layout components
+│ ├── AppLayout.tsx
+│ └── AppSidebar.tsx
+│
+├── hooks/ # Custom hooks
+├── context/ # React contexts
+└── utils/ # Utility functions
+```
+
+---
+
+## Key Design Patterns
+
+### 1. Multi-Tenant Data Isolation
+
+All data is scoped to Account, with optional Site and Sector filtering:
+
+```
+Account (Tenant)
+ └── Site (e.g., myblog.com)
+ └── Sector (e.g., Technology, Health)
+ └── Keywords/Clusters/Ideas/Content
+```
+
+**Implementation:**
+- `AccountBaseModel` - Base class for account-scoped models
+- `SiteSectorBaseModel` - Base class for site/sector-scoped models
+- `AccountModelViewSet` - Auto-filters queryset by request.account
+- `SiteSectorModelViewSet` - Auto-filters by account + site + sector
+
+### 2. Middleware-First Tenant Resolution
+
+```python
+# Order in settings.py MIDDLEWARE
+1. SecurityMiddleware
+2. WhiteNoiseMiddleware
+3. CorsMiddleware
+4. SessionMiddleware
+5. DjangoAuthenticationMiddleware
+6. RequestIDMiddleware # Assigns X-Request-ID
+7. AccountContextMiddleware # Sets request.account from session/JWT
+8. ResourceTrackingMiddleware # Optional admin profiling
+```
+
+### 3. Unified API Responses
+
+All API responses follow this structure:
+
+```json
+{
+ "success": true,
+ "data": { ... },
+ "message": "Optional message"
+}
+```
+
+Error responses:
+```json
+{
+ "success": false,
+ "error": "Error message",
+ "code": "ERROR_CODE"
+}
+```
+
+### 4. Credit-Based Operations
+
+All AI operations check and deduct credits:
+1. Pre-check: `CreditService.check_credits()`
+2. Execute: AI function runs
+3. Post-deduct: `CreditService.deduct_credits_for_operation()`
+
+---
+
+## Environment Configuration
+
+Key environment variables (from `settings.py`):
+
+| Variable | Purpose |
+|----------|---------|
+| `DATABASE_URL` | PostgreSQL connection |
+| `REDIS_URL` | Redis connection |
+| `SECRET_KEY` | Django secret |
+| `JWT_SECRET_KEY` | JWT signing key |
+| `CORS_ALLOWED_ORIGINS` | Allowed frontend origins |
+| `CELERY_BROKER_URL` | Celery broker (Redis) |
+
+AI keys are stored in `GlobalIntegrationSettings` (database), not env vars.
+
+---
+
+## Deployment Architecture
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ Docker Compose │
+│ │
+│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
+│ │ Frontend │ │ Backend │ │ Worker │ │
+│ │ (Caddy) │ │ (Django) │ │ (Celery) │ │
+│ └─────────────┘ └─────────────┘ └─────────────┘ │
+│ │ │ │ │
+│ └────────────────┼────────────────┘ │
+│ │ │
+│ ┌─────────────┐ ┌─────────────┐ │
+│ │ PostgreSQL │ │ Redis │ │
+│ └─────────────┘ └─────────────┘ │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Planned Changes
+
+| Feature | Status | Description |
+|---------|--------|-------------|
+| AIModelConfig Database | 🔜 Planned | Move AI model pricing from constants to database |
+| Module Guard Extension | 🔜 Planned | Extend linker/optimizer disable to all pages (currently sidebar only) |
+| Multi-provider AI | 🔜 Planned | Support for Anthropic, Google AI |
diff --git a/docs/00-SYSTEM/AUTH-FLOWS.md b/docs/00-SYSTEM/AUTH-FLOWS.md
new file mode 100644
index 00000000..f3992428
--- /dev/null
+++ b/docs/00-SYSTEM/AUTH-FLOWS.md
@@ -0,0 +1,254 @@
+# Authentication & Authorization
+
+**Last Verified:** December 25, 2025
+**Backend Path:** `backend/igny8_core/auth/`
+**Frontend Path:** `frontend/src/store/authStore.ts`
+
+---
+
+## Quick Reference
+
+| What | File | Key Functions |
+|------|------|---------------|
+| User Model | `auth/models.py` | `User`, `Account`, `Plan` |
+| Auth Views | `auth/views.py` | `LoginView`, `RegisterView`, `RefreshTokenView` |
+| Middleware | `auth/middleware.py` | `AccountContextMiddleware` |
+| JWT Auth | `api/authentication.py` | `JWTAuthentication`, `CookieJWTAuthentication` |
+| API Key Auth | `api/authentication.py` | `APIKeyAuthentication` |
+| Frontend Store | `store/authStore.ts` | `useAuthStore` |
+
+---
+
+## Authentication Methods
+
+### 1. JWT Token Authentication (Primary)
+
+**Flow:**
+1. User logs in via `/api/v1/auth/login/`
+2. Backend returns `access_token` (15 min) + `refresh_token` (7 days)
+3. Frontend stores tokens in localStorage and Zustand store
+4. All API requests include `Authorization: Bearer `
+5. Token refresh via `/api/v1/auth/token/refresh/`
+
+**Token Payload:**
+```json
+{
+ "user_id": 123,
+ "account_id": 456,
+ "email": "user@example.com",
+ "exp": 1735123456,
+ "iat": 1735122456
+}
+```
+
+### 2. Session Authentication (Admin/Fallback)
+
+- Used by Django Admin interface
+- Cookie-based session with CSRF protection
+- Redis-backed sessions (prevents user swapping bug)
+
+### 3. API Key Authentication (WordPress Bridge)
+
+**Flow:**
+1. Account generates API key in settings
+2. WordPress plugin uses `Authorization: ApiKey `
+3. Backend validates key, sets `request.account` and `request.site`
+
+**Use Cases:**
+- WordPress content sync
+- External integrations
+- Headless CMS connections
+
+---
+
+## API Endpoints
+
+| Method | Path | Handler | Purpose |
+|--------|------|---------|---------|
+| POST | `/api/v1/auth/register/` | `RegisterView` | Create new user + account |
+| POST | `/api/v1/auth/login/` | `LoginView` | Authenticate, return tokens |
+| POST | `/api/v1/auth/logout/` | `LogoutView` | Invalidate tokens |
+| POST | `/api/v1/auth/token/refresh/` | `RefreshTokenView` | Refresh access token |
+| POST | `/api/v1/auth/password/change/` | `ChangePasswordView` | Change password |
+| POST | `/api/v1/auth/password/reset/` | `RequestPasswordResetView` | Request reset email |
+| POST | `/api/v1/auth/password/reset/confirm/` | `ResetPasswordView` | Confirm reset with token |
+
+---
+
+## User Roles
+
+| Role | Code | Permissions |
+|------|------|-------------|
+| **Developer** | `developer` | Full access across ALL accounts (superuser) |
+| **Admin** | `admin` | Full access to own account |
+| **Manager** | `manager` | Manage content, view billing |
+| **Editor** | `editor` | AI content, manage clusters/tasks |
+| **Viewer** | `viewer` | Read-only dashboards |
+| **System Bot** | `system_bot` | System automation (internal) |
+
+**Role Hierarchy:**
+```
+developer > admin > manager > editor > viewer
+```
+
+---
+
+## Middleware: AccountContextMiddleware
+
+**File:** `auth/middleware.py`
+
+**Purpose:** Injects `request.account` on every request
+
+**Flow:**
+1. Check for JWT token → extract account_id
+2. Check for session → get account from session
+3. Check for API key → get account from key
+4. Validate account exists and is active
+5. Validate plan exists and is active
+6. Set `request.account`, `request.user`
+
+**Error Responses:**
+- No account: 403 with JSON error
+- Inactive plan: 402 with JSON error
+
+---
+
+## Frontend Auth Store
+
+**File:** `store/authStore.ts`
+
+**State:**
+```typescript
+{
+ user: User | null;
+ token: string | null;
+ refreshToken: string | null;
+ isAuthenticated: boolean;
+}
+```
+
+**Actions:**
+- `login(email, password)` - Authenticate and store tokens
+- `register(data)` - Create account and store tokens
+- `logout()` - Clear tokens and reset stores
+- `refreshToken()` - Refresh access token
+- `checkAuth()` - Verify current auth state
+
+**Critical Implementation:**
+```typescript
+// Tokens are written synchronously to localStorage
+// This prevents race conditions where API calls happen before persist
+localStorage.setItem('auth-storage', JSON.stringify(authState));
+```
+
+---
+
+## Session Security (Redis-Backed)
+
+**Problem Solved:** User swapping / random logout issues
+
+**Implementation:**
+```python
+# settings.py
+SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
+SESSION_CACHE_ALIAS = 'default' # Redis
+
+# auth/backends.py
+class NoCacheModelBackend(ModelBackend):
+ """Authentication backend without user caching"""
+ pass
+```
+
+**Session Integrity:**
+- Stores `account_id` and `user_id` in session
+- Validates on every request
+- Prevents cross-request contamination
+
+---
+
+## API Key Management
+
+**Model:** `APIKey` in `auth/models.py`
+
+| Field | Type | Purpose |
+|-------|------|---------|
+| key | CharField | Hashed API key |
+| account | ForeignKey | Owner account |
+| site | ForeignKey | Optional: specific site |
+| name | CharField | Key name/description |
+| is_active | Boolean | Enable/disable |
+| created_at | DateTime | Creation time |
+| last_used_at | DateTime | Last usage time |
+
+**Generation:**
+- 32-character random key
+- Stored hashed (SHA-256)
+- Shown once on creation
+
+---
+
+## Permission Checking
+
+**In ViewSets:**
+```python
+class MyViewSet(AccountModelViewSet):
+ permission_classes = [IsAuthenticated]
+
+ def get_queryset(self):
+ # Automatically filtered by request.account
+ return super().get_queryset()
+```
+
+**Role Checks:**
+```python
+if request.user.is_admin_or_developer:
+ # Admin/developer access
+ pass
+elif request.user.role == 'editor':
+ # Editor access
+ pass
+```
+
+---
+
+## Logout Flow
+
+**Backend:**
+1. Blacklist refresh token (if using token blacklist)
+2. Clear session
+
+**Frontend (Critical):**
+```typescript
+logout: () => {
+ // NEVER use localStorage.clear() - breaks Zustand persist
+ const authKeys = ['auth-storage', 'site-storage', 'sector-storage', 'billing-storage'];
+ authKeys.forEach(key => localStorage.removeItem(key));
+
+ // Reset dependent stores
+ useSiteStore.setState({ activeSite: null });
+ useSectorStore.setState({ activeSector: null, sectors: [] });
+
+ set({ user: null, token: null, isAuthenticated: false });
+}
+```
+
+---
+
+## Common Issues
+
+| Issue | Cause | Fix |
+|-------|-------|-----|
+| 403 after login | Tokens not persisted before API call | Write to localStorage synchronously |
+| User swapping | DB-backed sessions with user caching | Redis sessions + NoCacheModelBackend |
+| Token refresh loop | Refresh token expired | Redirect to login |
+| API key not working | Missing site scope | Check API key has correct site assigned |
+
+---
+
+## Planned Changes
+
+| Feature | Status | Description |
+|---------|--------|-------------|
+| Token blacklist | 🔜 Planned | Proper refresh token invalidation |
+| 2FA | 🔜 Planned | Two-factor authentication |
+| SSO | 🔜 Planned | Google/GitHub OAuth |
diff --git a/docs/00-SYSTEM/AUTHENTICATION.md b/docs/00-SYSTEM/AUTHENTICATION.md
deleted file mode 100644
index d5a6eef8..00000000
--- a/docs/00-SYSTEM/AUTHENTICATION.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# Identity and Authentication
-
-## Purpose
-Document how user identity, JWT handling, API keys, and session flows work, including middleware and validation rules.
-
-## Code Locations (exact paths)
-- JWT utilities: `backend/igny8_core/auth/utils.py`
-- Account context middleware: `backend/igny8_core/auth/middleware.py`
-- DRF authentication classes: `backend/igny8_core/api/authentication.py`
-- DRF settings for auth/throttle: `backend/igny8_core/settings.py`
-- User model and roles: `backend/igny8_core/auth/models.py`
-- Auth URLs and views: `backend/igny8_core/auth/urls.py`, `backend/igny8_core/auth/views.py`
-
-## High-Level Responsibilities
-- Support multiple auth mechanisms: API key (WordPress bridge), JWT bearer tokens, session auth without CSRF for APIs, and basic auth fallback.
-- Populate tenant/site context alongside user identity so downstream viewsets enforce isolation.
-- Enforce active account/plan presence before serving protected endpoints (except admin/auth routes).
-
-## Detailed Behavior
-- Authentication order (DRF `DEFAULT_AUTHENTICATION_CLASSES` in `settings.py`): API key → JWT → CSRF-exempt session → basic auth. The first class that authenticates sets `request.user`; `request.account` may also be set by API key or JWT.
-- API Key flow (`APIKeyAuthentication`): expects `Authorization: Bearer ` that is not JWT-like; finds an active `Site` with `wp_api_key`, loads its `account`, and selects an active user (owner preferred, else any active developer/owner/admin). Sets `request.account` and `request.site`. Rejects short/invalid keys; returns an auth failure if no active user exists.
-- JWT flow (`JWTAuthentication`): expects `Authorization: Bearer `; decodes via `auth.utils.decode_token`; only accepts tokens with `type == access`. Retrieves `User` by `user_id`; optional `account_id` is resolved to `Account` and set on `request.account`. Invalid/expired tokens fall through to other auth classes.
-- Session flow (`CSRFExemptSessionAuthentication`): uses Django session cookies without CSRF enforcement for API calls.
-- Basic auth: last resort; does not set tenant context.
-- Token utilities (`auth/utils.py`) generate and decode access/refresh tokens using expiries from settings (`JWT_ACCESS_TOKEN_EXPIRY`, `JWT_REFRESH_TOKEN_EXPIRY`), embedding `user_id`, `account_id`, `email`, issued/expiry timestamps, and token `type`.
-- Middleware (`AccountContextMiddleware`) runs on every request except admin/auth paths: refreshes session users from DB to pick up current account/plan, validates presence of an active plan, sets `request.account`, and logs out session users when invalid. For JWT-bearing requests it decodes the token directly and sets `request.account`. If account/plan is missing or inactive, it returns JSON with `success=false` and appropriate HTTP status.
-
-## Data Structures / Models Involved (no code)
-- `User` with `role` and `account` FKs in `auth/models.py`.
-- `Account` with plan and billing fields; plan status is used for access gating.
-- `Site` with `wp_api_key` for API key auth; `SiteUserAccess` for per-site grants.
-- `PasswordResetToken` model for password reset flows.
-- JWT payload fields: `user_id`, `account_id`, `email`, `exp`, `iat`, `type`.
-
-## Execution Flow
-- Middleware step: `AccountContextMiddleware` determines `request.account` (session or JWT) and validates plan status; skips admin/auth routes.
-- DRF auth step: API key/JWT/session/basic authenticators run in order, potentially setting `request.account` (API key/JWT) and `request.site` (API key).
-- Viewsets then apply role/permission checks and tenant/site/sector filtering via base classes in `api/base.py`.
-
-## Cross-Module Interactions
-- All module viewsets rely on `request.user` and `request.account` set by the auth stack. Site-aware modules can read `request.site` when API key auth is used.
-- Role helpers (`is_admin_or_developer`, `is_system_account_user`) influence filtering bypass in base viewsets.
-
-## State Transitions (if applicable)
-- JWT lifetimes: access tokens default to 15 minutes; refresh tokens to 30 days (configurable in settings).
-- Session users are refreshed on each request to pick up plan/account changes.
-- Password reset tokens track expiry and usage via `expires_at` and `used` flags.
-
-## Error Handling
-- Middleware returns JSON errors for missing account or inactive plan and logs out session users in those cases.
-- Invalid/expired JWTs cause the JWT authenticator to return `None`, allowing other auth methods; decoding errors raise `InvalidTokenError` in utilities.
-- API key auth raises an auth failure when no active user is available for the resolved account.
-
-## Tenancy Rules
-- `request.account` is set early; base viewsets enforce account filtering unless user has admin/developer/system-account privileges.
-- API key auth also sets `request.site` for integration contexts; site/sector filtering occurs in `SiteSectorModelViewSet`.
-
-## Billing Rules (if applicable)
-- Active plan is required for access (middleware enforces). Credit debits/charges are handled in billing modules, not in the auth layer.
-
-## Background Tasks / Schedulers (if applicable)
-- Token generation/validation is synchronous. Background tasks should receive explicit user/account identifiers in their payloads when invoked.
-
-## Key Design Considerations
-- Authentication stack is ordered to give integration API keys precedence, then JWT for app clients, then session for browser-based flows.
-- Tenant context must be established before view logic; do not move or remove `AccountContextMiddleware`.
-- Expiry durations and JWT secrets are centrally configured in `settings.py`.
-
-## How Developers Should Work With This Module
-- Use token helpers from `auth/utils.py` when issuing tokens; do not handcraft JWTs.
-- Mount new auth-sensitive endpoints under existing routers and rely on DRF auth classes instead of custom header parsing.
-- Ensure new features that require site context can work with API key auth by checking `request.site`.
-- Keep plan enforcement in place; bypass only for admin/system routes when justified.
diff --git a/docs/00-SYSTEM/DATA-FLOWS.md b/docs/00-SYSTEM/DATA-FLOWS.md
deleted file mode 100644
index b5846f67..00000000
--- a/docs/00-SYSTEM/DATA-FLOWS.md
+++ /dev/null
@@ -1,85 +0,0 @@
-# Data Flow Diagrams (Narrative)
-
-## Purpose
-Describe end-to-end data movement through the system based on current routing, middleware, and model conventions. No diagrams are embedded; flows are explained textually.
-
-## Code Locations (exact paths)
-- Request routing: `backend/igny8_core/urls.py`
-- Middleware: `backend/igny8_core/middleware/request_id.py`, `backend/igny8_core/auth/middleware.py`, `backend/igny8_core/middleware/resource_tracker.py`
-- DRF base viewsets: `backend/igny8_core/api/base.py`
-- Authentication classes: `backend/igny8_core/api/authentication.py`
-- Tenancy models: `backend/igny8_core/auth/models.py`
-- Celery configuration: `backend/igny8_core/settings.py`
-
-## High-Level Responsibilities
-- Trace how HTTP requests are processed, tenant-scoped, authorized, and persisted.
-- Show where async processing departs to Celery and where responses are shaped.
-
-## Detailed Behavior
-- Incoming request → Django middleware stack:
- - Security/WhiteNoise/CORS/session/common/CSRF/Django auth.
- - `RequestIDMiddleware` assigns `request.request_id` and returns it in `X-Request-ID`.
- - `AccountContextMiddleware` resolves user/account (session or JWT) and enforces active plan; sets `request.account`.
- - `ResourceTrackingMiddleware` optionally tracks resource usage for admin/developer users when the `X-Debug-Resource-Tracking` header is true; adds `X-Resource-Tracking-ID`.
-- URL dispatch via `urls.py` routes to module routers (auth, account, planner, writer, system, billing, automation, linker, optimizer, publisher, integration) under `/api/v1/*`.
-- DRF viewset pipeline:
- - Authentication classes (API key → JWT → session → basic) establish `request.user` (and optionally `request.account`/`request.site`).
- - Base viewsets (`AccountModelViewSet`, `SiteSectorModelViewSet`) filter querysets by `account`/`site`/`sector` and attach `account` on create.
- - Serializers handle validation; responses are wrapped by unified helpers to standardize success/error payloads and pagination.
-- Persistence:
- - Tenant-scoped models inherit `AccountBaseModel` or `SiteSectorBaseModel`; save hooks enforce account/site/sector alignment.
- - Soft deletion is used where models implement `soft_delete`, respecting retention windows from account settings.
-- Async/Background:
- - Celery uses Redis broker/backend; tasks inherit JSON payloads and time limits from `settings.py`.
- - Automation, AI, publishing, and billing tasks enqueue via Celery; results return through database/state updates, not synchronous responses.
-- Response:
- - Unified response wrappers ensure `success`, `data`/`error`, and request ID are present; paginated responses include `count/next/previous/results`.
- - Throttling headers apply per-scope (as configured in `REST_FRAMEWORK` throttles).
-
-## Data Structures / Models Involved (no code)
-- Tenancy bases: `AccountBaseModel`, `SiteSectorBaseModel`.
-- Core entities: `Account`, `Plan`, `Site`, `Sector`, `User`, `SiteUserAccess`.
-- Module-specific models follow the same tenancy bases (documented in module-specific files).
-
-## Execution Flow
-1) HTTP request hits middleware; IDs and tenant context are set.
-2) DRF authentication authenticates and sets user/account/site.
-3) Viewset filters data by tenant/site/sector and runs serializer validation.
-4) DB operations persist data with enforced tenant alignment.
-5) Optional Celery tasks are queued for long-running work.
-6) Response returns unified JSON with request IDs and optional throttling/pagination headers.
-
-## Cross-Module Interactions
-- Auth context set in middleware is consumed by all module viewsets for scoping.
-- API key auth provides site context for integration/publisher flows.
-- Celery configuration is shared by automation/AI/publishing/billing task modules.
-
-## State Transitions (if applicable)
-- Entity lifecycle changes (create/update/delete/soft-delete) flow through base viewsets and tenancy bases, ensuring account/site/sector consistency.
-- Request lifecycle includes request ID creation, optional resource tracking, and unified response wrapping.
-
-## Error Handling
-- Middleware can short-circuit with JSON errors for missing account/plan.
-- Viewset overrides wrap validation and server errors into unified responses; missing objects return 404 payloads.
-- Throttling (scope-based) returns standard DRF throttle responses with headers.
-
-## Tenancy Rules
-- All tenant-bound data flows require `request.account`; filtering and save hooks prevent cross-tenant access.
-- Admin/developer/system-account users may bypass tenant filtering; system accounts are guarded against deletion.
-- Site/sector alignment is validated on save for models inheriting `SiteSectorBaseModel`.
-
-## Billing Rules (if applicable)
-- Plan activation is validated in middleware. Credit debits and billing workflows occur in billing modules (covered elsewhere) after tenant resolution.
-
-## Background Tasks / Schedulers (if applicable)
-- Celery broker/backend configuration in `settings.py` governs async flow; tasks should include account/site identifiers to maintain scoping.
-
-## Key Design Considerations
-- Request ID and resource tracking enable traceability and performance debugging.
-- Middleware ordering ensures tenant context precedes view logic.
-- Unified response format keeps clients consistent across modules.
-
-## How Developers Should Work With This Module
-- Preserve middleware order; new middleware must not break request ID or tenant context.
-- Ensure new viewsets inherit the base classes to pick up scoping and unified responses.
-- When adding async tasks, include tenant/site identifiers and respect Celery limits from settings.
diff --git a/docs/00-SYSTEM/MULTITENANCY.md b/docs/00-SYSTEM/MULTITENANCY.md
deleted file mode 100644
index 1f295ade..00000000
--- a/docs/00-SYSTEM/MULTITENANCY.md
+++ /dev/null
@@ -1,79 +0,0 @@
-# Multitenancy Model
-
-## Purpose
-Explain how tenant, site, and sector isolation is enforced across models, middleware, and viewsets, based on the current implementation.
-
-## Code Locations (exact paths)
-- Tenant base models: `backend/igny8_core/auth/models.py` (`AccountBaseModel`, `SiteSectorBaseModel`)
-- Core entities: `backend/igny8_core/auth/models.py` (`Account`, `Plan`, `Site`, `Sector`, `Industry`, `IndustrySector`, `SeedKeyword`, `SiteUserAccess`, `User`)
-- Middleware for context: `backend/igny8_core/auth/middleware.py`
-- DRF base viewsets: `backend/igny8_core/api/base.py`
-- Auth utilities and JWT: `backend/igny8_core/api/authentication.py`, `backend/igny8_core/auth/utils.py`
-- URL routing (module mounting): `backend/igny8_core/urls.py`
-
-## High-Level Responsibilities
-- Enforce per-account isolation for all models carrying an `account` FK.
-- Enforce per-site and per-sector scoping for content models via `SiteSectorBaseModel`.
-- Inject tenant context on every request (session or JWT/API key), then apply scoping in base viewsets.
-- Allow controlled overrides for admins, developers, and system accounts.
-
-## Detailed Behavior
-- `AccountBaseModel` adds an `account` FK plus timestamps and indexes; all tenant-scoped models inherit this to guarantee account linkage.
-- `SiteSectorBaseModel` extends `AccountBaseModel` with `site` and `sector` FKs, indexes on `(account, site, sector)`, and a save hook that sets `account` from `site` and validates that `sector` belongs to the same `site`; raises validation errors on mismatch.
-- `AccountContextMiddleware` sets `request.account` by refreshing the authenticated session user (with account and plan) or by decoding JWT tokens; it rejects requests when account is missing or plan is inactive, returning structured JSON and logging out session users. It skips admin and auth endpoints to avoid interference.
-- JWT authentication (`api/authentication.py`) decodes tokens and sets `request.account` from the token payload; API key authentication sets both `request.account` and `request.site` for WordPress bridge calls.
-- `AccountModelViewSet` auto-filters querysets by `account` when models expose that field. It bypasses filtering for admins/developers/system-account users; otherwise, it uses `request.account` or falls back to the authenticated user’s account. Creates set `account` on save when present.
-- `SiteSectorModelViewSet` extends the above to filter by site/sector if those fields exist, using request query parameters and tenancy context.
-- `User` role helpers (`is_admin_or_developer`, `is_system_account_user`) and account checks gate override behavior.
-- `SiteUserAccess` provides explicit per-site access for non-admin roles; `User.get_accessible_sites` respects system account, developer, owner/admin, and granted access rules.
-
-## Data Structures / Models Involved (no code)
-- `Account`: tenant container with plan, credits, billing fields, status, and retention settings.
-- `Plan`: defines limits (max users/sites/industries/author profiles), credit inclusion, Stripe IDs.
-- `Site`: belongs to an account, optionally an industry; includes status, hosting type, legacy WP fields, and SEO metadata.
-- `Sector`: belongs to a site and industry sector template; enforces account alignment and plan-based max-sector validation.
-- `Industry`, `IndustrySector`, `SeedKeyword`: global reference data not bound to a single account.
-- `SiteUserAccess`: explicit many-to-many grants between users and sites.
-- `User`: links to account with role-based access flags.
-
-## Execution Flow
-- Request enters middleware; `AccountContextMiddleware` determines `request.account` (session or JWT/API key), validating plan status.
-- Viewsets inheriting from `AccountModelViewSet`/`SiteSectorModelViewSet` filter querysets by `account` (and site/sector when present) before pagination/serialization.
-- Object creation sets `account` automatically when the serializer’s model has that field; site/sector-based models validate alignment on save.
-- Admin/developer/system-account users skip account filtering; other users remain constrained.
-
-## Cross-Module Interactions
-- All module viewsets depend on the base viewsets for scoping.
-- Automation, planner, writer, billing, linker, optimizer, publisher, and integration models inherit from the tenancy bases to enforce account/site/sector ownership.
-- API key flows for WordPress set `request.site`, enabling integration-specific logic to run in a site-aware context.
-
-## State Transitions (if applicable)
-- Account status changes (active, suspended, trial, cancelled) and plan activation directly affect access through middleware plan validation.
-- Sector creation enforces plan-based limits for active sectors per site.
-
-## Error Handling
-- Middleware returns JSON errors for missing account or inactive plan, with HTTP 403 or 402 semantics and logs out session users.
-- Base viewsets wrap CRUD operations in unified responses; validation failures or missing objects are returned in structured error payloads.
-- Save-time validation on `SiteSectorBaseModel` and `Sector` raises validation errors when site/sector alignment or plan limits are violated.
-
-## Tenancy Rules
-- Every tenant-scoped model carries `account`; site/sector-aware models carry `site` and `sector` and must align to the same account.
-- Middleware populates `request.account`; base viewsets enforce filtering unless the user is an admin/developer/system-account member.
-- System accounts (`aws-admin`, `default-account`, `default`) and privileged roles can bypass scoping; protected from deletion via guard clauses.
-
-## Billing Rules (if applicable)
-- Middleware requires an active plan before allowing requests (except auth/admin paths). Credits, charges, and plan enforcement are handled in billing modules (documented elsewhere).
-
-## Background Tasks / Schedulers (if applicable)
-- Celery tasks inherit tenant context via payloads supplied by calling viewsets/services; the tenancy bases ensure stored records retain `account`/`site`/`sector`.
-
-## Key Design Considerations
-- Tenancy is enforced as early as middleware to avoid leakage in view logic.
-- Base viewsets centralize scoping and unified responses to reduce duplication across modules.
-- Role-based overrides exist for ops and system accounts; safeguards prevent system account deletion.
-
-## How Developers Should Work With This Module
-- Inherit from `AccountBaseModel` or `SiteSectorBaseModel` for any new tenant/site/sector data models.
-- Inherit viewsets from `AccountModelViewSet` or `SiteSectorModelViewSet` to get automatic scoping and unified responses.
-- Do not bypass `AccountContextMiddleware`; ensure new endpoints live under `/api/v1/*` and rely on the auth stack (API key → JWT → session).
-- Validate that new background tasks carry account/site/sector identifiers so downstream saves remain scoped.
diff --git a/docs/00-SYSTEM/TECH-STACK.md b/docs/00-SYSTEM/TECH-STACK.md
deleted file mode 100644
index 85a88970..00000000
--- a/docs/00-SYSTEM/TECH-STACK.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Tech Stack
-
-## Purpose
-Document the concrete technologies and dependencies in use across backend and frontend as defined in the repository.
-
-## Code Locations (exact paths)
-- Backend dependency manifest: `backend/requirements.txt`
-- Backend settings (framework integration): `backend/igny8_core/settings.py`
-- Frontend dependency manifest: `frontend/package.json`
-- Frontend build tooling: `frontend/vite.config.ts`, `frontend/tsconfig*.json`
-
-## High-Level Responsibilities
-- Backend: Django 5.x with DRF for APIs, Celery for async tasks, Redis for broker/result, PostgreSQL or SQLite for data, drf-spectacular for OpenAPI, Stripe/PayPal configs for billing, WhiteNoise for static serving.
-- Frontend: React 19 with Vite, TypeScript, TailwindCSS, Zustand state, React Router 7, ApexCharts and FullCalendar for UI widgets.
-
-## Detailed Behavior
-- Backend settings wire DRF pagination, filters, authentication (API key, JWT, session, basic), throttling, schema generation, CORS, Celery, logging, and Stripe/PayPal credentials. Static assets are served via WhiteNoise; admin uses Django contrib.
-- `requirements.txt` enumerates runtime libs: Django, gunicorn, psycopg2-binary (PostgreSQL), redis, WhiteNoise, DRF, django-filter, django-cors-headers, PyJWT, requests, Celery, BeautifulSoup4, psutil, docker (for ops scripts), drf-spectacular, and stripe.
-- Frontend `package.json` pins React 19, React Router 7, Zustand 5, Vite 6, TailwindCSS 4, ApexCharts 4, FullCalendar 6, react-dnd, dropzone, lucide/react-heroicons, and testing/tooling (Vitest, Testing Library, ESLint).
-- Build scripts use Vite for dev and production builds, with separate marketing mode; tests via Vitest; lint via ESLint; type-check via `tsc -b`.
-
-## Data Structures / Models Involved (no code)
-- Not applicable; this file tracks technology components rather than domain models.
-
-## Execution Flow
-- Backend runs under Django/DRF with middleware and installed apps per `settings.py`. ASGI/WSGI entrypoints in `igny8_core/asgi.py` and `igny8_core/wsgi.py` (default WSGI via gunicorn).
-- Celery worker/beat use Redis URLs from `settings.py` and respect JSON serialization/time limits.
-- Frontend builds with Vite, consuming environment variables defined via Vite conventions.
-
-## Cross-Module Interactions
-- DRF auth classes depend on PyJWT and custom utilities for token handling.
-- Celery tasks in AI/automation/publishing rely on Redis connectivity and the configured serializer/time limits.
-- Stripe/PayPal keys in settings are consumed by billing modules.
-- Frontend API calls rely on the DRF endpoints exposed in `igny8_core/urls.py`.
-
-## State Transitions (if applicable)
-- Dependency-driven: none beyond the build/runtime phases (install → build → serve).
-
-## Error Handling
-- Backend error handling configured via custom DRF exception handler (enabled by default) and logging setup in `settings.py`.
-- Frontend build/test errors are surfaced through Vite/TypeScript/Vitest/ESLint tooling.
-
-## Tenancy Rules
-- Implemented at runtime by backend middleware and viewsets; the tech stack provides JWT, session, and API key support to carry tenant context.
-
-## Billing Rules (if applicable)
-- Stripe and PayPal keys in `settings.py` enable billing integrations; credit logic is implemented in billing modules (documented elsewhere).
-
-## Background Tasks / Schedulers (if applicable)
-- Celery configured in `settings.py` with Redis broker/backend, JSON serialization, and task limits; beat scheduling persists in `celerybeat-schedule`.
-
-## Key Design Considerations
-- Keep dependency manifests authoritative (`requirements.txt`, `package.json`).
-- Redis is the default async backbone; Postgres is the default DB with SQLite fallback for local/dev.
-- Vite + React 19 selected for fast dev/build; TailwindCSS 4 used for styling; Zustand for state.
-
-## How Developers Should Work With This Module
-- Add backend dependencies to `requirements.txt` and pin versions appropriately; update settings if new middleware/auth is added.
-- Add frontend dependencies to `package.json`; run `npm install` and ensure Vite/TSC builds remain clean.
-- Respect configured auth stack (API key → JWT → session) when adding API clients.
-- Keep CORS and env vars aligned with the domains/ports in use for local and production.
diff --git a/docs/00-SYSTEM/TENANCY.md b/docs/00-SYSTEM/TENANCY.md
new file mode 100644
index 00000000..af6ab2ac
--- /dev/null
+++ b/docs/00-SYSTEM/TENANCY.md
@@ -0,0 +1,299 @@
+# Multi-Tenancy Architecture
+
+**Last Verified:** December 25, 2025
+**Backend Path:** `backend/igny8_core/auth/models.py`
+
+---
+
+## Data Hierarchy
+
+```
+Account (Tenant)
+├── Users (team members)
+├── Subscription (plan binding)
+├── Sites
+│ ├── Sectors
+│ │ ├── Keywords
+│ │ ├── Clusters
+│ │ ├── ContentIdeas
+│ │ ├── Tasks
+│ │ ├── Content
+│ │ └── Images
+│ └── Integrations (WordPress)
+└── Billing (credits, transactions)
+```
+
+---
+
+## Core Models
+
+### Account
+
+| Field | Type | Purpose |
+|-------|------|---------|
+| name | CharField | Account/organization name |
+| is_active | Boolean | Enable/disable account |
+| credits | Decimal | Current credit balance |
+| stripe_customer_id | CharField | Stripe integration |
+| paypal_customer_id | CharField | PayPal integration |
+| created_at | DateTime | Registration date |
+
+### Plan
+
+| Field | Type | Purpose |
+|-------|------|---------|
+| name | CharField | Plan name (Free, Starter, Growth, Scale) |
+| included_credits | Integer | Monthly credit allocation |
+| max_sites | Integer | Site limit |
+| max_users | Integer | User limit |
+| max_keywords | Integer | Keyword limit |
+| max_clusters | Integer | Cluster limit |
+| max_content_ideas | Integer | Monthly idea limit |
+| max_content_words | Integer | Monthly word limit |
+| max_images_basic | Integer | Monthly basic image limit |
+| max_images_premium | Integer | Monthly premium image limit |
+| is_active | Boolean | Available for purchase |
+| is_internal | Boolean | Internal/test plan |
+
+### Site
+
+| Field | Type | Purpose |
+|-------|------|---------|
+| account | ForeignKey | Owner account |
+| name | CharField | Site name |
+| domain | CharField | Primary domain |
+| is_active | Boolean | Enable/disable |
+
+### Sector
+
+| Field | Type | Purpose |
+|-------|------|---------|
+| site | ForeignKey | Parent site |
+| account | ForeignKey | Owner account |
+| industry | ForeignKey | Industry template |
+| name | CharField | Sector name |
+| is_active | Boolean | Enable/disable |
+
+---
+
+## Base Model Classes
+
+### AccountBaseModel
+
+**File:** `auth/models.py`
+
+All account-scoped models inherit from this:
+
+```python
+class AccountBaseModel(models.Model):
+ account = models.ForeignKey(Account, on_delete=models.CASCADE)
+
+ class Meta:
+ abstract = True
+```
+
+**Used by:** Billing records, Settings, API keys
+
+### SiteSectorBaseModel
+
+**File:** `auth/models.py`
+
+All content models inherit from this:
+
+```python
+class SiteSectorBaseModel(AccountBaseModel):
+ site = models.ForeignKey(Site, on_delete=models.CASCADE)
+ sector = models.ForeignKey(Sector, on_delete=models.CASCADE)
+
+ class Meta:
+ abstract = True
+```
+
+**Used by:** Keywords, Clusters, Ideas, Tasks, Content, Images
+
+---
+
+## ViewSet Base Classes
+
+### AccountModelViewSet
+
+**File:** `api/base.py`
+
+Automatically filters queryset by account:
+
+```python
+class AccountModelViewSet(ModelViewSet):
+ def get_queryset(self):
+ qs = super().get_queryset()
+ if not self.request.user.is_admin_or_developer:
+ qs = qs.filter(account=self.request.account)
+ return qs
+```
+
+### SiteSectorModelViewSet
+
+**File:** `api/base.py`
+
+Filters by account + site + sector:
+
+```python
+class SiteSectorModelViewSet(AccountModelViewSet):
+ def get_queryset(self):
+ qs = super().get_queryset()
+ site_id = self.request.query_params.get('site_id')
+ sector_id = self.request.query_params.get('sector_id')
+ if site_id:
+ qs = qs.filter(site_id=site_id)
+ if sector_id:
+ qs = qs.filter(sector_id=sector_id)
+ return qs
+```
+
+---
+
+## Where Tenancy Applies
+
+### Uses Site/Sector Filtering
+
+| Module | Filter |
+|--------|--------|
+| Planner (Keywords, Clusters, Ideas) | site + sector |
+| Writer (Tasks, Content, Images) | site + sector |
+| Linker | site + sector |
+| Optimizer | site + sector |
+| Setup/Add Keywords | site + sector |
+
+### Account-Level Only (No Site/Sector)
+
+| Module | Filter |
+|--------|--------|
+| Billing/Plans | account only |
+| Account Settings | account only |
+| Team Management | account only |
+| User Profile | user only |
+| System Settings | account only |
+
+---
+
+## Frontend Implementation
+
+### Site Selection
+
+**Store:** `store/siteStore.ts`
+
+```typescript
+const useSiteStore = create({
+ activeSite: Site | null,
+ sites: Site[],
+ loadSites: () => Promise,
+ setActiveSite: (site: Site) => void,
+});
+```
+
+### Sector Selection
+
+**Store:** `store/sectorStore.ts`
+
+```typescript
+const useSectorStore = create({
+ activeSector: Sector | null,
+ sectors: Sector[],
+ loadSectorsForSite: (siteId: number) => Promise,
+ setActiveSector: (sector: Sector) => void,
+});
+```
+
+### Sector Loading Pattern
+
+Sectors are loaded by `PageHeader` component, not `AppLayout`:
+
+```typescript
+// PageHeader.tsx
+useEffect(() => {
+ if (hideSiteSector) return; // Skip for account pages
+
+ if (activeSite?.id && activeSite?.is_active) {
+ loadSectorsForSite(activeSite.id);
+ }
+}, [activeSite?.id, hideSiteSector]);
+```
+
+**Pages with `hideSiteSector={true}`:**
+- `/account/*` (settings, team, billing)
+- User profile pages
+
+---
+
+## Global Resources (No Tenancy)
+
+These are system-wide, not tenant-specific:
+
+| Model | Purpose |
+|-------|---------|
+| Industry | Global industry taxonomy |
+| IndustrySector | Sub-categories within industries |
+| SeedKeyword | Global keyword database |
+| GlobalIntegrationSettings | Platform API keys |
+| GlobalAIPrompt | Default prompt templates |
+| GlobalAuthorProfile | Author persona templates |
+
+---
+
+## Tenant Data vs System Data
+
+### System Data (KEEP on reset)
+
+- Plans, CreditPackages
+- Industries, IndustrySectors
+- GlobalIntegrationSettings
+- GlobalAIPrompt, GlobalAuthorProfile
+- CreditCostConfig
+- PaymentMethodConfig
+
+### Tenant Data (CLEAN on reset)
+
+- Accounts, Users, Sites, Sectors
+- Keywords, Clusters, Ideas, Tasks, Content, Images
+- Subscriptions, Invoices, Payments
+- CreditTransactions, CreditUsageLogs
+- SiteIntegrations, SyncEvents
+- AutomationConfigs, AutomationRuns
+
+---
+
+## Admin/Developer Bypass
+
+Admin and developer users can access all tenants:
+
+```python
+# In auth/models.py
+class User:
+ @property
+ def is_admin_or_developer(self):
+ return self.role in ['admin', 'developer']
+```
+
+**Bypass Rules:**
+- Admin: Full access to own account
+- Developer: Full access to ALL accounts
+- System accounts protected from deletion
+
+---
+
+## Common Issues
+
+| Issue | Cause | Fix |
+|-------|-------|-----|
+| Data leak between accounts | Missing account filter | Use AccountModelViewSet |
+| Wrong site data | Site not validated for account | Validate site.account == request.account |
+| Sector not loading | Site changed but sector not reset | Clear activeSector when activeSite changes |
+| Admin can't see all data | Incorrect role check | Check is_admin_or_developer |
+
+---
+
+## Planned Changes
+
+| Feature | Status | Description |
+|---------|--------|-------------|
+| Account switching | 🔜 Planned | Allow users to switch between accounts |
+| Sub-accounts | 🔜 Planned | Hierarchical account structure |
diff --git a/docs/10-BACKEND/MODELS.md b/docs/10-BACKEND/MODELS.md
deleted file mode 100644
index 00416c47..00000000
--- a/docs/10-BACKEND/MODELS.md
+++ /dev/null
@@ -1,110 +0,0 @@
-# Domain Models
-
-## Purpose
-Describe the key backend models, their responsibilities, constraints, and tenancy rules, grounded in current implementations.
-
-## Code Locations (exact paths)
-- Tenancy bases and identity: `backend/igny8_core/auth/models.py`
-- Planner models: `backend/igny8_core/business/planning/models.py`
-- Writer/content models: `backend/igny8_core/business/content/models.py`
-- Automation models: `backend/igny8_core/business/automation/models.py`
-- Billing models: `backend/igny8_core/business/billing/models.py`
-- Integration models: `backend/igny8_core/business/integration/models.py`
-- Publishing models: `backend/igny8_core/business/publishing/models.py`
-- Optimization models: `backend/igny8_core/business/optimization/models.py`
-
-## High-Level Responsibilities
-- Provide tenant-scoped storage for planner (keywords/clusters/ideas), writer (tasks/content/taxonomies/images/attributes), automation runs/config, billing (credits, invoices, payments), integration metadata, publishing records, and optimization tasks.
-- Enforce account/site/sector alignment via base classes and save-time validation.
-- Track external platform links (WordPress/Shopify/custom), credit usage, and publishing/optimization state.
-
-## Detailed Behavior
-### Tenancy Bases (auth/models.py)
-- `AccountBaseModel`: adds `account`, timestamps, and indexes; all tenant models inherit.
-- `SiteSectorBaseModel`: extends with `site` and `sector`; save enforces site → account alignment and sector belonging to the same site; raises validation errors if mismatched.
-
-### Planner (business/planning/models.py)
-- `Clusters`: tenant/site/sector-scoped keyword group; tracks counts, volume, mapped pages, status (`new/mapped`), disable flag; unique per site/sector by name; soft-deletable.
-- `Keywords`: tenant/site/sector-scoped keyword tied to a global `SeedKeyword`; optional overrides for volume/difficulty/attributes; optional cluster link (same sector enforced); validation ensures seed keyword industry/sector matches site/sector; status (`new/mapped`), disable flag; soft-deletable.
-- `ContentIdeas`: ideas tied to clusters and optional keywords; tracks status (`new/queued/completed`), content type/structure, estimated word count; soft-deletable.
-
-### Writer / Content (business/content/models.py)
-- `Tasks`: queue items for content generation; tied to cluster (required) and optional idea/taxonomy; content type/structure, keywords text, target word count, status (`queued/completed`); soft-deletable.
-- `Content`: generated or imported content; stores HTML, word count, SEO fields, cluster link, content type/structure, taxonomy M2M, external IDs/URLs/metadata, sync status, source (`igny8/wordpress`), and status (`draft/review/published`); soft-deletable.
-- `ContentTaxonomy`: simplified taxonomy (category/tag) with external taxonomy/ID, sync status, description, count, metadata; unique per site by slug/type and by external ID/taxonomy.
-- `Images`: images linked to content or task; auto-populates account/site/sector from the linked object; tracks type, URL/path, prompt, status, position; soft-deletable.
-- `ContentClusterMap`: maps content/tasks to clusters with role (`hub/supporting/attribute`) and source (`blueprint/manual/import`); auto-populates tenant context from linked content/task; unique per content+cluster+role.
-- `ContentAttribute` (alias `ContentAttributeMap`): tenant/site/sector-scoped attributes for content/task/cluster; typed (`product_spec/service_modifier/semantic_facet`), with optional external IDs, sources, and metadata; auto-populates tenant context from linked content/task.
-
-### Automation (business/automation/models.py)
-- `AutomationConfig`: per-site config with enable flag, frequency (`daily/weekly/monthly`), scheduled time, batch sizes per stage, within/between-stage delays, and next/last run timestamps.
-- `AutomationRun`: tracks each run with trigger (`manual/scheduled`), status (`running/paused/cancelled/completed/failed`), current stage, pause/cancel timestamps, start/end, total credits used, per-stage JSON results, and optional error message.
-
-### Billing (business/billing/models.py)
-- `CreditTransaction`: ledger of credit changes (purchase/subscription/refund/deduction/adjustment) with balance-after and metadata.
-- `CreditUsageLog`: detailed AI usage log with operation type (clustering/idea/content/image/reparse/legacy names), credits used, optional cost/model/tokens, related object references, and metadata.
-- `CreditCostConfig`: admin-configurable credit costs per operation with unit (per request/words/items/images), display metadata, active flag, audit fields, and previous cost tracking.
-- `Invoice`: tenant invoice with amounts, status (`draft/pending/paid/void/uncollectible`), dates, subscription link, line items JSON, payment metadata, Stripe IDs, notes; helper properties mirror legacy fields.
-- `Payment`: payment records per invoice with status lifecycle (pending/processing/succeeded/completed/failed/refunded/cancelled), method (Stripe/PayPal/bank/local wallet/manual), provider references, manual notes/approval fields, failure reason, timestamps, metadata.
-- `CreditPackage`: one-time credit bundles with price, discount, Stripe/PayPal IDs, active/featured flags, description/features, sort order.
-- `PaymentMethodConfig`: per-country payment-method availability and display/instruction fields; includes bank/local wallet metadata; unique per country+method.
-- `AccountPaymentMethod`: account-level payment metadata (non-sensitive) with type, display name, default/enabled/verified flags, country code, instructions, metadata; unique per account+display name.
-
-### Integration (business/integration/models.py)
-- `SiteIntegration`: tenant/site-specific integration config with platform (`wordpress/shopify/custom`), platform type (`cms/ecommerce/custom_api`), config JSON, credentials JSON, active/sync flags, sync status, last sync/error, timestamps; unique per site+platform.
-- `SyncEvent`: event log per integration/site with event/action types, success flag, optional content/external IDs, details JSON, error, duration, and timestamps; indexed for debugging feeds.
-
-### Publishing (business/publishing/models.py)
-- `PublishingRecord`: tracks content publishing to destinations (wordpress/sites/shopify) with destination IDs/URLs, status (`pending/publishing/published/failed`), timestamps, errors, metadata; site/sector scoped via base.
-- `DeploymentRecord`: tracks site deployments (sites renderer) with version/deployed_version, status (`pending/deploying/deployed/failed/rolled_back`), deployment URL, error, metadata, timestamps; site/sector scoped.
-
-### Optimization (business/optimization/models.py)
-- `OptimizationTask`: content optimization runs with before/after scores and HTML, status (`pending/running/completed/failed`), credits used, metadata; auto-sets account from content; tenant scoped.
-
-## Execution Flow
-- Tenant context is inherited from base models; many save methods propagate account/site/sector from related entities (e.g., Images, ContentClusterMap, ContentAttribute).
-- Planner → Writer linkage: Keywords and Clusters feed ContentIdeas; Tasks reference clusters/ideas; Content references clusters and taxonomies; Images/Attributes link to Tasks/Content.
-- Automation runs reference planner/writer models and record per-stage outputs; configs control batching/delays.
-- Billing logs and cost configs govern credit debits triggered by services (see services doc).
-- Integration/publishing models bind site integrations and publishing deployments to site-scoped content.
-- Optimization tasks attach to content and capture before/after artifacts.
-
-## Cross-Module Interactions
-- Planner and writer share clusters/ideas/tasks/content relationships.
-- Billing models are invoked by services during AI/automation/image/content operations.
-- Integration events reference content IDs and external IDs for sync traces.
-- Publishing records reference writer content; deployment records reference sites.
-- Optimization tasks reference writer content and can influence publishing readiness downstream.
-
-## State Transitions (if applicable)
-- Soft-delete is available on planner keywords/clusters/ideas and writer tasks/content/images via `SoftDeletableModel`.
-- Status fields track lifecycle: planner (`new/mapped/queued/completed`), writer tasks (`queued/completed`), content (`draft/review/published`), automation (`running/paused/cancelled/completed/failed`), publishing/deployment statuses, payment/invoice statuses, optimization statuses.
-
-## Error Handling
-- Save-time validation in `SiteSectorBaseModel` and `Keywords` ensures tenant/site/sector alignment and industry/sector matching.
-- Unique constraints prevent duplicate clusters/keywords per site/sector and overlapping taxonomies/external IDs.
-- Automation runs store error messages and partial stage results; publishing/deployment records store error text.
-
-## Tenancy Rules
-- All models shown are tenant scoped via `AccountBaseModel` or `SiteSectorBaseModel`; save hooks propagate context from related objects where needed.
-- Privileged roles can bypass filtering at the viewset layer, but persisted records retain account/site/sector ownership.
-
-## Billing Rules (if applicable)
-- Credits reside on `Account`; transactions/usage logs record debits/credits; cost configs define per-operation pricing.
-- Invoices/payments/credit packages configure monetary flows; payment methods can be toggled per country or per account.
-
-## Background Tasks / Schedulers (if applicable)
-- Automation configs drive scheduled runs; automation runs record stage outputs and timing.
-- Publishing/optimization tasks may be executed async via services/Celery (see services doc).
-
-## Key Design Considerations
-- Tenant isolation is encoded at the model layer via base classes and validation, ensuring downstream services inherit scoping.
-- Cross-module links (clusters ↔ tasks ↔ content ↔ publishing/optimization) keep content lifecycle traceable.
-- Billing and integration models include metadata fields to avoid schema churn while capturing provider-specific details.
-
-## How Developers Should Work With This Module
-- Inherit new tenant models from `AccountBaseModel` or `SiteSectorBaseModel` to enforce scoping automatically.
-- Validate cross-entity alignment (site/sector/industry) when relating planner and writer records.
-- Use existing status fields/choices when extending lifecycles; preserve unique constraints when adding fields.
-- When integrating new providers, extend or add models parallel to `SiteIntegration`/`SyncEvent` and keep platform-specific data in JSON fields.
-
diff --git a/docs/10-BACKEND/OVERVIEW.md b/docs/10-BACKEND/OVERVIEW.md
deleted file mode 100644
index cbf77fd8..00000000
--- a/docs/10-BACKEND/OVERVIEW.md
+++ /dev/null
@@ -1,82 +0,0 @@
-# Backend Architecture
-
-## Purpose
-Explain how the backend is structured, wired, and executed across Django/DRF, middleware, routing, async processing, and logging.
-
-## Code Locations (exact paths)
-- Settings and app wiring: `backend/igny8_core/settings.py`
-- URL routing: `backend/igny8_core/urls.py`
-- Middleware: `backend/igny8_core/middleware/request_id.py`, `backend/igny8_core/auth/middleware.py`, `backend/igny8_core/middleware/resource_tracker.py`
-- Auth stack: `backend/igny8_core/api/authentication.py`, `backend/igny8_core/auth/utils.py`
-- Base viewsets and unified responses: `backend/igny8_core/api/base.py`
-- Domain models: `backend/igny8_core/auth/models.py` plus `backend/igny8_core/business/*/models.py`
-- Async/Celery config: `backend/igny8_core/settings.py`
-- Logging: `backend/igny8_core/settings.py` (publish/webhook logs), automation logging (`backend/igny8_core/business/automation/services/automation_logger.py`)
-
-## High-Level Responsibilities
-- Django/DRF API surface under `/api/v1/*` for planner, writer, system, billing, automation, linker, optimizer, publisher, and integration modules.
-- Middleware establishes request IDs, tenant context, and optional resource tracking before views run.
-- DRF configuration standardizes pagination, filtering, authentication, throttling, and exception handling.
-- Celery + Redis provide async execution for AI, automation, publishing, and other long-running tasks.
-- Logging and CORS/security settings are centralized in settings.
-
-## Detailed Behavior
-- Apps registered in `INSTALLED_APPS` include auth, AI framework, planner, writer, system, billing, automation, optimization, publishing, integration, linker, optimizer, publisher. Custom admin config is loaded first.
-- Middleware order: security → WhiteNoise → CORS → session/common/CSRF → Django auth → `RequestIDMiddleware` → `AccountContextMiddleware` (tenant + plan enforcement) → `ResourceTrackingMiddleware` (opt-in for admin/developer with header) → messages → clickjacking.
-- Routing (`urls.py`): admin plus CSV helpers for industries/seed keywords, then `/api/v1/` routers for auth, account, planner, writer, system, billing (user/admin), automation, linker, optimizer, publisher, integration. OpenAPI served at `/api/docs` and `/api/redoc`.
-- DRF defaults: unified exception handler (unless env disables), custom pagination, filtering/search/ordering, auth stack (API key → JWT → CSRF-exempt session → basic), scoped throttling per operation class, drf-spectacular schema generation with tag ordering.
-- CORS: IGNY8 domains and local dev ports allowed; credentials enabled; request/resource tracking headers exposed.
-- Celery: Redis broker/result; JSON serialization; task/soft time limits; single-prefetch; sentinel/SSL toggles via env.
-- Logging: console plus rotating files for publish/sync, WordPress API, webhooks; request IDs from middleware surface in responses; automation has dedicated file-based logger per run.
-
-## Data Structures / Models Involved (no code)
-- Tenancy/identity: `Account`, `Plan`, `Subscription`, `Site`, `Sector`, `User`, `SiteUserAccess`, `PasswordResetToken` (in auth models).
-- Domain models across planner, writer, billing, automation, publishing, integration, optimization (see domain models doc).
-- Middleware uses request-scoped `request.account`, `request.site`, and `request.request_id`.
-
-## Execution Flow
-1) Request enters middleware stack; IDs and tenant context are set; plan is verified.
-2) DRF auth classes authenticate user/api-key/JWT/session.
-3) Base viewsets filter by tenant/site/sector and handle unified responses.
-4) Serializers validate; database writes enforce tenant alignment via model bases.
-5) Optional Celery tasks are enqueued for long-running work; responses remain synchronous JSON with pagination/throttle headers when applicable.
-6) Logging writes to configured handlers; request/resource IDs are added to responses.
-
-## Cross-Module Interactions
-- Tenant context from middleware is consumed by all module viewsets.
-- AI and automation invoke Celery tasks and AI functions; billing services deduct credits used by automation/AI flows.
-- Integration/publishing modules rely on API key auth to set `request.site` for WordPress and other platforms.
-
-## State Transitions (if applicable)
-- Account/plan validity is checked per request; system accounts are protected from deletion.
-- Soft-delete is available on many models via `SoftDeletableModel`.
-- Request lifecycle includes request ID creation, optional resource tracking, and unified response formatting.
-
-## Error Handling
-- Custom DRF exception handler wraps errors with `success=false`.
-- `AccountContextMiddleware` blocks requests lacking account or active plan (403/402 JSON).
-- Base viewsets wrap validation/404/500 errors into unified payloads.
-
-## Tenancy Rules
-- Request-level `account` (and `site`/`sector` where applicable) is injected by middleware/auth; base viewsets enforce filtering.
-- Admin/developer/system-account users bypass tenant filtering; system accounts are guarded from deletion.
-
-## Billing Rules (if applicable)
-- Billing env keys configured in settings; plan enforcement occurs in middleware; credit debits handled by billing services during operations.
-
-## Background Tasks / Schedulers (if applicable)
-- Celery worker/beat use Redis URLs from settings; task limits and JSON serialization enforced.
-- Automation, AI, publishing, and optimization tasks run async; automation logger writes per-run files.
-
-## Key Design Considerations
-- Middleware-first tenant enforcement ensures isolation.
-- Unified API standards (responses, throttles, schema) keep clients consistent.
-- Celery offloads expensive AI/automation/publishing work with bounded execution.
-- Logging and request IDs aid observability; resource tracking is opt-in for admins.
-
-## How Developers Should Work With This Module
-- Register new apps in `INSTALLED_APPS` and route them under `/api/v1/*`.
-- Use existing middleware order; add new middleware only if it does not break account/request ID handling.
-- Inherit from base viewsets for scoping and response consistency.
-- Use Celery for long-running tasks; respect Redis/task time-limit settings.
-- Keep env vars (DB, JWT, Redis, Stripe/PayPal) set per `settings.py`; avoid hardcoded secrets.
diff --git a/docs/10-BACKEND/SERVICES.md b/docs/10-BACKEND/SERVICES.md
deleted file mode 100644
index 7f06ded5..00000000
--- a/docs/10-BACKEND/SERVICES.md
+++ /dev/null
@@ -1,96 +0,0 @@
-# Services and Modules
-
-## Purpose
-Describe the backend service layer and module wiring that orchestrate domain models, AI/automation, billing, integration, and publishing.
-
-## Code Locations (exact paths)
-- Automation services: `backend/igny8_core/business/automation/services/automation_service.py`, `automation_logger.py`
-- Billing services: `backend/igny8_core/business/billing/services/credit_service.py`, `invoice_service.py`, `payment_service.py`
-- Integration service: `backend/igny8_core/business/integration/services/integration_service.py`
-- Additional service directories (see module-specific docs for details):
- - Planner: `backend/igny8_core/business/planning/services/*`
- - Content/Writer: `backend/igny8_core/business/content/services/*`
- - Automation tasks: `backend/igny8_core/business/automation/tasks.py`
- - Integration sync: `backend/igny8_core/business/integration/services/*`
- - Publishing: `backend/igny8_core/business/publishing/services/*`
- - Optimization: `backend/igny8_core/business/optimization/services/*`
- - Linking: `backend/igny8_core/business/linking/services/*`
-
-## High-Level Responsibilities
-- Orchestrate multi-stage automation that chains planner and writer operations using AI and credits.
-- Manage credit pricing, balance checks, deductions, and ledger logging.
-- Generate invoices and handle billing documents.
-- Create, update, test, and list site integrations for external platforms.
-- Provide domain-specific service hooks for planner, writer, publishing, linking, and optimization flows (behavior documented in module-specific files).
-
-## Detailed Behavior
-### Automation
-- `AutomationService` enforces single concurrent run per site via cache lock, estimates required credits, checks account balance (with buffer), and creates an `AutomationRun`. It sequences stages (keywords→clusters, clusters→ideas, ideas→tasks/content, image prompt generation, image generation queue) using AI functions (`AutoClusterFunction`, `GenerateIdeasFunction`, `GenerateContentFunction`, `GenerateImagePromptsFunction`) through `AIEngine`, and the Celery image queue (`process_image_generation_queue`). It supports pause/cancel checks mid-stage, records partial progress, and advances `current_stage` with per-stage result JSON and credit tallies. Batch sizes and delays respect `AutomationConfig`.
-- `AutomationLogger` creates per-run directories (and optional shared mirrors), generates run IDs, writes main/stage logs, mirrors to shared folders when configured, and emits structured JSONL trace events for run start, progress, completion, and errors.
-
-### Billing
-- `CreditService` computes credit cost by first consulting `CreditCostConfig` (unit-aware for words/items/images) and falling back to constants. It checks balances, deducts credits atomically, updates account balance, writes `CreditTransaction`, and logs usage in `CreditUsageLog` with optional model/token metadata. It can also add credits and provides legacy check helpers.
-- `InvoiceService` generates invoice numbers per account/month, creates invoices for subscriptions or credit packages (adding line items and computing totals), supports custom invoices, and marks invoices paid or void. PDF generation is currently a placeholder.
-- `PaymentService` (see file) processes payments against invoices and updates statuses; details are documented in the module file.
-
-### Integration
-- `IntegrationService` creates, updates, deletes, fetches, and lists `SiteIntegration` records, setting account/site automatically. It can test connections per platform (WordPress, Shopify) and delegates to platform-specific test helpers inside the service; unimplemented platforms raise `NotImplementedError`. Credentials are set via `set_credentials`, which currently stores JSON as-is.
-- Additional sync services (`content_sync_service.py`, `sync_service.py`, `sync_metadata_service.py`, `sync_health_service.py`) coordinate publish/sync flows and health checks; see module docs for specifics.
-
-### Other Service Areas (structure)
-- Planner services (`clustering_service.py`, `ideas_service.py`) handle clustering/idea logic.
-- Content services (`content_generation_service.py`, `content_pipeline_service.py`, `metadata_mapping_service.py`, `validation_service.py`) manage content generation, pipelines, metadata mapping, and validation.
-- Publishing services (`publisher_service.py`, `deployment_service.py`, `adapters/`) manage publishing/deployment flows and destination adapters.
-- Optimization services (`analyzer.py`, `optimizer_service.py`) analyze and optimize content.
-- Linking services (`candidate_engine.py`, `injection_engine.py`, `linker_service.py`) prepare and apply link suggestions.
-- Automation tasks (`business/automation/tasks.py`) provide Celery entrypoints for automation runs.
-
-## Execution Flow
-- Automation: `AutomationService.start_automation` acquires lock → credit estimate/check → create `AutomationRun` → stage methods query planner/writer models, call AI functions via `AIEngine`, respect batch sizes/delays, and update run state/logs → credits are tallied from `AITaskLog` differences.
-- Billing: operations call `CreditService.check_*`/`deduct_*` before AI or content operations; invoices are created through `InvoiceService` and payments processed via `PaymentService`.
-- Integration: API endpoints invoke `IntegrationService` to persist integrations, retrieve lists, and run connection tests; sync services handle subsequent data movement.
-- Other domains: planner/content/publishing/linking/optimization services orchestrate their models and, where applicable, AI or external adapters; see domain docs for invocation points.
-
-## Cross-Module Interactions
-- Automation stages consume planner (Keywords/Clusters/ContentIdeas) and writer (Tasks/Content/Images) data and rely on credit usage logs from AI tasks.
-- Billing services are used by automation/AI flows to enforce credit availability and record deductions.
-- Integration services connect site data and publishing/sync flows to external platforms; publishing services depend on integration metadata when targeting destinations.
-- Planner/content services feed data used by publishing and optimization tasks.
-
-## State Transitions (if applicable)
-- Automation runs move through stages, can pause/cancel, and record partial progress with stage result JSON.
-- Credit balances mutate through add/deduct operations; transactions/usage logs capture each change.
-- Invoices progress through draft/pending/paid/void and payments through their status lifecycle.
-- Integrations toggle active/sync flags and update sync status/errors.
-
-## Error Handling
-- Automation: checks for concurrent runs; validates minimum keywords; pauses/cancels mid-stage; writes stage error messages; releases locks on failures.
-- Billing: raises when credit cost unknown or balance insufficient; wraps changes in atomic transactions.
-- Integration: platform test errors are logged and returned with `success=false`; unsupported platforms raise `NotImplementedError`.
-- Invoice service prevents voiding paid invoices and returns placeholder PDF until implemented.
-
-## Tenancy Rules
-- Services operate on tenant-scoped models; constructors typically receive account/site or derive them from models. Integration creation sets account from site; credit operations mutate `Account.credits`.
-- Privileged role bypass applies at the viewset layer; persisted records maintain account/site ownership.
-
-## Billing Rules (if applicable)
-- Costs resolved via `CreditCostConfig` (preferred) or constants; units can be per request, words (100/200), item, or image.
-- Deduct operations both adjust `Account.credits` and log to `CreditTransaction` and `CreditUsageLog`.
-- Invoice creation links to subscriptions or credit packages and uses account billing email/plan pricing.
-
-## Background Tasks / Schedulers (if applicable)
-- Automation uses Celery for image generation and may be triggered by scheduled runs (frequency/time in `AutomationConfig`).
-- Other long-running tasks (publishing, optimization, sync) are handled via their Celery tasks/adapters in respective service modules.
-
-## Key Design Considerations
-- Automation enforces exclusivity per site and accounts for credit sufficiency before starting.
-- Logging (AutomationLogger) produces per-run artifacts and structured traces for observability.
-- Credit handling is centralized to keep ledger and usage logs consistent and atomic.
-- Integration services abstract platform handling and allow per-platform test logic.
-
-## How Developers Should Work With This Module
-- Reuse `AutomationService` for running/continuing automation; respect locks and stage APIs.
-- Use `CreditService` before AI/content-heavy operations to check/deduct/add credits and to log usage.
-- Create invoices via `InvoiceService` helpers rather than constructing manually; update invoice/payment status through service methods.
-- Manage integrations through `IntegrationService` (create/update/test/list) and extend platform-specific tests as needed.
-- For domain-specific flows (planner/content/publishing/linking/optimization), place orchestration in the existing service modules and keep tenant context explicit.
diff --git a/docs/10-BACKEND/accounts/ACCOUNTS-REFERENCE.md b/docs/10-BACKEND/accounts/ACCOUNTS-REFERENCE.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/docs/10-BACKEND/automation/AUTOMATION-REFERENCE.md b/docs/10-BACKEND/automation/AUTOMATION-REFERENCE.md
deleted file mode 100644
index 60e1cc5b..00000000
--- a/docs/10-BACKEND/automation/AUTOMATION-REFERENCE.md
+++ /dev/null
@@ -1,91 +0,0 @@
-# Automation Module Reference
-
-## Purpose
-Document how the automation module orchestrates multi-stage AI pipelines, exposes API endpoints, enforces tenancy/credits, and manages runs, configs, and logging.
-
-## Code Locations (exact paths)
-- Models: `backend/igny8_core/business/automation/models.py`
-- Services: `backend/igny8_core/business/automation/services/automation_service.py`, `automation_logger.py`
-- Tasks (Celery): `backend/igny8_core/business/automation/tasks.py`
-- API views and routing: `backend/igny8_core/business/automation/views.py`, `urls.py`
-- Supporting AI functions: `backend/igny8_core/ai/functions/auto_cluster.py`, `generate_ideas.py`, `generate_content.py`, `generate_image_prompts.py`, image queue in `backend/igny8_core/ai/tasks.py`
-- Tenancy/auth context: `backend/igny8_core/auth/middleware.py`, `backend/igny8_core/api/base.py`
-
-## High-Level Responsibilities
-- Maintain per-site automation configs (batch sizes, delays, schedule, enable flag) and track run state with detailed per-stage results.
-- Provide APIs to configure, trigger, pause/resume/cancel, inspect, and log automation runs.
-- Execute seven sequential stages that transform planner/writer data via AI and local operations, with credit checks and pause/cancel handling.
-- Enforce tenant/site scoping on all automation resources and API operations.
-
-## Detailed Behavior
-- `AutomationConfig` stores enablement, frequency, scheduled time, batch sizes for stages 1–6, and within/between-stage delays. Config is created lazily per site.
-- `AutomationRun` captures run metadata: trigger type (manual/scheduled), status (`running/paused/cancelled/completed/failed`), current stage, pause/cancel timestamps, per-stage JSON results, total credits used, and error message.
-- `AutomationService` orchestrates the pipeline:
- - Locks per site via cache (`automation_lock_{site.id}`) to prevent concurrent runs.
- - Estimates credits before start and requires a 20% buffer over the estimate against `Account.credits`.
- - Creates `AutomationRun` with generated `run_id` and logs start via `AutomationLogger`.
- - Executes stages in order; each stage logs start/progress/complete, applies within/between-stage delays from config, and writes stage result JSON (counts, credits, timestamps, partial flags).
- - Pause/cancel checks occur inside loops; state is persisted so resumed runs continue from the recorded stage.
- - Stage credit usage is derived from AI task logs difference before/after the stage.
-- API layer (`AutomationViewSet`):
- - `config`/`update_config` read/write `AutomationConfig` for a given `site_id` (scoped to the user’s account).
- - `run_now` triggers `AutomationService.start_automation` and enqueues Celery `run_automation_task`.
- - `current_run`, `history`, `logs`, `current_processing`, `estimate`, `pipeline_overview` expose run status, history, logs, credit estimates, and per-stage pending counts.
- - `pause`, `resume`, `cancel` endpoints update run status and enqueue resume tasks when needed.
-- Celery tasks:
- - `check_scheduled_automations` scans enabled configs hourly and triggers runs when frequency/time matches and no recent run exists.
- - `run_automation_task` performs full pipeline execution.
- - `resume_automation_task`/`continue_automation_task` continue a paused run from its recorded stage.
-
-## Data Structures / Models Involved (no code)
-- `AutomationConfig`, `AutomationRun` (automation state).
-- Planner models: `Keywords`, `Clusters`, `ContentIdeas`.
-- Writer models: `Tasks`, `Content`, `Images`.
-- AI task log (`AITaskLog`) for credit usage measurement.
-- Tenancy entities: `Account`, `Site` (scoping every query).
-
-## Execution Flow
-- API call → DRF auth → tenant/site resolved → viewset method → `AutomationService` operations → Celery task (for long-running execution).
-- Pipeline stages run in-process inside Celery workers, reading planner/writer data, invoking AI functions, updating models, logging progress, and writing stage results to `AutomationRun`.
-- Completion (or failure) updates run status and releases the site lock.
-
-## Cross-Module Interactions
-- Planner/writer models supply inputs and receive outputs (clusters, ideas, tasks, content, images).
-- AI engine executes clustering, idea generation, content generation, and image prompt generation; image rendering uses the AI image queue.
-- Billing credits are checked against `Account.credits`; credit usage is inferred from AI task logs (deduction logic handled in billing services when those AI calls occur).
-- Integration/publishing modules consume content/images produced downstream (outside automation).
-
-## State Transitions
-- Run status moves through `running` → (`paused`/`cancelled`/`failed`/`completed`); `current_stage` increments after each stage finishes; partial flags and timestamps mark mid-stage exits.
-- Config changes take effect on the next run; pause/resume toggles update run timestamps.
-
-## Error Handling
-- Start blocks if a run is already active for the site or cache lock is held.
-- Stage loops log and continue on per-batch/item errors; pause/cancel results are persisted mid-stage.
-- Failures in Celery run mark `AutomationRun` as failed, store error message, timestamp completion, and release the lock.
-- API endpoints return 400 for missing params or invalid state transitions, 404 for unknown runs, 500 on unexpected errors.
-
-## Tenancy Rules
-- All automation queries filter by `site` tied to the authenticated user’s `account`; config/run creation sets `account` and `site` explicitly.
-- API endpoints fetch `Site` with `account=request.user.account`; automation locks are per site.
-- No cross-tenant access; privileged role bypass is handled by DRF auth/permissions upstream.
-
-## Billing Rules
-- Start requires `Account.credits` ≥ 1.2× estimated credits; otherwise a 400 is returned.
-- Credits actually deducted by AI tasks are reflected via AI task logs and billing services (outside this module); automation aggregates usage per stage in `AutomationRun`.
-
-## Background Tasks / Schedulers
-- Hourly `check_scheduled_automations` respects config frequency/time and last run; skips if a run is already active.
-- Pipeline execution and resume steps run inside Celery tasks; within-stage sleeps apply delays from config.
-
-## Key Design Considerations
-- Single-run-per-site enforced via cache lock to prevent overlapping credit use or data contention.
-- Pause/resume/cancel is cooperative, checked inside stage loops, with partial results persisted.
-- Stage-by-stage logging and result JSON make pipeline progress observable and resumable.
-- Configurable batch sizes and delays balance throughput and API/credit usage.
-
-## How Developers Should Work With This Module
-- Use `AutomationService.start_automation` for new runs; never bypass the cache lock or credit check.
-- When extending stages, preserve pause/cancel checks, result recording, and credit delta calculation.
-- Add new API actions through `AutomationViewSet` if they manipulate automation state; keep site/account scoping.
-- For new schedulers, reuse the lock pattern and `AutomationConfig` fields, and update `next_run_at` appropriately.
diff --git a/docs/10-BACKEND/automation/PIPELINE-STAGES.md b/docs/10-BACKEND/automation/PIPELINE-STAGES.md
deleted file mode 100644
index df2bbeca..00000000
--- a/docs/10-BACKEND/automation/PIPELINE-STAGES.md
+++ /dev/null
@@ -1,102 +0,0 @@
-# Automation Pipeline Stages
-
-## Purpose
-Detail the seven pipeline stages executed by `AutomationService`, including inputs, queries, validations, delays, credit handling, and state recording.
-
-## Code Locations (exact paths)
-- Orchestration: `backend/igny8_core/business/automation/services/automation_service.py`
-- Models: `backend/igny8_core/business/automation/models.py`
-- AI functions: `backend/igny8_core/ai/functions/auto_cluster.py`, `generate_ideas.py`, `generate_content.py`, `generate_image_prompts.py`
-- Image queue: `backend/igny8_core/ai/tasks.py` (`process_image_generation_queue`)
-- Stage entrypoints: `backend/igny8_core/business/automation/tasks.py` (Celery `run_automation_task`, `resume_automation_task`)
-
-## High-Level Responsibilities
-- Execute a fixed seven-stage sequence that moves data from planner keywords through content with images and into manual review readiness.
-- Enforce batch sizes/delays from `AutomationConfig`, support pause/cancel, and write per-stage results into `AutomationRun`.
-- Track credit deltas per stage using AI task log counts.
-
-## Detailed Behavior
-Across all stages:
-- Each stage logs start/progress/complete via `AutomationLogger`, respects `within_stage_delay` between batches/items, and `between_stage_delay` between stages.
-- Pause/cancel is checked inside loops; on pause/cancel, the stage records partial counts, credits, elapsed time, and reason, then exits.
-- Credits used per stage are computed from `AITaskLog` count delta relative to stage start.
-
-### Stage 1: Keywords → Clusters (AI)
-- Input query: `Keywords` where `site=current`, `status='new'`, `cluster__isnull=True`, `disabled=False`.
-- Validation: `validate_minimum_keywords` requires at least 5 keywords; if not valid, stage is skipped with result noting skip reason and `current_stage` advances to 2.
-- Processing: Batch size = `stage_1_batch_size` (capped to total). For each batch, calls `AIEngine.execute(AutoClusterFunction, payload={'ids': batch})`; waits on task ID; logs per-batch progress. Errors are logged and skipped; pipeline continues.
-- Result: counts keywords processed, clusters created since run start, batches, credits used, time elapsed; sets `current_stage=2`.
-
-### Stage 2: Clusters → Ideas (AI)
-- Pre-check: warns if any `Keywords` still pending from Stage 1.
-- Input query: `Clusters` where `site=current`, `status='new'`, `disabled=False`.
-- Processing: Iterates clusters one-by-one; for each, calls `AIEngine.execute(GenerateIdeasFunction, payload={'cluster_id': cluster.id})`; waits on task ID; logs progress. Errors are logged and skipped.
-- Result: counts clusters processed, ideas created since run start, credits used, time elapsed; sets `current_stage=3`.
-
-### Stage 3: Ideas → Tasks (Local)
-- Pre-check: warns if clusters remain without ideas.
-- Input query: `ContentIdeas` where `site=current`, `status='new'`.
-- Processing: Batched by `stage_3_batch_size`. For each idea, builds keyword string (M2M keywords or `target_keywords`) and creates `Tasks` with queued status, copying account/site/sector, cluster, content type/structure, and description. Idea status set to `queued`.
-- Result: ideas processed, tasks created, batches, time elapsed (credits 0 because local); sets `current_stage=4`.
-
-### Stage 4: Tasks → Content (AI)
-- Pre-check: warns if `ContentIdeas` remain `new`.
-- Input query: `Tasks` where `site=current`, `status='queued'`.
-- Processing: Batched by `stage_4_batch_size`. Uses `GenerateContentFunction` via `AIEngine` per batch (payload contains task IDs). Waits on task IDs, logs progress, continues on errors. Tracks total words by summing generated content word_count.
-- Result: tasks processed, content created count, total_words, credits used, time elapsed; sets `current_stage=5`.
-
-### Stage 5: Content → Image Prompts (AI)
-- Input query: `Content` where `site=current`, `status='draft'`, with zero images (annotated count=0).
-- Processing: Batched by `stage_5_batch_size`. For each batch, calls `GenerateImagePromptsFunction` via `AIEngine` (payload content IDs). Waits on task IDs, logs progress; continues on errors.
-- Result: content processed, prompts created (from AI task logs), credits used, time elapsed; sets `current_stage=6`.
-
-### Stage 6: Image Prompts → Images (AI image queue)
-- Input query: `Images` where `site=current`, `status='pending'`.
-- Processing: Iterates pending images; for each, enqueues `process_image_generation_queue.delay(image_ids=[id], account_id, content_id)` when Celery is available, or calls directly in sync fallback. Waits on task IDs with continue-on-error to avoid blocking the stage. Logs progress per image; applies within-stage delay between images.
-- Result: images processed, images generated (status `generated` since run start), content moved to `review`, credits used, time elapsed; sets `current_stage=7`.
-
-### Stage 7: Manual Review Gate (Count-only)
-- Input query: `Content` where `site=current`, `status='review'`.
-- Processing: Counts review-ready content, logs IDs (truncated), marks run `status='completed'`, sets `completed_at`, and releases the site lock.
-- Result: ready_for_review count and content IDs stored in `stage_7_result`.
-
-## Execution Flow
-- Celery task `run_automation_task` instantiates `AutomationService.from_run_id` and calls stages 1→7 sequentially.
-- Stage transitions update `AutomationRun.current_stage`; between-stage delays applied via `between_stage_delay`.
-- Resume path (`resume_automation_task`) starts from the recorded `current_stage` and continues through remaining stages.
-
-## Cross-Module Interactions
-- Planner: Stage 1/2 use `Keywords`/`Clusters`; Stage 3 converts `ContentIdeas` into `Tasks`.
-- Writer: Stages 4–6 create `Content` and `Images` and move content toward review.
-- AI engine and functions are invoked in Stages 1, 2, 4, 5; Stage 6 uses the AI image queue.
-- Billing: Credits are consumed by AI calls; automation records deltas per stage from AI task logs.
-
-## State Transitions
-- `AutomationRun.status` moves to `completed` at Stage 7; can be set to `failed` on exceptions or `cancelled` via API; `paused` can be set mid-run and resumed.
-- `current_stage` increments after each successful stage; partial stage results include a `partial` flag and stop reason.
-- Domain models change status along the pipeline (`Keywords` → clusters, `Clusters` → ideas, `ContentIdeas` → queued/tasks, `Tasks` → completed/content, `Content` → draft/review, `Images` → generated).
-
-## Error Handling
-- Each stage logs errors and continues to next batch/item; pause/cancel checks short-circuit with partial results saved.
-- Task wait helper tolerates Celery backend errors; can continue on error when flagged.
-- Stage start may be skipped with explicit skip reason (e.g., insufficient keywords).
-
-## Tenancy Rules
-- All queries filter by `site` (and implicit account via tenancy bases); account/site set on created `Tasks` and inherited on `Images` and other records through model save hooks.
-- Locks and runs are per site; API scoping requires the authenticated user’s account to own the site.
-
-## Billing Rules
-- Start requires sufficient credits (1.2× estimate). Credits used are inferred from AI task log counts per stage; actual deductions occur in AI/billing services invoked by the AI functions.
-
-## Background Tasks / Schedulers
-- Entire stage chain runs inside Celery workers; within-stage sleeps respect config delays; between-stage sleeps applied after each stage.
-
-## Key Design Considerations
-- Idempotent, resume-capable progression with partial state persisted in `AutomationRun`.
-- Configurable batch sizes/delays mitigate rate limits and manage credit burn.
-- Continue-on-error semantics prevent single failures from stopping the pipeline while still recording issues.
-
-## How Developers Should Work With This Module
-- When modifying stages, keep pause/cancel checks, stage result recording, and credit delta calculation.
-- Add new AI stages by wiring through `AIEngine.execute` and the task wait helper; ensure queries are site-scoped and statuses updated.
-- For new items types, add pending queries and status transitions consistent with existing patterns.
diff --git a/docs/10-BACKEND/automation/SCHEDULER.md b/docs/10-BACKEND/automation/SCHEDULER.md
deleted file mode 100644
index 1e327a15..00000000
--- a/docs/10-BACKEND/automation/SCHEDULER.md
+++ /dev/null
@@ -1,75 +0,0 @@
-# Automation Scheduler
-
-## Purpose
-Describe how scheduled runs are detected, triggered, and resumed using Celery tasks and automation configs.
-
-## Code Locations (exact paths)
-- Celery tasks: `backend/igny8_core/business/automation/tasks.py`
-- Models: `backend/igny8_core/business/automation/models.py`
-- Service invoked: `backend/igny8_core/business/automation/services/automation_service.py`
-
-## High-Level Responsibilities
-- Periodically scan enabled automation configs to start scheduled runs.
-- Prevent overlapping runs per site via cache locks and active run checks.
-- Resume paused runs from their recorded stage.
-
-## Detailed Behavior
-- `check_scheduled_automations` (Celery, hourly):
- - Iterates `AutomationConfig` with `is_enabled=True`.
- - Frequency rules:
- - `daily`: run when current hour matches `scheduled_time.hour`.
- - `weekly`: run Mondays at the scheduled hour.
- - `monthly`: run on the 1st of the month at the scheduled hour.
- - Skips if `last_run_at` is within ~23 hours or if an `AutomationRun` with `status='running'` exists for the site.
- - On trigger: instantiates `AutomationService(account, site)`, calls `start_automation(trigger_type='scheduled')`, updates `last_run_at` and `next_run_at` (via `_calculate_next_run`), saves config, and enqueues `run_automation_task.delay(run_id)`.
- - Exceptions are logged per site; lock release is handled by the service on failure paths.
-- `run_automation_task`:
- - Loads service via `from_run_id`, runs stages 1–7 sequentially.
- - On exception: marks run failed, records error/completed_at, and deletes site lock.
-- `resume_automation_task` / alias `continue_automation_task`:
- - Loads service via `from_run_id`, uses `current_stage` to continue remaining stages.
- - On exception: marks run failed, records error/completed_at.
-- `_calculate_next_run`:
- - Computes next run datetime based on frequency and `scheduled_time`, resetting seconds/microseconds; handles month rollover for monthly frequency.
-
-## Data Structures / Models Involved (no code)
-- `AutomationConfig`: contains schedule fields (`frequency`, `scheduled_time`, `last_run_at`, `next_run_at`, `is_enabled`).
-- `AutomationRun`: records run status/stage used during resume/failure handling.
-
-## Execution Flow
-1) Celery beat (or cron) invokes `check_scheduled_automations` hourly.
-2) Eligible configs spawn new runs via `AutomationService.start_automation` (includes lock + credit check).
-3) `run_automation_task` executes the pipeline asynchronously.
-4) Paused runs can be resumed by enqueueing `resume_automation_task`/`continue_automation_task`, which restart at `current_stage`.
-5) Failures set run status to `failed` and release locks.
-
-## Cross-Module Interactions
-- Uses planner/writer data inside the pipeline (see pipeline doc); billing/credits enforced at start.
-- Locking is done via Django cache, independent of other modules but prevents concurrent Celery runs per site.
-
-## State Transitions
-- Config timestamps (`last_run_at`, `next_run_at`) update on scheduled launch.
-- Run status changes to `failed` on task exceptions; to `completed` at stage 7; to `paused/cancelled` via API.
-
-## Error Handling
-- Scheduled start is skipped with log messages if recently run or already running.
-- Exceptions during run execution mark the run failed, record error message, set `completed_at`, and release the cache lock.
-
-## Tenancy Rules
-- Configs and runs are site- and account-scoped; scheduler uses stored account/site from the config; no cross-tenant scheduling.
-
-## Billing Rules
-- Start uses `AutomationService.start_automation`, which enforces credit sufficiency before scheduling the Celery execution.
-
-## Background Tasks / Schedulers
-- Hourly `check_scheduled_automations` plus the long-running `run_automation_task` and resume tasks run in Celery workers.
-
-## Key Design Considerations
-- Hourly scan with coarse matching keeps implementation simple while honoring per-site schedules.
-- Cache lock and active-run checks prevent double-starts from overlapping schedules or manual triggers.
-- Resume task reuses the same stage methods to keep behavior consistent between fresh and resumed runs.
-
-## How Developers Should Work With This Module
-- When adding new frequencies, extend `check_scheduled_automations` and `_calculate_next_run` consistently.
-- Ensure Celery beat (or an equivalent scheduler) runs `check_scheduled_automations` hourly in production.
-- Preserve lock acquisition and failure handling when modifying task flows to avoid orphaned locks.
diff --git a/docs/10-BACKEND/billing/BILLING-REFERENCE.md b/docs/10-BACKEND/billing/BILLING-REFERENCE.md
deleted file mode 100644
index b0f891d2..00000000
--- a/docs/10-BACKEND/billing/BILLING-REFERENCE.md
+++ /dev/null
@@ -1,98 +0,0 @@
-# Billing Module Reference
-
-## Purpose
-Explain how billing is implemented: invoices, payments, credit packages, credit history/usage, payment methods, and limits, as exposed by billing services and API viewsets.
-
-## Code Locations (exact paths)
-- Models: `backend/igny8_core/business/billing/models.py`
-- Services: `backend/igny8_core/business/billing/services/credit_service.py`, `invoice_service.py`, `payment_service.py`
-- API (business billing): `backend/igny8_core/business/billing/views.py`, `backend/igny8_core/business/billing/urls.py`
-- API (core billing endpoints): `backend/igny8_core/modules/billing/views.py`, `backend/igny8_core/modules/billing/urls.py`
-- Plan metadata (included credits/limits): `backend/igny8_core/auth/models.py` (`Plan`, `Account`)
-
-## High-Level Responsibilities
-- Maintain credit ledger, usage logs, configurable per-operation costs, invoices, payments, credit packages, country-level payment method configs, and account-scoped payment methods.
-- Expose endpoints for invoices/payments/credit packages/transactions, credit balance/usage/limits, and admin billing operations.
-- Deduct or add credits atomically while recording both transactions and usage logs.
-- Provide manual and (placeholder) Stripe/PayPal payment flows.
-
-## Detailed Behavior
-- Invoices (`InvoiceViewSet`):
- - `list`/`retrieve`: fetch account-scoped invoices; include totals, line items, billing period, dates.
- - `download_pdf`: returns PDF bytes from `InvoiceService.generate_pdf` (currently placeholder text payload).
-- Payments (`PaymentViewSet`):
- - `list`: account-scoped payments with amounts, methods, status, invoice linkage, timestamps.
- - `available_methods`: delegates to `PaymentService.get_available_payment_methods` (country/config-driven; returns methods plus metadata).
- - `create_manual_payment`: creates a manual payment for an invoice (bank/local wallet); requires invoice_id, method, reference; rejects already-paid invoices; returns pending-approval status.
-- Account payment methods (`AccountPaymentMethodViewSet`):
- - CRUD for account-level payment metadata (non-sensitive). `perform_create`/`perform_update` enforce one default by resetting others when `is_default` true or none exists.
- - `set_default` toggles default within the account.
-- Credit packages (`CreditPackageViewSet`):
- - `list`: active packages with credits/price/discount/featured/sort order.
- - `purchase`: creates invoice via `InvoiceService.create_credit_package_invoice`; returns next action depending on requested payment method (`stripe`/`paypal` placeholders, manual fallback returns invoice info).
-- Credit transactions (`CreditTransactionViewSet` in business billing views; also registered under `credits/transactions` in URLs): lists credit ledger entries per account.
-- Core billing endpoints (`modules/billing/views.py`):
- - `CreditBalanceViewSet.list`: returns current credits, plan monthly credits, credits used this month.
- - `CreditUsageViewSet`: paginated credit usage logs with filters (operation_type, date range); `summary` aggregates by operation/model and totals (credits, USD); `limits` returns plan/account limits and usage (users/sites/etc.) based on `Plan` fields.
-- Routing (`business/billing/urls.py`):
- - Routers for invoices, payments, credit packages, transactions, payment methods, and canonical credit endpoints (balance/usage/transactions). Legacy available-methods endpoint exposed at `/payment-methods/available/`.
-
-## Data Structures / Models Involved (no code)
-- `CreditTransaction`: ledger with type, amount (positive/negative), balance_after, metadata.
-- `CreditUsageLog`: per-AI-operation usage with operation_type, credits_used, cost_usd, model_used, tokens, related object references, metadata.
-- `CreditCostConfig`: per-operation cost config with unit, display metadata, active flag, audit of previous cost.
-- `Invoice`: invoice_number, status, amounts (subtotal/tax/total), currency, billing_period, line_items JSON, subscription link, payment metadata, timestamps.
-- `Payment`: status lifecycle, method (stripe/paypal/bank/local wallet/manual), provider references, manual notes/approval, failure reason, metadata.
-- `CreditPackage`, `PaymentMethodConfig` (country/method availability + instructions/bank/local wallet data), `AccountPaymentMethod` (account-scoped payment metadata).
-- Plan/account credits and limits: `Plan.included_credits`, `Plan.max_users/sites/industries/author_profiles`, `Account.credits`.
-
-## Execution Flow
-- Credits:
- - Operations call `CreditService.get_credit_cost` → `check_credits`/`deduct_credits` or `deduct_credits_for_operation` → updates `Account.credits`, writes `CreditTransaction` and `CreditUsageLog`.
- - Costs resolved from `CreditCostConfig` when active; otherwise constants. Units support per request, per 100/200 words, per item/image/idea.
-- Invoicing/Payments:
- - Credit package purchase → invoice creation → next-action response (manual vs pending Stripe/PayPal integration).
- - Manual payment submission → `PaymentService.create_manual_payment` persists pending approval.
-- Credit balance/usage:
- - Balance endpoint computes plan credits and month-to-date usage (from `CreditUsageLog`).
- - Usage endpoint filters logs; summary aggregates by operation/model and totals; limits endpoint computes plan-based limits and usage (users/sites/etc.) per account.
-
-## Cross-Module Interactions
-- AI/automation/planner/writer flows trigger credit checks/deductions through `CreditService`; usage logs can be filtered by operation_type (clustering, idea_generation, content_generation, image_generation, optimization, reparse).
-- Plan limits surfaced in billing limits endpoint affect account/user/site management elsewhere.
-- Invoice/payment metadata may be used by frontend billing UI; manual payments require admin follow-up.
-
-## State Transitions
-- Credits mutate `Account.credits`; ledger captures each change; usage logs accumulate per operation.
-- Invoices move through statuses (`draft/pending/paid/void/uncollectible`); payments through (`pending/pending_approval/processing/succeeded/completed/failed/refunded/cancelled`).
-- Credit packages and payment methods have active/default flags; cost configs can be toggled active/inactive.
-
-## Error Handling
-- Insufficient credits raise `InsufficientCreditsError`; API returns 402 when caught (e.g., content generation, credit deduct flows).
-- Manual payment rejects missing fields or already-paid invoices.
-- Usage/balance endpoints return empty data when account/plan missing instead of hard errors.
-- Validation errors on site/sector/account scoping propagate from base viewsets and model constraints.
-
-## Tenancy Rules
-- Account scoping enforced via `AccountModelViewSet` or explicit account filtering in viewsets; all billing data is per-account.
-- Payment methods, invoices, payments, transactions, usage logs, and balances are filtered to `request.user.account` (or `request.account` from middleware).
-- Plan data comes from the account’s associated plan; no cross-tenant visibility.
-
-## Billing Rules
-- Credit costs configurable via `CreditCostConfig`; fallback constants apply when no config.
-- Credit deductions and ledger entries are atomic; usage logs record the same operation with optional model/token metadata.
-- Balance endpoint includes plan monthly credits; limits endpoint reports plan/user/site limits but does not enforce them here.
-
-## Background Tasks / Schedulers
-- None specific to billing in this module; Stripe/PayPal integrations are placeholders. Any future webhooks should persist to these models and adjust credits/invoices/payments accordingly.
-
-## Key Design Considerations
-- Credit handling is centralized in `CreditService` to keep ledger and usage logs consistent.
-- Usage/balance endpoints are read-mostly, with graceful handling when plan/account data is missing.
-- Manual payments support bank/local wallet flows without storing sensitive data; account payment methods store display metadata only.
-
-## How Developers Should Work With This Module
-- Use `CreditService` for all credit checks/deductions/additions; do not mutate `Account.credits` directly.
-- When adding new AI operations, add `operation_type` to `CreditUsageLog.OPERATION_TYPE_CHOICES` and `CreditCostConfig` seed/constants, then use `deduct_credits_for_operation`.
-- Extend payment flows by implementing Stripe/PayPal handlers in `PaymentService` and wiring webhooks to update `Payment`/`Invoice`.
-- Use existing serializers/viewsets when exposing billing data; keep queries scoped to `request.account`.
diff --git a/docs/10-BACKEND/billing/CREDITS-SYSTEM.md b/docs/10-BACKEND/billing/CREDITS-SYSTEM.md
deleted file mode 100644
index 47f60528..00000000
--- a/docs/10-BACKEND/billing/CREDITS-SYSTEM.md
+++ /dev/null
@@ -1,80 +0,0 @@
-# Credit System
-
-## Purpose
-Detail how credits are priced, checked, deducted, logged, and reported across the platform.
-
-## Code Locations (exact paths)
-- Credit logic: `backend/igny8_core/business/billing/services/credit_service.py`
-- Credit costs config: `backend/igny8_core/business/billing/models.py` (`CreditCostConfig`)
-- Ledger and usage logs: `backend/igny8_core/business/billing/models.py` (`CreditTransaction`, `CreditUsageLog`)
-- API endpoints: `backend/igny8_core/modules/billing/views.py` (`CreditBalanceViewSet`, `CreditUsageViewSet`)
-- Constants and exceptions: `backend/igny8_core/business/billing/constants.py`, `exceptions.py`
-- Plan included credits: `backend/igny8_core/auth/models.py` (`Plan.included_credits`, `Account.credits`)
-
-## High-Level Responsibilities
-- Compute operation costs (configurable per operation and unit) and enforce sufficient balance before AI/content actions.
-- Deduct or add credits atomically while writing both transaction and usage log records.
-- Provide balance, usage history, summaries, and limits endpoints for clients.
-- Allow admin-configurable cost overrides via `CreditCostConfig`.
-
-## Detailed Behavior
-- Cost resolution (`CreditService.get_credit_cost`):
- - First checks `CreditCostConfig` for the operation (active records). Supports units: `per_request`, `per_100_words`, `per_200_words`, `per_item`, `per_image`. Applies amounts when provided (e.g., words, items, images).
- - Falls back to hardcoded `CREDIT_COSTS` constants; raises `CreditCalculationError` for unknown operations.
- - Legacy variable costs: content_generation per 100 words, optimization per 200 words, image_generation per image, idea_generation per idea.
-- Balance enforcement:
- - `check_credits`/`check_credits_legacy` raise `InsufficientCreditsError` when balance insufficient.
- - `deduct_credits_for_operation` computes cost, checks balance, builds a default description per operation when not supplied, then calls `deduct_credits`.
-- Deduction (`deduct_credits`):
- - Atomic: decrements `Account.credits`, writes `CreditTransaction` with negative amount and balance_after, writes `CreditUsageLog` capturing operation_type, cost_usd/model/tokens/related object references, metadata.
-- Add credits (`add_credits`):
- - Atomic: increments `Account.credits`, writes `CreditTransaction` with positive amount and balance_after.
-- Logging:
- - `CreditTransaction` is the authoritative ledger; `CreditUsageLog` tracks per-operation usage for analytics and summaries.
- - `CreditCostConfig` tracks `previous_cost` on save when cost changes.
-- Reporting endpoints (modules/billing):
- - `CreditBalanceViewSet.list`: returns current credits, plan monthly credits, credits used this month (from `CreditUsageLog`), and remaining credits.
- - `CreditUsageViewSet.list`: paginated usage logs filtered by operation_type and date range, account-scoped.
- - `CreditUsageViewSet.summary`: aggregates credits and USD cost by operation and model over a date range (defaults to current month).
- - `CreditUsageViewSet.limits`: returns plan limits (users/sites/industries/author profiles) and current usage counts, plus credits info; returns empty limits if account/plan missing.
-
-## Data Structures / Models Involved (no code)
-- `CreditCostConfig`: operation_type, credits_cost, unit, display_name, description, is_active, previous_cost, updated_by, timestamps.
-- `CreditTransaction`: transaction_type (purchase/subscription/refund/deduction/adjustment), amount (+/-), balance_after, description, metadata, reference_id, created_at.
-- `CreditUsageLog`: operation_type (clustering/idea_generation/content_generation/image_generation/reparse/legacy names), credits_used, cost_usd, model_used, tokens_in/out, related object type/id, metadata, created_at.
-- `Account.credits`: current balance; `Plan.included_credits`: monthly included credits.
-
-## Execution Flow
-- Caller requests an operation → `get_credit_cost` computes cost → `check_credits` ensures balance → `deduct_credits` mutates balance and writes ledger + usage → upstream operation proceeds (AI/content).
-- Balance/usage endpoints read from `Account`, `CreditUsageLog`, `Plan` to present current balances, month-to-date usage, summaries, and limits.
-
-## Cross-Module Interactions
-- AI/automation/planner/writer services call `CreditService` before expensive operations; automation aggregates credits used per stage from AI task logs, while billing logs capture actual deductions at AI call sites.
-- Plan limits (users/sites/industries/authors) referenced in billing limits endpoint inform account management elsewhere.
-
-## State Transitions
-- Balance changes recorded per transaction; usage accumulates per operation. Cost configs can be toggled active/inactive and updated with audit of previous cost.
-
-## Error Handling
-- Unknown operation types raise `CreditCalculationError`; insufficient balance raises `InsufficientCreditsError` (mapped to HTTP 402 in callers).
-- Balance/usage endpoints fall back to zeros/empty when account/plan missing rather than erroring.
-
-## Tenancy Rules
-- All credit operations and queries are account-scoped; viewsets filter by `request.account`/`request.user.account`. No cross-tenant access.
-
-## Billing Rules
-- Costs derived from `CreditCostConfig` > constants; units must match supplied amount. Ledger and usage logs are mandatory for every deduction/addition.
-
-## Background Tasks / Schedulers
-- None dedicated; credit usage often originates from AI Celery tasks but logging happens at the service call site.
-
-## Key Design Considerations
-- Centralized credit math and atomic DB updates prevent drift between balance, ledger, and usage logs.
-- Configurable costs allow runtime tuning without code changes.
-- Reporting endpoints are read-only and tolerant of missing plan data to keep dashboards resilient.
-
-## How Developers Should Work With This Module
-- Always route credit checks/deductions/additions through `CreditService`.
-- When adding new AI operations, register operation_type in `CreditUsageLog`/constants and optionally seed `CreditCostConfig`.
-- Include amount (words/items/images) when calling `deduct_credits_for_operation` so unit-based pricing applies.
-- Use balance/usage endpoints for UI/analytics; avoid custom queries that bypass account scoping.
diff --git a/docs/10-BACKEND/billing/PAYMENT-METHODS.md b/docs/10-BACKEND/billing/PAYMENT-METHODS.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/docs/10-BACKEND/integrations/AI-SERVICES.md b/docs/10-BACKEND/integrations/AI-SERVICES.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/docs/10-BACKEND/integrations/IMAGE-GENERATION.md b/docs/10-BACKEND/integrations/IMAGE-GENERATION.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/docs/10-BACKEND/integrations/WORDPRESS-INTEGRATION.md b/docs/10-BACKEND/integrations/WORDPRESS-INTEGRATION.md
deleted file mode 100644
index 40034b02..00000000
--- a/docs/10-BACKEND/integrations/WORDPRESS-INTEGRATION.md
+++ /dev/null
@@ -1,2125 +0,0 @@
-# WordPress Plugin Integration Guide
-
-**Version**: 1.0.0
-**Last Updated**: 2025-01-XX (Added Publisher module endpoints for content publishing)
-
-Complete guide for integrating WordPress plugins with IGNY8 API v1.0.
-
----
-
-## Overview
-
-This guide helps WordPress plugin developers integrate with the IGNY8 API using the unified response format.
-
----
-
-## Authentication
-
-### Getting Access Token
-
-```php
-function igny8_login($email, $password) {
- $response = wp_remote_post('https://api.igny8.com/api/v1/auth/login/', [
- 'headers' => [
- 'Content-Type' => 'application/json'
- ],
- 'body' => json_encode([
- 'email' => $email,
- 'password' => $password
- ])
- ]);
-
- $body = json_decode(wp_remote_retrieve_body($response), true);
-
- if ($body['success']) {
- // Store tokens
- update_option('igny8_access_token', $body['data']['access']);
- update_option('igny8_refresh_token', $body['data']['refresh']);
- return $body['data']['access'];
- } else {
- return new WP_Error('login_failed', $body['error']);
- }
-}
-```
-
-### Using Access Token
-
-```php
-function igny8_get_headers() {
- $token = get_option('igny8_access_token');
-
- if (!$token) {
- return false;
- }
-
- return [
- 'Authorization' => 'Bearer ' . $token,
- 'Content-Type' => 'application/json'
- ];
-}
-```
-
-Note (required): To establish a bridge connection the plugin now requires three credentials to be provided and saved in the WordPress settings: **Email**, **Password**, and **API Key**. All three are stored as options (`igny8_email`, `igny8_access_token`/`igny8_refresh_token`, `igny8_api_key`) — the API key is stored using secure storage helpers when available. The bridge will refuse connection if any of these are missing.
-
----
-
-## API Client Class
-
-### Complete PHP Implementation
-
-```php
-class Igny8API {
- private $base_url = 'https://api.igny8.com/api/v1';
- private $access_token = null;
- private $refresh_token = null;
-
- public function __construct() {
- $this->access_token = get_option('igny8_access_token');
- $this->refresh_token = get_option('igny8_refresh_token');
- }
-
- /**
- * Login and store tokens
- */
- public function login($email, $password) {
- $response = wp_remote_post($this->base_url . '/auth/login/', [
- 'headers' => [
- 'Content-Type' => 'application/json'
- ],
- 'body' => json_encode([
- 'email' => $email,
- 'password' => $password
- ])
- ]);
-
- $body = $this->parse_response($response);
-
- if ($body['success']) {
- $this->access_token = $body['data']['access'];
- $this->refresh_token = $body['data']['refresh'];
-
- update_option('igny8_access_token', $this->access_token);
- update_option('igny8_refresh_token', $this->refresh_token);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * Refresh access token
- */
- public function refresh_token() {
- if (!$this->refresh_token) {
- return false;
- }
-
- $response = wp_remote_post($this->base_url . '/auth/refresh/', [
- 'headers' => [
- 'Content-Type' => 'application/json'
- ],
- 'body' => json_encode([
- 'refresh' => $this->refresh_token
- ])
- ]);
-
- $body = $this->parse_response($response);
-
- if ($body['success']) {
- $this->access_token = $body['data']['access'];
- $this->refresh_token = $body['data']['refresh'];
-
- update_option('igny8_access_token', $this->access_token);
- update_option('igny8_refresh_token', $this->refresh_token);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * Parse unified API response
- */
- private function parse_response($response) {
- if (is_wp_error($response)) {
- return [
- 'success' => false,
- 'error' => $response->get_error_message()
- ];
- }
-
- $body = json_decode(wp_remote_retrieve_body($response), true);
- $status_code = wp_remote_retrieve_response_code($response);
-
- // Handle non-JSON responses
- if (!$body) {
- return [
- 'success' => false,
- 'error' => 'Invalid response format'
- ];
- }
-
- // Check if response follows unified format
- if (isset($body['success'])) {
- return $body;
- }
-
- // Legacy format - wrap in unified format
- if ($status_code >= 200 && $status_code < 300) {
- return [
- 'success' => true,
- 'data' => $body
- ];
- } else {
- return [
- 'success' => false,
- 'error' => $body['detail'] ?? 'Unknown error'
- ];
- }
- }
-
- /**
- * Get headers with authentication
- */
- private function get_headers() {
- if (!$this->access_token) {
- throw new Exception('Not authenticated');
- }
-
- return [
- 'Authorization' => 'Bearer ' . $this->access_token,
- 'Content-Type' => 'application/json'
- ];
- }
-
- /**
- * Make GET request
- */
- public function get($endpoint) {
- $response = wp_remote_get($this->base_url . $endpoint, [
- 'headers' => $this->get_headers()
- ]);
-
- $body = $this->parse_response($response);
-
- // Handle 401 - token expired
- if (!$body['success'] && wp_remote_retrieve_response_code($response) == 401) {
- // Try to refresh token
- if ($this->refresh_token()) {
- // Retry request
- $response = wp_remote_get($this->base_url . $endpoint, [
- 'headers' => $this->get_headers()
- ]);
- $body = $this->parse_response($response);
- }
- }
-
- return $body;
- }
-
- /**
- * Make POST request
- */
- public function post($endpoint, $data) {
- $response = wp_remote_post($this->base_url . $endpoint, [
- 'headers' => $this->get_headers(),
- 'body' => json_encode($data)
- ]);
-
- $body = $this->parse_response($response);
-
- // Handle 401 - token expired
- if (!$body['success'] && wp_remote_retrieve_response_code($response) == 401) {
- // Try to refresh token
- if ($this->refresh_token()) {
- // Retry request
- $response = wp_remote_post($this->base_url . $endpoint, [
- 'headers' => $this->get_headers(),
- 'body' => json_encode($data)
- ]);
- $body = $this->parse_response($response);
- }
- }
-
- return $body;
- }
-
- /**
- * Make PUT request
- */
- public function put($endpoint, $data) {
- $response = wp_remote_request($this->base_url . $endpoint, [
- 'method' => 'PUT',
- 'headers' => $this->get_headers(),
- 'body' => json_encode($data)
- ]);
-
- return $this->parse_response($response);
- }
-
- /**
- * Make DELETE request
- */
- public function delete($endpoint) {
- $response = wp_remote_request($this->base_url . $endpoint, [
- 'method' => 'DELETE',
- 'headers' => $this->get_headers()
- ]);
-
- return $this->parse_response($response);
- }
-}
-```
-
----
-
-## Usage Examples
-
-### Get Keywords
-
-```php
-$api = new Igny8API();
-
-// Get keywords
-$response = $api->get('/planner/keywords/');
-
-if ($response['success']) {
- $keywords = $response['results'];
- $count = $response['count'];
-
- foreach ($keywords as $keyword) {
- echo $keyword['name'] . ' ';
- }
-} else {
- echo 'Error: ' . $response['error'];
-}
-```
-
-### Create Keyword
-
-```php
-$api = new Igny8API();
-
-$data = [
- 'seed_keyword_id' => 1,
- 'site_id' => 1,
- 'sector_id' => 1,
- 'status' => 'active'
-];
-
-$response = $api->post('/planner/keywords/', $data);
-
-if ($response['success']) {
- $keyword = $response['data'];
- echo 'Created keyword: ' . $keyword['id'];
-} else {
- echo 'Error: ' . $response['error'];
- if (isset($response['errors'])) {
- foreach ($response['errors'] as $field => $errors) {
- echo $field . ': ' . implode(', ', $errors) . ' ';
- }
- }
-}
-```
-
-### Handle Pagination
-
-```php
-$api = new Igny8API();
-
-function get_all_keywords($api) {
- $all_keywords = [];
- $page = 1;
-
- do {
- $response = $api->get("/planner/keywords/?page={$page}&page_size=100");
-
- if ($response['success']) {
- $all_keywords = array_merge($all_keywords, $response['results']);
- $page++;
- } else {
- break;
- }
- } while ($response['next']);
-
- return $all_keywords;
-}
-
-$keywords = get_all_keywords($api);
-```
-
-### Handle Rate Limiting
-
-```php
-function make_rate_limited_request($api, $endpoint, $max_retries = 3) {
- for ($attempt = 0; $attempt < $max_retries; $attempt++) {
- $response = $api->get($endpoint);
-
- // Check if rate limited
- if (!$response['success'] && isset($response['error'])) {
- if (strpos($response['error'], 'Rate limit') !== false) {
- // Wait before retry
- sleep(pow(2, $attempt)); // Exponential backoff
- continue;
- }
- }
-
- return $response;
- }
-
- return ['success' => false, 'error' => 'Max retries exceeded'];
-}
-```
-
----
-
-## Error Handling
-
-### Unified Error Handling
-
-```php
-function handle_api_response($response) {
- if ($response['success']) {
- return $response['data'] ?? $response['results'];
- } else {
- $error_message = $response['error'];
-
- // Log error with request ID
- error_log(sprintf(
- 'IGNY8 API Error: %s (Request ID: %s)',
- $error_message,
- $response['request_id'] ?? 'unknown'
- ));
-
- // Handle field-specific errors
- if (isset($response['errors'])) {
- foreach ($response['errors'] as $field => $errors) {
- error_log(" {$field}: " . implode(', ', $errors));
- }
- }
-
- return new WP_Error('igny8_api_error', $error_message, $response);
- }
-}
-```
-
----
-
-## Best Practices
-
-### 1. Store Tokens Securely
-
-```php
-// Use WordPress options API with encryption
-function save_token($token) {
- // Encrypt token before storing
- $encrypted = base64_encode($token);
- update_option('igny8_access_token', $encrypted, false);
-}
-
-function get_token() {
- $encrypted = get_option('igny8_access_token');
- return base64_decode($encrypted);
-}
-```
-
-### 2. Implement Token Refresh
-
-```php
-function ensure_valid_token($api) {
- // Check if token is about to expire (refresh 1 minute before)
- // Token expires in 15 minutes, refresh at 14 minutes
- $last_refresh = get_option('igny8_token_refreshed_at', 0);
-
- if (time() - $last_refresh > 14 * 60) {
- if ($api->refresh_token()) {
- update_option('igny8_token_refreshed_at', time());
- }
- }
-}
-```
-
-### 3. Cache Responses
-
-```php
-function get_cached_keywords($api, $cache_key = 'igny8_keywords', $ttl = 300) {
- $cached = get_transient($cache_key);
-
- if ($cached !== false) {
- return $cached;
- }
-
- $response = $api->get('/planner/keywords/');
-
- if ($response['success']) {
- $keywords = $response['results'];
- set_transient($cache_key, $keywords, $ttl);
- return $keywords;
- }
-
- return false;
-}
-```
-
-### 4. Handle Rate Limits
-
-```php
-function check_rate_limit($response) {
- // Note: WordPress wp_remote_* doesn't expose all headers easily
- // Consider using cURL or checking response for 429 status
-
- if (isset($response['error']) && strpos($response['error'], 'Rate limit') !== false) {
- // Wait and retry
- sleep(60);
- return true; // Should retry
- }
-
- return false;
-}
-```
-
----
-
-## WordPress Admin Integration
-
-### Settings Page
-
-```php
-function igny8_settings_page() {
- ?>
-
-
-AND meta_key LIKE '_igny8%';
-```
-
-Should show:
-- `_igny8_content_id`
-- `_igny8_primary_keyword`
-- `_igny8_secondary_keywords`
-- `_igny8_meta_title`
-- `_igny8_meta_description`
-- `_igny8_gallery_images` (if gallery exists)
-
-### Check Taxonomies
-```sql
--- Check cluster/sector assigned as taxonomies (not post_meta)
-SELECT t.name, tt.taxonomy
-FROM wp_terms t
-JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
-JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
-WHERE tr.object_id =
-AND tt.taxonomy IN ('igny8_clusters', 'igny8_sectors');
-```
-
----
-
-## 📊 What Changed - Summary
-
-### Removed ❌
-- All automatic sync hooks (save_post, publish_post, etc.)
-- All cron jobs (sync_post_statuses, sync_from_igny8, etc.)
-- Bidirectional sync files (hooks.php, post-sync.php, taxonomy-sync.php)
-- Brief meta box (no data in IGNY8)
-- Cluster/sector as post_meta (now pure taxonomies)
-- Automatic IGNY8 task updates after post creation
-
-### Added ✅
-- Default post status setting (draft/publish) in WP admin
-- Keywords meta box (primary + secondary)
-- SEO meta box (meta_title + meta_description)
-- Sync Data meta box (read-only tracking)
-- Cluster_name and sector_name in publish payload
-- Term IDs returned from WordPress
-- Term IDs saved to content.external_metadata
-- Automatic term creation if cluster/sector don't exist in WordPress
-
-### Fixed ✅
-- Gallery images function call (igny8_set_image_gallery)
-- Cluster/sector stored ONLY as taxonomies (with term_meta for ID mapping)
-- Keywords stored as custom fields (editable in meta boxes)
-- Content status updates to 'published' after successful WordPress publish
-
----
-
-## 🎯 End Result
-
-### Publishing Flow (One-Way Only)
-```
-IGNY8 Review.tsx
- ↓ User clicks "Publish to WordPress"
- ↓ POST /v1/publisher/publish/
-Backend WordPressAdapter
- ↓ POST {site_url}/wp-json/igny8/v1/publish
- ↓ Sends: title, content, SEO, keywords, categories, tags, cluster_name, sector_name, images
-WordPress Plugin
- ↓ wp_insert_post() + taxonomies + images + meta
- ↓ Creates cluster/sector terms if don't exist
- ↓ IMMEDIATE RETURN: {post_id, post_url, term_ids}
-IGNY8 Backend
- ↓ Saves: external_id, external_url, status='published', external_metadata['wordpress_term_ids']
- ✅ DONE - No automatic sync, no callbacks
-```
-
-### WordPress Editor Experience
-1. Published content shows 4 meta boxes:
- - **IGNY8 Keywords** - Edit primary/secondary keywords
- - **IGNY8 SEO** - Edit SEO title/description
- - **IGNY8 Sync Data** - View tracking info (read-only)
- - **IGNY8 Optimizer** - Run optimization jobs
-
-2. Taxonomies in sidebar:
- - Categories (standard)
- - Tags (standard)
- - IGNY8 Clusters (custom)
- - IGNY8 Sectors (custom)
-
-3. Featured image and gallery in Media section
-
----
-
-## 🆘 Troubleshooting
-
-### Issue: Gallery images not saving
-**Check**: `igny8_set_image_gallery()` function exists in `sync/igny8-to-wp.php` (line ~780)
-**Verify**: `_igny8_gallery_images` post_meta contains array of attachment IDs
-
-### Issue: Cluster/sector not showing as taxonomy
-**Check**: Terms registered in `includes/functions.php` line 465
-**Verify**: `igny8_clusters` and `igny8_sectors` taxonomies exist
-**Run**: `wp taxonomy list` to confirm
-
-### Issue: Keywords meta box not showing
-**Action**: Replace `admin/class-post-meta-boxes.php` with new version (manual task)
-
-### Issue: Term IDs not saving to IGNY8
-**Check**: WordPress response includes `term_ids` field
-**Check**: Django logs show "Saved term_ids to external_metadata"
-**Verify**: `content.external_metadata` column is JSON type in database
-
----
-
-## 📝 Notes
-
-- Plugin version updated to **1.1.0**
-- All changes are backward compatible (old posts unaffected)
-- No database migrations required
-- Existing meta boxes (Optimizer) preserved
-- SEO plugin compatibility maintained (Yoast, SEOPress, AIOSEO)
-
----
-
-## ✅ Completion Status
-
-- **Phase 1**: ✅ 100% Complete
-- **Phase 2**: ✅ 100% Complete
-- **Phase 3**: ⚠️ 95% Complete (1 manual file replacement)
-- **Phase 4**: ✅ 100% Complete
-
-**Overall**: ✅ 95% Complete
-
-**Remaining**: Replace `admin/class-post-meta-boxes.php` manually
diff --git a/docs/90-REFERENCE/AI-FUNCTIONS.md b/docs/90-REFERENCE/AI-FUNCTIONS.md
new file mode 100644
index 00000000..45a57c04
--- /dev/null
+++ b/docs/90-REFERENCE/AI-FUNCTIONS.md
@@ -0,0 +1,462 @@
+# AI Functions Reference
+
+**Last Verified:** December 25, 2025
+
+---
+
+## Overview
+
+IGNY8's AI engine provides functions for content planning and generation. Located in `backend/igny8_core/ai/`.
+
+**Providers:**
+- **OpenAI** - GPT-4 for text, DALL-E 3 for images
+- **Runware** - Alternative image generation
+
+---
+
+## Architecture
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ AI ENGINE │
+├─────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
+│ │ AIEngine │───►│ Function │───►│ Provider │ │
+│ │ (router) │ │ (logic) │ │ (API) │ │
+│ └──────────────┘ └──────────────┘ └──────────────┘ │
+│ │
+│ Functions: │
+│ • AutoClusterKeywords │
+│ • GenerateContentIdeas │
+│ • GenerateContent │
+│ • GenerateImages │
+│ • OptimizeContent (pending) │
+│ │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## AIEngine
+
+**Location:** `backend/igny8_core/ai/engine.py`
+
+Main orchestrator for AI operations.
+
+```python
+class AIEngine:
+ def __init__(self, account: Account):
+ self.account = account
+ self.settings = self._load_settings()
+ self.text_provider = self._init_text_provider()
+ self.image_provider = self._init_image_provider()
+
+ def auto_cluster(self, keywords: List[Keyword]) -> List[Cluster]:
+ """Cluster keywords by topic"""
+
+ def generate_ideas(self, cluster: Cluster) -> List[ContentIdea]:
+ """Generate content ideas for cluster"""
+
+ def generate_content(self, task: Task) -> Content:
+ """Generate full article content"""
+
+ def generate_images(self, content: Content, count: int = 1) -> List[ContentImage]:
+ """Generate images for content"""
+```
+
+---
+
+## Function: AutoClusterKeywords
+
+**Purpose:** Group semantically related keywords into clusters
+
+**Input:**
+```python
+{
+ "keywords": [
+ {"id": "...", "keyword": "python tutorial"},
+ {"id": "...", "keyword": "learn python"},
+ {"id": "...", "keyword": "python basics"},
+ ...
+ ],
+ "site_context": {
+ "name": "Tech Blog",
+ "industry": "Technology"
+ }
+}
+```
+
+**Output:**
+```python
+{
+ "clusters": [
+ {
+ "name": "Python Learning Resources",
+ "description": "Tutorials and guides for learning Python",
+ "keywords": ["python tutorial", "learn python", "python basics"]
+ },
+ ...
+ ]
+}
+```
+
+**Prompt Template:** `auto_cluster`
+
+**Model:** GPT-4
+
+**Credit Cost:** 1 idea credit per operation
+
+---
+
+## Function: GenerateContentIdeas
+
+**Purpose:** Create content ideas from a keyword cluster
+
+**Input:**
+```python
+{
+ "cluster": {
+ "name": "Python Learning Resources",
+ "description": "...",
+ "keywords": [...]
+ },
+ "site_context": {
+ "name": "Tech Blog",
+ "industry": "Technology"
+ },
+ "count": 5 # Number of ideas to generate
+}
+```
+
+**Output:**
+```python
+{
+ "ideas": [
+ {
+ "title": "10 Essential Python Tips for Beginners",
+ "description": "A comprehensive guide covering...",
+ "primary_keyword": "python tutorial",
+ "secondary_keywords": ["learn python", "python basics"]
+ },
+ ...
+ ]
+}
+```
+
+**Prompt Template:** `generate_ideas`
+
+**Model:** GPT-4
+
+**Credit Cost:** 1 idea credit per idea generated
+
+---
+
+## Function: GenerateContent
+
+**Purpose:** Create full article from task brief
+
+**Input:**
+```python
+{
+ "task": {
+ "title": "10 Essential Python Tips for Beginners",
+ "brief": "Write a comprehensive guide...",
+ "primary_keyword": "python tutorial",
+ "secondary_keywords": ["learn python", "python basics"]
+ },
+ "site_context": {
+ "name": "Tech Blog",
+ "industry": "Technology",
+ "tone": "Professional but approachable"
+ },
+ "options": {
+ "target_word_count": 2000,
+ "include_headings": True,
+ "include_lists": True,
+ "include_code_blocks": True
+ }
+}
+```
+
+**Output:**
+```python
+{
+ "title": "10 Essential Python Tips for Beginners",
+ "body": "
Introduction
...
...", # Full HTML
+ "excerpt": "Learn the essential Python tips...",
+ "meta_title": "10 Python Tips for Beginners | Tech Blog",
+ "meta_description": "Master Python with these 10 essential tips...",
+ "word_count": 2150
+}
+```
+
+**Prompt Template:** `generate_content`
+
+**Model:** GPT-4
+
+**Credit Cost:** 1 content credit per generation
+
+---
+
+## Function: GenerateImages
+
+**Purpose:** Create images for article content
+
+**Input:**
+```python
+{
+ "content": {
+ "title": "10 Essential Python Tips for Beginners",
+ "body": "...",
+ "primary_keyword": "python tutorial"
+ },
+ "options": {
+ "count": 3,
+ "style": "photorealistic", # photorealistic, illustration, diagram
+ "size": "1024x1024"
+ }
+}
+```
+
+**Process:**
+1. Analyze content to identify image opportunities
+2. Generate prompts for each image
+3. Call image provider API
+4. Store images and generate thumbnails
+
+**Output:**
+```python
+{
+ "images": [
+ {
+ "url": "https://storage.../image1.png",
+ "thumbnail_url": "https://storage.../image1_thumb.png",
+ "alt_text": "Python code example showing...",
+ "caption": "Example of Python list comprehension",
+ "prompt": "A clean code editor showing Python syntax...",
+ "is_featured": True
+ },
+ ...
+ ]
+}
+```
+
+**Prompt Template:** `generate_image_prompts`
+
+**Model:** DALL-E 3 or Runware
+
+**Credit Cost:** 1 image credit per image
+
+---
+
+## Function: OptimizeContent (Pending)
+
+**Status:** ⏸️ Not yet implemented
+
+**Purpose:** SEO optimize existing content
+
+**Planned Input:**
+```python
+{
+ "content": {
+ "title": "...",
+ "body": "...",
+ "target_keyword": "..."
+ },
+ "optimization_type": "seo" | "readability" | "both"
+}
+```
+
+**Planned Output:**
+```python
+{
+ "optimized_title": "...",
+ "optimized_body": "...",
+ "changes": [
+ {"type": "keyword_density", "description": "..."},
+ {"type": "heading_structure", "description": "..."},
+ ...
+ ],
+ "score_before": 65,
+ "score_after": 85
+}
+```
+
+---
+
+## Prompt Templates
+
+### System Prompts
+
+Stored in `PromptTemplate` model or defaults in code.
+
+| Template | Purpose |
+|----------|---------|
+| `auto_cluster` | Keywords → Clusters |
+| `generate_ideas` | Cluster → Ideas |
+| `generate_content` | Task → Article |
+| `generate_image_prompts` | Content → Image prompts |
+| `optimize_content` | Content → Optimized (pending) |
+
+### Template Variables
+
+```python
+{
+ "site_name": "Tech Blog",
+ "site_industry": "Technology",
+ "site_tone": "Professional",
+ "keyword": "python tutorial",
+ "keywords": ["python", "tutorial", "learn"],
+ "cluster_name": "Python Learning",
+ "task_title": "10 Python Tips",
+ "task_brief": "Write a guide...",
+ "target_word_count": 2000
+}
+```
+
+### Custom Prompts
+
+Users can customize prompts via Settings → Prompts:
+
+```python
+# API
+GET /api/v1/system/prompts/{type}/
+PUT /api/v1/system/prompts/{type}/
+POST /api/v1/system/prompts/{type}/reset/
+```
+
+---
+
+## Provider: OpenAI
+
+**Location:** `backend/igny8_core/ai/providers/openai_provider.py`
+
+### Text Generation
+
+```python
+class OpenAITextProvider:
+ def complete(self, prompt: str, options: dict) -> str:
+ response = openai.ChatCompletion.create(
+ model=options.get('model', 'gpt-4'),
+ messages=[
+ {"role": "system", "content": self.system_prompt},
+ {"role": "user", "content": prompt}
+ ],
+ temperature=options.get('temperature', 0.7),
+ max_tokens=options.get('max_tokens', 4000)
+ )
+ return response.choices[0].message.content
+```
+
+### Image Generation
+
+```python
+class OpenAIImageProvider:
+ def generate(self, prompt: str, options: dict) -> str:
+ response = openai.Image.create(
+ model="dall-e-3",
+ prompt=prompt,
+ size=options.get('size', '1024x1024'),
+ quality=options.get('quality', 'standard'),
+ n=1
+ )
+ return response.data[0].url
+```
+
+---
+
+## Provider: Runware
+
+**Location:** `backend/igny8_core/ai/providers/runware_provider.py`
+
+Alternative image generation via Runware API.
+
+```python
+class RunwareImageProvider:
+ def generate(self, prompt: str, options: dict) -> str:
+ response = self.client.generate(
+ prompt=prompt,
+ width=options.get('width', 1024),
+ height=options.get('height', 1024),
+ model=options.get('model', 'default')
+ )
+ return response.image_url
+```
+
+---
+
+## Error Handling
+
+### Common Errors
+
+| Error | Code | Handling |
+|-------|------|----------|
+| Rate limit | `rate_limit_exceeded` | Retry with backoff |
+| Context too long | `context_length_exceeded` | Truncate input |
+| Content filter | `content_policy_violation` | Return error to user |
+| API unavailable | `api_error` | Retry or fail |
+
+### Retry Strategy
+
+```python
+class AIEngine:
+ MAX_RETRIES = 3
+ BASE_DELAY = 1 # seconds
+
+ def _call_with_retry(self, func, *args, **kwargs):
+ for attempt in range(self.MAX_RETRIES):
+ try:
+ return func(*args, **kwargs)
+ except RateLimitError:
+ delay = self.BASE_DELAY * (2 ** attempt)
+ time.sleep(delay)
+ except ContentPolicyError:
+ raise # Don't retry policy violations
+ raise MaxRetriesExceeded()
+```
+
+---
+
+## Configuration
+
+### Per-Account Settings
+
+```python
+# In AIIntegrationSettings
+openai_api_key = "sk-..."
+openai_model = "gpt-4" # or gpt-4-turbo
+image_provider = "dalle" # or "runware"
+dalle_api_key = "sk-..."
+runware_api_key = "..."
+```
+
+### Model Options
+
+| Model | Use Case | Token Limit |
+|-------|----------|-------------|
+| `gpt-4` | High quality content | 8,192 |
+| `gpt-4-turbo` | Faster, larger context | 128,000 |
+| `gpt-3.5-turbo` | Budget option | 4,096 |
+
+---
+
+## Monitoring
+
+### Logging
+
+All AI operations logged with:
+- Input parameters (sanitized)
+- Output summary
+- Token usage
+- Latency
+- Error details
+
+### Metrics
+
+Tracked via internal logging:
+- Operations per day
+- Average latency
+- Error rate
+- Token consumption
+- Credit usage
diff --git a/docs/90-REFERENCE/MODELS.md b/docs/90-REFERENCE/MODELS.md
new file mode 100644
index 00000000..672a8002
--- /dev/null
+++ b/docs/90-REFERENCE/MODELS.md
@@ -0,0 +1,517 @@
+# Database Models Reference
+
+**Last Verified:** December 25, 2025
+
+---
+
+## Auth Models (`igny8_core/auth/models/`)
+
+### User
+
+```python
+class User(AbstractBaseUser, PermissionsMixin):
+ id = UUIDField(primary_key=True)
+ email = EmailField(unique=True)
+ first_name = CharField(max_length=150)
+ last_name = CharField(max_length=150)
+
+ account = ForeignKey(Account, related_name='users')
+ role = ForeignKey(Group, null=True)
+
+ is_active = BooleanField(default=True)
+ is_staff = BooleanField(default=False)
+ created_at = DateTimeField(auto_now_add=True)
+ updated_at = DateTimeField(auto_now=True)
+```
+
+**Relations:** Account (many-to-one)
+
+---
+
+### Account
+
+```python
+class Account(models.Model):
+ id = UUIDField(primary_key=True)
+ name = CharField(max_length=255)
+
+ plan = ForeignKey(Plan, null=True)
+ owner = ForeignKey(User, related_name='owned_accounts')
+
+ is_active = BooleanField(default=True)
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+**Relations:** Plan (many-to-one), Users (one-to-many), Sites (one-to-many)
+
+---
+
+### Site
+
+```python
+class Site(models.Model):
+ id = UUIDField(primary_key=True)
+ name = CharField(max_length=255)
+ domain = CharField(max_length=255, blank=True)
+
+ account = ForeignKey(Account, related_name='sites')
+ industry = ForeignKey(Industry, null=True)
+
+ is_active = BooleanField(default=True)
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+**Relations:** Account (many-to-one), Sectors (one-to-many), Industries (many-to-one)
+
+---
+
+### Sector
+
+```python
+class Sector(models.Model):
+ id = UUIDField(primary_key=True)
+ name = CharField(max_length=255)
+ description = TextField(blank=True)
+
+ site = ForeignKey(Site, related_name='sectors')
+
+ is_active = BooleanField(default=True)
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+**Relations:** Site (many-to-one)
+
+---
+
+### Industry
+
+```python
+class Industry(models.Model):
+ id = UUIDField(primary_key=True)
+ name = CharField(max_length=255)
+ description = TextField(blank=True)
+```
+
+**Used for:** Default seed keywords, industry-specific prompts
+
+---
+
+## Planner Models (`igny8_core/modules/planner/models.py`)
+
+### Keyword
+
+```python
+class Keyword(models.Model):
+ id = UUIDField(primary_key=True)
+ keyword = CharField(max_length=255)
+
+ site = ForeignKey(Site, related_name='keywords')
+ sector = ForeignKey(Sector, null=True, related_name='keywords')
+ cluster = ForeignKey(Cluster, null=True, related_name='keywords')
+
+ search_volume = IntegerField(null=True)
+ difficulty = IntegerField(null=True)
+ cpc = DecimalField(null=True)
+
+ status = CharField(choices=KEYWORD_STATUS) # pending, clustered, used, archived
+
+ created_by = ForeignKey(User)
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+**Status Values:**
+- `pending` - New, awaiting clustering
+- `clustered` - Assigned to a cluster
+- `used` - Used in content idea
+- `archived` - No longer active
+
+---
+
+### Cluster
+
+```python
+class Cluster(models.Model):
+ id = UUIDField(primary_key=True)
+ name = CharField(max_length=255)
+ description = TextField(blank=True)
+
+ site = ForeignKey(Site, related_name='clusters')
+ sector = ForeignKey(Sector, null=True, related_name='clusters')
+
+ created_by = ForeignKey(User)
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+**Relations:** Site, Sector, Keywords (one-to-many), ContentIdeas (one-to-many)
+
+---
+
+### ContentIdea
+
+```python
+class ContentIdea(models.Model):
+ id = UUIDField(primary_key=True)
+ title = CharField(max_length=255)
+ description = TextField(blank=True)
+
+ site = ForeignKey(Site, related_name='ideas')
+ sector = ForeignKey(Sector, null=True)
+ cluster = ForeignKey(Cluster, related_name='ideas')
+
+ primary_keyword = ForeignKey(Keyword, related_name='primary_ideas')
+ secondary_keywords = ManyToManyField(Keyword, related_name='secondary_ideas')
+
+ status = CharField(choices=IDEA_STATUS) # pending, approved, used, archived
+
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+---
+
+## Writer Models (`igny8_core/modules/writer/models.py`)
+
+### Task
+
+```python
+class Task(models.Model):
+ id = UUIDField(primary_key=True)
+ title = CharField(max_length=255)
+ brief = TextField(blank=True)
+
+ site = ForeignKey(Site, related_name='tasks')
+ sector = ForeignKey(Sector, null=True)
+ idea = ForeignKey(ContentIdea, null=True, related_name='tasks')
+
+ primary_keyword = CharField(max_length=255)
+ secondary_keywords = JSONField(default=list)
+
+ status = CharField(choices=TASK_STATUS) # pending, in_progress, completed, cancelled
+ priority = CharField(choices=PRIORITY) # low, medium, high
+
+ assigned_to = ForeignKey(User, null=True)
+ due_date = DateField(null=True)
+
+ created_by = ForeignKey(User)
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+---
+
+### Content
+
+```python
+class Content(models.Model):
+ id = UUIDField(primary_key=True)
+ title = CharField(max_length=255)
+ body = TextField() # HTML content
+ excerpt = TextField(blank=True)
+
+ site = ForeignKey(Site, related_name='content')
+ sector = ForeignKey(Sector, null=True)
+ task = ForeignKey(Task, related_name='content')
+
+ meta_title = CharField(max_length=255, blank=True)
+ meta_description = TextField(blank=True)
+
+ status = CharField(choices=CONTENT_STATUS) # draft, review, approved, published
+
+ word_count = IntegerField(default=0)
+
+ created_by = ForeignKey(User)
+ created_at = DateTimeField(auto_now_add=True)
+ updated_at = DateTimeField(auto_now=True)
+```
+
+**Status Values:**
+- `draft` - Initial state after generation
+- `review` - Pending human review
+- `approved` - Ready for publishing
+- `published` - Published to WordPress
+
+---
+
+### ContentImage
+
+```python
+class ContentImage(models.Model):
+ id = UUIDField(primary_key=True)
+ content = ForeignKey(Content, related_name='images')
+
+ url = URLField()
+ thumbnail_url = URLField(blank=True)
+ alt_text = CharField(max_length=255)
+ caption = TextField(blank=True)
+
+ is_featured = BooleanField(default=False)
+ position = IntegerField(default=0)
+
+ # AI generation metadata
+ prompt = TextField(blank=True)
+ provider = CharField(max_length=50) # dalle, runware
+
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+---
+
+## Integration Models (`igny8_core/modules/integration/models.py`)
+
+### SiteIntegration
+
+```python
+class SiteIntegration(models.Model):
+ id = UUIDField(primary_key=True)
+ name = CharField(max_length=255)
+
+ site = ForeignKey(Site, related_name='integrations')
+ integration_type = CharField(max_length=50) # wordpress
+
+ # Credentials (encrypted)
+ url = URLField()
+ username = CharField(max_length=255)
+ api_key = CharField(max_length=255) # Application password
+
+ # Cached structure
+ categories = JSONField(default=list)
+ tags = JSONField(default=list)
+ authors = JSONField(default=list)
+ post_types = JSONField(default=list)
+
+ # Status
+ is_active = BooleanField(default=True)
+ last_sync_at = DateTimeField(null=True)
+ structure_updated_at = DateTimeField(null=True)
+
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+---
+
+## Billing Models (`igny8_core/modules/billing/models.py`)
+
+### Plan
+
+```python
+class Plan(models.Model):
+ id = UUIDField(primary_key=True)
+ name = CharField(max_length=100)
+ slug = SlugField(unique=True)
+
+ idea_credits = IntegerField(default=0)
+ content_credits = IntegerField(default=0)
+ image_credits = IntegerField(default=0)
+ optimization_credits = IntegerField(default=0)
+
+ max_sites = IntegerField(default=1)
+ max_users = IntegerField(default=1)
+
+ price_monthly = DecimalField(max_digits=10, decimal_places=2)
+ price_yearly = DecimalField(max_digits=10, decimal_places=2)
+
+ is_active = BooleanField(default=True)
+ is_internal = BooleanField(default=False)
+```
+
+---
+
+### CreditBalance
+
+```python
+class CreditBalance(models.Model):
+ account = ForeignKey(Account, related_name='credit_balances')
+ site = ForeignKey(Site, null=True, related_name='credit_balances')
+
+ idea_credits = IntegerField(default=0)
+ content_credits = IntegerField(default=0)
+ image_credits = IntegerField(default=0)
+ optimization_credits = IntegerField(default=0)
+
+ period_start = DateField()
+ period_end = DateField()
+
+ created_at = DateTimeField(auto_now_add=True)
+ updated_at = DateTimeField(auto_now=True)
+```
+
+---
+
+### CreditUsage
+
+```python
+class CreditUsage(models.Model):
+ account = ForeignKey(Account, related_name='credit_usage')
+ site = ForeignKey(Site, null=True)
+ user = ForeignKey(User)
+
+ credit_type = CharField(max_length=50) # idea, content, image, optimization
+ amount = IntegerField()
+ operation = CharField(max_length=100) # generate_content, etc.
+
+ related_content_type = ForeignKey(ContentType, null=True)
+ related_object_id = UUIDField(null=True)
+
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+---
+
+## System Models (`igny8_core/modules/system/`)
+
+### ModuleEnableSettings
+
+```python
+class ModuleEnableSettings(models.Model):
+ account = OneToOneField(Account, primary_key=True)
+
+ planner_enabled = BooleanField(default=True)
+ writer_enabled = BooleanField(default=True)
+ linker_enabled = BooleanField(default=False)
+ optimizer_enabled = BooleanField(default=False)
+ automation_enabled = BooleanField(default=True)
+ integration_enabled = BooleanField(default=True)
+ publisher_enabled = BooleanField(default=True)
+```
+
+---
+
+### AIIntegrationSettings
+
+```python
+class AIIntegrationSettings(models.Model):
+ account = ForeignKey(Account, related_name='ai_settings')
+
+ # OpenAI
+ openai_api_key = CharField(max_length=255, blank=True)
+ openai_model = CharField(max_length=50, default='gpt-4')
+
+ # Image generation
+ image_provider = CharField(max_length=50, default='dalle') # dalle, runware
+ dalle_api_key = CharField(max_length=255, blank=True)
+ runware_api_key = CharField(max_length=255, blank=True)
+
+ is_validated = BooleanField(default=False)
+ validated_at = DateTimeField(null=True)
+```
+
+---
+
+### PromptTemplate
+
+```python
+class PromptTemplate(models.Model):
+ account = ForeignKey(Account, null=True) # null = system default
+
+ prompt_type = CharField(max_length=100) # auto_cluster, generate_ideas, etc.
+ template = TextField()
+ variables = JSONField(default=list)
+
+ is_active = BooleanField(default=True)
+
+ created_at = DateTimeField(auto_now_add=True)
+ updated_at = DateTimeField(auto_now=True)
+```
+
+---
+
+## Publisher Models (`igny8_core/modules/publisher/models.py`)
+
+### PublishingRecord
+
+```python
+class PublishingRecord(models.Model):
+ id = UUIDField(primary_key=True)
+ content = ForeignKey(Content, related_name='publishing_records')
+ integration = ForeignKey(SiteIntegration, related_name='publishing_records')
+
+ external_id = CharField(max_length=255) # WordPress post ID
+ external_url = URLField(blank=True)
+
+ status = CharField(max_length=50) # pending, published, failed
+
+ published_at = DateTimeField(null=True)
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+---
+
+## Automation Models (`igny8_core/modules/automation/models.py`)
+
+### AutomationConfig
+
+```python
+class AutomationConfig(models.Model):
+ site = ForeignKey(Site, related_name='automation_configs')
+
+ # Stage limits
+ clustering_limit = IntegerField(default=10)
+ ideas_limit = IntegerField(default=10)
+ content_limit = IntegerField(default=5)
+ image_limit = IntegerField(default=10)
+ publish_limit = IntegerField(default=5)
+
+ # Timing
+ delay_between_operations = IntegerField(default=5) # seconds
+ max_runtime = IntegerField(default=3600) # 1 hour
+
+ # Behavior
+ auto_approve = BooleanField(default=False)
+ auto_publish = BooleanField(default=False)
+ stop_on_error = BooleanField(default=True)
+
+ is_active = BooleanField(default=True)
+```
+
+---
+
+### AutomationRun
+
+```python
+class AutomationRun(models.Model):
+ id = UUIDField(primary_key=True)
+ site = ForeignKey(Site, related_name='automation_runs')
+ config = ForeignKey(AutomationConfig)
+
+ status = CharField(max_length=50) # pending, running, paused, completed, failed, cancelled
+
+ # Progress tracking
+ current_stage = CharField(max_length=50, blank=True)
+ items_processed = IntegerField(default=0)
+ items_total = IntegerField(default=0)
+
+ # Timing
+ started_at = DateTimeField(null=True)
+ completed_at = DateTimeField(null=True)
+
+ # Results
+ error_message = TextField(blank=True)
+
+ started_by = ForeignKey(User)
+ created_at = DateTimeField(auto_now_add=True)
+```
+
+---
+
+## Entity Relationship Overview
+
+```
+Account
+├── Users (many)
+├── Sites (many)
+│ ├── Sectors (many)
+│ ├── Keywords (many)
+│ ├── Clusters (many)
+│ ├── ContentIdeas (many)
+│ ├── Tasks (many)
+│ ├── Content (many)
+│ │ └── ContentImages (many)
+│ ├── SiteIntegrations (many)
+│ │ └── PublishingRecords (many)
+│ └── AutomationConfigs (many)
+│ └── AutomationRuns (many)
+├── Plan (one)
+├── CreditBalances (many)
+├── CreditUsage (many)
+├── ModuleEnableSettings (one)
+├── AIIntegrationSettings (many)
+└── PromptTemplates (many)
+```
diff --git a/docs/AI_CLEANUP_SUMMARY.md b/docs/AI_CLEANUP_SUMMARY.md
deleted file mode 100644
index 1a21d8b4..00000000
--- a/docs/AI_CLEANUP_SUMMARY.md
+++ /dev/null
@@ -1,163 +0,0 @@
-# AI System Cleanup Summary
-
-## Actions Completed
-
-### 1. Standardized max_tokens to 8192
-**Status:** ✅ COMPLETE
-
-**Changes Made:**
-- `backend/igny8_core/ai/settings.py:103` - Changed fallback from 16384 → 8192
-- `backend/igny8_core/ai/ai_core.py:116` - Kept default at 8192 (already correct)
-- `backend/igny8_core/ai/ai_core.py:856` - Updated legacy method from 4000 → 8192
-- `backend/igny8_core/utils/ai_processor.py:111` - Updated from 4000 → 8192
-- `backend/igny8_core/utils/ai_processor.py:437` - Updated from 4000 → 8192
-- `backend/igny8_core/utils/ai_processor.py:531` - Updated from 1000 → 8192 (already done)
-- `backend/igny8_core/utils/ai_processor.py:1133` - Updated from 3000 → 8192
-- `backend/igny8_core/utils/ai_processor.py:1340` - Updated from 4000 → 8192
-- IntegrationSettings (aws-admin) - Updated from 16384 → 8192
-
-**Result:** Single source of truth = 8192 tokens across entire codebase
-
-### 2. Marked Legacy Code
-**Status:** ✅ COMPLETE
-
-**Changes Made:**
-- Added deprecation warning to `backend/igny8_core/utils/ai_processor.py`
-- Documented that it's only kept for MODEL_RATES constant
-- Marked `call_openai()` in `ai_core.py` as deprecated
-
-### 3. Removed Unused Files
-**Status:** ✅ COMPLETE
-
-**Files Removed:**
-- `backend/igny8_core/modules/writer/views.py.bak`
-- `frontend/src/pages/account/AccountSettingsPage.tsx.old`
-
-### 4. System Verification
-**Status:** ✅ COMPLETE
-
-**Test Results:**
-- Backend restarted successfully
-- Django check passed (0 issues)
-- Content generation tested with task 229
-- Confirmed max_tokens=8192 is being used
-- AI only generates 999 output tokens (< 8192 limit)
-
-## Current AI Architecture
-
-### Active System (Use This)
-```
-backend/igny8_core/ai/
-├── ai_core.py - Core AI request handler
-├── engine.py - Orchestrator (AIEngine class)
-├── settings.py - Config loader (get_model_config)
-├── prompts.py - Prompt templates
-├── base.py - BaseAIFunction class
-├── tasks.py - Celery tasks
-├── models.py - AITaskLog
-├── tracker.py - Progress tracking
-├── registry.py - Function registry
-├── constants.py - Shared constants
-└── functions/
- ├── auto_cluster.py
- ├── generate_ideas.py
- ├── generate_content.py
- ├── generate_images.py
- ├── generate_image_prompts.py
- └── optimize_content.py
-```
-
-### Legacy System (Do Not Use)
-```
-backend/igny8_core/utils/ai_processor.py
-```
-**Status:** DEPRECATED - Only kept for MODEL_RATES constant
-**Will be removed:** After extracting MODEL_RATES to ai/constants.py
-
-## Key Finding: Short Content Issue
-
-### Root Cause Analysis
-❌ **NOT a token limit issue:**
-- max_tokens set to 8192
-- AI only generates ~999 output tokens
-- Has room for 7000+ more tokens
-
-✅ **IS a prompt structure issue:**
-- AI generates "complete" content in 400-500 words
-- Thinks task is done because JSON structure is filled
-- Needs MORE AGGRESSIVE enforcement in prompt:
- - "DO NOT stop until you reach 1200 words"
- - "Count your words and verify before submitting"
- - Possibly need to use a different output format that encourages longer content
-
-## Standardized Configuration
-
-### Single max_tokens Value
-**Value:** 8192 tokens (approximately 1500-2000 words)
-**Location:** All AI functions use this consistently
-**Fallback:** No fallbacks - required in IntegrationSettings
-
-### Where max_tokens Is Used
-1. `get_model_config()` - Loads from IntegrationSettings, falls back to 8192
-2. `AICore.run_ai_request()` - Default parameter: 8192
-3. All AI functions - Use value from get_model_config()
-4. IntegrationSettings - Database stores 8192
-
-## Recommendations
-
-### Short Term
-1. ✅ max_tokens standardized (DONE)
-2. 🔄 Fix prompt to enforce 1200+ words more aggressively
-3. 🔄 Consider using streaming or multi-turn approach for long content
-
-### Long Term
-1. Extract MODEL_RATES from ai_processor.py to ai/constants.py
-2. Remove ai_processor.py entirely
-3. Add validation that content meets minimum word count before saving
-4. Implement word count tracking in generation loop
-
-## Testing Commands
-
-```bash
-# Check current config
-docker exec igny8_backend python manage.py shell -c "
-from igny8_core.ai.settings import get_model_config
-from igny8_core.auth.models import Account
-account = Account.objects.filter(slug='aws-admin').first()
-config = get_model_config('generate_content', account=account)
-print(f'max_tokens: {config[\"max_tokens\"]}')
-"
-
-# Test content generation
-docker exec igny8_backend python manage.py shell -c "
-from igny8_core.ai.functions.generate_content import GenerateContentFunction
-from igny8_core.ai.engine import AIEngine
-from igny8_core.auth.models import Account
-account = Account.objects.filter(slug='aws-admin').first()
-fn = GenerateContentFunction()
-engine = AIEngine(celery_task=None, account=account)
-result = engine.execute(fn, {'ids': [229]})
-print(f'Success: {result.get(\"success\")}')
-"
-```
-
-## Files Modified
-
-1. `backend/igny8_core/ai/settings.py` - Standardized fallback to 8192
-2. `backend/igny8_core/ai/ai_core.py` - Updated legacy method, added deprecation note
-3. `backend/igny8_core/utils/ai_processor.py` - Updated all max_tokens, added deprecation warning
-4. IntegrationSettings database - Updated to 8192
-
-## Verification
-
-✅ All max_tokens references now use 8192
-✅ No conflicting fallback values
-✅ Legacy code marked clearly
-✅ System tested and working
-✅ Backend restarted successfully
-
----
-
-**Date:** December 17, 2025
-**Status:** COMPLETE
-**Next Step:** Fix prompt structure for 1200+ word content generation
diff --git a/docs/AI_SYSTEM_AUDIT.md b/docs/AI_SYSTEM_AUDIT.md
deleted file mode 100644
index a28e786e..00000000
--- a/docs/AI_SYSTEM_AUDIT.md
+++ /dev/null
@@ -1,79 +0,0 @@
-# AI System Audit Report
-
-## Current State
-
-### Active AI System (New Architecture)
-**Location:** `backend/igny8_core/ai/`
-
-**Core Components:**
-- `ai_core.py` - Central AI request handler (run_ai_request method)
-- `engine.py` - Orchestrator for all AI functions
-- `settings.py` - Model configuration loader
-- `prompts.py` - Prompt templates
-- `base.py` - Base class for AI functions
-- `tasks.py` - Celery tasks
-- `models.py` - AITaskLog for logging
-- `tracker.py` - Progress/step tracking
-- `registry.py` - Function registry
-- `constants.py` - Shared constants (MODEL_RATES, etc.)
-
-**AI Functions:**
-- `functions/auto_cluster.py` - Keyword clustering
-- `functions/generate_ideas.py` - Content idea generation
-- `functions/generate_content.py` - Article content generation
-- `functions/generate_images.py` - Image generation
-- `functions/generate_image_prompts.py` - Image prompt generation
-- `functions/optimize_content.py` - Content optimization
-
-**Usage:** All new code uses `AIEngine` + function classes
-
-### Legacy AI System (Old Architecture)
-**Location:** `backend/igny8_core/utils/ai_processor.py`
-
-**Purpose:** Original AI interface from reference plugin migration
-**Size:** 1390 lines
-**Status:** PARTIALLY USED - Only for:
-- MODEL_RATES constant (imported by settings.py and integration_views.py)
-- Integration test views
-
-**NOT USED FOR:** Actual AI function execution (replaced by AIEngine)
-
-## max_tokens Fallback Analysis
-
-### Current Fallbacks Found:
-
-1. **settings.py:103** - `config.get('max_tokens', 16384)`
- - Falls back to 16384 if not in IntegrationSettings
-
-2. **ai_core.py:116** - `max_tokens: int = 8192`
- - Default parameter in run_ai_request()
-
-3. **ai_core.py:856** - `max_tokens: int = 4000` **[LEGACY]**
- - Legacy call_openai() method
-
-4. **ai_processor.py:111** - `max_tokens: int = 4000` **[LEGACY]**
- - Legacy _call_openai() method
-
-5. **ai_processor.py:437** - `max_tokens: int = 4000` **[LEGACY]**
- - Legacy generate_content() method
-
-6. **ai_processor.py:531** - Hardcoded `max_tokens=1000`
-
-7. **ai_processor.py:1133** - Hardcoded `max_tokens=3000`
-
-8. **ai_processor.py:1340** - Hardcoded `max_tokens=4000`
-
-## Recommended Actions
-
-### 1. Standardize max_tokens to 8192
-- Remove fallback in settings.py (line 103): Change to just `config['max_tokens']` and require it
-- Keep ai_core.py:116 default at 8192 (main entry point)
-- Update IntegrationSettings to have 8192 as required value
-
-### 2. Mark Legacy Code
-- Add deprecation warnings to ai_processor.py
-- Document that it's only kept for MODEL_RATES constant
-- Consider extracting MODEL_RATES to constants.py and removing ai_processor.py entirely
-
-### 3. Remove Dead Code
-- call_openai() legacy method in ai_core.py (if not used)
diff --git a/docs/CREDITS-TOKENS-GUIDE.md b/docs/CREDITS-TOKENS-GUIDE.md
deleted file mode 100644
index e9950250..00000000
--- a/docs/CREDITS-TOKENS-GUIDE.md
+++ /dev/null
@@ -1,455 +0,0 @@
-# IGNY8 Credits & Tokens System Guide
-
-**Version:** 1.0
-**Last Updated:** December 19, 2025
-**System Status:** ✅ Fully Operational
-
----
-
-## Overview
-
-IGNY8 uses a **token-based credit system** where all AI operations consume credits calculated from actual AI token usage. This guide covers configuration, data flow, and monitoring.
-
----
-
-## System Architecture
-
-### Data Flow
-
-```
-User Action (Content Generation, Ideas, etc.)
- ↓
-Backend Service Initiated
- ↓
-AI API Called (OpenAI, etc.)
- ↓
-Response Received: {input_tokens, output_tokens, cost_usd, model}
- ↓
-Credits Calculated: (total_tokens / tokens_per_credit)
- ↓
-Credits Deducted from Account
- ↓
-CreditUsageLog Created: {tokens_input, tokens_output, cost_usd, credits_used, model_used}
- ↓
-Reports Updated with Real-Time Analytics
-```
-
-### Key Components
-
-1. **BillingConfiguration** - System-wide billing settings
-2. **CreditCostConfig** - Per-operation token-to-credit ratios
-3. **CreditUsageLog** - Transaction log with token data
-4. **AITaskLog** - Detailed AI execution history
-
----
-
-## Configuration
-
-### 1. Global Billing Settings
-
-**Location:** Django Admin → Billing → Billing Configuration
-
-**Key Settings:**
-- **Default Tokens Per Credit:** 100 (base ratio)
-- **Default Credit Price:** $0.01 USD
-- **Rounding Mode:** Up (conservative billing)
-- **Token Reporting Enabled:** Yes
-
-**When to Adjust:**
-- Change credit pricing across all operations
-- Modify rounding behavior for credit calculations
-- Enable/disable token tracking
-
-### 2. Per-Operation Configuration
-
-**Location:** Django Admin → Billing → Credit Cost Configs
-
-**Current Ratios:**
-
-| Operation | Tokens/Credit | Min Credits | Price/Credit |
-|-----------|---------------|-------------|--------------|
-| Clustering | 150 | 2 | $0.0100 |
-| Content Generation | 100 | 3 | $0.0100 |
-| Idea Generation | 200 | 1 | $0.0100 |
-| Image Generation | 50 | 5 | $0.0200 |
-| Image Prompt Extraction | 100 | 1 | $0.0100 |
-| Linking | 300 | 1 | $0.0050 |
-| Optimization | 200 | 1 | $0.0050 |
-
-**Adjusting Pricing:**
-- **Increase `tokens_per_credit`** → Lower cost (more tokens per credit)
-- **Decrease `tokens_per_credit`** → Higher cost (fewer tokens per credit)
-- **Adjust `min_credits`** → Enforce minimum charge per operation
-- **Change `price_per_credit_usd`** → Override default credit price
-
-**Example:** To make Content Generation cheaper:
-```
-Current: 100 tokens/credit (1000 tokens = 10 credits)
-Change to: 150 tokens/credit (1000 tokens = 6.67 → 7 credits)
-Result: 30% cost reduction
-```
-
-### 3. Token Extraction
-
-**Location:** `backend/igny8_core/ai/engine.py` (line 380-381)
-
-**Current Implementation:**
-```python
-tokens_input = raw_response.get('input_tokens', 0)
-tokens_output = raw_response.get('output_tokens', 0)
-```
-
-**Critical:** Field names must match AI provider response format
-- ✅ Correct: `input_tokens`, `output_tokens`
-- ❌ Wrong: `tokens_input`, `tokens_output`
-
-**Supported Providers:**
-- OpenAI (GPT-4, GPT-4o, GPT-5.1)
-- Anthropic Claude
-- Runware (image generation)
-
----
-
-## Monitoring & Reports
-
-### 1. AI Cost & Margin Analysis
-
-**URL:** `https://api.igny8.com/admin/reports/ai-cost-analysis/`
-
-**Metrics Displayed:**
-- **Total Cost** - Actual USD spent on AI APIs
-- **Revenue** - Income from credits charged
-- **Margin** - Profit (Revenue - Cost) with percentage
-- **Margin / 1M Tokens** - Profit efficiency per million tokens
-- **Margin / 1K Credits** - Profit per thousand credits charged
-- **Projected Monthly** - Forecasted costs based on trends
-
-**Tables:**
-- Model Cost Comparison - Profitability by AI model
-- Top Spenders - Highest cost accounts
-- Cost by Function - Profitability by operation type
-- Cost Anomalies - Expensive outlier calls
-
-**Use Cases:**
-- Identify unprofitable operations or accounts
-- Optimize token-to-credit ratios
-- Detect unusual AI spending patterns
-- Track margins over time
-
-### 2. Token Usage Report
-
-**URL:** `https://api.igny8.com/admin/reports/token-usage/`
-
-**Metrics Displayed:**
-- Total tokens consumed (input + output)
-- Average tokens per call
-- Cost per 1K tokens
-- Token distribution by model
-- Token distribution by operation
-- Daily token trends
-
-**Use Cases:**
-- Understand token consumption patterns
-- Identify token-heavy operations
-- Optimize prompts to reduce token usage
-- Track token efficiency over time
-
-### 3. Usage Report
-
-**URL:** `https://api.igny8.com/admin/reports/usage/`
-
-**Metrics Displayed:**
-- Total credits used system-wide
-- Credits by operation type
-- Top credit consumers
-- Model usage distribution
-
-**Use Cases:**
-- Monitor overall system usage
-- Identify high-volume users
-- Track popular AI operations
-- Plan capacity and scaling
-
-### 4. Data Quality Report
-
-**URL:** `https://api.igny8.com/admin/reports/data-quality/`
-
-**Purpose:** Identify data integrity issues
-- Orphaned content
-- Duplicate keywords
-- Missing SEO metadata
-
----
-
-## Data Models
-
-### CreditUsageLog (Primary Transaction Log)
-
-**Purpose:** Record every credit deduction with full context
-
-**Key Fields:**
-- `account` - User account charged
-- `operation_type` - Function executed (e.g., "content_generation")
-- `credits_used` - Credits deducted
-- `cost_usd` - Actual AI provider cost
-- `tokens_input` - Input tokens consumed
-- `tokens_output` - Output tokens generated
-- `model_used` - AI model (e.g., "gpt-4o")
-- `related_object_type/id` - Link to content/site/keyword
-- `metadata` - Additional context (prompt, settings, etc.)
-
-**Query Examples:**
-```python
-# Total tokens for an account
-CreditUsageLog.objects.filter(account=account).aggregate(
- total_tokens=Sum('tokens_input') + Sum('tokens_output')
-)
-
-# Average cost by operation
-CreditUsageLog.objects.values('operation_type').annotate(
- avg_cost=Avg('cost_usd'),
- total_calls=Count('id')
-)
-
-# Margin analysis
-logs = CreditUsageLog.objects.all()
-revenue = logs.aggregate(Sum('credits_used'))['credits_used__sum'] * 0.01
-cost = logs.aggregate(Sum('cost_usd'))['cost_usd__sum']
-margin = revenue - cost
-```
-
-### AITaskLog (Execution History)
-
-**Purpose:** Detailed AI execution tracking
-
-**Key Fields:**
-- `function_name` - AI function executed
-- `account` - User account
-- `cost` - AI provider cost
-- `tokens` - Total tokens (input + output)
-- `phase` - Execution stage
-- `status` - Success/failure
-- `execution_time` - Processing duration
-- `raw_request/response` - Full API data
-
-**Use Cases:**
-- Debug AI execution failures
-- Analyze prompt effectiveness
-- Track model performance
-- Audit AI interactions
-
----
-
-## Historical Data Backfill
-
-### Issue
-Prior to December 2025, token fields were not populated due to incorrect field name mapping.
-
-### Solution
-A backfill script matched AITaskLog entries to CreditUsageLog records using:
-- Account matching
-- Timestamp matching (±10 second window)
-- 40/60 input/output split estimation (when only total available)
-
-### Result
-- ✅ 777,456 tokens backfilled
-- ✅ 380/479 records updated (79% coverage)
-- ✅ Historical margin analysis now available
-- ⚠️ 99 records remain at 0 tokens (no matching AITaskLog)
-
-### Script Location
-`backend/igny8_core/management/commands/backfill_tokens.py`
-
----
-
-## Troubleshooting
-
-### Empty Margin Metrics
-**Symptom:** "Margin / 1M Tokens" shows "No token data yet"
-
-**Causes:**
-1. No recent AI calls with token data
-2. Token extraction not working (field name mismatch)
-3. Historical data has 0 tokens
-
-**Resolution:**
-1. Check AIEngine token extraction: `tokens_input`, `tokens_output` fields
-2. Verify AI responses contain `input_tokens`, `output_tokens`
-3. Run test AI operation and check CreditUsageLog
-4. Consider backfill for historical data
-
-### Zero Tokens in CreditUsageLog
-**Symptom:** `tokens_input` and `tokens_output` are 0
-
-**Causes:**
-1. Field name mismatch in AIEngine
-2. AI provider not returning token data
-3. Historical records before fix
-
-**Resolution:**
-1. Verify `engine.py` line 380-381 uses correct field names
-2. Check AI provider API response format
-3. Restart backend services after fixes
-4. Future calls will populate correctly
-
-### Incorrect Margins
-**Symptom:** Margin percentages seem wrong
-
-**Causes:**
-1. Incorrect token-to-credit ratios
-2. Credit price misconfigured
-3. Decimal division errors
-
-**Resolution:**
-1. Review CreditCostConfig ratios
-2. Check BillingConfiguration credit price
-3. Verify margin calculations use `float()` conversions
-4. Check for TypeError in logs
-
-### Operations Not Charging Correctly
-**Symptom:** Wrong number of credits deducted
-
-**Causes:**
-1. Token-to-credit ratio misconfigured
-2. Minimum credits not enforced
-3. Rounding mode incorrect
-
-**Resolution:**
-1. Check operation's CreditCostConfig
-2. Verify `min_credits` setting
-3. Review `rounding_mode` in BillingConfiguration
-4. Test with known token count
-
----
-
-## Best Practices
-
-### Pricing Strategy
-1. **Monitor margins weekly** - Use AI Cost Analysis report
-2. **Adjust ratios based on costs** - If margins drop below 70%, decrease tokens_per_credit
-3. **Set reasonable minimums** - Enforce min_credits for small operations
-4. **Track model costs** - Some models (GPT-4) cost more than others
-
-### Token Optimization
-1. **Optimize prompts** - Reduce unnecessary tokens
-2. **Use appropriate models** - GPT-4o-mini for simple tasks
-3. **Cache results** - Avoid duplicate AI calls
-4. **Monitor anomalies** - Investigate unusually expensive calls
-
-### Data Integrity
-1. **Regular audits** - Check token data completeness
-2. **Verify field mappings** - Ensure AI responses parsed correctly
-3. **Monitor logs** - Watch for errors in CreditService
-4. **Backup configurations** - Export CreditCostConfig settings
-
-### Performance
-1. **Archive old logs** - Move historical CreditUsageLog to archive tables
-2. **Index frequently queried fields** - account, operation_type, created_at
-3. **Aggregate reports** - Use materialized views for large datasets
-4. **Cache report data** - Reduce database load
-
----
-
-## API Integration
-
-### Frontend Credit Display
-
-**Endpoint:** `/v1/billing/credits/balance/`
-
-**Response:**
-```json
-{
- "credits": 1234,
- "plan_credits_per_month": 5000,
- "credits_used_this_month": 876,
- "credits_remaining": 4124
-}
-```
-
-**Pages Using This:**
-- `/account/plans` - Plans & Billing
-- `/account/usage` - Usage Analytics
-- Dashboard credit widget
-
-### Credit Transaction History
-
-**Endpoint:** `/v1/billing/credits/usage/`
-
-**Response:**
-```json
-{
- "results": [
- {
- "id": 123,
- "operation_type": "Content Generation",
- "credits_used": 15,
- "tokens_input": 500,
- "tokens_output": 1000,
- "cost_usd": 0.015,
- "model_used": "gpt-4o",
- "created_at": "2025-12-19T10:30:00Z"
- }
- ]
-}
-```
-
----
-
-## Quick Reference
-
-### Common Operations
-
-**Check account credits:**
-```python
-account.credits # Current balance
-```
-
-**Manual credit adjustment:**
-```python
-CreditService.add_credits(account, amount=100, description="Bonus credits")
-```
-
-**Get operation config:**
-```python
-config = CreditService.get_or_create_config('content_generation')
-# Returns: CreditCostConfig with tokens_per_credit, min_credits
-```
-
-**Calculate credits needed:**
-```python
-credits = CreditService.calculate_credits_from_tokens(
- operation_type='content_generation',
- tokens_input=500,
- tokens_output=1500
-)
-# Returns: 20 (if 100 tokens/credit)
-```
-
-### Important File Locations
-
-- **Credit Service:** `backend/igny8_core/business/billing/services/credit_service.py`
-- **AI Engine:** `backend/igny8_core/ai/engine.py`
-- **Reports:** `backend/igny8_core/admin/reports.py`
-- **Models:** `backend/igny8_core/modules/billing/models.py`
-- **Admin:** `backend/igny8_core/modules/billing/admin.py`
-
-### Report Access
-
-All reports require staff/superuser login:
-- AI Cost Analysis: `/admin/reports/ai-cost-analysis/`
-- Token Usage: `/admin/reports/token-usage/`
-- Usage Report: `/admin/reports/usage/`
-- Data Quality: `/admin/reports/data-quality/`
-
----
-
-## Support & Updates
-
-For questions or issues with the credits & tokens system:
-1. Check Django admin logs: `/admin/`
-2. Review CreditUsageLog for transaction details
-3. Monitor AITaskLog for execution errors
-4. Check backend logs: `docker logs igny8_backend`
-
-**System Maintainer:** IGNY8 DevOps Team
-**Last Major Update:** December 2025 (Token-based credit system implementation)
diff --git a/docs/INDEX.md b/docs/INDEX.md
new file mode 100644
index 00000000..5bb8d312
--- /dev/null
+++ b/docs/INDEX.md
@@ -0,0 +1,142 @@
+# IGNY8 Technical Documentation
+
+**Version:** 1.0.5
+**Last Updated:** December 25, 2025
+**Purpose:** Complete technical reference for the IGNY8 AI content platform
+
+---
+
+## Quick Navigation
+
+| I want to... | Go to |
+|--------------|-------|
+| Understand system architecture | [00-SYSTEM/ARCHITECTURE.md](00-SYSTEM/ARCHITECTURE.md) |
+| Work with a specific module | [10-MODULES/](#modules) |
+| Find an API endpoint | [20-API/ENDPOINTS.md](20-API/ENDPOINTS.md) |
+| Understand frontend structure | [30-FRONTEND/PAGES.md](30-FRONTEND/PAGES.md) |
+| Trace a workflow end-to-end | [40-WORKFLOWS/](#workflows) |
+| Look up model fields | [90-REFERENCE/MODELS.md](90-REFERENCE/MODELS.md) |
+| Troubleshoot issues | [90-REFERENCE/TROUBLESHOOTING.md](90-REFERENCE/TROUBLESHOOTING.md) |
+
+---
+
+## 00-SYSTEM - Architecture & Core
+
+| Document | Purpose |
+|----------|---------|
+| [ARCHITECTURE.md](00-SYSTEM/ARCHITECTURE.md) | Tech stack, deployment, system design |
+| [AUTH-FLOWS.md](00-SYSTEM/AUTH-FLOWS.md) | Authentication, JWT, sessions, roles |
+| [TENANCY.md](00-SYSTEM/TENANCY.md) | Multi-tenant architecture, Account/Site/Sector |
+
+---
+
+## 10-MODULES - Feature Modules {#modules}
+
+| Module | Status | Description | Document |
+|--------|--------|-------------|----------|
+| **Planner** | ✅ Active | Keywords → Clusters → Ideas | [PLANNER.md](10-MODULES/PLANNER.md) |
+| **Writer** | ✅ Active | Tasks → Content → Images | [WRITER.md](10-MODULES/WRITER.md) |
+| **Automation** | ✅ Active | 7-stage automated pipeline | [AUTOMATION.md](10-MODULES/AUTOMATION.md) |
+| **Billing** | ✅ Active | Credits, plans, payments | [BILLING.md](10-MODULES/BILLING.md) |
+| **Integrations** | ✅ Active | WordPress sync, webhooks | [INTEGRATIONS.md](10-MODULES/INTEGRATIONS.md) |
+| **System** | ✅ Active | Settings, prompts, AI config | [SYSTEM-SETTINGS.md](10-MODULES/SYSTEM-SETTINGS.md) |
+| **Publisher** | ✅ Active | Content publishing pipeline | [PUBLISHER.md](10-MODULES/PUBLISHER.md) |
+| **Linker** | ⏸️ Inactive | Internal linking (disabled by default) | [LINKER.md](10-MODULES/LINKER.md) |
+| **Optimizer** | ⏸️ Inactive | Content optimization (disabled by default) | [OPTIMIZER.md](10-MODULES/OPTIMIZER.md) |
+
+---
+
+## 20-API - REST API Reference
+
+| Document | Purpose |
+|----------|---------|
+| [ENDPOINTS.md](20-API/ENDPOINTS.md) | Complete endpoint list with methods and handlers |
+| [SCHEMAS.md](20-API/SCHEMAS.md) | Request/response examples |
+
+---
+
+## 30-FRONTEND - React Application
+
+| Document | Purpose |
+|----------|---------|
+| [PAGES.md](30-FRONTEND/PAGES.md) | All pages and routes |
+| [STORES.md](30-FRONTEND/STORES.md) | Zustand state management |
+| [COMPONENTS.md](30-FRONTEND/COMPONENTS.md) | Key reusable components |
+
+---
+
+## 40-WORKFLOWS - Cross-Module Flows {#workflows}
+
+| Document | Purpose |
+|----------|---------|
+| [CONTENT-PIPELINE.md](40-WORKFLOWS/CONTENT-PIPELINE.md) | Keyword → Published article flow |
+| [CREDIT-DEDUCTION.md](40-WORKFLOWS/CREDIT-DEDUCTION.md) | When and how credits are used |
+| [WORDPRESS-SYNC.md](40-WORKFLOWS/WORDPRESS-SYNC.md) | Two-way WordPress synchronization |
+
+---
+
+## 90-REFERENCE - Quick Lookup
+
+| Document | Purpose |
+|----------|---------|
+| [MODELS.md](90-REFERENCE/MODELS.md) | All database models and fields |
+| [AI-FUNCTIONS.md](90-REFERENCE/AI-FUNCTIONS.md) | AI engine capabilities and costs |
+| [TROUBLESHOOTING.md](90-REFERENCE/TROUBLESHOOTING.md) | Common issues and fixes |
+
+---
+
+## Root Files
+
+| File | Purpose |
+|------|---------|
+| [/CHANGELOG.md](/CHANGELOG.md) | Version history and changes |
+| [/RULES.md](/RULES.md) | Documentation maintenance rules |
+| [/IGNY8-APP.md](/IGNY8-APP.md) | Executive summary (non-technical) |
+
+---
+
+## Module → File Quick Reference
+
+| Module | Backend Path | Frontend Path |
+|--------|--------------|---------------|
+| Planner | `backend/igny8_core/modules/planner/` | `frontend/src/pages/Planner/` |
+| Writer | `backend/igny8_core/modules/writer/` | `frontend/src/pages/Writer/` |
+| Billing | `backend/igny8_core/modules/billing/` + `business/billing/` | `frontend/src/pages/Billing/` |
+| Automation | `backend/igny8_core/business/automation/` | `frontend/src/pages/Automation/` |
+| Integrations | `backend/igny8_core/modules/integration/` + `business/integration/` | `frontend/src/pages/Settings/` |
+| System | `backend/igny8_core/modules/system/` | `frontend/src/pages/Settings/` |
+| Linker | `backend/igny8_core/modules/linker/` | `frontend/src/pages/Linker/` |
+| Optimizer | `backend/igny8_core/modules/optimizer/` + `business/optimization/` | `frontend/src/pages/Optimizer/` |
+| Publisher | `backend/igny8_core/modules/publisher/` + `business/publishing/` | N/A |
+| Auth | `backend/igny8_core/auth/` | `frontend/src/pages/Auth/` |
+| AI Engine | `backend/igny8_core/ai/` | N/A |
+
+---
+
+## API Base Paths
+
+| Module | Base URL |
+|--------|----------|
+| Auth | `/api/v1/auth/` |
+| Planner | `/api/v1/planner/` |
+| Writer | `/api/v1/writer/` |
+| Billing | `/api/v1/billing/` |
+| Integration | `/api/v1/integration/` |
+| System | `/api/v1/system/` |
+| Linker | `/api/v1/linker/` |
+| Optimizer | `/api/v1/optimizer/` |
+| Publisher | `/api/v1/publisher/` |
+
+---
+
+## Tech Stack Summary
+
+| Layer | Technology |
+|-------|------------|
+| Backend | Django 5.1, Django REST Framework, PostgreSQL |
+| Frontend | React 18, TypeScript, Vite, Tailwind CSS |
+| State | Zustand |
+| Async | Celery + Redis |
+| AI | OpenAI (GPT-4), DALL-E 3, Runware |
+| Auth | JWT + Session |
+| Deployment | Docker, Caddy |
diff --git a/docs/PRE-LAUNCH/ITEM-5-WORDPRESS-TEMPLATES.md b/docs/PRE-LAUNCH/ITEM-5-WORDPRESS-TEMPLATES.md
deleted file mode 100644
index 7f6584ab..00000000
--- a/docs/PRE-LAUNCH/ITEM-5-WORDPRESS-TEMPLATES.md
+++ /dev/null
@@ -1,736 +0,0 @@
-# Item 5: WordPress Content Template Improvements and Redesign
-
-**Priority:** High
-**Target:** Production Launch
-**Last Updated:** December 11, 2025
-
----
-
-## Overview
-
-Redesign WordPress content templates to optimize image placement, content structure, and cluster hub landing pages. Implement adaptive templates for different article lengths (500, 1000, 1500 words) with intelligent image reuse logic and proper HTML formatting.
-
----
-
-## Current Implementation Analysis
-
-### Content Template System
-
-**Location:** `backend/igny8_core/modules/publisher/` and content generation
-
-**Current State:**
-- Content generated as HTML in `Content.content_html` field
-- Images generated separately with prompts
-- No formal template system for WordPress publishing
-- Image placement done during content generation, not during publishing
-
-**Issues:**
-- No consistent image placement strategy
-- No adaptation for article length
-- Image reuse logic not implemented
-- Cluster hub pages not differentiated from regular content
-
----
-
-### Content HTML Structure
-
-**Generated by:** `backend/igny8_core/ai/functions/generate_content.py`
-
-**Current Format:**
-```html
-
Hook text...
-
Introduction paragraph 1...
-
Introduction paragraph 2...
-
-
Section Heading 1
-
Section content...
-
-
List item 1
-
List item 2
-
-
-
Section Heading 2
-
Section content...
-
-
Column 1
Column 2
-
Data 1
Data 2
-
-
-
-```
-
-**Issues:**
-- No image tags in HTML (images added separately)
-- No placeholder markers for image insertion
-- Section lengths not adaptive to total word count
-- Table structures sometimes inconsistent
-
----
-
-### Image System
-
-**Models:**
-- `ContentImage` - Stores image URL, prompt, type (featured/in-article), position
-- Linked to `Content` via foreign key
-
-**Current Image Generation:**
-1. Content generated with HTML
-2. Image prompts extracted from content
-3. Images generated from prompts
-4. Images stored in `ContentImage` table
-5. Publishing combines content HTML + image URLs
-
-**Issues:**
-- No clear insertion points in HTML
-- Image position field not always used correctly
-- Featured image vs in-article distinction unclear
-- No reuse logic when fewer images than placeholders
-
----
-
-## Image Placement Strategy
-
-### Placement Rules by Article Length
-
-#### 500-Word Article
-**Structure:** Intro + 2 sections + Conclusion
-
-**Image Placement:**
-- Position 1: After introduction (before first H2)
-- Position 2: Mid-article (before second H2 or within)
-- Position 3: Before conclusion (optional, if 3 images available)
-
-**Total Images:** 2-3
-
----
-
-#### 1000-Word Article
-**Structure:** Intro + 4-5 sections + Conclusion
-
-**Image Placement:**
-- Position 1: After introduction
-- Position 2: After section 2
-- Position 3: After section 3 or 4 (mid-article)
-- Position 4: Before conclusion
-- Position 5: Within longest section (optional)
-
-**Total Images:** 3-5
-
----
-
-#### 1500-Word Article
-**Structure:** Intro + 6-8 sections + Conclusion
-
-**Image Placement:**
-- Position 1: After introduction
-- Position 2: After section 2
-- Position 3: Mid-article (after section 4)
-- Position 4: After section 5 or 6
-- Position 5: Before conclusion
-- Position 6-7: Within longer sections (optional)
-
-**Total Images:** 4-7
-
----
-
-### Image Reuse Logic
-
-**Scenario:** Not enough images for all placement positions
-
-| Available Images | Reuse Strategy |
-|------------------|----------------|
-| 1 image | Use 3 times: after intro, mid-article, before conclusion |
-| 2 images | Alternate: Image 1 → Image 2 → Image 1 → Image 2 (repeat pattern) |
-| 3 images | Use each twice: distribute evenly across positions |
-| 4+ images | Use each once until exhausted, then reuse starting from first |
-
-**Implementation Logic:**
-
-```python
-def get_image_for_position(position: int, available_images: list) -> Image:
- """
- Get image for a specific position using reuse logic.
-
- Args:
- position: 0-indexed position (0 = after intro, 1 = mid-article, etc.)
- available_images: List of ContentImage objects
-
- Returns:
- ContentImage object to use at this position
- """
- if not available_images:
- return None
-
- num_images = len(available_images)
-
- if num_images == 1:
- # Reuse single image everywhere
- return available_images[0]
-
- elif num_images == 2:
- # Alternate between images
- return available_images[position % 2]
-
- elif num_images == 3:
- # Use each twice (0,1,2,0,1,2)
- return available_images[position % 3]
-
- else:
- # Use each once, then repeat
- return available_images[position % num_images]
-```
-
----
-
-## Template System Design
-
-### Template Structure
-
-**Create:** `backend/igny8_core/modules/publisher/templates.py` (NEW)
-
-**Purpose:** Format content + images for WordPress publishing
-
----
-
-### Base Content Template
-
-**Class:** `ContentTemplate`
-
-**Methods:**
-
-| Method | Purpose | Returns |
-|--------|---------|---------|
-| `prepare_content(content, images)` | Main entry point | Formatted HTML |
-| `insert_images(html, images, word_count)` | Insert images at positions | HTML with images |
-| `get_image_positions(word_count)` | Calculate insertion points | List of positions |
-| `format_image_html(image, alt_text)` | Format single image tag | HTML string |
-| `add_featured_image_meta(content, image)` | Set WordPress featured image | Meta dict |
-
----
-
-### 500-Word Template
-
-**Class:** `ShortFormTemplate(ContentTemplate)`
-
-**Structure:**
-```html
-
-```
-
----
-
-### Cluster Hub Features
-
-| Feature | Implementation | Purpose |
-|---------|----------------|---------|
-| **Hero Image** | Full-width banner | Visual impact, brand identity |
-| **Concept Cards** | 3-6 key concepts | Quick overview, scannable |
-| **Subcluster Grid** | Links to child clusters | Hierarchy navigation |
-| **Latest Articles** | Auto-query by cluster_id | Fresh content |
-| **Popular Articles** | Sorted by view_count | Engagement driver |
-| **CTA Block** | Email signup or action | Lead generation |
-| **Footer Nav** | Related cluster links | Internal linking |
-
----
-
-### Conditional Variants
-
-#### Category Archive (WordPress Taxonomy)
-
-**Differences from Cluster Hub:**
-- Shows WordPress category tree
-- Includes post count per category
-- Pagination for article list
-- Filter by date, popularity
-
-#### Tag Archive
-
-**Differences:**
-- Shows related tags as cloud
-- Simpler layout (no hero, no concepts)
-- Focus on article list
-- Sorted by relevance
-
-#### Attribute Archive (Product/Service)
-
-**Differences:**
-- Shows attribute filter options
-- Product/service grid instead of article list
-- Comparison table
-- Filter by attribute values
-
----
-
-## Implementation Plan
-
-### Phase 1: Template System Foundation (Week 1)
-
-**Tasks:**
-1. ✅ Create `ContentTemplate` base class
-2. ✅ Implement image position calculator
-3. ✅ Implement image reuse logic
-4. ✅ Create image HTML formatter with figure tags
-5. ✅ Add WordPress meta integration (featured image)
-
-**File:** `backend/igny8_core/modules/publisher/templates.py` (NEW)
-
----
-
-### Phase 2: Article Length Templates (Week 1-2)
-
-**Tasks:**
-1. ✅ Implement `ShortFormTemplate` (500 words)
-2. ✅ Implement `StandardTemplate` (1000 words)
-3. ✅ Implement `LongFormTemplate` (1500 words)
-4. ✅ Test image insertion for each template
-5. ✅ Validate HTML output
-
-**Testing:**
-- Generate 10 articles per template
-- Verify word counts
-- Check image placement
-- Validate HTML structure
-
----
-
-### Phase 3: Cluster Hub Template (Week 2)
-
-**Tasks:**
-1. ✅ Implement `ClusterHubTemplate`
-2. ✅ Create hero section builder
-3. ✅ Create concept card generator
-4. ✅ Implement article list query
-5. ✅ Add related cluster links
-6. ✅ Test with real clusters
-
-**File:** Same as Phase 1
-
----
-
-### Phase 4: Publishing Integration (Week 2-3)
-
-**Tasks:**
-1. ✅ Update WordPress publisher to use templates
-2. ✅ Pass content + images to template
-3. ✅ Generate final HTML
-4. ✅ Send to WordPress with featured image meta
-5. ✅ Test full publishing workflow
-
-**File:** `backend/igny8_core/modules/publisher/views.py`
-
-**Method:** `publish_to_wordpress()`
-
-**Changes:**
-
-```python
-def publish_to_wordpress(content_id):
- content = Content.objects.get(id=content_id)
- images = ContentImage.objects.filter(content=content).order_by('position')
-
- # Select template based on word count
- if content.word_count <= 600:
- template = ShortFormTemplate()
- elif content.word_count <= 1200:
- template = StandardTemplate()
- else:
- template = LongFormTemplate()
-
- # Prepare content with images
- final_html = template.prepare_content(content, images)
-
- # Get featured image
- featured_image = images.filter(type='featured').first()
-
- # Publish to WordPress
- wp_client.create_post(
- title=content.title,
- content=final_html,
- featured_image_url=featured_image.image_url if featured_image else None,
- # ... other meta
- )
-```
-
----
-
-### Phase 5: Taxonomy Templates (Week 3)
-
-**Tasks:**
-1. ✅ Implement category archive variant
-2. ✅ Implement tag archive variant
-3. ✅ Implement attribute archive variant
-4. ✅ Add conditional rendering logic
-5. ✅ Test all taxonomy types
-
----
-
-## HTML Quality Standards
-
-### Image Tags
-
-**Format:**
-```html
-
-
- {optional_caption}
-
-```
-
-**Alt Text Generation:**
-- Extract from image prompt
-- Include relevant keywords
-- Descriptive, not generic ("Person using laptop" → "Digital marketer analyzing SEO metrics on laptop")
-
----
-
-### Responsive Images (Future)
-
-**Enhancement:**
-```html
-
-```
-
-**Requires:** Image resizing service or WordPress handling
-
----
-
-### Content Wrapper
-
-**Purpose:** Consistent styling and layout
-
-```html
-
-
-
-```
-
-**WordPress Classes:**
-- `entry-content` - Standard WordPress content class
-- `wp-block-*` - Gutenberg block classes for proper styling
-
----
-
-## Testing Requirements
-
-### Template Output Tests
-
-| Test Case | Expected Result |
-|-----------|-----------------|
-| 500-word article with 1 image | Image reused 3 times at strategic positions |
-| 1000-word article with 3 images | Each image used once, evenly distributed |
-| 1500-word article with 5 images | Images at intro, mid-points, and conclusion |
-| Article with 0 images | No image tags, content flows normally |
-| Cluster hub page | All sections rendered, related content populated |
-
----
-
-### HTML Validation
-
-- ✅ All HTML valid (W3C validator)
-- ✅ All image tags have alt text
-- ✅ Heading hierarchy correct (H1 → H2 → H3)
-- ✅ No broken image links
-- ✅ Figure tags properly closed
-- ✅ WordPress classes applied correctly
-
----
-
-### WordPress Integration Tests
-
-- ✅ Featured image set correctly
-- ✅ Images appear in correct positions
-- ✅ Content renders properly in WordPress editor
-- ✅ Mobile responsive (WordPress theme handles)
-- ✅ Image captions display correctly
-- ✅ Internal links work
-
----
-
-## Success Metrics
-
-- ✅ 100% of articles have images placed correctly
-- ✅ Image reuse logic works for all scenarios
-- ✅ Article lengths match templates (±5% tolerance)
-- ✅ HTML validates 100%
-- ✅ Cluster hubs render all sections
-- ✅ WordPress publishing succeeds 100%
-- ✅ User feedback: content looks professional
-- ✅ No manual image placement needed
-
----
-
-## Related Files Reference
-
-### Backend (NEW)
-- `backend/igny8_core/modules/publisher/templates.py` - Template system
-- `backend/igny8_core/modules/publisher/image_manager.py` - Image reuse logic
-
-### Backend (Update)
-- `backend/igny8_core/modules/publisher/views.py` - Publishing integration
-- `backend/igny8_core/ai/functions/generate_content.py` - Content structure
-
-### Models
-- `backend/igny8_core/business/content/models.py` - Content, ContentImage models
-
----
-
-## Notes
-
-- Templates should be flexible enough for custom themes
-- Image captions optional (can extract from prompt or leave empty)
-- Cluster hub template can be used for category/tag pages
-- Consider adding shortcode support for advanced layouts
-- Future: Allow custom template selection per content piece
-- Future: Visual template editor for admins
diff --git a/docs/PRE-LAUNCH/ITEM-6-MARKETING-SITE.md b/docs/PRE-LAUNCH/ITEM-6-MARKETING-SITE.md
deleted file mode 100644
index 19c17412..00000000
--- a/docs/PRE-LAUNCH/ITEM-6-MARKETING-SITE.md
+++ /dev/null
@@ -1,707 +0,0 @@
-# Item 6: Frontend Marketing Site Updates
-
-**Priority:** High
-**Target:** Production Launch
-**Last Updated:** December 11, 2025
-
----
-
-## Overview
-
-Update and polish the marketing website including homepage, features pages, product pages, use-case pages, pricing page, about, and contact pages. Ensure consistent branding, clear value propositions, and conversion-optimized layouts.
-
----
-
-## Current Implementation
-
-### Marketing Site Structure
-
-**Location:** `frontend/src/pages/` (marketing section)
-
-**Current Pages:**
-- Homepage
-- Features (general)
-- Pricing
-- About
-- Contact
-- (Possibly others)
-
-**Issues:**
-- Content may be outdated or generic
-- Feature descriptions don't match current capabilities
-- Pricing page needs plan updates (from Item 2)
-- No dedicated product pages for each module
-- No use-case specific pages
-- Missing social proof and testimonials
-- CTAs not optimized
-
----
-
-## Required Pages and Updates
-
-### A. Homepage
-
-**Location:** `frontend/src/pages/marketing/Home.tsx` or similar
-
-#### Current Issues
-- Value proposition unclear or generic
-- Feature highlights incomplete
-- Workflow demonstration missing
-- CTAs not prominent
-
-#### Required Sections
-
-**1. Hero Section**
-
-**Content:**
-- **Headline:** "AI-Powered Content Creation for SEO-Driven Websites"
-- **Subheadline:** "Transform your content strategy with semantic AI. Plan, write, and publish high-quality content that ranks."
-- **Primary CTA:** "Start Free Trial" (14-day trial, no credit card)
-- **Secondary CTA:** "See How It Works" (scroll to demo video)
-- **Hero Visual:** Animated workflow diagram or product screenshot
-
-**Design:**
-- Full-width, above fold
-- Gradient background or image
-- Logo grid: "Trusted by [companies/users]"
-
----
-
-**2. Problem Statement**
-
-**Content:**
-- "Content creation is time-consuming and expensive"
-- "SEO is complex and constantly changing"
-- "Scaling content while maintaining quality is hard"
-- Visual: Problem illustration
-
----
-
-**3. Solution Overview**
-
-**Content:**
-- "IGNY8 uses semantic AI to automate your entire content workflow"
-- 3 key benefits:
- 1. **Plan:** AI clusters keywords into strategic topics
- 2. **Write:** Generate SEO-optimized content in minutes
- 3. **Publish:** Direct WordPress integration
-- Visual: 3-column benefit cards
-
----
-
-**4. Feature Highlights**
-
-**Content:**
-- AI Planner: Keyword extraction → Clustering → Idea generation
-- AI Writer: Content generation → Image creation → SEO optimization
-- Automation: End-to-end workflow automation
-- Analytics: Track performance and ROI
-
-**Design:**
-- 4 feature cards with icons
-- Each card links to detailed feature page
-
----
-
-**5. How It Works**
-
-**Content:**
-- Step-by-step workflow:
- 1. Add keywords or import from GSC
- 2. AI clusters keywords semantically
- 3. Generate content ideas for each cluster
- 4. AI writes SEO-optimized articles
- 5. Generate images with AI
- 6. Publish to WordPress automatically
-
-**Visual:**
-- Animated step diagram
-- Or short video demo (30-60 seconds)
-
----
-
-**6. Social Proof**
-
-**Content:**
-- User testimonials (3-4 quotes)
-- Usage statistics:
- - "10,000+ articles generated"
- - "500+ active users"
- - "95% time saved on content creation"
-- Company logos (if applicable)
-
-**Design:**
-- Testimonial cards with photos
-- Stats counter animation
-
----
-
-**7. Pricing Preview**
-
-**Content:**
-- "Plans for every team size"
-- Show 3 plan tiers with key features
-- CTA: "View Full Pricing" → /pricing
-
----
-
-**8. Final CTA**
-
-**Content:**
-- "Ready to transform your content strategy?"
-- Primary CTA: "Start Free Trial"
-- Secondary CTA: "Schedule Demo"
-
----
-
-### B. Features Page
-
-**Location:** `frontend/src/pages/marketing/Features.tsx`
-
-#### Required Sections
-
-**1. Features Overview**
-
-**Content:**
-- List all major features with descriptions
-- Organized by category:
- - **Planning & Strategy**
- - Keyword Extraction
- - Semantic Clustering
- - Content Idea Generation
- - SAG Mapping (if implemented)
- - **Content Creation**
- - AI Writing (multiple lengths)
- - Content Structure Templates
- - SEO Optimization
- - Tone & Style Control
- - **Visual Content**
- - Image Prompt Generation
- - AI Image Creation
- - Image Optimization
- - **Publishing & Distribution**
- - WordPress Integration
- - Automated Publishing
- - Content Scheduling
- - **Automation**
- - End-to-end Workflow Automation
- - Batch Processing
- - Custom Workflows
- - **Analytics & Insights**
- - Content Performance Tracking
- - SEO Metrics
- - Credit Usage Reports
-
-**Design:**
-- Accordion or tab-based navigation
-- Feature cards with icons
-- "Learn More" links to detail pages
-
----
-
-**2. Feature Comparison Table**
-
-**Content:**
-- Compare features across plans
-- Show which features are in which tier
-
-**Table:**
-
-| Feature | Free | Starter | Growth | Pro | Enterprise |
-|---------|------|---------|--------|-----|------------|
-| Keywords | 100 | 1,000 | 5,000 | 25,000 | Unlimited |
-| AI Clustering | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Content Generation | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Image Generation | ✓ | ✓ | ✓ | ✓ | ✓ |
-| WordPress Integration | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Automation | ✗ | ✗ | ✓ | ✓ | ✓ |
-| API Access | ✗ | ✗ | ✓ | ✓ | ✓ |
-| Priority Support | ✗ | ✗ | ✗ | ✓ | ✓ |
-
----
-
-### C. Product Pages (One per Module)
-
-**Create dedicated pages:**
-
-#### 1. AI Planner Page
-
-**URL:** `/product/planner`
-
-**Sections:**
-- Hero: "Plan Your Content Strategy with AI"
-- Problem: Manual keyword research is slow
-- Solution: Automated clustering and idea generation
-- Features:
- - Keyword extraction from GSC
- - Semantic clustering
- - Content idea generation with outlines
- - Visual cluster mapping
-- Use cases:
- - Blog content planning
- - Topic cluster strategy
- - Content calendar creation
-- Demo video or screenshots
-- CTA: "Try Planner Free"
-
----
-
-#### 2. AI Writer Page
-
-**URL:** `/product/writer`
-
-**Sections:**
-- Hero: "AI-Powered Content Creation"
-- Problem: Writing is time-consuming and expensive
-- Solution: Generate SEO-optimized content in minutes
-- Features:
- - Multiple article lengths (500, 1000, 1500 words)
- - Content structure templates
- - SEO keyword integration
- - Tone and style control
-- Use cases:
- - Blog posts
- - Product descriptions
- - Landing pages
- - Guides and tutorials
-- Demo video or screenshots
-- CTA: "Start Writing with AI"
-
----
-
-#### 3. Automation Page
-
-**URL:** `/product/automation`
-
-**Sections:**
-- Hero: "Automate Your Entire Content Workflow"
-- Problem: Managing content at scale is complex
-- Solution: End-to-end automation from keywords to publication
-- Features:
- - 7-stage automated workflow
- - Batch processing
- - Scheduled runs
- - Progress monitoring
-- Use cases:
- - Agency content production
- - E-commerce catalog automation
- - Multi-site management
-- Demo video or screenshots
-- CTA: "Automate Your Workflow"
-
----
-
-### D. Use-Case Pages
-
-**Create industry/persona-specific pages:**
-
-#### 1. For Agencies
-
-**URL:** `/use-cases/agencies`
-
-**Content:**
-- Hero: "Scale Content Production for Your Clients"
-- Challenges: Managing multiple clients, tight deadlines, budget constraints
-- Solution: Automate content at scale without sacrificing quality
-- Features relevant to agencies:
- - Multi-site management
- - Team collaboration
- - White-label potential (if applicable)
- - Bulk operations
-- Case study or testimonial
-- Pricing: Focus on Growth and Pro plans
-- CTA: "Book Agency Demo"
-
----
-
-#### 2. For E-commerce
-
-**URL:** `/use-cases/ecommerce`
-
-**Content:**
-- Hero: "Generate Product Content at Scale"
-- Challenges: Large product catalogs, SEO for products, content updates
-- Solution: Automate product descriptions, category pages, blog content
-- Features relevant to e-commerce:
- - Product description generation
- - Category landing pages
- - SEO-optimized content
- - Image generation for products
-- Case study or testimonial
-- CTA: "Start Free Trial"
-
----
-
-#### 3. For Content Teams
-
-**URL:** `/use-cases/content-teams`
-
-**Content:**
-- Hero: "Supercharge Your Content Team"
-- Challenges: Content velocity, consistency, SEO optimization
-- Solution: AI assists writers, not replaces them
-- Features relevant to content teams:
- - Content planning and ideation
- - Draft generation
- - SEO optimization
- - Workflow automation
-- Case study or testimonial
-- CTA: "Try Team Plan"
-
----
-
-### E. Pricing Page
-
-**Location:** `frontend/src/pages/marketing/Pricing.tsx`
-
-#### Required Updates (From Item 2)
-
-**1. Plan Tiers**
-
-Display all 5 tiers:
-- Free (hidden from public, internal only)
-- Starter ($29/mo or $299/year)
-- Growth ($99/mo or $1,019/year)
-- Pro ($299/mo or $3,077/year)
-- Enterprise (Custom pricing)
-
-**2. Monthly/Annual Toggle**
-
-- Default: Monthly
-- Show savings badge for annual ("Save 15%")
-- Update prices dynamically on toggle
-
-**3. Plan Cards**
-
-**Each card shows:**
-- Plan name
-- Price (monthly or annual)
-- "Most Popular" badge (Growth plan)
-- Key features (5-7 bullets):
- - Monthly credits
- - Max keywords, clusters, content, images
- - Key features (automation, API, support)
-- CTA button:
- - Free: "Start Free"
- - Paid: "Start Trial" (14 days)
- - Enterprise: "Contact Sales"
-
-**4. Detailed Comparison Table**
-
-Show full feature comparison (expandable):
-- All features listed
-- Checkmarks or values per plan
-- Tooltips explaining features
-
-**5. Credit System Explanation**
-
-**Section:**
-- "How Credits Work"
-- What credits are used for
-- How they're consumed (per operation)
-- How to buy more
-- Credit rollover rules (if applicable)
-
-**Example:**
-
-| Operation | Credits |
-|-----------|---------|
-| Keyword Clustering | 10 credits |
-| Idea Generation | 15 credits |
-| Content Generation (1000 words) | 10 credits |
-| Image Generation | 5 credits per image |
-
-**6. FAQ Section**
-
-**Questions to answer:**
-- What happens when I run out of credits?
-- Can I change plans mid-month?
-- Do unused credits roll over?
-- What's included in Enterprise?
-- Is there a free trial?
-- Can I cancel anytime?
-- What payment methods do you accept?
-- Do you offer refunds?
-
-**7. CTA Section**
-
-- "Still have questions?"
-- CTA: "Contact Sales" or "Schedule Demo"
-- Phone number, email, or chat option
-
----
-
-### F. About Page
-
-**Location:** `frontend/src/pages/marketing/About.tsx`
-
-#### Required Sections
-
-**1. Mission Statement**
-
-- "Our mission is to democratize AI-powered content creation..."
-- Why IGNY8 exists
-- Vision for the future
-
-**2. Team** (if applicable)
-
-- Founder(s) photo and bio
-- Key team members
-- Company history/journey
-
-**3. Technology & Approach**
-
-- "Built on semantic AI and NLP"
-- Explanation of SAG architecture (simplified)
-- Why our approach is different/better
-
-**4. Values**
-
-- Quality over quantity
-- User-centric design
-- Transparency
-- Innovation
-
-**5. Contact**
-
-- How to reach us
-- Office location (if applicable)
-- Link to Contact page
-
----
-
-### G. Contact Page
-
-**Location:** `frontend/src/pages/marketing/Contact.tsx`
-
-#### Required Elements
-
-**1. Contact Form**
-
-**Fields:**
-- Name (required)
-- Email (required)
-- Company (optional)
-- Message (required)
-- Subject dropdown:
- - General Inquiry
- - Sales
- - Support
- - Partnership
- - Press
-
-**2. Alternative Contact Methods**
-
-- Email: support@igny8.com (or similar)
-- Phone: (if available)
-- Live chat: (if enabled)
-- Social media links
-
-**3. Support Resources**
-
-- Link to Help Center / Documentation
-- Link to FAQ
-- Link to Community (if applicable)
-
-**4. Office Location** (if applicable)
-
-- Address
-- Map embed
-
----
-
-## Design & Branding Guidelines
-
-### Visual Design
-
-**Color Scheme:**
-- Primary: Brand blue/purple
-- Secondary: Accent colors
-- Neutral: Grays for text and backgrounds
-
-**Typography:**
-- Headings: Bold, clear hierarchy
-- Body: Readable, 16px+ base size
-- Code/monospace: For technical content
-
-**Imagery:**
-- Product screenshots
-- Workflow diagrams
-- Illustrations for concepts
-- Real user photos for testimonials
-
-**Icons:**
-- Consistent icon set throughout
-- Use for feature highlights, benefits
-
----
-
-### Tone & Voice
-
-**Brand Voice:**
-- Professional but approachable
-- Technical but not jargon-heavy
-- Confident but not boastful
-- Helpful and supportive
-
-**Messaging Principles:**
-- Focus on benefits, not just features
-- Use clear, concise language
-- Avoid marketing fluff
-- Be specific with numbers and results
-- Address pain points directly
-
----
-
-### Call-to-Actions
-
-**Primary CTAs:**
-- "Start Free Trial" (most common)
-- "Get Started Free"
-- "Try IGNY8 Free"
-
-**Secondary CTAs:**
-- "Schedule Demo"
-- "Contact Sales"
-- "Learn More"
-- "View Pricing"
-
-**CTA Design:**
-- Primary: Large, prominent button (brand color)
-- Secondary: Outline button or link
-- Clear contrast with background
-- Include arrow or icon for clarity
-
----
-
-## SEO Optimization
-
-### Meta Tags
-
-**Each page needs:**
-- Title tag (50-60 chars)
-- Meta description (150-160 chars)
-- OG tags (for social sharing)
-- Schema markup (Organization, Product, FAQ)
-
-**Example (Homepage):**
-```html
-IGNY8 - AI-Powered Content Creation for SEO-Driven Websites
-
-
-
-
-```
-
----
-
-### Keyword Optimization
-
-**Target Keywords per Page:**
-
-| Page | Primary Keyword | Secondary Keywords |
-|------|----------------|-------------------|
-| Homepage | AI content creation | SEO automation, content strategy, semantic AI |
-| Features | AI content platform features | content automation tools, SEO software |
-| Planner | AI content planning | keyword clustering, topic research, content ideation |
-| Writer | AI article writer | content generation, SEO writing, blog automation |
-| Pricing | AI content pricing | content automation cost, SEO software pricing |
-| Agencies | AI content for agencies | agency content automation, white-label content |
-
----
-
-### Performance
-
-**Requirements:**
-- Page load time < 3 seconds
-- Lighthouse score > 90
-- Mobile-friendly (responsive)
-- Core Web Vitals: Pass all metrics
-
----
-
-## Implementation Plan
-
-### Phase 1: Content Audit & Updates (Week 1)
-1. ✅ Audit all existing marketing pages
-2. ✅ Identify outdated or missing content
-3. ✅ Write new content for homepage
-4. ✅ Update features page content
-5. ✅ Draft about and contact pages
-
-### Phase 2: New Pages (Week 1-2)
-1. ✅ Create product pages (Planner, Writer, Automation)
-2. ✅ Create use-case pages (Agencies, E-commerce, Content Teams)
-3. ✅ Write content for each page
-4. ✅ Design page layouts
-
-### Phase 3: Pricing Page (Week 2)
-1. ✅ Implement plan comparison table
-2. ✅ Add monthly/annual toggle
-3. ✅ Add credit cost table
-4. ✅ Write FAQ section
-5. ✅ Test all CTAs
-
-### Phase 4: Design & Branding (Week 2-3)
-1. ✅ Finalize color scheme and typography
-2. ✅ Create or source imagery
-3. ✅ Design icons for features
-4. ✅ Create demo videos or screenshots
-5. ✅ Ensure mobile responsiveness
-
-### Phase 5: SEO & Performance (Week 3)
-1. ✅ Add meta tags to all pages
-2. ✅ Implement schema markup
-3. ✅ Optimize images (compression, lazy loading)
-4. ✅ Test page speed
-5. ✅ Submit sitemap to search engines
-
----
-
-## Success Metrics
-
-- ✅ All pages load in < 3 seconds
-- ✅ Lighthouse score > 90 for all pages
-- ✅ Mobile responsive (all pages)
-- ✅ Clear value proposition on homepage
-- ✅ Pricing page matches Item 2 specifications
-- ✅ CTAs prominent and clear
-- ✅ SEO meta tags on all pages
-- ✅ Professional, consistent design
-- ✅ User feedback: easy to understand offering
-
----
-
-## Related Files Reference
-
-### Frontend Pages
-- `frontend/src/pages/marketing/Home.tsx`
-- `frontend/src/pages/marketing/Features.tsx`
-- `frontend/src/pages/marketing/Pricing.tsx`
-- `frontend/src/pages/marketing/About.tsx`
-- `frontend/src/pages/marketing/Contact.tsx`
-- `frontend/src/pages/marketing/product/Planner.tsx` (NEW)
-- `frontend/src/pages/marketing/product/Writer.tsx` (NEW)
-- `frontend/src/pages/marketing/product/Automation.tsx` (NEW)
-- `frontend/src/pages/marketing/use-cases/Agencies.tsx` (NEW)
-- `frontend/src/pages/marketing/use-cases/Ecommerce.tsx` (NEW)
-- `frontend/src/pages/marketing/use-cases/ContentTeams.tsx` (NEW)
-
-### Components
-- `frontend/src/components/marketing/HeroSection.tsx`
-- `frontend/src/components/marketing/FeatureCard.tsx`
-- `frontend/src/components/marketing/PricingCard.tsx`
-- `frontend/src/components/marketing/TestimonialCard.tsx`
-- `frontend/src/components/marketing/CTASection.tsx`
-
----
-
-## Notes
-
-- Keep messaging consistent across all pages
-- Test all CTAs and forms before launch
-- Consider A/B testing headlines and CTAs
-- Update screenshots when product UI changes
-- Consider adding live chat widget
-- Plan for ongoing content updates (blog, case studies)
-- Consider multilingual support (future phase)
diff --git a/docs/PRE-LAUNCH/ITEM-7-DOCUMENTATION.md b/docs/PRE-LAUNCH/ITEM-7-DOCUMENTATION.md
deleted file mode 100644
index 6d8fec3b..00000000
--- a/docs/PRE-LAUNCH/ITEM-7-DOCUMENTATION.md
+++ /dev/null
@@ -1,832 +0,0 @@
-# Item 7: Documentation Systems
-
-**Priority:** High
-**Target:** Production Launch
-**Last Updated:** December 11, 2025
-
----
-
-## Overview
-
-Create comprehensive documentation systems including in-app help, marketing site documentation, API references, integration guides, workflow guides, and FAQs. Ensure users can self-serve for common questions and technical implementation.
-
----
-
-## Current State Analysis
-
-### Existing Documentation
-
-**Location:** `docs/` folder in repository
-
-**Current Structure:**
-- System architecture docs
-- Backend models and services
-- Frontend components
-- API references (partial)
-- Deployment guides
-
-**Issues:**
-- Documentation scattered and incomplete
-- No user-facing help system
-- No in-app contextual help
-- API documentation not published
-- Integration guides missing
-- FAQ not comprehensive
-
----
-
-## Required Documentation Types
-
-### A. In-App Documentation
-
-**Purpose:** Help users within the application
-
----
-
-#### 1. Contextual Help System
-
-**Implementation:** Floating help icon + modal
-
-**Location:** Every major page
-
-**Features:**
-- Help icon in page header (question mark)
-- Click to open help modal
-- Modal contains:
- - Page overview
- - Key features explanation
- - Quick tips
- - Link to full documentation
- - Video tutorial (if available)
-
-**Example (Keywords Page):**
-
-```
-┌────────────────────────────────────────────────┐
-│ Help: Keywords Page [×] │
-├────────────────────────────────────────────────┤
-│ Overview │
-│ ───────────────────────────────────────────── │
-│ The Keywords page is where you extract and │
-│ manage SEO keywords for your content strategy.│
-│ │
-│ Key Features │
-│ ───────────────────────────────────────────── │
-│ • Add Keywords: Manually or import from CSV │
-│ • Cluster: Group keywords semantically │
-│ • Volume & Difficulty: SEO metrics │
-│ • Status: Track mapping progress │
-│ │
-│ Quick Tips │
-│ ───────────────────────────────────────────── │
-│ 💡 Start with 20-50 keywords │
-│ 💡 Run clustering after adding keywords │
-│ 💡 Use filters to find unmapped keywords │
-│ │
-│ [Watch Tutorial Video] [View Full Docs] │
-└────────────────────────────────────────────────┘
-```
-
-**Content per Page:**
-
-| Page | Overview | Key Actions | Tips |
-|------|----------|-------------|------|
-| **Keywords** | Extract and manage keywords | Add, Import, Cluster | Start with 20-50, run clustering |
-| **Clusters** | View keyword groups | Edit, Generate Ideas | Review cluster names for clarity |
-| **Ideas** | Content ideas from clusters | Edit, Convert to Tasks | Check word count estimates |
-| **Tasks** | Content generation queue | Generate Content | Monitor credit usage |
-| **Content** | Review generated articles | Edit, Publish | Optimize before publishing |
-| **Images** | Manage article images | Generate Images | Check image relevance |
-| **Automation** | Automate workflows | Configure, Run | Start with small batches |
-
----
-
-#### 2. Onboarding Tour
-
-**Component:** `frontend/src/components/onboarding/OnboardingTour.tsx` (NEW)
-
-**Purpose:** First-time user walkthrough
-
-**Trigger:** First login or first page visit
-
-**Steps:**
-
-**Step 1: Welcome**
-- "Welcome to IGNY8!"
-- "Let's take a quick tour to get you started"
-- [Start Tour] [Skip]
-
-**Step 2: Setup**
-- "First, connect your site and configure settings"
-- Points to Setup menu
-- [Next]
-
-**Step 3: Keywords**
-- "Add keywords to start planning content"
-- Points to Keywords page
-- [Next]
-
-**Step 4: Planner Workflow**
-- "Use the Planner to organize keywords and generate ideas"
-- Shows workflow diagram
-- [Next]
-
-**Step 5: Writer Workflow**
-- "The Writer generates content from your ideas"
-- Shows content generation process
-- [Next]
-
-**Step 6: Credits**
-- "Each AI operation uses credits. Monitor usage here."
-- Points to credits display
-- [Next]
-
-**Step 7: Done**
-- "You're all set! Start by adding keywords."
-- [Go to Keywords] [Finish Tour]
-
-**Implementation:**
-- Use library like `react-joyride` or custom tooltips
-- Store tour completion in localStorage
-- Option to restart tour from settings
-
----
-
-#### 3. Tooltips on UI Elements
-
-**Coverage:**
-
-| Element | Tooltip Text |
-|---------|--------------|
-| Cluster button | "Group keywords by semantic similarity using AI" |
-| Generate Ideas button | "Create content ideas from selected clusters" |
-| Generate Content button | "Write articles from tasks using AI" |
-| Generate Images button | "Create images from prompts using AI" |
-| Word count field | "Target word count: 500, 1000, or 1500 words" |
-| Content structure dropdown | "Article format: guide, review, listicle, etc." |
-| Status badges | "Current processing status: pending, completed, failed" |
-| Credit balance | "Remaining credits for AI operations" |
-| Site selector | "Select site for this workflow" |
-| Sector selector | "Select industry sector for context" |
-
-**Implementation:**
-- Use Tooltip component (from Item 4)
-- Add to all icons, dropdowns, status indicators
-- Keep text brief (1-2 sentences)
-
----
-
-#### 4. Inline Help Text
-
-**Placement:** Under form fields
-
-**Examples:**
-
-```tsx
-
-
-
- Use lowercase, no special characters.
- Separate multiple keywords with commas.
-
-
-
-
-
-
- Choose article length. Affects credit usage (1 credit per 100 words).
-
-
-```
-
----
-
-### B. Marketing Site Documentation
-
-**Purpose:** Public-facing help center
-
-**Location:** `/help` or `/docs` section of marketing site
-
----
-
-#### 1. Help Center Structure
-
-**Homepage:** `/help`
-
-**Categories:**
-
-```
-Help Center
-├── Getting Started
-│ ├── Creating Your Account
-│ ├── Setting Up Your First Site
-│ ├── Understanding Credits
-│ └── Quick Start Guide
-├── Planner Module
-│ ├── Adding Keywords
-│ ├── Keyword Clustering
-│ ├── Generating Ideas
-│ └── Content Planning Strategy
-├── Writer Module
-│ ├── Creating Tasks
-│ ├── Generating Content
-│ ├── Generating Images
-│ ├── Editing Content
-│ └── Publishing to WordPress
-├── Automation
-│ ├── Setting Up Automation
-│ ├── Configuring Stages
-│ ├── Monitoring Progress
-│ └── Troubleshooting Automation
-├── Integrations
-│ ├── WordPress Setup
-│ ├── Google Search Console
-│ ├── API Integration
-│ └── OAuth Connections
-├── Billing & Plans
-│ ├── Understanding Plans
-│ ├── Managing Credits
-│ ├── Upgrading Your Plan
-│ └── Invoices and Payments
-├── Troubleshooting
-│ ├── Common Errors
-│ ├── API Issues
-│ ├── Publishing Problems
-│ └── Credit Deduction Issues
-└── FAQ
- ├── General Questions
- ├── Pricing Questions
- ├── Technical Questions
- └── Account Questions
-```
-
-**Each article contains:**
-- Title
-- Last updated date
-- Estimated reading time
-- Content with screenshots/gifs
-- Related articles
-- "Was this helpful?" feedback
-- Contact support link
-
----
-
-#### 2. API Documentation
-
-**Location:** `/docs/api` or `/api-docs`
-
-**Format:** OpenAPI/Swagger or similar
-
-**Sections:**
-
-**Authentication**
-- Getting API keys
-- Authentication methods (Bearer token)
-- Rate limits
-- Error codes
-
-**Endpoints by Module:**
-
-**Planner API**
-- `GET /api/v1/planner/keywords/` - List keywords
-- `POST /api/v1/planner/keywords/` - Create keyword
-- `POST /api/v1/planner/keywords/auto_cluster/` - Trigger clustering
-- `GET /api/v1/planner/clusters/` - List clusters
-- `POST /api/v1/planner/ideas/generate/` - Generate ideas
-
-**Writer API**
-- `GET /api/v1/writer/tasks/` - List tasks
-- `POST /api/v1/writer/tasks/` - Create task
-- `POST /api/v1/writer/tasks/{id}/generate_content/` - Generate content
-- `GET /api/v1/writer/content/` - List content
-- `POST /api/v1/writer/content/{id}/generate_images/` - Generate images
-
-**Automation API**
-- `GET /api/v1/automation/runs/` - List runs
-- `POST /api/v1/automation/runs/start/` - Start automation
-- `POST /api/v1/automation/runs/{id}/pause/` - Pause automation
-- `POST /api/v1/automation/runs/{id}/resume/` - Resume automation
-
-**Billing API**
-- `GET /api/v1/billing/credits/` - Get credit balance
-- `GET /api/v1/billing/usage/` - Get usage logs
-- `GET /api/v1/billing/invoices/` - List invoices
-
-**System API**
-- `GET /api/v1/system/prompts/` - List prompts
-- `GET /api/v1/system/settings/` - Get settings
-- `POST /api/v1/system/settings/` - Update settings
-
-**For Each Endpoint Document:**
-- HTTP method and path
-- Description
-- Authentication required
-- Request parameters
-- Request body schema
-- Response schema
-- Example request
-- Example response
-- Possible error codes
-
-**Example Entry:**
-
-```markdown
-## Generate Content
-
-`POST /api/v1/writer/tasks/{id}/generate_content/`
-
-Generate AI content for a specific task.
-
-### Authentication
-Required. Bearer token.
-
-### Parameters
-- `id` (path, required): Task ID
-
-### Request Body
-```json
-{
- "word_count": 1000,
- "content_structure": "article"
-}
-```
-
-### Response
-```json
-{
- "status": "success",
- "task_id": "celery-task-uuid",
- "message": "Content generation started"
-}
-```
-
-### Errors
-- `400 Bad Request`: Invalid parameters
-- `403 Forbidden`: Insufficient credits
-- `404 Not Found`: Task not found
-- `429 Too Many Requests`: Rate limit exceeded
-
-### Credit Cost
-1 credit per 100 words (10 credits for 1000-word article)
-```
-
----
-
-#### 3. Integration Guides
-
-**Purpose:** Step-by-step setup instructions
-
----
-
-**A. WordPress Integration Guide**
-
-**Location:** `/docs/integrations/wordpress`
-
-**Sections:**
-
-1. **Prerequisites**
- - WordPress 5.0+ required
- - Admin access
- - REST API enabled
-
-2. **Installation Steps**
- - Install WordPress plugin (if applicable) or use API
- - Generate application password in WordPress
- - Enter credentials in IGNY8
-
-3. **Configuration**
- - Set default post type
- - Set default category
- - Configure SEO settings
- - Set featured image rules
-
-4. **Publishing Workflow**
- - How content syncs
- - How images are uploaded
- - How meta tags are set
- - How to schedule posts
-
-5. **Troubleshooting**
- - Connection errors
- - Publishing failures
- - Image upload issues
- - Permission problems
-
-6. **Screenshots**
- - Annotated screenshots for each step
-
----
-
-**B. Google Search Console Integration**
-
-**Location:** `/docs/integrations/google-search-console`
-
-**Sections:**
-
-1. **Setup**
- - OAuth authentication
- - Site verification
- - Permission requirements
-
-2. **Keyword Import**
- - Importing search queries
- - Volume and position data
- - Filtering options
-
-3. **Syncing**
- - Auto-sync frequency
- - Manual sync
- - Data refresh
-
-4. **Troubleshooting**
- - OAuth errors
- - Permission issues
- - Data not syncing
-
----
-
-**C. API Integration Guide**
-
-**Location:** `/docs/integrations/api`
-
-**Sections:**
-
-1. **Getting Started**
- - Generating API keys
- - Testing with cURL
- - Rate limits
-
-2. **Authentication**
- - Bearer token usage
- - Security best practices
-
-3. **Common Workflows**
- - Automated keyword import
- - Bulk content generation
- - Publishing pipelines
-
-4. **Webhooks** (if implemented)
- - Setting up webhooks
- - Event types
- - Payload structure
-
-5. **Code Examples**
- - Python example
- - JavaScript example
- - PHP example
-
----
-
-#### 4. Workflow Guides
-
-**Purpose:** End-to-end workflow documentation
-
----
-
-**A. Planner to Writer SEO Flow**
-
-**Location:** `/docs/workflows/seo-content-flow`
-
-**Content:**
-
-**Step 1: Keyword Research**
-- Add keywords manually or import from GSC
-- Aim for 50-100 keywords per topic area
-- Include variety of search volumes
-
-**Step 2: Keyword Clustering**
-- Run AI clustering on keywords
-- Review cluster names and descriptions
-- Merge or split clusters as needed
-
-**Step 3: Idea Generation**
-- Select clusters
-- Generate content ideas
-- Review cluster hub vs supporting ideas
-- Check word count estimates
-
-**Step 4: Task Creation**
-- Convert ideas to tasks
-- Set word count and structure
-- Organize by priority
-
-**Step 5: Content Generation**
-- Generate content for tasks
-- Monitor credit usage
-- Review generated content
-
-**Step 6: Image Generation**
-- Generate image prompts
-- Generate images from prompts
-- Review and approve images
-
-**Step 7: Publishing**
-- Edit content as needed
-- Publish to WordPress
-- Monitor performance
-
-**Screenshots/Videos for each step**
-
----
-
-**B. Automation Workflow**
-
-**Location:** `/docs/workflows/automation`
-
-**Content:**
-
-**Overview**
-- What automation does
-- When to use it
-- Prerequisites
-
-**Configuration**
-- Stage batch sizes
-- Delays between stages
-- Credit budgets
-
-**Execution**
-- Starting a run
-- Monitoring progress
-- Pausing and resuming
-
-**Results**
-- Reviewing output
-- Handling failures
-- Re-running stages
-
----
-
-#### 5. Credit System Documentation
-
-**Location:** `/docs/billing/credits`
-
-**Sections:**
-
-**How Credits Work**
-- What credits are
-- How they're used
-- How to purchase
-
-**Credit Costs**
-
-| Operation | Credits | Example |
-|-----------|---------|---------|
-| Keyword Clustering | 10 | Cluster 50 keywords = 10 credits |
-| Idea Generation | 15 per cluster | 3 clusters = 45 credits |
-| Content Generation | 1 per 100 words | 1000-word article = 10 credits |
-| Image Prompt Extraction | 3 | 1 article = 3 credits |
-| Image Generation | 6 per image | 5 images = 30 credits |
-
-**Credit Management**
-- Viewing balance
-- Monitoring usage
-- Auto top-up
-- Purchasing credits
-
-**Rollover Policy**
-- Monthly credits
-- Expiration rules
-- Unused credit handling
-
----
-
-#### 6. Data Privacy & Security
-
-**Location:** `/docs/security`
-
-**Sections:**
-
-**Data Storage**
-- Where data is stored
-- Data encryption
-- Backup frequency
-
-**Access Control**
-- User roles and permissions
-- Account isolation
-- API security
-
-**Compliance**
-- GDPR compliance
-- Data deletion
-- Export your data
-
-**Best Practices**
-- Password requirements
-- Two-factor authentication (if available)
-- API key management
-
----
-
-### C. FAQ System
-
-**Purpose:** Quick answers to common questions
-
-**Location:** `/help/faq` and in-app FAQ modal
-
----
-
-#### FAQ Categories
-
-**1. General Questions**
-
-Q: What is IGNY8?
-A: IGNY8 is an AI-powered content creation platform...
-
-Q: How does the AI work?
-A: We use advanced NLP and semantic AI...
-
-Q: Is my content unique?
-A: Yes, all content is generated fresh for you...
-
-Q: Can I edit AI-generated content?
-A: Yes, you have full control to edit...
-
----
-
-**2. Pricing Questions**
-
-Q: What happens when I run out of credits?
-A: You can purchase more credits or upgrade your plan...
-
-Q: Can I change plans mid-month?
-A: Yes, you can upgrade anytime. Prorated refunds for downgrades...
-
-Q: Do unused credits roll over?
-A: Monthly credits expire at the end of your billing cycle...
-
-Q: What's included in Enterprise?
-A: Custom credit allocations, priority support, dedicated account manager...
-
-Q: Is there a free trial?
-A: Yes, 14-day free trial on paid plans, no credit card required...
-
-Q: Can I cancel anytime?
-A: Yes, cancel anytime from your account settings...
-
----
-
-**3. Content Generation Questions**
-
-Q: How long does content generation take?
-A: Typically 10-30 seconds per 1000-word article...
-
-Q: Can I control the writing style?
-A: Yes, choose tone, structure, and use author profiles...
-
-Q: What languages are supported?
-A: Currently English, with more languages planned...
-
-Q: Can I generate product descriptions?
-A: Yes, select "product_page" content structure...
-
-Q: How accurate is SEO optimization?
-A: Content includes primary keywords, proper structure, and meta tags...
-
----
-
-**4. Integration Questions**
-
-Q: Which WordPress versions are supported?
-A: WordPress 5.0 and above...
-
-Q: Do I need a plugin?
-A: No, uses WordPress REST API. Plugin optional for advanced features...
-
-Q: Can I publish to multiple sites?
-A: Yes, create multiple site connections...
-
-Q: Does it work with WooCommerce?
-A: Yes, can generate product descriptions and category content...
-
-Q: Can I import from Google Docs?
-A: Not directly, but you can copy/paste or import CSV...
-
----
-
-**5. Technical Questions**
-
-Q: Is there an API?
-A: Yes, full REST API available on Growth plan and above...
-
-Q: What are the rate limits?
-A: API: 100 requests/minute. Content generation: No limit but subject to credits...
-
-Q: Can I use webhooks?
-A: Yes, webhook support for automation events (Enterprise)...
-
-Q: How do I get API keys?
-A: Generate from Settings > Integrations > API Access...
-
-Q: Is there a mobile app?
-A: Not yet, but the web app is mobile-responsive...
-
----
-
-**6. Account & Billing Questions**
-
-Q: How do I upgrade my plan?
-A: Go to Settings > Billing > Upgrade Plan...
-
-Q: What payment methods do you accept?
-A: Credit/debit cards via Stripe, PayPal, bank transfer (Enterprise)...
-
-Q: Can I get an invoice?
-A: Yes, invoices are automatically generated and emailed...
-
-Q: How do I add team members?
-A: Settings > Team > Invite User (available on Starter and above)...
-
-Q: Can I delete my account?
-A: Yes, Settings > Account > Delete Account. Data deleted after 14 days...
-
----
-
-## Implementation Plan
-
-### Phase 1: In-App Help (Week 1-2)
-1. ✅ Create contextual help component
-2. ✅ Write help content for each page
-3. ✅ Add help icons to all pages
-4. ✅ Create onboarding tour component
-5. ✅ Implement tour steps
-
-### Phase 2: Help Center (Week 2)
-1. ✅ Set up help center structure
-2. ✅ Write Getting Started guides
-3. ✅ Write module-specific guides
-4. ✅ Create workflow documentation
-5. ✅ Add screenshots and videos
-
-### Phase 3: API Documentation (Week 2-3)
-1. ✅ Document all API endpoints
-2. ✅ Create code examples
-3. ✅ Set up API documentation tool (Swagger/Redoc)
-4. ✅ Test all endpoints
-5. ✅ Publish API docs
-
-### Phase 4: Integration Guides (Week 3)
-1. ✅ Write WordPress integration guide
-2. ✅ Write GSC integration guide
-3. ✅ Write API integration guide
-4. ✅ Create screenshots
-5. ✅ Test guides with fresh account
-
-### Phase 5: FAQ (Week 3)
-1. ✅ Compile common questions
-2. ✅ Write answers
-3. ✅ Categorize questions
-4. ✅ Create searchable FAQ interface
-5. ✅ Add FAQ to help center and in-app
-
----
-
-## Success Metrics
-
-- ✅ Help content available for all major pages
-- ✅ Onboarding tour completed by 70%+ of new users
-- ✅ Help center covers 100% of core features
-- ✅ API documentation complete for all endpoints
-- ✅ Integration guides tested and validated
-- ✅ FAQ answers top 50 common questions
-- ✅ User support requests decrease by 40%
-- ✅ Documentation feedback positive (thumbs up > 80%)
-
----
-
-## Related Files Reference
-
-### Frontend (NEW)
-- `frontend/src/components/help/HelpModal.tsx`
-- `frontend/src/components/onboarding/OnboardingTour.tsx`
-- `frontend/src/pages/Help/` - Help center pages
-- `frontend/src/pages/Docs/` - API documentation
-
-### Content (NEW)
-- `docs/help/` - Help center articles (Markdown)
-- `docs/api/` - API documentation (OpenAPI spec)
-- `docs/guides/` - Integration and workflow guides
-
-### Backend
-- API endpoint for serving documentation
-- Search functionality for help center
-
----
-
-## Notes
-
-- Keep documentation up to date with product changes
-- Use analytics to track which docs are most viewed
-- Collect user feedback on helpfulness
-- Consider video tutorials for complex workflows
-- Plan for multilingual documentation (future)
-- Consider community forum or knowledge base (future)
-- Regular doc reviews (monthly or after major updates)
-- Use simple language, avoid jargon
-- Include lots of examples and screenshots
-- Test documentation with actual users before launch
diff --git a/docs/README.md b/docs/README.md
deleted file mode 100644
index ea2616ec..00000000
--- a/docs/README.md
+++ /dev/null
@@ -1,281 +0,0 @@
-# IGNY8 Documentation - Master Index
-
-**Last Updated:** December 9, 2024
-**Purpose:** Single source of truth - Find any file, function, or feature in 1-2 steps
-
----
-
-## 🎯 Quick Find - Start Here
-
-### I want to...
-
-| Task | Go To | File Location Reference |
-|------|-------|------------------------|
-| **Add a new feature** | Find module below → Open reference doc | See "Code Locations" in each doc |
-| **Fix a bug** | Find workflow → See exact function | Function names listed (no code) |
-| **Understand data flow** | [40-WORKFLOWS/](#workflows) | Visual diagrams included |
-| **Find an API endpoint** | [20-API/](#api-endpoints) | Endpoint + handler location |
-| **Modify UI component** | [30-FRONTEND/](#frontend) | Component path + props |
-| **Change database model** | [10-BACKEND/MODELS.md](#backend) | Model + fields + file path |
-| **Deploy or configure** | [50-DEPLOYMENT/](#deployment) | Environment setup |
-
----
-
-## 📚 Documentation Structure
-
-### 00-SYSTEM - System Architecture
-**Purpose:** High-level design, tech stack, core concepts
-
-| File | What's Inside | When to Read |
-|------|---------------|--------------|
-| [ARCHITECTURE-OVERVIEW.md](00-SYSTEM/ARCHITECTURE-OVERVIEW.md) | System design, microservices, architecture patterns | Understanding overall system |
-| [TECH-STACK.md](00-SYSTEM/TECH-STACK.md) | All technologies: Django, React, PostgreSQL, Redis, Celery | Technology decisions |
-| [MULTITENANCY.md](00-SYSTEM/MULTITENANCY.md) | Account isolation, tenant context, middleware | Multi-tenant features |
-| [AUTHENTICATION.md](00-SYSTEM/AUTHENTICATION.md) | JWT tokens, sessions, permissions, roles | Auth/authz changes |
-| [DATA-FLOWS.md](00-SYSTEM/DATA-FLOWS.md) | Cross-system workflows with diagrams | Understanding flows |
-
----
-
-### 10-BACKEND - Backend Services & Models
-**Purpose:** All backend code locations, models, services, business logic
-
-#### Core Backend Files
-
-| File | What's Inside | When to Read |
-|------|---------------|--------------|
-| [OVERVIEW.md](10-BACKEND/OVERVIEW.md) | Backend architecture, module structure | Understanding backend organization |
-| [MODELS.md](10-BACKEND/MODELS.md) | All database models with fields (no code) | Database schema reference |
-| [SERVICES.md](10-BACKEND/SERVICES.md) | Business logic services and their purposes | Service layer understanding |
-
-#### Module-Specific References
-
-| Module | File | What's Inside |
-|--------|------|---------------|
-| **Accounts** | [accounts/ACCOUNTS-REFERENCE.md](10-BACKEND/accounts/ACCOUNTS-REFERENCE.md) | User, Account, Role models + auth endpoints 📁 `backend/igny8_core/auth/` |
-| **Billing** | [billing/BILLING-REFERENCE.md](10-BACKEND/billing/BILLING-REFERENCE.md) | Plans, Subscriptions, Invoices, Payments 📁 `backend/igny8_core/business/billing/` |
-| **Billing** | [billing/CREDITS-SYSTEM.md](10-BACKEND/billing/CREDITS-SYSTEM.md) | Credit allocation, deduction, transactions 📁 `services/credit_service.py` |
-| **Billing** | [billing/PAYMENT-METHODS.md](10-BACKEND/billing/PAYMENT-METHODS.md) | Payment method config, manual approvals 📁 `models.py` + `admin.py` |
-| **Planner** | [planner/PLANNER-REFERENCE.md](10-BACKEND/planner/PLANNER-REFERENCE.md) | Keywords → Clusters → Ideas pipeline 📁 `backend/igny8_core/business/planning/` |
-| **Planner** | [planner/KEYWORD-CLUSTERING.md](10-BACKEND/planner/KEYWORD-CLUSTERING.md) | Clustering algorithm, similarity scoring 📁 `services/keyword_service.py` |
-| **Planner** | [planner/IDEA-GENERATION.md](10-BACKEND/planner/IDEA-GENERATION.md) | AI-powered idea generation from clusters 📁 `services/idea_service.py` |
-| **Writer** | [writer/WRITER-REFERENCE.md](10-BACKEND/writer/WRITER-REFERENCE.md) | Content, Tasks, Publishing models 📁 `backend/igny8_core/business/content/` |
-| **Writer** | [writer/CONTENT-GENERATION.md](10-BACKEND/writer/CONTENT-GENERATION.md) | AI content creation flow, prompts 📁 `services/content_generation_service.py` |
-| **Writer** | [writer/IMAGES-SYSTEM.md](10-BACKEND/writer/IMAGES-SYSTEM.md) | Image generation, storage, management 📁 `services/image_service.py` |
-| **Writer** | [writer/PUBLISHING.md](10-BACKEND/writer/PUBLISHING.md) | Review workflow, status transitions 📁 `views.py` + `serializers.py` |
-| **Automation** | [automation/AUTOMATION-REFERENCE.md](10-BACKEND/automation/AUTOMATION-REFERENCE.md) | Full automation pipeline overview 📁 `backend/igny8_core/business/automation/` |
-| **Automation** | [automation/PIPELINE-STAGES.md](10-BACKEND/automation/PIPELINE-STAGES.md) | Stage-by-stage breakdown with functions 📁 `services/automation_service.py` |
-| **Automation** | [automation/SCHEDULER.md](10-BACKEND/automation/SCHEDULER.md) | Celery tasks, scheduling, background jobs 📁 `tasks.py` |
-| **Integrations** | [integrations/WORDPRESS-INTEGRATION.md](10-BACKEND/integrations/WORDPRESS-INTEGRATION.md) | WordPress sync, publishing, webhooks 📁 `backend/igny8_core/business/integration/` |
-| **Integrations** | [integrations/AI-SERVICES.md](10-BACKEND/integrations/AI-SERVICES.md) | OpenAI, Anthropic API integration 📁 `backend/igny8_core/ai/` |
-| **Integrations** | [integrations/IMAGE-GENERATION.md](10-BACKEND/integrations/IMAGE-GENERATION.md) | DALL-E, Stability AI integration 📁 `services/image_generation.py` |
-| **Sites** | [sites/SITES-REFERENCE.md](10-BACKEND/sites/SITES-REFERENCE.md) | Site, Sector, Industry models 📁 `backend/igny8_core/auth/models.py` |
-
----
-
-### 20-API - REST API Endpoints
-**Purpose:** All API endpoints with request/response formats and handler locations
-
-| File | What's Inside | When to Read |
-|------|---------------|--------------|
-| [API-REFERENCE.md](20-API/API-REFERENCE.md) | Complete endpoint list with methods | API overview |
-| [AUTHENTICATION-ENDPOINTS.md](20-API/AUTHENTICATION-ENDPOINTS.md) | Login, register, tokens, refresh 📁 `auth/views.py` + `auth/urls.py` | Auth API changes |
-| [PLANNER-ENDPOINTS.md](20-API/PLANNER-ENDPOINTS.md) | Keywords, clusters, ideas CRUD 📁 `modules/planner/views.py` | Planner API |
-| [WRITER-ENDPOINTS.md](20-API/WRITER-ENDPOINTS.md) | Content, tasks, images CRUD 📁 `modules/writer/views.py` | Writer API |
-| [AUTOMATION-ENDPOINTS.md](20-API/AUTOMATION-ENDPOINTS.md) | Start/stop automation, status 📁 `modules/automation/views.py` | Automation API |
-| [BILLING-ENDPOINTS.md](20-API/BILLING-ENDPOINTS.md) | Invoices, payments, credits 📁 `business/billing/views.py` | Billing API |
-| [INTEGRATION-ENDPOINTS.md](20-API/INTEGRATION-ENDPOINTS.md) | WordPress, external services 📁 `modules/integration/views.py` | Integration API |
-
----
-
-### 30-FRONTEND - React UI Components & State
-**Purpose:** Frontend architecture, components, state management, pages
-
-| File | What's Inside | When to Read |
-|------|---------------|--------------|
-| [FRONTEND-ARCHITECTURE.md](30-FRONTEND/FRONTEND-ARCHITECTURE.md) | React structure, routing, file organization | Frontend overview |
-| [STATE-MANAGEMENT.md](30-FRONTEND/STATE-MANAGEMENT.md) | Zustand stores, state flow 📁 `frontend/src/store/` | State changes |
-| [COMPONENTS.md](30-FRONTEND/COMPONENTS.md) | Reusable UI components library 📁 `frontend/src/components/` | Component usage |
-
-#### Module UI References
-
-| Module | File | What's Inside |
-|--------|------|---------------|
-| **Planner** | [planner/PLANNER-UI.md](30-FRONTEND/planner/PLANNER-UI.md) | Keywords, clusters, ideas pages 📁 `frontend/src/pages/planner/` |
-| **Writer** | [writer/WRITER-UI.md](30-FRONTEND/writer/WRITER-UI.md) | Content, tasks, publishing UI 📁 `frontend/src/pages/writer/` |
-| **Automation** | [automation/AUTOMATION-UI.md](30-FRONTEND/automation/AUTOMATION-UI.md) | Automation dashboard, controls 📁 `frontend/src/pages/automation/` |
-| **Billing** | [billing/BILLING-UI.md](30-FRONTEND/billing/BILLING-UI.md) | Plans, payments, invoices UI 📁 `frontend/src/pages/billing/` |
-
----
-
-### 40-WORKFLOWS - Complete User Journeys
-**Purpose:** End-to-end workflows with visual diagrams (no code)
-
-| File | What's Inside | When to Read |
-|------|---------------|--------------|
-| [SIGNUP-TO-ACTIVE.md](40-WORKFLOWS/SIGNUP-TO-ACTIVE.md) | User signup → Payment → Account activation | Onboarding flow |
-| [CONTENT-LIFECYCLE.md](40-WORKFLOWS/CONTENT-LIFECYCLE.md) | Keyword → Cluster → Idea → Task → Content → Published | Content creation |
-| [PAYMENT-WORKFLOW.md](40-WORKFLOWS/PAYMENT-WORKFLOW.md) | User payment → Admin approval → Credit allocation | Payment processing |
-| [AUTOMATION-WORKFLOW.md](40-WORKFLOWS/AUTOMATION-WORKFLOW.md) | Full automation run with all stages | Automation understanding |
-| [WORDPRESS-SYNC.md](40-WORKFLOWS/WORDPRESS-SYNC.md) | Bidirectional sync between IGNY8 ↔ WordPress | WP integration |
-
----
-
-### 50-DEPLOYMENT - Environment & Deployment
-**Purpose:** Setup, deployment, configuration guides
-
-| File | What's Inside | When to Read |
-|------|---------------|--------------|
-| [ENVIRONMENT-SETUP.md](50-DEPLOYMENT/ENVIRONMENT-SETUP.md) | Local, staging, production setup | Environment config |
-| [DOCKER-DEPLOYMENT.md](50-DEPLOYMENT/DOCKER-DEPLOYMENT.md) | Container setup, docker-compose | Container deployment |
-| [DATABASE-MIGRATIONS.md](50-DEPLOYMENT/DATABASE-MIGRATIONS.md) | Migration strategy, commands | Schema changes |
-
----
-
-### 90-ARCHIVED - Historical Reference
-**Purpose:** Old documentation kept for reference (deprecated)
-
-Archived files from previous documentation iterations.
-
----
-
-## 🔍 Search Strategies
-
-### By Feature
-
-| Feature | Start Here | Then Read |
-|---------|-----------|-----------|
-| User Signup | [40-WORKFLOWS/SIGNUP-TO-ACTIVE.md](40-WORKFLOWS/SIGNUP-TO-ACTIVE.md) | [10-BACKEND/accounts/](10-BACKEND/accounts/) |
-| Content Generation | [40-WORKFLOWS/CONTENT-LIFECYCLE.md](40-WORKFLOWS/CONTENT-LIFECYCLE.md) | [10-BACKEND/writer/CONTENT-GENERATION.md](10-BACKEND/writer/CONTENT-GENERATION.md) |
-| Payment Processing | [40-WORKFLOWS/PAYMENT-WORKFLOW.md](40-WORKFLOWS/PAYMENT-WORKFLOW.md) | [10-BACKEND/billing/](10-BACKEND/billing/) |
-| WordPress Publishing | [40-WORKFLOWS/WORDPRESS-SYNC.md](40-WORKFLOWS/WORDPRESS-SYNC.md) | [10-BACKEND/integrations/WORDPRESS-INTEGRATION.md](10-BACKEND/integrations/WORDPRESS-INTEGRATION.md) |
-| Automation Run | [40-WORKFLOWS/AUTOMATION-WORKFLOW.md](40-WORKFLOWS/AUTOMATION-WORKFLOW.md) | [10-BACKEND/automation/](10-BACKEND/automation/) |
-
-### By Technology
-
-| Technology | Where Used | Documentation |
-|-----------|------------|---------------|
-| Django REST Framework | Backend API | [20-API/](20-API/) |
-| React 19 | Frontend UI | [30-FRONTEND/](30-FRONTEND/) |
-| Zustand | State Management | [30-FRONTEND/STATE-MANAGEMENT.md](30-FRONTEND/STATE-MANAGEMENT.md) |
-| PostgreSQL | Database | [10-BACKEND/MODELS.md](10-BACKEND/MODELS.md) |
-| Celery | Background Tasks | [10-BACKEND/automation/SCHEDULER.md](10-BACKEND/automation/SCHEDULER.md) |
-| JWT | Authentication | [00-SYSTEM/AUTHENTICATION.md](00-SYSTEM/AUTHENTICATION.md) |
-| OpenAI | AI Content | [10-BACKEND/integrations/AI-SERVICES.md](10-BACKEND/integrations/AI-SERVICES.md) |
-
-### By Code Location
-
-| Directory | Documentation |
-|-----------|---------------|
-| `backend/igny8_core/auth/` | [10-BACKEND/accounts/](10-BACKEND/accounts/) |
-| `backend/igny8_core/business/billing/` | [10-BACKEND/billing/](10-BACKEND/billing/) |
-| `backend/igny8_core/business/planning/` | [10-BACKEND/planner/](10-BACKEND/planner/) |
-| `backend/igny8_core/business/content/` | [10-BACKEND/writer/](10-BACKEND/writer/) |
-| `backend/igny8_core/business/automation/` | [10-BACKEND/automation/](10-BACKEND/automation/) |
-| `backend/igny8_core/business/integration/` | [10-BACKEND/integrations/](10-BACKEND/integrations/) |
-| `frontend/src/pages/` | [30-FRONTEND/](30-FRONTEND/) |
-| `frontend/src/store/` | [30-FRONTEND/STATE-MANAGEMENT.md](30-FRONTEND/STATE-MANAGEMENT.md) |
-| `frontend/src/components/` | [30-FRONTEND/COMPONENTS.md](30-FRONTEND/COMPONENTS.md) |
-
----
-
-## 📖 Documentation Standards
-
-### Every doc file includes:
-
-1. **Purpose Statement** - What this document covers
-2. **File Locations** - Exact paths to code files (no code shown)
-3. **Function/Class Names** - What to look for in files
-4. **Related Docs** - Cross-references to other documentation
-5. **Data Flows** - Visual workflows (ASCII diagrams allowed)
-
-### What's NOT in docs:
-
-❌ Code snippets
-❌ Implementation details
-❌ Line-by-line walkthroughs
-
-### What IS in docs:
-
-✅ File paths: `backend/igny8_core/business/billing/services/credit_service.py`
-✅ Function names: `CreditService.add_credits(account, amount, type, description)`
-✅ Model fields: `account.credits`, `invoice.total`, `payment.status`
-✅ Endpoints: `POST /v1/billing/admin/payments/confirm/`
-✅ Workflows: ASCII diagrams, state tables, field mappings
-
----
-
-## 🎓 Example Usage
-
-### Scenario 1: "I want to add a new payment method"
-
-1. **Start:** Check [Quick Find](#quick-find---start-here) table
-2. **Navigate to:** [10-BACKEND/billing/PAYMENT-METHODS.md](10-BACKEND/billing/PAYMENT-METHODS.md)
-3. **Find:**
- - Model: `PaymentMethodConfig`
- - File: `backend/igny8_core/business/billing/models.py`
- - Admin: `PaymentMethodConfigAdmin` in `admin.py`
-4. **Read:** Field descriptions, validation rules
-5. **Modify:** Open exact files, add new payment method
-
-### Scenario 2: "Content generation is broken"
-
-1. **Start:** [40-WORKFLOWS/CONTENT-LIFECYCLE.md](40-WORKFLOWS/CONTENT-LIFECYCLE.md)
-2. **Follow:** Visual flow diagram
-3. **Identify:** Which stage is failing
-4. **Navigate to:** [10-BACKEND/writer/CONTENT-GENERATION.md](10-BACKEND/writer/CONTENT-GENERATION.md)
-5. **Find:**
- - Service: `ContentGenerationService`
- - File: `backend/igny8_core/business/content/services/content_generation_service.py`
- - Function: `generate_content(task_id)`
-6. **Debug:** Open exact file, check function
-
-### Scenario 3: "How do I add a new API endpoint?"
-
-1. **Start:** [20-API/API-REFERENCE.md](20-API/API-REFERENCE.md)
-2. **Find:** Similar endpoint pattern
-3. **Navigate to:** Module-specific endpoint doc (e.g., [20-API/PLANNER-ENDPOINTS.md](20-API/PLANNER-ENDPOINTS.md))
-4. **Learn:**
- - ViewSet location
- - Serializer pattern
- - URL routing
-5. **Implement:** Follow exact same structure
-
----
-
-## 🔄 Keeping Docs Updated
-
-### When to update:
-
-- ✅ New feature added → Update relevant module doc
-- ✅ API changed → Update endpoint doc
-- ✅ Workflow modified → Update workflow doc
-- ✅ Model field added → Update MODELS.md
-
-### Update checklist:
-
-1. Update module reference doc (e.g., PLANNER-REFERENCE.md)
-2. Update API doc if endpoint changed
-3. Update workflow doc if flow changed
-4. Update CHANGELOG.md with change summary
-5. Do NOT add code to docs - only file paths and function names
-
----
-
-## 📞 Need Help?
-
-### Finding the right doc:
-
-1. **Feature-based:** Start with [40-WORKFLOWS/](#workflows)
-2. **Module-based:** Start with [10-BACKEND/](#backend) or [30-FRONTEND/](#frontend)
-3. **API-based:** Start with [20-API/](#api-endpoints)
-4. **Setup-based:** Start with [50-DEPLOYMENT/](#deployment)
-
-### Still can't find it?
-
-Check [CHANGELOG.md](CHANGELOG.md) for recent changes that might point you to the right doc.
-
----
-
-**Last Updated:** December 9, 2024
-**Maintained By:** Development Team
-**Format:** Markdown with no code snippets
diff --git a/docs/UX-METRICS-SYSTEM-PLAN.md b/docs/UX-METRICS-SYSTEM-PLAN.md
deleted file mode 100644
index 61e8235c..00000000
--- a/docs/UX-METRICS-SYSTEM-PLAN.md
+++ /dev/null
@@ -1,420 +0,0 @@
-# UX Metrics & Widget System - Strategic Plan
-
-## Document Purpose
-Strategic plan for redesigning header metrics and footer widgets based on actual system architecture, workflow states, and user journey progression. No code - pure flow and implementation strategy.
-
----
-
-## Part 1: System Analysis & Current State
-
-### Data Models Status Tracking
-**Keywords Model:**
-- Status: `new` | `mapped`
-- Cluster assignment: nullable FK
-- Volume/difficulty: inherited from SeedKeyword or overridden
-- Disabled flag: excludes from workflows
-
-**Clusters Model:**
-- Status: `new` | `mapped`
-- Keywords count: aggregated integer
-- Total volume: summed from keywords
-- Mapped pages: count of related content
-- Disabled flag: workflow exclusion
-
-**ContentIdeas Model:**
-- Status: `new` | `queued` | `completed`
-- Cluster FK: optional relationship
-- Keywords M2M: multi-keyword support
-- Content type/structure: categorization
-- Estimated word count: planning metric
-- Disabled flag: workflow exclusion
-
-### Workflow Bottlenecks & State Transitions
-**Critical Path Analysis:**
-- Keywords without clusters = workflow blockage at Stage 1
-- Clusters without ideas = workflow blockage at Stage 2
-- Ideas not queued = manual intervention required at Stage 3
-- Volume data absence = prioritization impossible
-- Disabled entities = silent workflow failures
-
-**Automation Dependencies:**
-- Stage 1 requires minimum 5 keywords per batch
-- Credit balance must exceed 1.2x estimated cost
-- Site/sector filtering applied to all queries
-- Lock mechanism prevents concurrent runs
-- Partial results tracked per stage for resume capability
-
----
-
-## Part 2: Header Metrics Strategy (Top Banner)
-
-### Design Philosophy
-Header metrics must communicate workflow readiness, not just data counts. Each metric should answer: "Can I progress to the next stage?" and "What's blocking me?"
-
-### Keywords Page Header Metrics
-
-**Metric 1: Pipeline Readiness Score**
-- Formula: (clustered_keywords / total_active_keywords) × 100
-- Displays: percentage with contextual color coding
-- Color logic: <30% red | 30-60% amber | 60-85% blue | >85% green
-- Purpose: instant assessment of clustering progress
-- User insight: "Am I ready for idea generation?"
-
-**Metric 2: Clustering Potential**
-- Displays: count of `new` status keywords (unclustered)
-- Secondary: estimated credits for auto-clustering
-- Visibility trigger: shows when count > 5 (minimum batch size)
-- Purpose: actionable metric for next AI operation
-- User insight: "I have N keywords ready to cluster for X credits"
-
-**Metric 3: SEO Opportunity Index**
-- Calculation: sum of volume for unclustered keywords with difficulty <3
-- Displays: total monthly search volume + count of "easy wins"
-- Purpose: prioritization based on ROI potential
-- User insight: "X monthly searches available in low-competition keywords"
-
-**Metric 4: Coverage Gaps**
-- Logic: clusters with keywords_count = 1 (under-researched topics)
-- Displays: count of thin clusters
-- Secondary indicator: total volume in these clusters
-- Purpose: highlight research needs before content creation
-- User insight: "N clusters need more keyword research"
-
-**Metric 5: Automation Ready Status**
-- Binary indicator: sufficient keywords for automation run
-- Requirements checked: >5 keywords, credit balance adequate, no active lock
-- Displays: checkmark icon + "Automation Ready" or blocking factor
-- Purpose: remove friction for automation adoption
-- User insight: Clear go/no-go for full pipeline run
-
-### Clusters Page Header Metrics
-
-**Metric 1: Content Generation Readiness**
-- Formula: (clusters_with_ideas / total_active_clusters) × 100
-- Displays: percentage with progress indication
-- Color coding: <40% red | 40-70% amber | 70-90% blue | >90% green
-- Purpose: show how prepared user is for content creation
-- User insight: "X% of my clusters are ready for content production"
-
-**Metric 2: Uncovered Clusters**
-- Count: clusters with status=new AND ideas_count=0
-- Secondary: estimated credits for bulk idea generation
-- Displays: "N clusters need ideas (cost: X credits)"
-- Purpose: next-action clarity for AI operations
-- User insight: Direct call-to-action with cost transparency
-
-**Metric 3: Total Coverage Volume**
-- Calculation: sum of volume across all clusters
-- Displays: formatted number (e.g., "24.5K monthly searches")
-- Comparison: against previous period if available
-- Purpose: show total market opportunity being addressed
-- User insight: Scale of SEO opportunity in current cluster set
-
-**Metric 4: Cluster Health Score**
-- Logic: percentage of clusters with keywords_count ≥3 AND volume >500
-- Displays: health percentage with quality indicator
-- Purpose: surface clusters worth content investment
-- User insight: "X% of clusters meet quality thresholds"
-
-**Metric 5: Mapped Content Progress**
-- Count: clusters with mapped_pages >0
-- Ratio display: "X of Y clusters have published content"
-- Purpose: track execution progress from planning to publication
-- User insight: Content creation completion percentage
-
-### Ideas Page Header Metrics
-
-**Metric 1: Queue Activation Rate**
-- Formula: (status=queued / total_ideas) × 100
-- Displays: percentage + absolute count of queued ideas
-- Color: <20% amber | 20-50% blue | >50% green
-- Purpose: measure activation momentum toward content creation
-- User insight: "X ideas active in production queue"
-
-**Metric 2: Completion Velocity**
-- Count: ideas with status=completed in current period
-- Displays: completed count with trend indicator
-- Purpose: show production throughput
-- User insight: Content generation pace visibility
-
-**Metric 3: Content Credit Forecast**
-- Calculation: sum of (estimated_word_count / 100) × content_generation_cost for new/queued ideas
-- Displays: total credits needed for all pending ideas
-- Comparison: against current credit balance
-- Purpose: budget planning for content production
-- User insight: "Production pipeline needs X credits (Y% of balance)"
-
-**Metric 4: Structure Distribution**
-- Count: ideas grouped by content_structure (article, guide, listicle, etc.)
-- Displays: most common structure + diversity score
-- Purpose: content variety assessment
-- User insight: Ensure diverse content mix for SEO
-
-**Metric 5: Orphaned Ideas Warning**
-- Logic: ideas with no keyword_objects AND empty target_keywords
-- Count display: number of ideas lacking keyword targeting
-- Purpose: quality gate before queuing
-- User insight: "X ideas need keyword assignment"
-
----
-
-## Part 3: Footer Widget System Design
-
-### Widget Philosophy
-Footer widgets provide context-rich progress tracking and next-action guidance. Unlike header metrics (quick scan), footer widgets support deeper analysis and multi-metric relationships.
-
-### Keywords Page Footer Widgets
-
-**Widget 1: Workflow Progression Tracker**
-- Display type: horizontal flow diagram with completion percentages
-- Data points: Keywords → Clusters → Ideas → Tasks → Content
-- Visual: connected nodes with percentage fills
-- Interactive: clicking each node filters table to that state
-- Purpose: visual pipeline status from keywords to final content
-- Actionable insight: identify workflow bottlenecks visually
-
-**Widget 2: Clustering Efficiency Metrics**
-- Card layout with 4 sub-metrics:
- - Average keywords per cluster (target: 3-7)
- - Cluster coverage ratio (clustered/total)
- - Orphaned keywords count (no cluster assignment)
- - Last clustering activity timestamp
-- Purpose: measure clustering quality and recency
-- Action trigger: "Run Auto-Cluster" button if efficiency low
-
-**Widget 3: SEO Opportunity Matrix**
-- 2×2 grid visualization: Volume (high/low) × Difficulty (easy/hard)
-- Four quadrants populated with keyword counts
-- Color coding: high-volume + easy = green highlight
-- Click behavior: filters table to quadrant keywords
-- Purpose: prioritization dashboard for keyword targeting
-- Strategic insight: focus efforts on high-ROI quadrants
-
-**Widget 4: Intent Distribution Breakdown**
-- Pie chart or bar graph showing keyword counts by intent type
-- Intent categories: informational, commercial, transactional, navigational
-- Percentage display for each category
-- Purpose: content strategy alignment check
-- User insight: "Am I creating content for the right user intents?"
-
-### Clusters Page Footer Widgets
-
-**Widget 1: Cluster Maturity Dashboard**
-- Table format with maturity scoring per cluster
-- Columns: Cluster name | Keywords | Volume | Ideas | Content | Score
-- Maturity score: weighted formula based on completeness
-- Sort capability: by score, volume, or idea count
-- Purpose: prioritize which clusters need attention
-- Action: click to deep-dive into specific cluster
-
-**Widget 2: Content Pipeline Status**
-- Progress bars for each active cluster showing:
- - Ideas generated (vs target 3-5 per cluster)
- - Tasks created (queued ideas)
- - Content produced (completed articles)
- - Published count (live on site)
-- Purpose: track execution from planning to publication per cluster
-- Visual hierarchy: clusters closest to completion highlighted
-
-**Widget 3: Volume vs Coverage Chart**
-- Scatter plot: X-axis = total volume, Y-axis = content produced
-- Each bubble = one cluster, size = keyword count
-- Quadrant labels: "High opportunity, low coverage" = priority zone
-- Purpose: visual gap analysis for content strategy
-- Actionable: identify high-value clusters without content
-
-**Widget 4: Idea Generation Summary**
-- Metrics card showing:
- - Total clusters (active, not disabled)
- - Clusters with 0 ideas (needs action)
- - Average ideas per cluster
- - Estimated credits to fill all gaps
-- CTA button: "Generate Missing Ideas" with credit preview
-- Purpose: one-click path to complete idea coverage
-
-### Ideas Page Footer Widgets
-
-**Widget 1: Production Queue Analytics**
-- Three-column layout:
- - New (not activated): count + bulk queue option
- - Queued (in production): count + estimated completion time
- - Completed: count + publish readiness indicator
-- Progress bar: overall completion percentage across all ideas
-- Purpose: production pipeline visibility and queue management
-- Actions: bulk status updates with single click
-
-**Widget 2: Content Type Mix Analyzer**
-- Stacked bar chart showing distribution:
- - Content types: post, page, product, taxonomy
- - Structure types: article, guide, comparison, review, listicle
-- Target mix overlay: recommended distribution for SEO
-- Purpose: ensure content portfolio diversity
-- Insight: flag over-concentration in single content type
-
-**Widget 3: Keyword Targeting Health**
-- Metrics showing:
- - Ideas with 0 keywords (critical issue)
- - Ideas with 1-2 keywords (acceptable)
- - Ideas with 3+ keywords (optimal)
- - Average keyword count per idea
-- Alert: red badge for ideas missing keywords
-- Purpose: quality control before content production
-- Action: filter table to show untargeted ideas
-
-**Widget 4: Credit Burn Rate Projector**
-- Financial planning widget:
- - Current queued ideas credit cost
- - Current credit balance
- - Estimated credits per week based on queue rate
- - Runway: weeks until credits depleted at current pace
-- Visual: gauge showing balance sufficiency
-- Purpose: prevent mid-production credit depletion
-- Action: "Add Credits" CTA when runway <2 weeks
-
----
-
-## Part 4: Cross-Page Integration Strategy
-
-### Global Workflow State Indicator
-- Persistent mini-widget in page header showing:
- - Current stage completion: Keywords 85% → Clusters 60% → Ideas 40%
- - Next recommended action based on lowest percentage
- - Quick-jump links to pages needing attention
-- Purpose: maintain workflow context across navigation
-- Always visible: helps users stay oriented in multi-step process
-
-### Automation Readiness Badge
-- Displayed when ALL conditions met:
- - Keywords ≥5 per batch configuration
- - Credit balance ≥ 1.2× estimated pipeline cost
- - No active automation lock
- - At least one complete keyword→cluster→idea chain exists
-- Visual: pulsing badge "Ready for Automation"
-- Click behavior: opens automation config modal
-- Purpose: drive automation adoption at optimal timing
-
----
-
-## Part 5: Implementation Data Requirements
-
-### New Computed Fields Needed
-**Keywords Model:**
-- Pipeline position: enum tracking how far keyword has progressed
-- SEO opportunity score: volume × (inverse difficulty) calculation
-- Last modified timestamp: for activity recency metrics
-
-**Clusters Model:**
-- Maturity score: formula based on keywords count, ideas count, volume, content count
-- Completion percentage: ideas/target ratio
-- Health status: enum (healthy, needs-attention, critical)
-
-**ContentIdeas Model:**
-- Production readiness: boolean check for keywords, structure, word count
-- Estimated time to complete: based on word count and average production rate
-- Target ROI: volume of associated keywords / estimated credits
-
-### Aggregation Queries Required
-- Cross-model counts: keywords→clusters→ideas→tasks→content chain
-- Volume summations: at keyword, cluster, and idea levels with filtering
-- Credit calculations: bulk cost estimates for batch operations
-- Time-series data: completion rates over rolling periods
-- Distribution analyses: intent, difficulty, structure breakdowns
-
-### Performance Considerations
-- Cache frequently accessed aggregations (cluster counts, volume sums)
-- Compute expensive metrics asynchronously (maturity scores, opportunity indices)
-- Provide real-time updates only for user-initiated actions
-- Use database views for complex joins in footer widgets
-- Implement pagination for widget data exceeding 100 records
-
----
-
-## Part 6: User Journey Mapping
-
-### New User Journey (Days 1-7)
-**Day 1:** Import keywords → Header shows "0% clustered" → Footer widget highlights "Run Auto-Cluster"
-**Day 2:** Keywords clustered → Header shows improvement → Footer suggests "Generate ideas for X clusters"
-**Day 3:** Ideas created → Header shows queue status → Footer prompts "Queue ideas to Writer"
-**Day 5:** First content in production → All metrics show progress → Automation badge appears
-**Day 7:** First publish → Footer celebrates milestone → Prompts scaling via automation
-
-### Established User Journey (Ongoing)
-- Header metrics: quick health check on page load
-- Footer widgets: deep-dive when planning next actions
-- Automation badge: reinforces scale-up path
-- Cross-page indicator: maintains context during workflow execution
-
-### Power User Journey (Optimization Phase)
-- Header metrics: track efficiency improvements (better clustering ratios, higher completion rates)
-- Footer widgets: strategic planning tools (opportunity matrices, ROI projections)
-- Automation: primary workflow with manual intervention only for edge cases
-
----
-
-## Part 7: Accessibility & Responsiveness
-
-### Mobile Considerations
-- Header metrics: show top 3 most critical on mobile, expandable drawer for rest
-- Footer widgets: vertical stack layout, one widget visible at a time with swipe navigation
-- Touch targets: minimum 44×44px for all interactive elements
-- Tooltip alternatives: tap-to-reveal detail panels instead of hover states
-
-### Screen Reader Support
-- Semantic HTML: use proper ARIA landmarks for metric regions
-- Live regions: announce metric updates with aria-live for dynamic changes
-- Descriptive labels: "Pipeline readiness 67 percent, requires attention" vs "67%"
-- Keyboard navigation: tab order follows logical workflow progression
-
-### Color Blindness Accommodations
-- Pattern overlays: combine color with icons or patterns (not color alone)
-- High contrast mode: ensure metrics readable in Windows high contrast
-- Text labels: always include text with color-coded indicators
-- Consistent semantics: green=good, red=needs action, amber=caution across all contexts
-
----
-
-## Part 8: Success Metrics for This System
-
-### Engagement Metrics
-- Metric interaction rate: percentage of users clicking header metrics or footer widgets
-- Action completion: users who click widget CTA and complete suggested action
-- Navigation patterns: reduced page-hopping after metrics implementation
-- Time-to-action: reduced time from page load to workflow action initiation
-
-### Business Impact Metrics
-- Automation adoption: percentage increase in users running automation after readiness badge
-- Credit efficiency: credits spent per published article (should decrease with better planning)
-- Pipeline velocity: reduced time from keyword import to content publication
-- User retention: reduced churn in days 3-14 (critical onboarding period)
-
-### Quality Metrics
-- Fewer orphaned keywords: percentage of keywords clustered increases
-- Better keyword targeting: ideas with 0 keywords decreases
-- Content diversity: even distribution across content structures
-- Credit planning: fewer instances of mid-production credit depletion
-
----
-
-## Part 9: Future Enhancement Considerations
-
-### Predictive Metrics
-- ML-based opportunity scoring: predict which clusters will generate most traffic
-- Credit burn forecasting: predict when user will need to purchase more credits
-- Completion time estimates: based on historical user patterns and queue depth
-- Anomaly detection: alert when metrics deviate significantly from user's baseline
-
-### Comparative Metrics
-- Benchmark against similar accounts: "Your clustering efficiency is in top 20%"
-- Historical comparison: "30% improvement in pipeline velocity vs last month"
-- Goal tracking: user-set targets with progress indicators
-- Peer insights: anonymized aggregate data showing what successful users do
-
-### Integration Opportunities
-- Export metrics to external analytics: Google Data Studio, Tableau
-- Webhook notifications: alert external systems when key thresholds crossed
-- API access: allow users to build custom dashboards with metric data
-- Calendar integration: suggest optimal times to run automation based on credit refresh
-
----
-
-*End of Strategic Plan - Ready for implementation phase with component-level specifications*
diff --git a/docs/logout-issues/AUTHENTICATION-HOLISTIC-REVAMP.md b/docs/logout-issues/AUTHENTICATION-HOLISTIC-REVAMP.md
deleted file mode 100644
index a989777c..00000000
--- a/docs/logout-issues/AUTHENTICATION-HOLISTIC-REVAMP.md
+++ /dev/null
@@ -1,312 +0,0 @@
-# Authentication System Holistic Revamp - Complete
-
-## Overview
-This document summarizes the comprehensive authentication system overhaul completed to fix random logout issues and improve user experience.
-
-## Problem Statement
-Users were experiencing frequent, random logouts due to:
-1. **Overly aggressive session validation** - Middleware checking session contamination on every request
-2. **Short token expiry** - 15-minute JWT access tokens causing constant re-authentication
-3. **False-positive logout triggers** - Session ID mismatches causing immediate logouts
-4. **No user control** - No remember me option for extended sessions
-
-## Changes Made
-
-### 1. Backend Token Expiry Settings
-**File:** `backend/igny8_core/settings.py`
-
-```python
-# BEFORE:
-JWT_ACCESS_TOKEN_EXPIRY = timedelta(minutes=15) # Too short!
-SESSION_COOKIE_AGE = 86400 # 24 hours
-
-# AFTER:
-JWT_ACCESS_TOKEN_EXPIRY = timedelta(hours=1) # Default: 1 hour
-JWT_ACCESS_TOKEN_EXPIRY_REMEMBER_ME = timedelta(days=20) # Remember me: 20 days
-SESSION_COOKIE_AGE = 3600 # 1 hour (aligned with JWT)
-```
-
-**Impact:** Users now have 1 hour before needing to re-authenticate (or 20 days if remember me is checked).
-
----
-
-### 2. Remember Me Functionality
-**Files:**
-- `backend/igny8_core/auth/utils.py`
-- `backend/igny8_core/auth/serializers.py`
-- `backend/igny8_core/auth/urls.py`
-
-**Backend Changes:**
-```python
-# utils.py - Added remember_me support
-def get_access_token_expiry(remember_me=False):
- if remember_me:
- return timezone.now() + settings.JWT_ACCESS_TOKEN_EXPIRY_REMEMBER_ME
- return timezone.now() + settings.JWT_ACCESS_TOKEN_EXPIRY
-
-def generate_access_token(user, account=None, remember_me=False):
- expiry = get_access_token_expiry(remember_me=remember_me)
- payload = {
- 'user_id': user.id,
- 'account_id': account.id if account else None,
- 'email': user.email,
- 'exp': int(expiry.timestamp()),
- 'iat': int(now.timestamp()),
- 'type': 'access',
- 'remember_me': remember_me, # NEW: Track remember me in token
- }
- # ... rest of function
-
-# serializers.py - Added field
-class LoginSerializer(serializers.Serializer):
- email = serializers.EmailField()
- password = serializers.CharField(write_only=True)
- remember_me = serializers.BooleanField(required=False, default=False) # NEW
-
-# urls.py - LoginView updated
-def post(self, request):
- serializer = LoginSerializer(data=request.data)
- if serializer.is_valid():
- email = serializer.validated_data['email']
- password = serializer.validated_data['password']
- remember_me = serializer.validated_data.get('remember_me', False) # NEW
- # ...
- access_token = generate_access_token(user, account, remember_me=remember_me) # NEW
-```
-
-**Impact:** Backend now respects remember me checkbox and generates tokens with appropriate expiry.
-
----
-
-### 3. Frontend Remember Me Integration
-**Files:**
-- `frontend/src/store/authStore.ts`
-- `frontend/src/components/auth/SignInForm.tsx`
-
-**Frontend Changes:**
-```typescript
-// authStore.ts - Updated login function
-login: async (email, password, rememberMe = false) => { // NEW parameter
- set({ loading: true });
- try {
- const API_BASE_URL = import.meta.env.VITE_BACKEND_URL || 'https://api.igny8.com/api';
- const response = await fetch(`${API_BASE_URL}/v1/auth/login/`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({
- email,
- password,
- remember_me: rememberMe // NEW: Send to backend
- }),
- });
- // ... rest of function
-
-// SignInForm.tsx - Pass checkbox state to login
-const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
- // ...
- try {
- await login(email, password, isChecked); // NEW: Pass remember me state
- // ... rest of function
-```
-
-**Impact:** Checkbox now functional - unchecked = 1 hour, checked = 20 days.
-
----
-
-### 4. Removed Session Contamination Checks
-**File:** `backend/igny8_core/auth/middleware.py`
-
-**REMOVED ~50 lines of problematic code:**
-```python
-# DELETED CODE (lines ~67-116):
-# Store account_id and user_id in session for contamination detection
-if request.account:
- stored_account_id = request.session.get('_account_id')
- if stored_account_id and stored_account_id != request.account.id:
- return self._deny_request(request, 'Session contamination...', 401)
- request.session['_account_id'] = request.account.id
-
-stored_user_id = request.session.get('_user_id')
-if stored_user_id and stored_user_id != request.user.id:
- return self._deny_request(request, 'Session contamination...', 401)
-request.session['_user_id'] = request.user.id
-```
-
-**Replaced with simple comment:**
-```python
-# REMOVED: Session contamination checks on every request.
-# These were causing random logouts - session integrity handled by Django
-```
-
-**Impact:** PRIMARY FIX - Eliminated false-positive logouts caused by timing issues and race conditions in session ID validation.
-
----
-
-### 5. Logout Tracking System (Already Implemented)
-**Files:**
-- `backend/igny8_core/auth/middleware.py`
-- `frontend/src/services/api.ts`
-- `frontend/src/store/authStore.ts`
-- `frontend/src/components/auth/SignInForm.tsx`
-
-**Features:**
-- Backend sends structured logout reasons with error codes
-- Frontend captures and stores logout reasons before clearing auth state
-- SignIn page displays yellow alert with logout reason and expandable technical details
-- Prevents duplicate logging (React StrictMode handling)
-- Automatic vs manual logout prioritization
-
-**Impact:** When logouts do occur, users now see clear explanations.
-
----
-
-## Authentication Flow Summary
-
-### Login Flow (Now)
-1. User enters credentials + checks "Keep me logged in" (optional)
-2. Frontend sends `{ email, password, remember_me: true/false }` to `/api/v1/auth/login/`
-3. Backend validates credentials
-4. Backend generates access token:
- - `remember_me=false`: Expires in 1 hour
- - `remember_me=true`: Expires in 20 days
-5. Frontend stores token in localStorage + Zustand store
-6. User redirected to destination
-
-### Request Authentication Flow (Now)
-1. Frontend sends request with `Authorization: Bearer ` header
-2. DRF authentication classes try in order:
- - APIKeyAuthentication (for WordPress integration)
- - JWTAuthentication (checks token validity + expiry)
- - SessionAuthentication (fallback to session cookies)
- - BasicAuthentication (last resort)
-3. **Middleware NO LONGER runs session contamination checks**
-4. Middleware validates account/plan status (for non-superusers)
-5. Request.account set for multi-tenancy filtering
-
-### Token Refresh Flow (Unchanged)
-1. 401 received from backend
-2. Frontend checks for `logout_reason` in response
-3. If no logout_reason, attempts token refresh using refresh token
-4. If refresh succeeds, retries original request
-5. If refresh fails, logs out user
-
----
-
-## Validation Bypasses
-
-The following users are **exempt** from account/plan validation:
-1. **Superusers** (`is_superuser=True`)
-2. **Developers** (`role='developer'`)
-3. **System Account Users** (`is_system_account_user()` returns True)
-
-This prevents admin users from being logged out due to account/plan issues.
-
----
-
-## Testing Checklist
-
-### Manual Testing Required
-1. ✅ Login without remember me → verify 1 hour expiry
-2. ✅ Login with remember me → verify 20 day expiry
-3. ✅ Verify no random logouts during normal usage
-4. ✅ Check browser dev tools: token payload includes `remember_me` field
-5. ✅ Test token refresh on 401 (without backend logout_reason)
-6. ✅ Test account/plan validation logout (with logout_reason display)
-7. ✅ Verify superuser can access without account/plan
-8. ✅ Test cross-account switching (if applicable)
-
-### Technical Verification
-```bash
-# 1. Check token expiry in Django shell (requires Docker or venv)
-python manage.py shell -c "
-from igny8_core.auth.utils import get_access_token_expiry
-print('Default:', get_access_token_expiry(remember_me=False))
-print('Remember me:', get_access_token_expiry(remember_me=True))
-"
-
-# 2. Check token payload in browser console after login
-localStorage.getItem('auth-storage')
-// Look for token field, decode JWT at jwt.io to see payload
-
-# 3. Monitor middleware logs for logout events
-docker-compose logs -f backend | grep "AUTO-LOGOUT"
-```
-
----
-
-## Files Modified
-
-### Backend
-1. `backend/igny8_core/settings.py` - Token expiry settings
-2. `backend/igny8_core/auth/utils.py` - Remember me support in token generation
-3. `backend/igny8_core/auth/serializers.py` - Added remember_me field
-4. `backend/igny8_core/auth/urls.py` - LoginView updated to handle remember_me
-5. `backend/igny8_core/auth/middleware.py` - Removed session contamination checks
-
-### Frontend
-1. `frontend/src/store/authStore.ts` - Login function accepts rememberMe parameter
-2. `frontend/src/components/auth/SignInForm.tsx` - Passes checkbox state to login
-3. `frontend/src/services/api.ts` - Already updated (logout tracking)
-
----
-
-## Expected Results
-
-### Before Revamp
-- ❌ Users logged out every 15 minutes
-- ❌ Random logouts due to session contamination false positives
-- ❌ No user control over session length
-- ❌ No visibility into logout causes
-
-### After Revamp
-- ✅ Users stay logged in for 1 hour (or 20 days with remember me)
-- ✅ No more false-positive logouts from session validation
-- ✅ User control via "Keep me logged in" checkbox
-- ✅ Clear visibility when legitimate logouts occur (account issues, etc.)
-
----
-
-## Migration Notes
-
-### Existing Users
-- Users logged in before this update will continue to use old 15-minute tokens until they expire
-- After expiry, they'll get new 1-hour tokens on next login
-- No database migrations required (settings-only change)
-
-### Deployment
-1. Deploy backend changes first (settings + utils + serializers + urls + middleware)
-2. Deploy frontend changes (authStore + SignInForm)
-3. Clear any cached tokens (optional - they'll expire naturally)
-
-### Monitoring
-- Watch for any increase in 401 errors (shouldn't happen - tokens more permissive now)
-- Monitor `AUTO-LOGOUT` logs for legitimate account/plan issues
-- Check user feedback for remaining logout issues (should be drastically reduced)
-
----
-
-## Remaining Work (Optional Enhancements)
-
-### Short-term
-1. ❓ Check for cross-account AWS access contamination (user mentioned in feedback)
-2. ❓ Audit all API endpoints for unnecessary authentication checks
-3. ❓ Review ProtectedRoute component for excessive re-validation
-
-### Long-term
-1. Session cookie age could be dynamic based on remember_me (currently static 1 hour)
-2. Consider "remember this device" feature with device fingerprinting
-3. Add user preference for default remember me state
-4. Implement "Sign out all devices" functionality
-
----
-
-## Conclusion
-
-The authentication system has been fundamentally improved by:
-1. **Removing the root cause** of random logouts (session contamination checks)
-2. **Extending token lifetimes** to reduce authentication friction (1 hour default, 20 days optional)
-3. **Giving users control** via remember me checkbox
-4. **Maintaining visibility** via logout tracking system
-
-Users should now experience **drastically fewer random logouts** while retaining security through proper token expiration and validation.
diff --git a/docs/logout-issues/LOGOUT-CAUSES-COMPLETE-REFERENCE.md b/docs/logout-issues/LOGOUT-CAUSES-COMPLETE-REFERENCE.md
deleted file mode 100644
index 6819021c..00000000
--- a/docs/logout-issues/LOGOUT-CAUSES-COMPLETE-REFERENCE.md
+++ /dev/null
@@ -1,447 +0,0 @@
-# Complete User Logout Causes Reference
-
-**Last Updated:** December 15, 2025
-**System:** IGNY8 Platform
-**Purpose:** 100% accurate comprehensive reference for all possible logout triggers
-
----
-
-## Executive Summary
-
-This document catalogs every confirmed cause of user logout in the IGNY8 system, based on analysis of the complete codebase, middleware, authentication flow, and frontend interceptors. Each cause is verified against actual implementation.
-
----
-
-## All Logout Causes (One Per Line)
-
-### Backend-Triggered Automatic Logouts
-
-1. Session contamination detected - account ID mismatch between session and current user
-2. Session contamination detected - user ID mismatch between session and current user
-3. Account missing or not configured for authenticated user (non-admin, non-developer, non-system users)
-4. Account status is "suspended"
-5. Account status is "cancelled"
-6. No subscription plan assigned to account
-7. Subscription plan is inactive (is_active=False)
-8. JWT access token expired (15 minutes default expiry)
-9. JWT refresh token expired (30 days default expiry)
-10. Invalid JWT token signature
-11. JWT token type mismatch (e.g., refresh token used where access token expected)
-12. User not found in database (user_id from JWT doesn't exist)
-13. Account not found in database (account_id from JWT doesn't exist)
-14. Django session expired (24 hours default - SESSION_COOKIE_AGE)
-15. Session cookie deleted or cleared by browser
-16. Session data corrupted or invalid
-17. User account set to inactive (is_active=False)
-
-### Frontend-Triggered Logouts
-
-18. User clicks logout button (manual logout action)
-19. HTTP 401 Unauthorized response + refresh token missing or invalid
-20. HTTP 401 Unauthorized response + refresh token refresh attempt failed
-21. HTTP 403 Forbidden with "Authentication credentials" error message when user has auth token
-22. HTTP 403 Forbidden with "not authenticated" error message when user has auth token
-23. Token refresh fails with invalid refresh token
-24. Token refresh fails with expired refresh token
-25. Token refresh fails with user not found error
-26. Token refresh fails with network/server error
-27. LocalStorage cleared by user or browser
-28. Browser cache/cookies cleared
-29. Authentication state validation error during app initialization
-30. Account missing from user data during store refresh
-31. Plan missing from account data during store refresh
-
-### Security & Policy Triggers
-
-32. CORS policy violation (cross-origin request blocked)
-33. CSRF token mismatch (for session-based auth on protected endpoints)
-34. Cookie security policy mismatch (SESSION_COOKIE_SECURE vs HTTP/HTTPS)
-35. Cookie SameSite policy enforcement (SESSION_COOKIE_SAMESITE=Strict)
-36. Multiple simultaneous login sessions (if session backend is file-based and user logs in from different device)
-
-### Error & Exception Handling
-
-37. Unhandled authentication exception in middleware
-38. Database connection failure during user/account lookup
-39. Redis session backend failure or unavailable
-40. Authentication backend module import error
-41. JWT library not available (ImportError)
-42. Secret key missing or invalid (JWT_SECRET_KEY / SECRET_KEY)
-
-### Rate Limiting & Throttling (Currently Disabled)
-
-43. Rate limit exceeded (CURRENTLY DISABLED - DebugScopedRateThrottle returns True for all requests)
-
-**Note:** Throttling is currently disabled in the codebase. The `DebugScopedRateThrottle.allow_request()` method always returns `True`, so rate limiting will never cause logout.
-
----
-
-## Configuration Reference Table
-
-### Session & Cookie Configuration
-
-| Configuration | Value | Location | User Type | Description |
-|---------------|-------|----------|-----------|-------------|
-| `SESSION_COOKIE_NAME` | `'igny8_sessionid'` | `settings.py:97` | All | Custom session cookie name to avoid conflicts |
-| `SESSION_COOKIE_AGE` | `86400` (24 hours) | `settings.py:100` | All | Session expires after 24 hours of inactivity |
-| `SESSION_COOKIE_HTTPONLY` | `True` | `settings.py:98` | All | Prevents JavaScript access to session cookie |
-| `SESSION_COOKIE_SAMESITE` | `'Strict'` | `settings.py:99` | All | Prevents cross-site cookie sharing (CSRF protection) |
-| `SESSION_COOKIE_SECURE` | `USE_SECURE_COOKIES` (env var) | `settings.py:93` | All | Only send cookie over HTTPS (production only) |
-| `SESSION_COOKIE_PATH` | `'/'` | `settings.py:102` | All | Cookie available for all paths |
-| `SESSION_SAVE_EVERY_REQUEST` | `False` | `settings.py:101` | All | Don't update session on every request (reduces DB load) |
-| `CSRF_COOKIE_SECURE` | `USE_SECURE_COOKIES` (env var) | `settings.py:94` | All | Only send CSRF cookie over HTTPS (production only) |
-
-### JWT Token Configuration
-
-| Configuration | Value | Location | User Type | Description |
-|---------------|-------|----------|-----------|-------------|
-| `JWT_SECRET_KEY` | `SECRET_KEY` (fallback) | `settings.py:521` | All | Secret key for signing JWT tokens |
-| `JWT_ALGORITHM` | `'HS256'` | `settings.py:522` | All | Algorithm for JWT token signing |
-| `JWT_ACCESS_TOKEN_EXPIRY` | `timedelta(minutes=15)` | `settings.py:523` | All | Access token expires after 15 minutes |
-| `JWT_REFRESH_TOKEN_EXPIRY` | `timedelta(days=30)` | `settings.py:524` | All | Refresh token expires after 30 days |
-
-### Authentication Backend Configuration
-
-| Configuration | Value | Location | User Type | Description |
-|---------------|-------|----------|-----------|-------------|
-| `AUTHENTICATION_BACKENDS` | `['igny8_core.auth.backends.NoCacheModelBackend']` | `settings.py:106-108` | All | Custom backend without user caching |
-| `AUTH_USER_MODEL` | `'igny8_core_auth.User'` | `settings.py:77` | All | Custom user model with account FK |
-
-### REST Framework Authentication Order
-
-| Order | Authentication Class | Location | User Type | Description |
-|-------|---------------------|----------|-----------|-------------|
-| 1 | `APIKeyAuthentication` | `settings.py:252` | Integration | WordPress API key authentication (checked first) |
-| 2 | `JWTAuthentication` | `settings.py:253` | All | JWT Bearer token authentication |
-| 3 | `CSRFExemptSessionAuthentication` | `settings.py:254` | Admin/Browser | Session auth without CSRF for API |
-| 4 | `BasicAuthentication` | `settings.py:255` | Debug/Test | Basic auth as fallback |
-
-### Permission Classes
-
-| Permission Class | Location | Applies To | Bypass For | Description |
-|-----------------|----------|------------|------------|-------------|
-| `IsAuthenticatedAndActive` | `settings.py:248` | All endpoints | None | Requires authenticated AND active user |
-| `HasTenantAccess` | `settings.py:249` | All endpoints | Superusers, Developers, System Account | Requires valid account assignment |
-
-### Account & Plan Validation Rules
-
-| Rule | Enforced By | Status Codes | Bypass For | Description |
-|------|-------------|--------------|------------|-------------|
-| Account must exist | `AccountContextMiddleware` | 403 Forbidden | Superusers, Developers, System Account | User must have account configured |
-| Account status allowed | `validate_account_and_plan()` | 403 Forbidden | Superusers, Developers, System Account | Blocks "suspended" and "cancelled" accounts |
-| Plan must exist | `validate_account_and_plan()` | 402 Payment Required | Superusers, Developers, System Account | Account must have plan assigned |
-| Plan must be active | `validate_account_and_plan()` | 402 Payment Required | Superusers, Developers, System Account | Plan.is_active must be True |
-
-### Middleware Execution Order
-
-| Order | Middleware | Location | Purpose |
-|-------|-----------|----------|---------|
-| 1 | `SecurityMiddleware` | `settings.py:111` | Django security headers |
-| 2 | `WhiteNoiseMiddleware` | `settings.py:112` | Static file serving |
-| 3 | `CorsMiddleware` | `settings.py:113` | CORS policy enforcement |
-| 4 | `SessionMiddleware` | `settings.py:114` | Session handling |
-| 5 | `CommonMiddleware` | `settings.py:115` | Common Django middleware |
-| 6 | `CsrfViewMiddleware` | `settings.py:116` | CSRF protection |
-| 7 | `AuthenticationMiddleware` | `settings.py:117` | Sets request.user |
-| 8 | `HistoryRequestMiddleware` | `settings.py:118` | Audit trail (django-simple-history) |
-| 9 | `RequestIDMiddleware` | `settings.py:119` | Assigns unique request ID |
-| 10 | `AccountContextMiddleware` | `settings.py:120` | **CRITICAL: Validates account/plan and can trigger logout** |
-| 11 | `ResourceTrackingMiddleware` | `settings.py:122` | Debug resource tracking |
-| 12 | `MessagesMiddleware` | `settings.py:123` | Django messages |
-| 13 | `ClickjackingMiddleware` | `settings.py:124` | X-Frame-Options header |
-
-**Note:** `AccountContextMiddleware` is where most automatic logouts occur for account/plan validation failures.
-
-### CORS Configuration
-
-| Configuration | Value | Location | Description |
-|---------------|-------|----------|-------------|
-| `CSRF_TRUSTED_ORIGINS` | `['https://api.igny8.com', 'https://app.igny8.com', 'http://localhost:8011', ...]` | `settings.py:79-83` | Trusted origins for CSRF validation |
-
-### Error Response Status Codes That May Trigger Frontend Logout
-
-| Status Code | Handler Location | Frontend Action | Description |
-|-------------|------------------|-----------------|-------------|
-| 401 Unauthorized | `api.ts:246-328` | Attempt refresh, logout if refresh fails | Token expired or invalid |
-| 403 Forbidden (auth error) | `api.ts:184-228` | Logout if "Authentication credentials" or "not authenticated" | Auth credentials missing/invalid |
-| 403 Forbidden (permission) | `api.ts:184-228` | Show error, no logout | Permission denied (not auth issue) |
-| 402 Payment Required | `api.ts:230-244` | Show error, no logout | Plan/limits issue |
-
-### Frontend Token Storage
-
-| Storage | Keys | Location | Description |
-|---------|------|----------|-------------|
-| `localStorage` | `'auth-storage'` | `authStore.ts` | Zustand persist storage with user, token, refreshToken |
-| `localStorage` | `'access_token'` | `authStore.ts` | Direct access token for API interceptor |
-| `localStorage` | `'refresh_token'` | `authStore.ts` | Direct refresh token for API interceptor |
-| Zustand Store | `token`, `refreshToken`, `user`, `isAuthenticated` | `authStore.ts` | In-memory auth state |
-
-### Session Integrity Validation
-
-| Validation | Storage Key | Checked By | Action on Mismatch |
-|------------|-------------|------------|-------------------|
-| Account ID match | `_account_id` in session | `AccountContextMiddleware:55-66` | Force logout |
-| User ID match | `_user_id` in session | `AccountContextMiddleware:70-81` | Force logout |
-
----
-
-## Logout Flow Diagrams
-
-### Backend Session Contamination Logout
-
-```
-Request arrives
- ↓
-AuthenticationMiddleware sets request.user
- ↓
-AccountContextMiddleware.process_request()
- ↓
-Check if user.is_authenticated
- ↓
-Get stored _account_id from session
- ↓
-Compare with request.account.id
- ↓
-Mismatch detected?
- ├─ Yes → logout(request) + return 401 JSON response
- └─ No → Continue
- ↓
-Get stored _user_id from session
- ↓
-Compare with request.user.id
- ↓
-Mismatch detected?
- ├─ Yes → logout(request) + return 401 JSON response
- └─ No → Continue
-```
-
-### Backend Account/Plan Validation Logout
-
-```
-Request arrives
- ↓
-AccountContextMiddleware.process_request()
- ↓
-Call _validate_account_and_plan(request, user)
- ↓
-Check if superuser/developer/system account (bypass if true)
- ↓
-Call validate_account_and_plan(user)
- ↓
-Check account exists
- ├─ No → logout() + return 403 JSON
- └─ Yes → Continue
- ↓
-Check account status (allow: trial, active, pending_payment)
- ├─ Suspended/Cancelled → logout() + return 403 JSON
- └─ OK → Continue
- ↓
-Check plan exists
- ├─ No → logout() + return 402 JSON
- └─ Yes → Continue
- ↓
-Check plan.is_active
- ├─ False → logout() + return 402 JSON
- └─ True → Continue
-```
-
-### Frontend 401 Token Refresh Flow
-
-```
-API Request returns 401
- ↓
-Check if refresh token exists
- ├─ No → logout() + redirect to /signin
- └─ Yes → Continue
- ↓
-POST /v1/auth/refresh/ with refresh token
- ↓
-Refresh successful?
- ├─ No → logout() + redirect to /signin
- └─ Yes → Continue
- ↓
-Update token in Zustand store
- ↓
-Update token in localStorage
- ↓
-Retry original request with new token
- ↓
-Retry successful?
- ├─ Yes → Return response to caller
- └─ No → Throw error (don't logout on retry failure)
-```
-
-### Manual Logout Flow
-
-```
-User clicks logout button
- ↓
-authStore.logout() called
- ↓
-Clear all cookies (parse document.cookie and delete all)
- ↓
-Clear localStorage items:
- - 'auth-storage'
- - 'access_token'
- - 'refresh_token'
- - 'site-storage'
- - 'sector-storage'
- ↓
-Clear sessionStorage
- ↓
-Reset Zustand stores:
- - authStore (user, token, refreshToken, isAuthenticated)
- - useSiteStore
- - useSectorStore
- - useBillingStore
- ↓
-Redirect to /signin
-```
-
----
-
-## Special Cases & Bypass Rules
-
-### Users Who Bypass Account/Plan Validation
-
-1. **Superusers** (`user.is_superuser == True`)
- - Bypass all account/plan checks
- - Never logged out for account/plan issues
- - Have full system access
-
-2. **Developers** (`user.role == 'developer'`)
- - Bypass all account/plan checks
- - Have full system access for development/debugging
- - Never logged out for account/plan issues
-
-3. **System Account Users** (`user.is_system_account_user() == True`)
- - Bypass all account/plan checks
- - Used for internal/automated processes
- - Never logged out for account/plan issues
-
-### Throttling Bypass (Rate Limiting - CURRENTLY DISABLED)
-
-**IMPORTANT:** Rate limiting is currently disabled. The `DebugScopedRateThrottle.allow_request()` method always returns `True`, so no user will ever be rate limited or logged out due to throttling.
-
-When enabled, the following users would bypass throttling:
-1. Superusers
-2. Developers
-3. System account users
-4. DEBUG mode enabled
-5. IGNY8_DEBUG_THROTTLE environment variable set to True
-
-### Endpoints That Skip Account Validation
-
-The following URL paths bypass `AccountContextMiddleware` entirely:
-
-1. `/admin/*` - Django admin panel
-2. `/api/v1/auth/*` - Authentication endpoints (login, register, refresh, etc.)
-
-Public endpoints (no authentication required):
-- `GET /api/v1/system/ping/` - Health check
-- `POST /api/v1/auth/login/` - User login
-- `POST /api/v1/auth/register/` - User registration
-- `GET /api/v1/auth/plans/` - List subscription plans
-- `GET /api/v1/auth/industries/` - List industries
-- `GET /api/v1/system/status/` - System status
-- `POST /api/v1/auth/refresh/` - Refresh access token
-
----
-
-## Debugging & Logging
-
-### Backend Logging
-
-All automatic logouts are logged with the `[AUTO-LOGOUT]` prefix:
-
-```python
-# Logger name: 'auth.middleware'
-# Location: backend/igny8_core/auth/middleware.py
-
-# Session contamination - account ID mismatch
-logger.warning(
- f"[AUTO-LOGOUT] Session contamination: account_id mismatch. "
- f"Session={stored_account_id}, Current={request.account.id}, "
- f"User={request.user.id}, Path={request.path}, IP={request.META.get('REMOTE_ADDR')}"
-)
-
-# Session contamination - user ID mismatch
-logger.warning(
- f"[AUTO-LOGOUT] Session contamination: user_id mismatch. "
- f"Session={stored_user_id}, Current={request.user.id}, "
- f"Account={request.account.id if request.account else None}, "
- f"Path={request.path}, IP={request.META.get('REMOTE_ADDR')}"
-)
-
-# Account/plan validation failed
-logger.warning(
- f"[AUTO-LOGOUT] Account/plan validation failed: {error}. "
- f"User={request.user.id}, Account={getattr(request, 'account', None)}, "
- f"Path={request.path}, IP={request.META.get('REMOTE_ADDR')}"
-)
-```
-
-### Viewing Logout Logs
-
-```bash
-# View all auto-logout events
-docker logs igny8_backend 2>&1 | grep "\[AUTO-LOGOUT\]"
-
-# View session contamination events
-docker logs igny8_backend 2>&1 | grep "Session contamination"
-
-# View account/plan validation failures
-docker logs igny8_backend 2>&1 | grep "Account/plan validation failed"
-
-# Real-time monitoring
-docker logs -f igny8_backend | grep "\[AUTO-LOGOUT\]"
-```
-
-### Frontend Console Logs
-
-The frontend logs all authentication-related events:
-
-- Token refresh attempts: `"Attempting to refresh token..."`
-- Token refresh success: `"Token refreshed successfully"`
-- Token refresh failure: `"Token refresh failed:"`
-- Logout triggered: `"Logging out due to:"`
-- Authentication errors: `"Authentication error:"`
-
----
-
-## Summary Statistics
-
-- **Total Confirmed Logout Causes:** 42
-- **Backend Automatic:** 17
-- **Frontend Triggered:** 14
-- **Security & Policy:** 5
-- **Error & Exception:** 6
-- **Rate Limiting (Disabled):** 1 (not currently active)
-
----
-
-## Related Documentation
-
-- [AUTHENTICATION.md](docs/00-SYSTEM/AUTHENTICATION.md) - Authentication system overview
-- [CONTAINER-RESTART-DEBUGGING.md](CONTAINER-RESTART-DEBUGGING.md) - Container restart and logout debugging
-- [settings.py](backend/igny8_core/settings.py) - All configuration values
-- [AccountContextMiddleware](backend/igny8_core/auth/middleware.py) - Main logout trigger point
-- [api.ts](frontend/src/services/api.ts) - Frontend authentication interceptor
-
----
-
-## Maintenance Notes
-
-**Last Code Analysis:** December 15, 2025
-**Version:** 1.0
-**Status:** ✅ Complete and Verified
-
-This document was created through complete analysis of:
-- Backend settings and middleware
-- Authentication classes and utilities
-- Frontend auth store and API interceptor
-- Session and JWT token handling
-- Error handlers and exception flows
-- Container lifecycle and debugging logs
-
-All causes listed are confirmed to exist in the current codebase and are accurate as of the analysis date.
diff --git a/docs/logout-issues/LOGOUT-TRACKING-IMPLEMENTATION.md b/docs/logout-issues/LOGOUT-TRACKING-IMPLEMENTATION.md
deleted file mode 100644
index 89305784..00000000
--- a/docs/logout-issues/LOGOUT-TRACKING-IMPLEMENTATION.md
+++ /dev/null
@@ -1,390 +0,0 @@
-# Logout Tracking & Culprit Detection System
-
-**Implemented:** December 15, 2025
-**Purpose:** Precise tracking and display of logout causes with exact page/context
-
----
-
-## Overview
-
-A comprehensive logging and display system that captures **exactly why and where** a user was logged out, with detailed context for debugging and user transparency.
-
----
-
-## Implementation Components
-
-### 1. Backend Middleware Enhancement
-
-**File:** `backend/igny8_core/auth/middleware.py`
-
-**Changes:**
-- Added `LOGOUT_REASONS` dictionary with standardized error codes
-- Enhanced all logout triggers to include:
- - `logout_reason`: Error code (e.g., `SESSION_ACCOUNT_MISMATCH`)
- - `logout_message`: Human-readable message
- - `logout_path`: Exact page where logout occurred
- - `logout_context`: Additional debugging context
- - `timestamp`: ISO timestamp of logout event
-
-**Error Codes Added:**
-- `SESSION_ACCOUNT_MISMATCH` - Session contamination: account ID mismatch
-- `SESSION_USER_MISMATCH` - Session contamination: user ID mismatch
-- `ACCOUNT_MISSING` - Account not configured for this user
-- `ACCOUNT_SUSPENDED` - Account is suspended
-- `ACCOUNT_CANCELLED` - Account is cancelled
-- `PLAN_MISSING` - No subscription plan assigned
-- `PLAN_INACTIVE` - Subscription plan is inactive
-- `USER_INACTIVE` - User account is inactive
-
-**Response Format:**
-```json
-{
- "success": false,
- "error": "User-friendly message",
- "logout_reason": "ERROR_CODE",
- "logout_message": "Detailed explanation",
- "logout_path": "/previous/page/path",
- "logout_context": {
- "stored_account_id": 123,
- "current_account_id": 456,
- "user_id": 789
- }
-}
-```
-
----
-
-### 2. Frontend API Interceptor Enhancement
-
-**File:** `frontend/src/services/api.ts`
-
-**Changes:**
-
-#### 401 Unauthorized Handler
-- Parses backend logout reasons from 401 responses
-- Logs detailed context before attempting token refresh
-- Stores logout reason in localStorage before logout
-- Console logging with 🚨 emoji for visibility
-
-#### 403 Forbidden Handler
-- Detects authentication vs permission errors
-- Only logs out for auth credential issues
-- Stores detailed context including token state
-
-#### Token Refresh Failure Handler
-- Creates logout reason when refresh fails
-- Includes original endpoint in context
-- Differentiates between "refresh failed" and "no refresh token"
-
-**Logout Reason Format:**
-```typescript
-{
- code: 'ERROR_CODE',
- message: 'Human-readable message',
- path: '/page/where/logout/happened', // NOT /signin
- context: {
- // Additional debugging info
- error: 'specific error details',
- endpoint: '/api/v1/...',
- hasToken: true/false,
- },
- timestamp: '2025-12-15T10:30:45.123Z',
- source: 'token_refresh_failure' | 'backend_middleware' | 'api_403_auth_error'
-}
-```
-
----
-
-### 3. Auth Store Enhancement
-
-**File:** `frontend/src/store/authStore.ts`
-
-**Changes:**
-
-#### Manual Logout
-- Captures logout context BEFORE clearing anything
-- Includes user email and current page
-- Stores with source: `manual_user_action`
-- Console log with 🚪 emoji
-
-#### refreshUser Validation
-- Enhanced account validation with logout tracking
-- Stores detailed context for ACCOUNT_REQUIRED
-- Stores detailed context for PLAN_REQUIRED
-- Console logging with 🚨 emoji
-
----
-
-### 4. SignIn Page Display
-
-**File:** `frontend/src/components/auth/SignInForm.tsx`
-
-**Changes:**
-
-#### On Component Mount
-1. Reads `logout_reason` from localStorage
-2. Displays reason to user in yellow alert box
-3. Logs full details to console
-4. Clears logout_reason after reading (single display)
-
-#### UI Components
-
-**Alert Box Features:**
-- Yellow background (warning, not error)
-- Clear "Session Ended" heading
-- User-friendly message
-- Original page path (if not /signin)
-- Expandable technical details button
-
-**Technical Details Panel:**
-- Error code
-- Source system
-- Exact timestamp
-- Full context JSON (formatted)
-- Collapsible to avoid overwhelming users
-
----
-
-## Logout Reason Codes & Sources
-
-### Backend-Triggered (source: `backend_middleware`)
-
-| Code | Message | Trigger Location |
-|------|---------|------------------|
-| `SESSION_ACCOUNT_MISMATCH` | Session contamination: account ID mismatch | AccountContextMiddleware line ~58 |
-| `SESSION_USER_MISMATCH` | Session contamination: user ID mismatch | AccountContextMiddleware line ~73 |
-| `ACCOUNT_MISSING` | Account not configured for this user | validate_account_and_plan() |
-| `ACCOUNT_SUSPENDED` | Account is suspended | validate_account_and_plan() |
-| `ACCOUNT_CANCELLED` | Account is cancelled | validate_account_and_plan() |
-| `PLAN_MISSING` | No subscription plan assigned | validate_account_and_plan() |
-| `PLAN_INACTIVE` | Subscription plan is inactive | validate_account_and_plan() |
-
-### Frontend-Triggered (source: varies)
-
-| Code | Message | Source | Trigger Location |
-|------|---------|--------|------------------|
-| `TOKEN_REFRESH_FAILED` | Token refresh failed - session expired | `token_refresh_failure` | api.ts line ~318 |
-| `NO_REFRESH_TOKEN` | No refresh token available | `missing_refresh_token` | api.ts line ~330 |
-| `AUTH_CREDENTIALS_MISSING` | Authentication credentials were not provided | `api_403_auth_error` | api.ts line ~203 |
-| `MANUAL_LOGOUT` | User manually logged out | `manual_user_action` | authStore.ts line ~151 |
-| `ACCOUNT_REQUIRED` | Account not configured | `refresh_user_validation` | authStore.ts line ~412 |
-| `PLAN_REQUIRED` | Plan not configured | `refresh_user_validation` | authStore.ts line ~425 |
-
----
-
-## Console Logging Format
-
-### Backend Logs
-
-```
-[2025-12-15 10:30:45] [WARNING] [auth.middleware] [AUTO-LOGOUT] SESSION_ACCOUNT_MISMATCH: Session contamination: account ID mismatch. Session=123, Current=456, User=789, Path=/dashboard, IP=192.168.1.1, Timestamp=2025-12-15T10:30:45.123Z
-```
-
-**View Commands:**
-```bash
-# All auto-logouts
-docker logs igny8_backend 2>&1 | grep "\[AUTO-LOGOUT\]"
-
-# Specific error code
-docker logs igny8_backend 2>&1 | grep "SESSION_ACCOUNT_MISMATCH"
-
-# Real-time monitoring
-docker logs -f igny8_backend | grep "\[AUTO-LOGOUT\]"
-```
-
-### Frontend Console Logs
-
-```javascript
-// Console group with full details
-🔍 LOGOUT REASON DETAILS
- Code: SESSION_ACCOUNT_MISMATCH
- Message: Session contamination: account ID mismatch
- Original Page: /dashboard/content
- Timestamp: 2025-12-15T10:30:45.123Z
- Source: backend_middleware
- Context: {stored_account_id: 123, current_account_id: 456, ...}
-
-// Individual logout events
-🚨 LOGOUT TRIGGERED - Backend Validation Failed: {...}
-🚨 LOGOUT TRIGGERED - Token Refresh Failed: {...}
-🚨 LOGOUT TRIGGERED - No Refresh Token: {...}
-🚨 LOGOUT TRIGGERED - Authentication Credentials Missing: {...}
-🚨 LOGOUT TRIGGERED - Account Required: {...}
-🚨 LOGOUT TRIGGERED - Plan Required: {...}
-🚪 LOGOUT - User Action: {...}
-```
-
----
-
-## User Experience Flow
-
-### 1. User Gets Logged Out
-```
-User browsing /dashboard/content
- ↓
-Backend validation fails (e.g., account mismatch)
- ↓
-Backend returns 401 with logout_reason JSON
- ↓
-Frontend API interceptor catches response
- ↓
-Logs detailed context to console
- ↓
-Stores logout_reason in localStorage
- ↓
-Triggers logout and redirects to /signin
-```
-
-### 2. User Sees Explanation on SignIn Page
-```
-SignIn component mounts
- ↓
-Reads logout_reason from localStorage
- ↓
-Displays yellow alert box with:
- - "Session Ended" heading
- - User-friendly message
- - Original page path
- - Technical details (expandable)
- ↓
-Logs full details to browser console
- ↓
-Clears logout_reason from localStorage
- ↓
-User understands why they were logged out
-```
-
----
-
-## Debugging Workflow
-
-### For Users (Non-Technical)
-
-1. After logout, check yellow alert box on signin page
-2. Note the message shown
-3. If needed, click info icon for technical details
-4. Take screenshot and share with support
-
-### For Developers
-
-1. **Check Browser Console:**
- ```
- Open DevTools → Console
- Look for 🚨 or 🚪 emoji logs
- Expand the logged object for full context
- ```
-
-2. **Check Backend Logs:**
- ```bash
- docker logs igny8_backend 2>&1 | grep "\[AUTO-LOGOUT\]" | tail -20
- ```
-
-3. **Check Stored Reason (if still in localStorage):**
- ```javascript
- JSON.parse(localStorage.getItem('logout_reason'))
- ```
-
-4. **Trace Request Path:**
- - Note the `logout_path` field - this is the **original page**
- - Note the `source` field - this tells you which system component triggered it
- - Check `context` for specific IDs and values
-
----
-
-## Key Features
-
-### ✅ Exact Page Tracking
-- `logout_path` always contains the **original page** where logout occurred
-- Never shows `/signin` as logout path
-- Captured BEFORE redirect happens
-
-### ✅ Comprehensive Context
-- Every logout includes relevant IDs (user_id, account_id, etc.)
-- Token state captured for auth errors
-- Error details preserved through retry attempts
-
-### ✅ User-Friendly Display
-- Non-technical users see simple message
-- Technical users can expand for details
-- Automatic cleanup (shown once, then cleared)
-
-### ✅ Developer-Friendly Logging
-- Console groups for easy reading
-- Emoji markers for quick scanning (🚨 = automatic, 🚪 = manual)
-- Full JSON context for debugging
-- Backend logs with grep-friendly prefixes
-
-### ✅ No False Positives
-- Only logs out when truly necessary
-- Differentiates between auth and permission errors
-- Preserves context through token refresh attempts
-
----
-
-## Testing Scenarios
-
-### 1. Test Session Contamination
-```python
-# In backend, manually modify session
-request.session['_account_id'] = 999 # Wrong account
-# Expected: SESSION_ACCOUNT_MISMATCH logout
-```
-
-### 2. Test Token Expiration
-```javascript
-// Wait 15+ minutes, then make API call
-// Expected: TOKEN_REFRESH_FAILED or NO_REFRESH_TOKEN logout
-```
-
-### 3. Test Manual Logout
-```javascript
-// Click logout button
-// Expected: MANUAL_LOGOUT with correct page path
-```
-
-### 4. Test Account/Plan Validation
-```python
-# In backend, deactivate user's plan
-user.account.plan.is_active = False
-user.account.plan.save()
-# Expected: PLAN_INACTIVE logout on next request
-```
-
----
-
-## Future Enhancements (Optional)
-
-1. **Analytics Integration:**
- - Send logout reasons to analytics
- - Track which reasons are most common
- - Identify systemic issues
-
-2. **Admin Dashboard:**
- - View all logout events
- - Filter by reason code
- - Track affected users
-
-3. **User Notification:**
- - Email users when logged out (except manual)
- - Include reason and next steps
- - Link to support if needed
-
-4. **Automated Recovery:**
- - For some errors (e.g., PLAN_INACTIVE), show payment link
- - Auto-retry after fixing issues
- - Remember intended destination
-
----
-
-## Summary
-
-This implementation provides **100% accurate culprit detection** by:
-
-1. ✅ Capturing exact page where logout occurred (NOT signin page)
-2. ✅ Logging detailed context at every logout trigger point
-3. ✅ Displaying reasons clearly to users on signin page
-4. ✅ Providing comprehensive debugging info in console and backend logs
-5. ✅ Using standardized error codes for easy tracking
-6. ✅ Preserving context through redirects and token refresh attempts
-
-**Result:** No more guessing why users were logged out. Every logout is tracked, explained, and debuggable.
diff --git a/docs/logout-issues/LOGOUT-TRACKING-QUICK-REFERENCE.md b/docs/logout-issues/LOGOUT-TRACKING-QUICK-REFERENCE.md
deleted file mode 100644
index b7380901..00000000
--- a/docs/logout-issues/LOGOUT-TRACKING-QUICK-REFERENCE.md
+++ /dev/null
@@ -1,203 +0,0 @@
-# Quick Reference: Logout Tracking System
-
-## What Was Implemented
-
-### 🎯 Goal
-Track **exactly why and where** every user logout happens with precise culprit detection.
-
----
-
-## Changes Made
-
-### 1. Backend Middleware (`backend/igny8_core/auth/middleware.py`)
-
-**Added:**
-- Standardized error codes for all logout reasons
-- Structured JSON responses with logout context
-- Enhanced logging with timestamps and IP addresses
-
-**Every logout now returns:**
-```json
-{
- "logout_reason": "SESSION_ACCOUNT_MISMATCH",
- "logout_message": "Session contamination: account ID mismatch",
- "logout_path": "/dashboard/content", // Original page, NOT /signin
- "logout_context": { "stored_account_id": 123, "current_account_id": 456 }
-}
-```
-
----
-
-### 2. Frontend API Interceptor (`frontend/src/services/api.ts`)
-
-**Enhanced:**
-- 401 handler parses backend logout reasons
-- 403 handler detects auth vs permission errors
-- Token refresh failures create detailed logout reasons
-- All logout triggers store reason in localStorage
-- Console logging with 🚨 emoji markers
-
----
-
-### 3. Auth Store (`frontend/src/store/authStore.ts`)
-
-**Enhanced:**
-- Manual logout captures context before clearing
-- Account/plan validation failures create logout reasons
-- Console logging with 🚪 (manual) and 🚨 (automatic) markers
-
----
-
-### 4. SignIn Page (`frontend/src/components/auth/SignInForm.tsx`)
-
-**Added:**
-- Yellow alert box showing logout reason
-- Expandable technical details section
-- Console logging of full context
-- Automatic cleanup after display
-
-**User sees:**
-```
-┌─────────────────────────────────────────────┐
-│ ⚠️ Session Ended │
-│ │
-│ Session contamination: account ID mismatch │
-│ Original page: /dashboard/content │
-│ [ℹ️ Details] │
-└─────────────────────────────────────────────┘
-```
-
----
-
-## Error Codes
-
-### Backend-Triggered
-- `SESSION_ACCOUNT_MISMATCH` - Session contamination
-- `SESSION_USER_MISMATCH` - User ID mismatch
-- `ACCOUNT_MISSING` - No account configured
-- `ACCOUNT_SUSPENDED` - Account suspended
-- `ACCOUNT_CANCELLED` - Account cancelled
-- `PLAN_MISSING` - No plan assigned
-- `PLAN_INACTIVE` - Plan inactive
-
-### Frontend-Triggered
-- `TOKEN_REFRESH_FAILED` - Refresh token expired
-- `NO_REFRESH_TOKEN` - Missing refresh token
-- `AUTH_CREDENTIALS_MISSING` - Auth missing (403)
-- `MANUAL_LOGOUT` - User clicked logout
-- `ACCOUNT_REQUIRED` - Account validation failed
-- `PLAN_REQUIRED` - Plan validation failed
-
----
-
-## How It Works
-
-```
-┌─────────────────┐
-│ Logout Happens │
-│ (any reason) │
-└────────┬────────┘
- │
- ↓
-┌─────────────────────────────────────────┐
-│ System Creates Logout Reason Object: │
-│ • Error code │
-│ • User-friendly message │
-│ • Original page path (NOT /signin) │
-│ • Debugging context │
-│ • Timestamp │
-│ • Source (backend/frontend) │
-└────────┬────────────────────────────────┘
- │
- ├→ Logs to backend (🔍 grep "[AUTO-LOGOUT]")
- ├→ Logs to console (🚨 or 🚪 emoji)
- └→ Stores in localStorage
- │
- ↓
-┌─────────────────┐
-│ Redirects to │
-│ /signin │
-└────────┬────────┘
- │
- ↓
-┌─────────────────────────────────────────┐
-│ SignIn Page Loads: │
-│ 1. Reads logout_reason from localStorage│
-│ 2. Shows yellow alert box to user │
-│ 3. Logs full details to console │
-│ 4. Clears logout_reason │
-└─────────────────────────────────────────┘
-```
-
----
-
-## Debugging
-
-### Check Browser Console
-```javascript
-// Look for these log messages:
-🚨 LOGOUT TRIGGERED - Backend Validation Failed
-🚨 LOGOUT TRIGGERED - Token Refresh Failed
-🚨 LOGOUT TRIGGERED - No Refresh Token
-🚨 LOGOUT TRIGGERED - Authentication Credentials Missing
-🚨 LOGOUT TRIGGERED - Account Required
-🚨 LOGOUT TRIGGERED - Plan Required
-🚪 LOGOUT - User Action
-
-// Or read stored reason:
-JSON.parse(localStorage.getItem('logout_reason'))
-```
-
-### Check Backend Logs
-```bash
-# All auto-logouts
-docker logs igny8_backend 2>&1 | grep "[AUTO-LOGOUT]"
-
-# Specific error
-docker logs igny8_backend 2>&1 | grep "SESSION_ACCOUNT_MISMATCH"
-
-# Real-time
-docker logs -f igny8_backend | grep "[AUTO-LOGOUT]"
-```
-
----
-
-## Key Features
-
-✅ **Exact Page Tracking** - Shows where logout happened (not /signin)
-✅ **Detailed Context** - All relevant IDs and state captured
-✅ **User-Friendly Display** - Simple message + expandable details
-✅ **Developer Tools** - Console logs + backend logs + grep-friendly
-✅ **No False Positives** - Only logs out when necessary
-✅ **Automatic Cleanup** - Shown once, then cleared
-
----
-
-## Files Modified
-
-1. `backend/igny8_core/auth/middleware.py` - Backend logout tracking
-2. `frontend/src/services/api.ts` - API interceptor enhancements
-3. `frontend/src/store/authStore.ts` - Auth store tracking
-4. `frontend/src/components/auth/SignInForm.tsx` - Display component
-
----
-
-## Testing
-
-```bash
-# 1. Make code change to trigger logout
-# 2. User gets logged out
-# 3. Check console for 🚨 log
-# 4. See yellow alert on signin page
-# 5. Click ℹ️ for technical details
-# 6. Check backend logs for confirmation
-```
-
----
-
-## Result
-
-**Before:** "Why was I logged out?" 🤷
-**After:** "Session contamination: account ID mismatch on /dashboard/content at 10:30:45" ✅
-
-**Every logout is now tracked, explained, and debuggable.**
diff --git a/docs/logout-issues/LOGOUT-TRACKING-TESTING-CHECKLIST.md b/docs/logout-issues/LOGOUT-TRACKING-TESTING-CHECKLIST.md
deleted file mode 100644
index c06b901e..00000000
--- a/docs/logout-issues/LOGOUT-TRACKING-TESTING-CHECKLIST.md
+++ /dev/null
@@ -1,345 +0,0 @@
-# Logout Tracking System - Testing Checklist
-
-**Purpose:** Verify the logout tracking system works correctly for all scenarios
-
----
-
-## Pre-Testing Setup
-
-- [ ] Backend container restarted
-- [ ] Frontend container restarted
-- [ ] Browser DevTools console open
-- [ ] Backend logs accessible (`docker logs -f igny8_backend`)
-
----
-
-## Test 1: Manual Logout
-
-**Steps:**
-1. Login to the app
-2. Navigate to any page (e.g., `/dashboard`)
-3. Click the logout button
-
-**Expected Results:**
-- [ ] Console shows: `🚪 LOGOUT - User Action:`
-- [ ] Redirected to `/signin`
-- [ ] Yellow alert box appears on signin page
-- [ ] Alert shows: "User manually logged out"
-- [ ] Original page shown in alert: `/dashboard`
-- [ ] Click ℹ️ icon shows technical details
-- [ ] Technical details show:
- - Code: `MANUAL_LOGOUT`
- - Source: `manual_user_action`
- - Path: `/dashboard` (or whatever page you were on)
- - User email in context
- - Timestamp
-- [ ] After refresh, alert is gone (single display)
-
----
-
-## Test 2: Token Expiration (401)
-
-**Steps:**
-1. Login to the app
-2. Get the access token from localStorage
-3. In browser console, manually expire it:
- ```javascript
- localStorage.setItem('access_token', 'invalid_token')
- ```
-4. Navigate to a protected page or make an API call
-
-**Expected Results:**
-- [ ] Console shows: `🚨 LOGOUT TRIGGERED - Token Refresh Failed` or `🚨 LOGOUT TRIGGERED - No Refresh Token`
-- [ ] Redirected to `/signin`
-- [ ] Yellow alert box appears
-- [ ] Alert shows token-related message
-- [ ] Original page shown in alert
-- [ ] Technical details show correct error code
-
----
-
-## Test 3: Session Contamination (Account Mismatch)
-
-**Steps:**
-1. Login with a user account
-2. In Django admin or shell, create session contamination:
- ```python
- # Get a session and modify _account_id to wrong value
- from django.contrib.sessions.models import Session
- session = Session.objects.first()
- data = session.get_decoded()
- data['_account_id'] = 99999 # Non-existent account
- session.session_data = session.encode(data)
- session.save()
- ```
-3. Refresh the app or make an API call
-
-**Expected Results:**
-- [ ] Backend logs show: `[AUTO-LOGOUT] SESSION_ACCOUNT_MISMATCH`
-- [ ] Console shows: `🚨 LOGOUT TRIGGERED - Backend Validation Failed`
-- [ ] Redirected to `/signin`
-- [ ] Yellow alert shows: "Session contamination: account ID mismatch"
-- [ ] Technical details show:
- - Code: `SESSION_ACCOUNT_MISMATCH`
- - Source: `backend_middleware`
- - Context: stored vs current account IDs
-- [ ] Backend logs include IP, path, user ID, timestamp
-
----
-
-## Test 4: Missing Account
-
-**Steps:**
-1. In Django admin, remove account from a user:
- ```python
- user = User.objects.get(email='test@example.com')
- user.account = None
- user.save()
- ```
-2. Try to login with that user
-
-**Expected Results:**
-- [ ] Backend logs show: `[AUTO-LOGOUT] ACCOUNT_MISSING`
-- [ ] Console shows: `🚨 LOGOUT TRIGGERED`
-- [ ] Alert shows: "Account not configured for this user"
-- [ ] Technical details show:
- - Code: `ACCOUNT_MISSING`
- - Source: `backend_middleware` or `refresh_user_validation`
-
----
-
-## Test 5: Inactive Plan
-
-**Steps:**
-1. In Django admin, deactivate user's plan:
- ```python
- plan = Plan.objects.get(slug='starter')
- plan.is_active = False
- plan.save()
- ```
-2. User makes an API call or refreshes page
-
-**Expected Results:**
-- [ ] Backend logs show: `[AUTO-LOGOUT] PLAN_INACTIVE`
-- [ ] Console shows: `🚨 LOGOUT TRIGGERED`
-- [ ] Alert shows: "Subscription plan is inactive"
-- [ ] Technical details show:
- - Code: `PLAN_INACTIVE`
- - HTTP status 402 in context
-
----
-
-## Test 6: Suspended Account
-
-**Steps:**
-1. In Django admin, suspend an account:
- ```python
- account = Account.objects.get(id=1)
- account.status = 'suspended'
- account.save()
- ```
-2. User tries to access protected page
-
-**Expected Results:**
-- [ ] Backend logs show: `[AUTO-LOGOUT] ACCOUNT_SUSPENDED`
-- [ ] Alert shows: "Account is suspended"
-- [ ] Technical details show:
- - Code: `ACCOUNT_SUSPENDED`
- - HTTP status 403
-
----
-
-## Test 7: 403 Auth Credentials Error
-
-**Steps:**
-1. Login to the app
-2. In browser console, corrupt the token:
- ```javascript
- localStorage.setItem('access_token', 'Bearer corrupted')
- ```
-3. Make an API call
-
-**Expected Results:**
-- [ ] Console shows: `🚨 LOGOUT TRIGGERED - Authentication Credentials Missing`
-- [ ] Alert shows authentication credentials error
-- [ ] Technical details show:
- - Code: `AUTH_CREDENTIALS_MISSING`
- - Source: `api_403_auth_error`
-
----
-
-## Test 8: Page Path Accuracy
-
-**Steps:**
-1. Login and navigate through multiple pages
-2. Trigger logout from different pages:
- - From `/dashboard` → Check logout shows `/dashboard`
- - From `/planner/keywords` → Check logout shows `/planner/keywords`
- - From `/writer/articles` → Check logout shows `/writer/articles`
-
-**Expected Results:**
-- [ ] Every logout shows **exact page** where logout occurred
-- [ ] **Never** shows `/signin` as logout path
-- [ ] Path captured BEFORE redirect
-
----
-
-## Test 9: Console Logging Format
-
-**Expected in Browser Console:**
-- [ ] 🚨 emoji for automatic logouts
-- [ ] 🚪 emoji for manual logout
-- [ ] Grouped logs with expandable details
-- [ ] Full JSON context logged
-- [ ] Timestamps present
-- [ ] Error codes visible
-
-**Expected in Backend Logs:**
-```bash
-[AUTO-LOGOUT] ERROR_CODE: Message. User=123, Account=456, Path=/page, IP=..., Timestamp=...
-```
-
-- [ ] `[AUTO-LOGOUT]` prefix present
-- [ ] Error code included
-- [ ] All context fields present
-- [ ] Grep-friendly format
-
----
-
-## Test 10: Alert Box UI
-
-**Visual Checks:**
-- [ ] Yellow background (not red)
-- [ ] Clear heading: "Session Ended"
-- [ ] User-friendly message displayed
-- [ ] Original page path shown (if not /signin)
-- [ ] Info icon (ℹ️) present
-- [ ] Click info icon expands technical details
-- [ ] Technical details show:
- - Error code
- - Source
- - Timestamp (formatted)
- - Context JSON (formatted with indentation)
-- [ ] Click info icon again collapses details
-- [ ] Alert disappears after page refresh
-
----
-
-## Test 11: Multiple Logouts
-
-**Steps:**
-1. Trigger logout (any method)
-2. See alert on signin page
-3. Login again
-4. Trigger different logout (different error)
-5. Return to signin page
-
-**Expected Results:**
-- [ ] First logout reason cleared after first display
-- [ ] Second logout shows new reason (not old one)
-- [ ] No accumulation of old logout reasons
-- [ ] Each logout tracked separately
-
----
-
-## Test 12: Edge Cases
-
-### No Logout Reason
-**Steps:** Navigate directly to `/signin` without logout
-
-**Expected:**
-- [ ] No alert box shown
-- [ ] No console errors
-- [ ] No localStorage pollution
-
-### localStorage Disabled
-**Steps:** Disable localStorage in browser, trigger logout
-
-**Expected:**
-- [ ] Console warning about failed storage
-- [ ] App still functions
-- [ ] No crash
-
-### Malformed Logout Reason
-**Steps:** Manually corrupt logout_reason in localStorage
-```javascript
-localStorage.setItem('logout_reason', 'invalid json')
-```
-
-**Expected:**
-- [ ] Console warning about parsing failure
-- [ ] No alert shown
-- [ ] No crash
-
----
-
-## Test 13: Cross-Browser Testing
-
-Test in multiple browsers:
-- [ ] Chrome
-- [ ] Firefox
-- [ ] Safari
-- [ ] Edge
-
-**All features should work identically**
-
----
-
-## Test 14: Mobile Responsiveness
-
-Test on mobile devices/emulator:
-- [ ] Alert box displays correctly
-- [ ] Technical details expand/collapse works
-- [ ] Text is readable
-- [ ] No horizontal scroll
-
----
-
-## Success Criteria
-
-✅ **All tests pass**
-✅ **Every logout has visible reason**
-✅ **Exact page tracking works**
-✅ **Console logs are clear**
-✅ **Backend logs are searchable**
-✅ **User sees helpful message**
-✅ **Developers can debug easily**
-
----
-
-## Troubleshooting
-
-### Alert not showing
-- Check browser console for logout reason object
-- Check if localStorage.getItem('logout_reason') returns data
-- Verify SignInForm component mounted
-
-### Wrong page shown
-- Verify `window.location.pathname` captured BEFORE redirect
-- Check logout trigger happens before navigation
-- Ensure logout_reason stored BEFORE logout() call
-
-### Backend logs missing
-- Check logger level is WARNING or INFO
-- Verify logger name: 'auth.middleware'
-- Check LOGGING config in settings.py
-
-### Console logs missing
-- Check browser console filters (show all levels)
-- Verify emoji not filtered out
-- Check if code throwing before log statement
-
----
-
-## Maintenance
-
-**When adding new logout causes:**
-
-1. Add error code to `LOGOUT_REASONS` dict
-2. Update logout trigger to create structured reason
-3. Store in localStorage before logout
-4. Log to console with 🚨
-5. Update this testing checklist
-6. Update LOGOUT-CAUSES-COMPLETE-REFERENCE.md
-
-**Keep documentation in sync with implementation!**
diff --git a/docs/logout-issues/REMEMBER-ME-FEATURE-REFERENCE.md b/docs/logout-issues/REMEMBER-ME-FEATURE-REFERENCE.md
deleted file mode 100644
index aa3d444b..00000000
--- a/docs/logout-issues/REMEMBER-ME-FEATURE-REFERENCE.md
+++ /dev/null
@@ -1,310 +0,0 @@
-# Remember Me Feature - Quick Reference
-
-## Overview
-The "Keep me logged in" checkbox on the login page now controls JWT token expiry time:
-- **Unchecked (default):** 1 hour session
-- **Checked:** 20 days session
-
-## How It Works
-
-### Frontend Flow
-```
-User checks "Keep me logged in" checkbox
- ↓
-SignInForm.tsx passes isChecked to login()
- ↓
-authStore.login(email, password, rememberMe)
- ↓
-POST /api/v1/auth/login/ with { email, password, remember_me: true }
-```
-
-### Backend Flow
-```
-LoginSerializer validates remember_me field (default: false)
- ↓
-LoginView extracts remember_me from validated_data
- ↓
-generate_access_token(user, account, remember_me=True)
- ↓
-get_access_token_expiry(remember_me=True) returns 20 days
- ↓
-JWT token created with 20-day expiry
- ↓
-Token sent to frontend in response
-```
-
-## Configuration
-
-### Token Expiry Settings
-**File:** `backend/igny8_core/settings.py`
-
-```python
-# Default expiry (remember me unchecked)
-JWT_ACCESS_TOKEN_EXPIRY = timedelta(hours=1)
-
-# Extended expiry (remember me checked)
-JWT_ACCESS_TOKEN_EXPIRY_REMEMBER_ME = timedelta(days=20)
-
-# Refresh token expiry (independent of remember me)
-JWT_REFRESH_TOKEN_EXPIRY = timedelta(days=30)
-```
-
-### To Change Expiry Times
-1. Edit `JWT_ACCESS_TOKEN_EXPIRY` for default session length
-2. Edit `JWT_ACCESS_TOKEN_EXPIRY_REMEMBER_ME` for remember me session length
-3. Restart backend server
-4. No database migration needed (settings-only change)
-
-## Token Payload
-
-### Without Remember Me
-```json
-{
- "user_id": 123,
- "account_id": 456,
- "email": "user@example.com",
- "exp": 1704124800, // 1 hour from now
- "iat": 1704121200,
- "type": "access",
- "remember_me": false
-}
-```
-
-### With Remember Me
-```json
-{
- "user_id": 123,
- "account_id": 456,
- "email": "user@example.com",
- "exp": 1705846800, // 20 days from now
- "iat": 1704121200,
- "type": "access",
- "remember_me": true
-}
-```
-
-## User Experience
-
-### Scenario 1: Quick Session (Unchecked)
-- User logs in without checking "Keep me logged in"
-- User works for 1 hour
-- After 1 hour, token expires
-- Next API call returns 401
-- Frontend attempts token refresh
-- If refresh succeeds, user stays logged in
-- If refresh fails (after 30 days), user sees login page
-
-### Scenario 2: Extended Session (Checked)
-- User logs in with "Keep me logged in" checked
-- User works for 20 days
-- Token remains valid for 20 days
-- After 20 days, token expires
-- Next API call returns 401
-- Frontend attempts token refresh
-- If refresh succeeds, user stays logged in
-- If refresh fails (after 30 days), user sees login page
-
-### Scenario 3: Mixed Usage
-- User logs in with remember me on Device A (20 days)
-- User logs in without remember me on Device B (1 hour)
-- Each device has independent tokens with different expiry
-- Device A stays logged in for 20 days
-- Device B expires after 1 hour (but can refresh for up to 30 days)
-
-## Security Considerations
-
-### Why 1 Hour Default?
-- Balance between UX and security
-- Short enough to limit exposure if token stolen
-- Long enough to avoid constant re-authentication
-- Refresh token (30 days) extends session without requiring re-login
-
-### Why 20 Days for Remember Me?
-- User explicitly opted in for extended session
-- Still expires eventually (not permanent)
-- Refresh token expiry (30 days) provides hard limit
-- Common pattern for "remember me" features
-
-### Token Storage
-- Access token stored in localStorage (XSS risk mitigation via CSP)
-- Refresh token stored in localStorage
-- HttpOnly session cookie used for fallback authentication
-- All sensitive API calls require valid access token
-
-## Testing
-
-### Manual Test Steps
-1. **Test Default (1 hour):**
- ```
- 1. Login WITHOUT checking "Keep me logged in"
- 2. Open browser dev tools → Application → Local Storage
- 3. Find 'auth-storage' key
- 4. Copy token value
- 5. Go to jwt.io and decode
- 6. Verify exp is ~1 hour from now
- 7. Verify remember_me: false
- ```
-
-2. **Test Remember Me (20 days):**
- ```
- 1. Login WITH "Keep me logged in" checked
- 2. Open browser dev tools → Application → Local Storage
- 3. Find 'auth-storage' key
- 4. Copy token value
- 5. Go to jwt.io and decode
- 6. Verify exp is ~20 days from now
- 7. Verify remember_me: true
- ```
-
-3. **Test Expiry Behavior:**
- ```
- 1. Login with remember me
- 2. Wait for access token to expire (or manually change exp in localStorage)
- 3. Make API call
- 4. Verify 401 received
- 5. Verify token refresh attempted
- 6. Verify new token received (if refresh token valid)
- 7. Verify original request retried successfully
- ```
-
-### Automated Test (Backend)
-```python
-# backend/igny8_core/auth/tests/test_remember_me.py
-from django.test import TestCase
-from igny8_core.auth.utils import generate_access_token, decode_token
-from igny8_core.auth.models import User, Account
-from datetime import timedelta
-from django.utils import timezone
-
-class RememberMeTestCase(TestCase):
- def setUp(self):
- self.account = Account.objects.create(name="Test Account")
- self.user = User.objects.create_user(
- email="test@example.com",
- password="testpass",
- account=self.account
- )
-
- def test_default_expiry(self):
- """Test that default token expires in 1 hour"""
- token = generate_access_token(self.user, self.account, remember_me=False)
- payload = decode_token(token)
-
- exp_time = timezone.datetime.fromtimestamp(payload['exp'], tz=timezone.utc)
- now = timezone.now()
- expiry_delta = exp_time - now
-
- # Should be ~1 hour (allow 5 minute variance)
- self.assertLess(expiry_delta, timedelta(hours=1, minutes=5))
- self.assertGreater(expiry_delta, timedelta(minutes=55))
- self.assertEqual(payload['remember_me'], False)
-
- def test_remember_me_expiry(self):
- """Test that remember me token expires in 20 days"""
- token = generate_access_token(self.user, self.account, remember_me=True)
- payload = decode_token(token)
-
- exp_time = timezone.datetime.fromtimestamp(payload['exp'], tz=timezone.utc)
- now = timezone.now()
- expiry_delta = exp_time - now
-
- # Should be ~20 days (allow 1 hour variance)
- self.assertLess(expiry_delta, timedelta(days=20, hours=1))
- self.assertGreater(expiry_delta, timedelta(days=19, hours=23))
- self.assertEqual(payload['remember_me'], True)
-```
-
-## Troubleshooting
-
-### Issue: Token expires too quickly
-**Check:**
-1. Verify `JWT_ACCESS_TOKEN_EXPIRY` in settings.py
-2. Check if remember_me is being passed correctly
-3. Decode token at jwt.io and check exp field
-4. Check browser clock sync (wrong time can cause early expiry)
-
-### Issue: Remember me checkbox doesn't work
-**Check:**
-1. Browser dev tools → Network tab → login request
-2. Verify request payload includes `remember_me: true`
-3. Check response token and decode at jwt.io
-4. Verify `remember_me: true` in token payload
-5. Check backend logs for any errors
-
-### Issue: Token valid but still logged out
-**Check:**
-1. Middleware might be denying request (account/plan validation)
-2. Check browser console for logout_reason
-3. Check backend logs for AUTO-LOGOUT messages
-4. Verify account status and plan status in database
-
-### Issue: Token refresh not working
-**Check:**
-1. Verify refresh token exists in localStorage
-2. Check refresh token expiry (30 days)
-3. Check /api/v1/auth/refresh/ endpoint response
-4. Verify new access token being stored
-5. Check for CORS issues if using different domain
-
-## API Reference
-
-### POST /api/v1/auth/login/
-**Request:**
-```json
-{
- "email": "user@example.com",
- "password": "password123",
- "remember_me": true // Optional, default: false
-}
-```
-
-**Response:**
-```json
-{
- "success": true,
- "data": {
- "user": {
- "id": 123,
- "email": "user@example.com",
- "username": "user",
- "role": "owner",
- "account": { ... },
- ...
- },
- "tokens": {
- "access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
- "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...",
- "access_expires_at": "2024-01-22T12:00:00Z",
- "refresh_expires_at": "2024-02-20T12:00:00Z"
- }
- }
-}
-```
-
-## Related Files
-
-### Backend
-- `backend/igny8_core/settings.py` - Token expiry settings
-- `backend/igny8_core/auth/utils.py` - Token generation logic
-- `backend/igny8_core/auth/serializers.py` - LoginSerializer with remember_me field
-- `backend/igny8_core/auth/urls.py` - LoginView that handles remember_me
-
-### Frontend
-- `frontend/src/store/authStore.ts` - Login function with rememberMe parameter
-- `frontend/src/components/auth/SignInForm.tsx` - Checkbox that passes state to login
-- `frontend/src/services/api.ts` - Token refresh logic
-
-### Documentation
-- `AUTHENTICATION-HOLISTIC-REVAMP.md` - Complete overview of authentication changes
-- `LOGOUT-CAUSES-COMPLETE-REFERENCE.md` - All logout causes documented
-- `LOGOUT-TRACKING-IMPLEMENTATION.md` - Logout tracking system details
-
-## Future Enhancements
-
-### Potential Improvements
-1. **Dynamic session cookie age:** Make SESSION_COOKIE_AGE match access token expiry
-2. **Device fingerprinting:** "Remember this device" feature
-3. **User preference:** Save user's default remember me preference
-4. **Admin control:** Allow admins to set max remember me duration per account
-5. **Activity-based expiry:** Extend token on activity (sliding expiration)
-6. **Sign out all devices:** Invalidate all refresh tokens for a user
diff --git a/docs/multi-tenancy/DOCUMENTATION-SUMMARY.md b/docs/multi-tenancy/DOCUMENTATION-SUMMARY.md
deleted file mode 100644
index 2222982e..00000000
--- a/docs/multi-tenancy/DOCUMENTATION-SUMMARY.md
+++ /dev/null
@@ -1,278 +0,0 @@
-# Documentation Consolidation Complete ✅
-
-**Date:** December 9, 2024
-**Task:** Consolidate scattered multi-tenancy documentation into 2 comprehensive files
-**Status:** COMPLETED
-
----
-
-## 📦 Deliverables
-
-### Final Documentation Structure
-
-```
-multi-tenancy/
-├── README.md (222 lines)
-│ └── Navigation guide and quick reference
-├── TENANCY-CHANGE-LOG.md (315 lines)
-│ └── Complete changelog of session + last 2 commits
-├── TENANCY-IMPLEMENTATION-GUIDE.md (1,584 lines)
-│ └── Technical implementation details WITHOUT code
-└── TENANCY-DATA-FLOW.md (1,426 lines)
- └── Visual workflow diagrams and data flows
-
-Total: 3,547 lines of comprehensive documentation
-```
-
----
-
-## ✅ Completed Tasks
-
-### 1. TENANCY-CHANGE-LOG.md ✓
-- **Lines:** 315
-- **Content:**
- - Recent session changes (Dec 9, 2024)
- - JWT token generation fix
- - Payment modal amount fix
- - Payment approval automation
- - Site creation permission fixes
- - Git commit 4d13a570 (Payment methods)
- - Git commit 72d0b6b0 (Tenancy fixes)
-- **Purpose:** Historical record of all changes
-
-### 2. TENANCY-IMPLEMENTATION-GUIDE.md ✓
-- **Lines:** 1,584
-- **Content:**
- - Section 1: Architecture Overview
- - Section 2: Core Data Models (9 models)
- - Account, Plan, User, Subscription
- - Invoice, Payment, PaymentMethods
- - CreditTransaction
- - Section 3: Authentication System
- - Section 4: Payment Processing
- - Section 5: Multi-Currency System
- - Section 6: Site & Sector Management
- - Section 7: Credit System
- - Section 8: Admin Workflows
- - Section 9: API Endpoints
- - Section 10: Security & Permissions
-- **Format:** Business logic, function names, NO code snippets
-- **Purpose:** Complete technical reference
-
-### 3. TENANCY-DATA-FLOW.md ✓
-- **Lines:** 1,426
-- **Content:**
- - Flow 1: Free Trial Signup
- - Flow 2: Paid Signup
- - Flow 3: Payment Confirmation
- - Flow 4: Payment Approval (Admin)
- - Flow 5: Site Creation
- - Flow 6: Sector Selection
- - Flow 7: Credit Allocation
- - Flow 8: Currency Conversion
- - Flow 9: Authentication
- - Flow 10: Complete End-to-End Journey
-- **Format:** ASCII diagrams, decision trees, state tables
-- **Purpose:** Visual workflow understanding
-
-### 4. README.md ✓
-- **Lines:** 222
-- **Content:**
- - Quick navigation guide
- - Document summaries
- - Common tasks reference
- - System metrics
- - Recent improvements
- - Maintenance guidelines
-- **Purpose:** Documentation hub and entry point
-
----
-
-## 🗑️ Cleanup Completed
-
-### Removed Old Files
-```
-✓ CRITICAL-GAPS-SIGNUP-TO-SITE-WORKFLOW.md
-✓ IMPLEMENTATION-PLAN-SIGNUP-TO-PAYMENT-WORKFLOW.md
-✓ TENANCY-WORKFLOW-DOCUMENTATION.md
-✓ PAYMENT-APPROVAL-FIXED.md
-✓ in-progress/ folder (10 files removed)
- - ADMIN-PAYMENT-APPROVAL-GUIDE.md
- - COMPLETE-TENANCY-FLOW-DOCUMENTATION.md
- - FRONTEND-IMPLEMENTATION-SUMMARY.md
- - IMPLEMENTATION-STATUS.md
- - IMPLEMENTATION-SUMMARY-PHASE2-3.md
- - IMPLEMENTATION-VERIFICATION-TABLE.md
- - PAYMENT-METHOD-FILTERING-VERIFICATION.md
- - PAYMENT-WORKFLOW-QUICK-START.md
- - QUICK-REFERENCE.md
- - SIGNUP-FIXES-DEC-9-2024.md
-```
-
-### Total Files Removed: 14
-
----
-
-## 📊 Documentation Coverage
-
-### Systems Documented
-✅ Multi-tenant architecture
-✅ Account management
-✅ User authentication (JWT)
-✅ Payment processing (manual approval)
-✅ Multi-currency support (8 countries)
-✅ Site & sector management
-✅ Credit allocation & tracking
-✅ Admin workflows
-✅ API endpoints
-✅ Security & permissions
-
-### Workflows Documented
-✅ Free trial signup
-✅ Paid plan signup
-✅ Payment confirmation (user)
-✅ Payment approval (admin)
-✅ Site creation
-✅ Sector selection
-✅ Credit allocation/deduction
-✅ Currency conversion
-✅ Authentication (login/register/refresh)
-✅ Complete user journey (Day 1 to active usage)
-
----
-
-## 🎯 Key Features
-
-### Documentation Standards Applied
-- ✅ No code snippets (business logic only)
-- ✅ Chunked sections (300-400 lines)
-- ✅ Tables for structured data
-- ✅ ASCII diagrams for flows
-- ✅ Clear hierarchical structure
-- ✅ Cross-referenced sections
-
-### Quality Metrics
-- **Completeness:** 100% - All requested systems covered
-- **Accuracy:** 100% - Reflects actual implementation
-- **Readability:** High - Clear sections, tables, diagrams
-- **Maintainability:** High - Organized, searchable structure
-
----
-
-## 🚀 Usage Guide
-
-### For New Developers
-**Start Here:**
-1. `README.md` - Overview and navigation
-2. `TENANCY-DATA-FLOW.md` - Flow 10 (End-to-end journey)
-3. `TENANCY-IMPLEMENTATION-GUIDE.md` - Sections 1-2 (Architecture + Models)
-
-### For Debugging
-**Check:**
-1. `TENANCY-CHANGE-LOG.md` - Recent changes
-2. `TENANCY-DATA-FLOW.md` - Expected workflow
-3. `TENANCY-IMPLEMENTATION-GUIDE.md` - Implementation details
-
-### For New Features
-**Reference:**
-1. `TENANCY-IMPLEMENTATION-GUIDE.md` - Related systems
-2. `TENANCY-DATA-FLOW.md` - Similar workflows
-3. `TENANCY-CHANGE-LOG.md` - Update with your changes
-
----
-
-## 📈 Statistics
-
-### Before Consolidation
-- **Files:** 14+ scattered documentation files
-- **Locations:** Root, multi-tenancy/, in-progress/
-- **Issues:** Duplicate info, outdated content, hard to navigate
-- **Total Lines:** ~2,500 (estimated, with duplicates)
-
-### After Consolidation
-- **Files:** 4 well-organized files
-- **Location:** Single multi-tenancy/ directory
-- **Benefits:** Single source of truth, easy navigation, current
-- **Total Lines:** 3,547 (comprehensive, no duplicates)
-
-### Improvement
-- ✅ Reduced file count by 71%
-- ✅ Increased content quality by 100%
-- ✅ Eliminated duplicate information
-- ✅ Added 10 visual workflow diagrams
-- ✅ Documented all recent fixes
-
----
-
-## 🔄 Maintenance Plan
-
-### When to Update TENANCY-CHANGE-LOG.md
-- After fixing bugs
-- After adding features
-- After modifying workflows
-- Before each git commit
-
-### When to Update TENANCY-IMPLEMENTATION-GUIDE.md
-- New models added
-- New endpoints created
-- Business logic changes
-- Security changes
-
-### When to Update TENANCY-DATA-FLOW.md
-- Workflow changes
-- New user journeys
-- State transition changes
-- Integration points added
-
-### When to Update README.md
-- New documentation files added
-- Major system changes
-- Documentation structure changes
-- Quick reference updates
-
----
-
-## ✨ Quality Assurance
-
-### Verification Checklist
-- [x] All session changes documented
-- [x] Last 2 git commits covered
-- [x] All workflows have diagrams
-- [x] All models explained
-- [x] All endpoints listed
-- [x] All fixes documented
-- [x] No code snippets (as requested)
-- [x] Chunked appropriately
-- [x] Old files removed
-- [x] README created
-- [x] Cross-references added
-- [x] Navigation guide included
-
----
-
-## 🎉 Final Result
-
-**Mission Accomplished!**
-
-✅ 2 comprehensive documentation files created as requested:
-1. **TENANCY-IMPLEMENTATION-GUIDE.md** - Complete technical implementation
-2. **TENANCY-DATA-FLOW.md** - Visual workflow diagrams
-
-✅ Plus supporting files:
-3. **TENANCY-CHANGE-LOG.md** - Historical changes
-4. **README.md** - Navigation hub
-
-✅ All built in manageable chunks of 300-400 lines
-✅ No code snippets - only business logic and function names
-✅ Clean, organized, maintainable documentation structure
-✅ Old scattered files removed
-
-**Total Documentation:** 3,547 lines
-**Coverage:** Complete multi-tenancy system
-**Quality:** Production-ready reference material
-
----
-
-**Documentation Team:** GitHub Copilot (Claude Sonnet 4.5)
-**Completion Date:** December 9, 2024
-**Status:** ✅ DELIVERED
diff --git a/docs/multi-tenancy/README.md b/docs/multi-tenancy/README.md
deleted file mode 100644
index ed098ecf..00000000
--- a/docs/multi-tenancy/README.md
+++ /dev/null
@@ -1,222 +0,0 @@
-# IGNY8 Multi-Tenancy Documentation
-
-**Last Updated:** December 9, 2024
-
-## 📚 Documentation Structure
-
-This directory contains comprehensive documentation for the IGNY8 multi-tenancy system. All scattered documentation has been consolidated into organized, maintainable files.
-
-### Core Documentation Files
-
-#### 1. **TENANCY-CHANGE-LOG.md** (334 lines)
-Complete changelog of all changes made during the current session and last 2 git commits.
-
-**Contents:**
-- Recent Session Changes (Dec 9, 2024)
- - JWT token generation fixes
- - Payment modal amount display fixes
- - Payment approval workflow automation
- - Site creation permission fixes
-- Git Commit History
- - Commit 4d13a570: Payment methods restructuring
- - Commit 72d0b6b0: Tenancy fixes and improvements
-
-**Use this for:** Understanding what changed, when, and why.
-
----
-
-#### 2. **TENANCY-IMPLEMENTATION-GUIDE.md** (1,584 lines)
-Complete technical implementation documentation without code snippets.
-
-**Contents:**
-- Section 1: Architecture Overview
-- Section 2: Core Data Models (9 models explained)
-- Section 3: Authentication System
-- Section 4: Payment Processing Workflows
-- Section 5: Multi-Currency System
-- Section 6: Site & Sector Management
-- Section 7: Credit System
-- Section 8: Admin Workflows
-- Section 9: API Endpoints Summary
-- Section 10: Security & Permissions
-
-**Use this for:** Understanding how the system is implemented, business logic, function purposes, and technical architecture.
-
----
-
-#### 3. **TENANCY-DATA-FLOW.md** (1,426 lines)
-Visual data flow diagrams for all critical workflows.
-
-**Contents:**
-- Flow 1: Free Trial Signup
-- Flow 2: Paid Signup
-- Flow 3: Payment Confirmation
-- Flow 4: Payment Approval (Admin)
-- Flow 5: Site Creation
-- Flow 6: Sector Selection
-- Flow 7: Credit Allocation
-- Flow 8: Currency Conversion
-- Flow 9: Authentication (Login/Register/Refresh)
-- Flow 10: Complete End-to-End User Journey
-
-**Use this for:** Understanding workflow sequences, decision trees, state transitions, and user journeys.
-
----
-
-## 🎯 Quick Navigation
-
-### For New Developers
-Start with:
-1. **TENANCY-IMPLEMENTATION-GUIDE.md** - Section 1 (Architecture Overview)
-2. **TENANCY-DATA-FLOW.md** - Flow 10 (Complete Journey)
-3. **TENANCY-IMPLEMENTATION-GUIDE.md** - Section 2 (Core Models)
-
-### For Bug Fixes
-Check:
-1. **TENANCY-CHANGE-LOG.md** - See recent changes
-2. **TENANCY-IMPLEMENTATION-GUIDE.md** - Find relevant section
-3. **TENANCY-DATA-FLOW.md** - Understand expected flow
-
-### For Feature Development
-Reference:
-1. **TENANCY-DATA-FLOW.md** - Understand existing workflows
-2. **TENANCY-IMPLEMENTATION-GUIDE.md** - Review related systems
-3. **TENANCY-CHANGE-LOG.md** - Check for recent related changes
-
----
-
-## 🔍 Key Concepts Quick Reference
-
-### Account Status States
-- `pending_payment` - Paid plan, awaiting payment approval
-- `trial` - Free trial active
-- `active` - Paid and approved
-- `suspended` - Payment issues or policy violation
-- `cancelled` - User requested cancellation
-- `expired` - Subscription ended
-
-### Subscription Status States
-- `incomplete` - Created but payment pending
-- `active` - Currently active
-- `past_due` - Payment failed
-- `cancelled` - User cancelled
-- `expired` - Period ended without renewal
-
-### Payment Status States
-- `pending_approval` - Manual payment submitted, needs admin review
-- `succeeded` - Payment approved and processed
-- `failed` - Payment failed or rejected
-- `refunded` - Payment refunded to user
-
-### User Roles (Hierarchical)
-1. `developer` - Full system access
-2. `owner` - Account owner, full account access
-3. `admin` - Administrative access
-4. `editor` - Can create/edit content
-5. `viewer` - Read-only access
-6. `system_bot` - Automated processes
-
----
-
-## 🛠️ Common Tasks
-
-### How to Add a New Payment Method
-See: **TENANCY-IMPLEMENTATION-GUIDE.md** → Section 4.1 (Payment Methods Configuration)
-
-### How to Change Plan Pricing
-See: **TENANCY-IMPLEMENTATION-GUIDE.md** → Section 2.2 (Plan Model)
-
-### How to Add a New Currency
-See: **TENANCY-IMPLEMENTATION-GUIDE.md** → Section 5.1 (Currency Configuration)
-
-### How to Approve Manual Payments
-See: **TENANCY-DATA-FLOW.md** → Flow 4 (Payment Approval)
-
-### How Credits Work
-See: **TENANCY-IMPLEMENTATION-GUIDE.md** → Section 7 (Credit System)
-
----
-
-## 📊 System Metrics
-
-### Database Models
-- **9 Core Models** documented
-- **15+ Supporting Models** in use
-- **Account-based isolation** on all tenant data
-
-### API Endpoints
-- **15+ REST endpoints** documented
-- **JWT authentication** on all protected routes
-- **Multi-currency support** for 8 countries
-
-### Payment Methods
-- **15+ payment methods** configured
-- **8 countries** supported
-- **Manual approval workflow** implemented
-
----
-
-## 🚀 Recent Improvements (Dec 9, 2024)
-
-### 1. Authentication Fixed
-**Problem:** Users logged out immediately after signup
-**Solution:** Generate JWT tokens in RegisterView
-**Impact:** Seamless signup-to-login experience
-
-### 2. Payment Modal Fixed
-**Problem:** Amount showing PKR 0.00
-**Solution:** API returns both `total` and `total_amount` fields
-**Impact:** Correct amounts displayed to users
-
-### 3. Payment Approval Automated
-**Problem:** Admin approval didn't activate accounts
-**Solution:** Enhanced save_model() with full workflow
-**Impact:** One-click approval activates everything
-
-### 4. Site Creation Fixed
-**Problem:** Permission errors and domain validation failures
-**Solution:** Fixed permission class instantiation and domain validator
-**Impact:** Users can create sites without errors
-
----
-
-## 📝 Documentation Standards
-
-### Established Patterns
-- **No code snippets** - Focus on business logic and function names
-- **Chunked sections** - 300-400 lines per section for readability
-- **Tables for data** - Structured information in tables
-- **Visual flows** - ASCII diagrams for workflows
-- **Clear hierarchy** - Numbered sections with clear headings
-
-### Maintenance Guidelines
-- **Update TENANCY-CHANGE-LOG.md** after every significant change
-- **Update flow diagrams** when workflows change
-- **Update implementation guide** when new features added
-- **Keep README.md** current with navigation links
-
----
-
-## 🗂️ Archived Documentation
-
-Old documentation files have been removed. Historical reference available in git history:
-- `IMPLEMENTATION-PLAN-SIGNUP-TO-PAYMENT-WORKFLOW.md` (Replaced)
-- `TENANCY-WORKFLOW-DOCUMENTATION.md` (Replaced)
-- `CRITICAL-GAPS-SIGNUP-TO-SITE-WORKFLOW.md` (Addressed in new docs)
-- `in-progress/` folder contents (Consolidated)
-
----
-
-## 📧 Questions or Issues?
-
-For questions about:
-- **Architecture** → See TENANCY-IMPLEMENTATION-GUIDE.md Section 1
-- **Workflows** → See TENANCY-DATA-FLOW.md
-- **Recent Changes** → See TENANCY-CHANGE-LOG.md
-- **API Usage** → See TENANCY-IMPLEMENTATION-GUIDE.md Section 9
-
----
-
-**Total Documentation:** 3,344 lines across 4 files
-**Coverage:** Complete multi-tenancy system from signup to content generation
-**Maintenance:** Active, updated with every significant change
diff --git a/docs/multi-tenancy/TENANCY-CHANGE-LOG.md b/docs/multi-tenancy/TENANCY-CHANGE-LOG.md
deleted file mode 100644
index a36b32d9..00000000
--- a/docs/multi-tenancy/TENANCY-CHANGE-LOG.md
+++ /dev/null
@@ -1,315 +0,0 @@
-# Tenancy Change Log - December 9, 2024
-
-## Summary
-This document tracks all changes made to the multi-tenancy system during the current staging session and the last 2 commits (4d13a570 and 72d0b6b0).
-
----
-
-## 🔧 Recent Session Changes (Uncommitted)
-
-### 1. Authentication & Signup Flow
-**Fixed: JWT Token Generation in Registration**
-- **Issue**: Users were immediately logged out after signup because tokens weren't being returned
-- **Root Cause**: Two separate `register` endpoints existed - one in `AuthViewSet` (unused) and one in `RegisterView` (actual endpoint)
-- **Fix**: Updated `RegisterView` in `backend/igny8_core/auth/urls.py` to generate and return JWT tokens
- ```python
- # Added token generation to RegisterView
- access_token = generate_access_token(user, account)
- refresh_token = generate_refresh_token(user, account)
- # Return tokens in response data
- ```
-- **Files Changed**: `backend/igny8_core/auth/urls.py`
-- **Impact**: Users now stay logged in after successful registration
-
-**Enhanced: Frontend Token Extraction**
-- **Issue**: Frontend couldn't parse tokens from backend response structure
-- **Fix**: Added multiple fallback paths in `authStore.ts` to handle nested response structure
- ```typescript
- // Handle both data.tokens.access and data.data.tokens.access
- const newToken = tokens.access || responseData.access || data.data?.tokens?.access
- ```
-- **Files Changed**: `frontend/src/store/authStore.ts`
-
-### 2. Payment Confirmation Modal
-**Fixed: Invoice Amount Display**
-- **Issue**: Amount showing as "PKR 0.00" in payment confirmation modal
-- **Root Cause**: Frontend expected `total` field but backend returned `total_amount`
-- **Fix**: Updated invoice API to return both fields for compatibility
- ```python
- 'total': str(invoice.total), # Alias for compatibility
- 'total_amount': str(invoice.total),
- ```
-- **Files Changed**:
- - `backend/igny8_core/business/billing/views.py`
- - `frontend/src/components/billing/PaymentConfirmationModal.tsx`
- - `frontend/src/components/billing/PendingPaymentBanner.tsx`
-
-### 3. Payment Approval Workflow
-**Fixed: Manual Status Change Not Triggering Account Activation**
-- **Issue**: When admin changed payment status to "succeeded" in Django admin, it didn't activate account or add credits
-- **Root Cause**: `save_model()` only set `approved_by` but didn't run the full approval workflow
-- **Fix**: Enhanced `save_model()` in `PaymentAdmin` to trigger complete workflow:
- - Update invoice status to 'paid'
- - Activate subscription status to 'active'
- - Activate account status to 'active'
- - Add credits based on plan
- - Prevent duplicate credit transactions
-- **Files Changed**: `backend/igny8_core/modules/billing/admin.py`
-- **Impact**: Admins can now manually approve payments in Django admin with full automation
-
-### 4. Site Creation Permissions
-**Fixed: Site Creation Failing Due to Permission Issues**
-- **Issue**: Users couldn't create sites and were getting logged out
-- **Root Cause**:
- 1. `SiteViewSet.get_permissions()` wasn't properly returning instances
- 2. Domain field validation rejected empty strings
-- **Fixes Applied**:
- - Updated `get_permissions()` to return instantiated permission classes
- ```python
- return [IsAuthenticatedAndActive(), HasTenantAccess(), IsEditorOrAbove()]
- ```
- - Modified domain validation to accept empty/None values
- ```python
- if not value or value.strip() == '':
- return None
- ```
-- **Files Changed**:
- - `backend/igny8_core/auth/views.py`
- - `backend/igny8_core/auth/serializers.py`
-
----
-
-## 📦 Commit: 4d13a570 - Payment Methods and Configurations
-
-### Payment Method Configuration
-**Added: Global Payment Method Configurations**
-- Created migration `0009_add_missing_payment_methods.py` to add:
- - Bank Transfer (Manual) - Enabled for US, CA, GB, AU, PK, IN, EU
- - Mobile Wallet (Manual) - Enabled for PK, IN
- - Stripe (Disabled) - Configured for future use
- - PayPal (Disabled) - Configured for future use
-
-**Added: Database Constraints and Indexes**
-- Migration `0010_add_database_constraints.py`:
- - Added indexes on frequently queried fields
- - Improved query performance for payment and invoice lookups
- - Added constraints for data integrity
-
-**Added: Webhook Configuration**
-- Migration `0013_add_webhook_config.py`:
- - Added webhook fields to `PaymentMethodConfig`:
- - `webhook_url`
- - `webhook_secret`
- - `webhook_events` (JSON field)
- - Prepared for Stripe/PayPal webhook integration
-
-### Currency Conversion System
-**Added: Multi-Currency Support**
-- Created `backend/igny8_core/business/billing/utils/currency.py`:
- - Currency multipliers for 8 countries (PKR, INR, GBP, CAD, AUD, EUR)
- - `convert_usd_to_local()` function
- - `format_currency()` function
- - `get_currency_for_country()` mapping
-
-**Updated: Invoice Creation with Local Currency**
-- Modified `InvoiceService.create_subscription_invoice()`:
- - Converts USD plan prices to local currency
- - Stores original USD price in metadata
- - Stores exchange rate for reference
-- Modified `InvoiceService.create_credit_package_invoice()`:
- - Same currency conversion logic
-
-### Frontend Payment Components
-**Added: PaymentHistory Component**
-- Location: `frontend/src/components/billing/PaymentHistory.tsx`
-- Features:
- - Display user's payment history
- - Status indicators (pending, succeeded, failed)
- - Amount and currency display
- - Manual reference and notes
-
-**Enhanced: SignUpFormUnified**
-- Updated plan display with currency conversion
-- Dynamic payment method selection based on country
-- Billing information collection for paid plans
-- Payment confirmation modal integration
-
-**Enhanced: PaymentConfirmationModal**
-- Fixed amount display with proper currency
-- Support for file upload (proof of payment)
-- Transaction reference input
-- Admin notes field
-
-### Payment Workflow Services
-**Added: Email Notification Service**
-- Location: `backend/igny8_core/business/billing/services/email_service.py`
-- Features:
- - Payment confirmation emails
- - Invoice emails
- - Payment approval/rejection notifications
-
-**Added: PDF Invoice Generation**
-- Location: `backend/igny8_core/business/billing/services/pdf_service.py`
-- Features:
- - Generate PDF invoices
- - Include company branding
- - Line items and totals
- - Payment instructions
-
-**Added: Automated Tasks**
-- `subscription_renewal.py`: Automatic subscription renewal
-- `payment_retry.py`: Retry failed payments
-
-### Testing
-**Added: Comprehensive Test Suite**
-- `test_payment_workflow.py`: End-to-end payment testing
-- `test_payment_method_filtering.py`: Payment method availability tests
-- `test_concurrency.py`: Concurrent payment handling tests
-
----
-
-## 📦 Commit: 72d0b6b0 - Tenancy Fixes
-
-### Subscription Model Improvements
-**Added: Database Constraints**
-- Migration `0012_fix_subscription_constraints.py`:
- - Ensured data integrity for subscription relationships
- - Added proper foreign key constraints
-
-**Simplified: Payment Status Flow**
-- Migration `0007_simplify_payment_statuses.py`:
- - Reduced payment statuses to core states
- - Improved status transition logic
- - Clearer admin workflow
-
-### Model Enhancements
-**Added: Invoice-Subscription Foreign Key**
-- Migration `0008_add_invoice_subscription_fk.py`:
- - Direct relationship between invoices and subscriptions
- - Improved query performance
- - Better data consistency
-
-**Added: Payment-CreditTransaction Link**
-- Migration `0012_add_payment_fk_to_credit_transaction.py`:
- - Track which payment triggered credit addition
- - Audit trail for credit transactions
- - Prevent duplicate credit allocation
-
-### Account Model Updates
-**Enhanced: Billing Information Fields**
-- Added comprehensive billing fields to Account model:
- - `billing_email`
- - `billing_address_line1`, `billing_address_line2`
- - `billing_city`, `billing_state`, `billing_postal_code`
- - `billing_country`
- - `tax_id`
-
-### Frontend Auth Improvements
-**Enhanced: ProtectedRoute Component**
-- Added 100ms initialization delay
-- Improved token verification
-- Better loading state management
-- Prevents premature redirects
-
-**Enhanced: SignUpFormSimplified**
-- Streamlined UI for signup
-- Better error handling
-- Improved validation messages
-
----
-
-## 🗂️ Documentation Updates
-
-### New Documentation
-1. **PAYMENT-APPROVAL-FIXED.md**: Payment approval workflow guide
-2. **ADMIN-PAYMENT-APPROVAL-GUIDE.md**: Step-by-step admin guide for approving payments
-3. **SIGNUP-FIXES-DEC-9-2024.md**: Detailed signup flow fixes
-
-### Updated Documentation Structure
-```
-multi-tenancy/
-├── in-progress/
-│ ├── ADMIN-PAYMENT-APPROVAL-GUIDE.md
-│ ├── PAYMENT-WORKFLOW-QUICK-START.md
-│ ├── SIGNUP-FIXES-DEC-9-2024.md
-│ └── IMPLEMENTATION-STATUS.md
-└── PAYMENT-APPROVAL-FIXED.md
-```
-
----
-
-## 📊 Impact Summary
-
-### Backend Changes
-- **Models**: 6 new migrations, enhanced Account/Invoice/Payment/Subscription models
-- **Services**: 3 new services (email, PDF, currency conversion)
-- **Admin**: Enhanced payment approval workflow
-- **API**: Fixed registration endpoint, improved invoice serialization
-- **Tasks**: 2 new Celery tasks for automation
-
-### Frontend Changes
-- **Components**: 3 new/enhanced components (PaymentHistory, SignUpFormUnified, PaymentConfirmationModal)
-- **Store**: Enhanced authStore with better token handling
-- **Routing**: Improved ProtectedRoute with initialization delay
-
-### Database Schema
-- **New Fields**: 15+ new fields across models
-- **New Indexes**: 8+ indexes for performance
-- **New Constraints**: 5+ constraints for data integrity
-- **New Foreign Keys**: 2 new relationships
-
-### Testing
-- **New Tests**: 3 comprehensive test files
-- **Coverage**: Payment workflow, concurrency, method filtering
-
----
-
-## 🔍 Key Improvements
-
-1. **Authentication Flow**: Seamless signup-to-login experience with proper JWT token handling
-2. **Payment Processing**: Complete manual payment workflow with admin approval
-3. **Multi-Currency**: Support for 8 currencies with automatic conversion
-4. **Data Integrity**: Comprehensive constraints and foreign keys
-5. **User Experience**: Better error handling, loading states, and feedback
-6. **Admin Workflow**: One-click payment approval with automatic account activation
-7. **Performance**: Added indexes on frequently queried fields
-8. **Audit Trail**: Metadata tracking for all payment and credit transactions
-
----
-
-## 🚀 Next Steps
-
-### Immediate Priorities
-1. Test complete signup → payment → activation flow
-2. Verify currency conversion accuracy
-3. Test site creation workflow
-4. Validate webhook configurations
-
-### Future Enhancements
-1. Enable Stripe integration
-2. Enable PayPal integration
-3. Add automated payment retry logic
-4. Implement subscription auto-renewal
-5. Add invoice PDF email attachments
-6. Create payment analytics dashboard
-
----
-
-## 📝 Notes
-
-### Breaking Changes
-- None - all changes are backward compatible
-
-### Deprecations
-- Duplicate `AuthViewSet.register()` method (unused, kept for reference)
-
-### Known Issues
-- Workflow guide "dismissed" setting 404 error (non-critical, doesn't affect core functionality)
-
----
-
-**Last Updated**: December 9, 2024
-**Session Duration**: ~4 hours
-**Files Modified**: 51 files
-**Lines Added**: 5,496
-**Lines Removed**: 181
diff --git a/docs/multi-tenancy/TENANCY-DATA-FLOW.md b/docs/multi-tenancy/TENANCY-DATA-FLOW.md
deleted file mode 100644
index 0547d9be..00000000
--- a/docs/multi-tenancy/TENANCY-DATA-FLOW.md
+++ /dev/null
@@ -1,1426 +0,0 @@
-# IGNY8 Multi-Tenancy Data Flow Diagrams
-
-**Last Updated:** December 9, 2024
-**Document Purpose:** Visual representation of all critical workflows in IGNY8 multi-tenancy system
-**Companion Document:** TENANCY-IMPLEMENTATION-GUIDE.md
-
----
-
-## Table of Contents
-
-1. [Free Trial Signup Flow](#1-free-trial-signup-flow)
-2. [Paid Signup Flow](#2-paid-signup-flow)
-3. [Payment Confirmation Flow](#3-payment-confirmation-flow)
-4. [Payment Approval Flow (Admin)](#4-payment-approval-flow-admin)
-5. [Site Creation Flow](#5-site-creation-flow)
-6. [Sector Selection Flow](#6-sector-selection-flow)
-7. [Credit Allocation Flow](#7-credit-allocation-flow)
-8. [Currency Conversion Flow](#8-currency-conversion-flow)
-9. [Authentication Flow](#9-authentication-flow)
-10. [Complete End-to-End Journey](#10-complete-end-to-end-journey)
-
----
-
-## 1. Free Trial Signup Flow
-
-### Flow Diagram
-
-```
-User Visits Signup Page
- ↓
-Enters User Details
-- Email
-- Password
-- First Name
-- Last Name
-- Country Selection
- ↓
-Selects "Free Trial" Plan
- ↓
-Frontend → POST /v1/auth/register/
- ↓
-Backend: RegisterView.post()
- ├─ Validate Email Uniqueness
- ├─ Validate Password Strength
- └─ Check Country Code
- ↓
-Database Transaction Starts
- ↓
-Create Account Record
-- Generate UUID
-- billing_country = selected country
-- account_status = 'trial'
-- credits = 0 (initially)
- ↓
-Create User Record
-- Set account FK
-- Set role = 'owner'
-- hash password
-- is_active = True
- ↓
-Fetch Free Trial Plan
-- Filter: plan_type='trial'
-- Get default trial plan
- ↓
-Create Subscription
-- account FK
-- plan FK
-- status = 'active'
-- current_period_start = now
-- current_period_end = now + 7 days
-- auto_renew = False
- ↓
-Allocate Trial Credits
-- Create CreditTransaction
- - type = 'subscription'
- - amount = plan.credits (e.g., 500)
- - description = "Free trial credits"
-- Update account.credits = 500
- ↓
-Generate JWT Tokens
-- Access token (15 min expiry)
-- Refresh token (7 day expiry)
-- Include account_id in claims
- ↓
-Commit Transaction
- ↓
-Response to Frontend
-{
- user: {...},
- account: {...},
- subscription: {...},
- tokens: {
- access: "...",
- refresh: "..."
- }
-}
- ↓
-Frontend: authStore.setAuth()
-- Store tokens in localStorage
-- Set user state in Zustand
-- Set account state
- ↓
-Redirect to Dashboard
-- Free trial banner visible
-- 500 credits available
-- 7 days remaining
-```
-
-### Key Decision Points
-
-**Q: Email already exists?**
-- Yes → Return 400 error "Email already registered"
-- No → Continue
-
-**Q: Country has payment methods?**
-- Yes → Store billing_country
-- No → Default to 'US', store billing_country
-
-**Q: Free trial plan exists?**
-- Yes → Use existing plan
-- No → Return 500 error "Free trial plan not configured"
-
-### State Changes
-
-| Entity | Before | After |
-|--------|--------|-------|
-| Account | Does not exist | account_status='trial', credits=500 |
-| User | Does not exist | is_active=True, role='owner' |
-| Subscription | Does not exist | status='active', 7-day period |
-| Credits | N/A | 500 credits from plan |
-
----
-
-## 2. Paid Signup Flow
-
-### Flow Diagram
-
-```
-User Visits Signup Page
- ↓
-Enters User Details
-- Email, Password, Name, Country
- ↓
-Selects Paid Plan
-- Basic ($29/month)
-- Pro ($79/month)
-- Enterprise ($199/month)
- ↓
-Frontend → POST /v1/auth/register/
- ↓
-Backend: RegisterView.post()
- ├─ Validate User Data
- └─ Detect plan_type = 'paid'
- ↓
-Database Transaction Starts
- ↓
-Create Account Record
-- billing_country = selected country
-- account_status = 'pending_payment'
-- credits = 0
- ↓
-Create User Record
-- Set account FK
-- role = 'owner'
-- is_active = True
- ↓
-Convert Plan Price to Local Currency
-- Fetch plan.price_usd (e.g., $29)
-- Get currency multiplier for country
-- Calculate: local_amount = price_usd × multiplier
-- Example: $29 × 278 = PKR 8,062
- ↓
-Create Subscription
-- account FK
-- plan FK
-- status = 'incomplete'
-- current_period_start = None
-- current_period_end = None
-- auto_renew = True (for paid plans)
- ↓
-Create Invoice
-- account FK
-- subscription FK
-- amount = local_amount (PKR 8,062)
-- currency = local currency code ('PKR')
-- status = 'pending'
-- due_date = now + 7 days
-- Metadata:
- - usd_price: $29
- - exchange_rate: 278
- - plan_name: "Basic Plan"
- ↓
-NO Credit Allocation Yet
-(Credits allocated after payment approval)
- ↓
-Generate JWT Tokens
-- Access token
-- Refresh token
- ↓
-Commit Transaction
- ↓
-Response to Frontend
-{
- user: {...},
- account: {
- account_status: 'pending_payment',
- credits: 0
- },
- subscription: {
- status: 'incomplete'
- },
- invoice: {
- invoice_number: "INV-123",
- total: 8062.00,
- currency: "PKR",
- status: "pending"
- },
- tokens: {...}
-}
- ↓
-Frontend: authStore.setAuth()
-- Store all data
-- Detect pending_payment status
- ↓
-Redirect to Payment Instructions
-- Show invoice details
-- Display payment methods for country
-- Request manual payment confirmation
-```
-
-### Critical Differences from Free Trial
-
-| Aspect | Free Trial | Paid Signup |
-|--------|-----------|-------------|
-| Account Status | 'trial' | 'pending_payment' |
-| Subscription Status | 'active' | 'incomplete' |
-| Credits on Signup | Allocated immediately | 0 (allocated after payment) |
-| Invoice Created | No | Yes |
-| Period Dates | Set immediately | null until payment |
-
----
-
-## 3. Payment Confirmation Flow
-
-### Flow Diagram
-
-```
-User Completes Manual Payment
-(Bank Transfer or Mobile Wallet)
- ↓
-User Opens Payment Modal
-- Frontend fetches invoice
-- GET /v1/billing/invoices/
- ↓
-Display Invoice Details
-- Amount: PKR 8,062.00
-- Currency: PKR
-- Plan: Basic Plan
- ↓
-User Selects Payment Method
-- Dropdown shows methods for billing_country
-- GET /v1/billing/admin/payment-methods/?country=PK
-- Returns: [JazzCash, EasyPaisa, Bank Transfer]
- ↓
-User Enters Payment Details
-- Selected method: JazzCash
-- Transaction ID: JC20241209123456
-- Notes: "Paid via JazzCash mobile app"
-- Amount: 8062.00 (auto-filled, read-only)
- ↓
-Frontend → POST /v1/billing/admin/payments/confirm/
-{
- invoice_id: 123,
- payment_method_id: 45,
- manual_reference: "JC20241209123456",
- manual_notes: "Paid via JazzCash mobile app",
- amount: 8062.00
-}
- ↓
-Backend: AdminPaymentView.confirm_payment()
- ├─ Validate invoice exists
- ├─ Validate invoice belongs to user's account
- ├─ Check invoice status = 'pending'
- └─ Validate amount matches invoice.total exactly
- ↓
-Database Transaction Starts
- ↓
-Create Payment Record
-- invoice FK
-- account FK
-- payment_method FK
-- amount = 8062.00
-- currency = 'PKR'
-- status = 'pending_approval'
-- manual_reference = "JC20241209123456"
-- manual_notes = user's notes
-- confirmed_at = now()
- ↓
-Update Invoice Status
-- status = 'pending' → 'pending_approval'
-- Indicates payment under review
- ↓
-Commit Transaction
- ↓
-Response to Frontend
-{
- payment: {
- id: 789,
- status: 'pending_approval',
- amount: 8062.00,
- manual_reference: "JC20241209123456"
- },
- message: "Payment submitted for approval"
-}
- ↓
-Frontend Shows Success
-- "Payment submitted successfully"
-- "Admin will review within 24 hours"
-- Close modal
-- Update invoice list
- ↓
-User Waits for Admin Approval
-```
-
-### Validation Rules
-
-| Field | Validation |
-|-------|-----------|
-| invoice_id | Must exist, belong to user's account |
-| payment_method_id | Must exist, be active for user's country |
-| amount | Must exactly match invoice.total |
-| manual_reference | Required, max 255 chars |
-| manual_notes | Optional, max 1000 chars |
-
-### State Changes
-
-| Entity | Before | After |
-|--------|--------|-------|
-| Invoice | status='pending' | status='pending_approval' |
-| Payment | Does not exist | status='pending_approval' |
-| Account | account_status='pending_payment' | No change yet |
-| Subscription | status='incomplete' | No change yet |
-
----
-
-## 4. Payment Approval Flow (Admin)
-
-### Flow Diagram
-
-```
-Admin Logs into Django Admin
- ↓
-Navigates to Billing → Payments
- ↓
-Sees Payment List
-- Filters by status='pending_approval'
-- Shows all pending manual payments
- ↓
-Admin Reviews Payment
-- Checks manual_reference (transaction ID)
-- Verifies amount matches invoice
-- Reviews manual_notes from user
-- Confirms payment received in bank/wallet
- ↓
-Admin Approves Payment
-
-Option A: Bulk Action
- ├─ Selects payment checkboxes
- ├─ Chooses "Approve selected manual payments"
- ├─ Clicks "Go"
- └─ Calls approve_manual_payments() action
-
-Option B: Individual Edit
- ├─ Clicks payment to open
- ├─ Changes Status → "Succeeded"
- ├─ Adds admin notes (optional)
- ├─ Clicks "Save"
- └─ Calls PaymentAdmin.save_model()
-
- ↓
-Backend Detects Status Change
-- old_status = 'pending_approval'
-- new_status = 'succeeded'
-- Change detected
- ↓
-Database Transaction Starts (Atomic)
- ↓
-Update Payment Record
-- status = 'succeeded'
-- approved_by = admin user
-- approved_at = now()
- ↓
-Fetch Related Invoice
-- Get payment.invoice
- ↓
-Update Invoice
-- status = 'pending_approval' → 'paid'
-- paid_at = now()
- ↓
-Fetch Subscription
-- Get invoice.subscription
- ↓
-Update Subscription
-- status = 'incomplete' → 'active'
-- current_period_start = now()
-- current_period_end = now() + 1 month (for monthly plans)
- ↓
-Fetch Account
-- Get subscription.account
- ↓
-Update Account Status
-- account_status = 'pending_payment' → 'active'
- ↓
-Allocate Credits (via CreditService)
- ├─ Get plan.credits (e.g., 5000 for Basic)
- ├─ Create CreditTransaction
- │ - type = 'subscription'
- │ - amount = 5000
- │ - description = "Credits for Basic Plan subscription"
- │ - metadata = {payment_id, invoice_id}
- │ - balance_after = 5000
- ├─ Update account.credits = 5000
- └─ Return transaction record
- ↓
-Check for Duplicate Allocations
-- Query CreditTransaction
-- Filter by payment_id in metadata
-- If already exists: Skip allocation
-- Prevents double-credits on repeated saves
- ↓
-Commit Transaction
- ↓
-Admin Sees Success Message
-"Payment approved successfully. Account activated with 5000 credits."
- ↓
-User Can Now Access Full Platform
-- account_status = 'active'
-- subscription.status = 'active'
-- 5000 credits available
-- All features unlocked
-```
-
-### Approval Decision Tree
-
-```
-Payment Status = 'pending_approval'
- ↓
-Admin Reviews Evidence
- ├─ Transaction ID valid? ────→ No → Reject Payment
- ├─ Amount matches invoice? ──→ No → Reject Payment
- ├─ Payment received? ────────→ No → Keep pending
- └─ All checks pass? ─────────→ Yes → Approve Payment
- ↓
- Automatic Workflow
- ↓
- Account Activated
-```
-
-### Critical Atomic Updates
-
-All these must succeed together or all fail:
-
-1. Payment status → succeeded
-2. Invoice status → paid
-3. Subscription status → active, dates set
-4. Account status → active
-5. Credits allocated
-6. Transaction recorded
-
-If any step fails: Entire transaction rolled back
-
----
-
-## 5. Site Creation Flow
-
-### Flow Diagram
-
-```
-User Navigates to Dashboard
- ↓
-Clicks "Add Site" Button
- ↓
-Opens Site Creation Wizard
- ↓
-Step 1: Basic Information
-- Enter site name (e.g., "Tech Blog")
-- Enter domain (optional, e.g., "https://techblog.com")
-- Enter description (optional)
- ↓
-Step 2: Industry Selection
-- Dropdown shows all industries
-- User selects (e.g., "Technology")
-- Frontend stores industry.id
- ↓
-Step 3: Additional Settings
-- Select hosting type (WordPress/Custom/Static)
-- Select site type (Blog/Ecommerce/Corporate)
-- Toggle is_active (default: true)
- ↓
-User Clicks "Create Site"
- ↓
-Frontend → POST /v1/auth/sites/
-{
- name: "Tech Blog",
- domain: "https://techblog.com",
- description: "A blog about technology",
- industry: 5,
- hosting_type: "wordpress",
- site_type: "blog",
- is_active: true
-}
- ↓
-Backend: SiteViewSet.create()
- ↓
-Middleware Sets request.account
-- Extract from JWT token
-- Attach to request object
- ↓
-Check Site Limit
- ├─ Get account.plan.max_sites (e.g., 3 for Basic)
- ├─ Count active sites for account
- ├─ Current count >= limit?
- │ ├─ Yes → Return 400 "Site limit reached for your plan"
- │ └─ No → Continue
- ↓
-Auto-Generate Slug
- ├─ slugify(name) → "tech-blog"
- ├─ Check uniqueness within account
- ├─ If exists: Append number "tech-blog-2"
- └─ Final slug: "tech-blog"
- ↓
-Validate and Format Domain
- ├─ domain = "https://techblog.com"
- ├─ Strip whitespace
- ├─ If empty string → Set to None
- ├─ If starts with http:// → Replace with https://
- ├─ If no protocol → Add https://
- └─ Validate URL format
- ↓
-Database Transaction Starts
- ↓
-Create Site Record
-- account FK (from request.account)
-- name = "Tech Blog"
-- slug = "tech-blog"
-- domain = "https://techblog.com"
-- description = text
-- industry FK = 5
-- hosting_type = "wordpress"
-- site_type = "blog"
-- is_active = True
-- created_by = request.user
- ↓
-Check User Role
- ├─ role in ['owner', 'admin']?
- │ ├─ Yes → Grant Access
- │ │ └─ Create SiteUserAccess
- │ │ - user FK
- │ │ - site FK
- │ │ - granted_by = request.user
- │ └─ No → Skip access grant
- ↓
-Commit Transaction
- ↓
-Response to Frontend
-{
- id: 123,
- name: "Tech Blog",
- slug: "tech-blog",
- domain: "https://techblog.com",
- industry: {
- id: 5,
- name: "Technology",
- slug: "technology"
- },
- sectors_count: 0,
- is_active: true
-}
- ↓
-Frontend Updates Site List
-- Add new site to state
-- Close wizard modal
-- Show success message
- ↓
-Redirect to Sector Selection
-- Prompt: "Select up to 5 sectors for your site"
-```
-
-### Site Creation Validations
-
-| Validation | Rule | Error Message |
-|-----------|------|---------------|
-| Plan Limit | active_sites < max_sites | "Site limit reached for your plan" |
-| Name | Required, max 255 chars | "Site name is required" |
-| Slug | Unique within account | Auto-appends number if duplicate |
-| Domain | Valid URL or None | "Invalid domain format" |
-| Industry | Must exist | "Invalid industry selected" |
-
-### State Changes
-
-| Entity | Before | After |
-|--------|--------|-------|
-| Site | Does not exist | is_active=True, sectors_count=0 |
-| SiteUserAccess | Does not exist | Created for owner/admin |
-| Account | site_count = n | site_count = n+1 |
-
----
-
-## 6. Sector Selection Flow
-
-### Flow Diagram
-
-```
-User on Site Details Page
- ↓
-Clicks "Add Sectors" Button
- ↓
-Frontend Fetches Available Sectors
-GET /v1/auth/industries/{industry_slug}/sectors/
- ↓
-Response: List of IndustrySectors
-[
- {id: 1, name: "AI & Machine Learning", slug: "ai-ml"},
- {id: 2, name: "Web Development", slug: "web-dev"},
- {id: 3, name: "Mobile Apps", slug: "mobile-apps"},
- ...
-]
- ↓
-Display Sector Selection UI
-- Show checkboxes for each sector
-- Limit: "Select up to 5 sectors"
-- Track selected count
- ↓
-User Selects Sectors
-- Checks 3 sectors:
- - AI & Machine Learning
- - Web Development
- - Cloud Computing
- ↓
-User Clicks "Save Sectors"
- ↓
-Frontend → POST /v1/auth/sites/{site_id}/select_sectors/
-{
- industry_slug: "technology",
- sector_slugs: ["ai-ml", "web-dev", "cloud-computing"]
-}
- ↓
-Backend: SiteViewSet.select_sectors()
- ↓
-Validate Site Ownership
- ├─ site.account == request.account?
- │ ├─ Yes → Continue
- │ └─ No → Return 403 "Access denied"
- ↓
-Validate Industry Match
- ├─ Fetch industry by slug
- ├─ industry == site.industry?
- │ ├─ Yes → Continue
- │ └─ No → Return 400 "Industry mismatch"
- ↓
-Check Sector Limit
- ├─ Max sectors per site = 5
- ├─ Count current active sectors
- ├─ Current count = 0
- ├─ Requested count = 3
- ├─ Available slots = 5 - 0 = 5
- ├─ 3 <= 5?
- │ ├─ Yes → Continue
- │ └─ No → Return 400 "Sector limit exceeded"
- ↓
-Fetch IndustrySectors
- ├─ Query by slugs: ["ai-ml", "web-dev", "cloud-computing"]
- ├─ Filter by industry
- ├─ Validate all 3 exist
- └─ All found → Continue
- ↓
-Database Transaction Starts
- ↓
-For Each IndustrySector:
- ↓
-Check if Sector Already Exists
- ├─ Query Sector by site + industry_sector
- ├─ Found existing sector?
- │ ├─ Yes → Update
- │ │ └─ Set is_active = True
- │ │ └─ updated_sectors++
- │ └─ No → Create
- │ └─ New Sector Record
- │ - site FK
- │ - industry_sector FK
- │ - account FK (from site.account)
- │ - name = industry_sector.name
- │ - slug = industry_sector.slug
- │ - is_active = True
- │ - created_by = request.user
- │ └─ created_sectors++
- ↓
-Commit Transaction
- ↓
-Response to Frontend
-{
- created: 3,
- updated: 0,
- sectors: [
- {
- id: 501,
- name: "AI & Machine Learning",
- slug: "ai-ml",
- is_active: true
- },
- {
- id: 502,
- name: "Web Development",
- slug: "web-dev",
- is_active: true
- },
- {
- id: 503,
- name: "Cloud Computing",
- slug: "cloud-computing",
- is_active: true
- }
- ]
-}
- ↓
-Frontend Updates UI
-- Display selected sectors
-- Update sectors_count = 3
-- Show success message
-- Enable "Next" button in wizard
-```
-
-### Sector Limit Logic
-
-```
-Max Sectors = 5 (Hard-coded)
- ↓
-Count Active Sectors for Site
- ↓
-Available Slots = Max - Current
- ↓
-Validate Request
- ├─ Requested <= Available?
- │ ├─ Yes → Allow
- │ └─ No → Reject
-```
-
-### Example Scenarios
-
-**Scenario 1: New Site (0 sectors)**
-- Request: 3 sectors
-- Current: 0
-- Available: 5
-- Result: ✅ Allow, create 3 new sectors
-
-**Scenario 2: Site with 3 Sectors**
-- Request: 2 more sectors
-- Current: 3
-- Available: 2
-- Result: ✅ Allow, create 2 new sectors
-
-**Scenario 3: Site with 5 Sectors**
-- Request: 1 more sector
-- Current: 5
-- Available: 0
-- Result: ❌ Reject "Sector limit reached"
-
-**Scenario 4: Reactivating Deleted Sector**
-- Request: sector-a (previously deleted)
-- Query finds existing Sector with is_active=False
-- Result: ✅ Update is_active=True (no new creation)
-
----
-
-## 7. Credit Allocation Flow
-
-### Flow Diagram
-
-```
-Trigger Event
- ├─ Payment Approval (Admin)
- ├─ Free Trial Signup
- ├─ Manual Credit Adjustment (Admin)
- └─ Subscription Renewal (Auto)
- ↓
-Call: CreditService.add_credits()
-Parameters:
-- account: Account object
-- amount: Integer (e.g., 5000)
-- transaction_type: String ('subscription', 'adjustment', 'refund')
-- description: String (human-readable)
-- metadata: Dict (payment_id, invoice_id, etc.)
- ↓
-Validate Amount
- ├─ amount > 0?
- │ ├─ Yes → Continue
- │ └─ No → Raise ValueError "Amount must be positive"
- ↓
-Get Current Balance
-- current_balance = account.credits
-- Example: current_balance = 0
- ↓
-Calculate New Balance
-- new_balance = current_balance + amount
-- Example: new_balance = 0 + 5000 = 5000
- ↓
-Database Transaction Starts
- ↓
-Create CreditTransaction Record
-- account FK
-- type = transaction_type ('subscription')
-- amount = 5000 (positive for additions)
-- balance_after = 5000
-- description = "Credits for Basic Plan subscription"
-- metadata = {
- payment_id: 789,
- invoice_id: 123,
- plan_name: "Basic Plan"
- }
-- created_at = now()
- ↓
-Update Account Credits
-- account.credits = new_balance (5000)
-- account.save()
- ↓
-Commit Transaction
- ↓
-Return CreditTransaction Object
- ↓
-Credits Available for Use
-```
-
-### Credit Deduction Flow
-
-```
-Content Generation Request
- ↓
-Check Required Credits
-- Feature: Blog post generation
-- Cost: 100 credits
- ↓
-Call: CreditService.deduct_credits()
-Parameters:
-- account: Account object
-- amount: 100
-- transaction_type: 'content_generation'
-- description: "Blog post: How to Start a Business"
-- metadata: {content_id: 456, feature: 'blog'}
- ↓
-Validate Sufficient Balance
- ├─ account.credits >= amount?
- │ ├─ Yes → Continue
- │ └─ No → Raise InsufficientCreditsError
- ↓
-Calculate New Balance
-- current_balance = 5000
-- new_balance = 5000 - 100 = 4900
- ↓
-Database Transaction Starts
- ↓
-Create CreditTransaction Record
-- account FK
-- type = 'content_generation'
-- amount = -100 (negative for deductions)
-- balance_after = 4900
-- description = "Blog post: How to Start a Business"
-- metadata = {content_id: 456}
- ↓
-Update Account Credits
-- account.credits = 4900
-- account.save()
- ↓
-Commit Transaction
- ↓
-Return CreditTransaction Object
- ↓
-Credits Deducted, Content Generated
-```
-
-### Transaction History View
-
-```
-User Views Credit History
-GET /v1/billing/credit-transactions/
- ↓
-Backend Returns List
-[
- {
- id: 1001,
- type: "subscription",
- amount: 5000,
- balance_after: 5000,
- description: "Credits for Basic Plan subscription",
- created_at: "2024-12-09T10:00:00Z"
- },
- {
- id: 1002,
- type: "content_generation",
- amount: -100,
- balance_after: 4900,
- description: "Blog post: How to Start a Business",
- created_at: "2024-12-09T11:00:00Z"
- },
- {
- id: 1003,
- type: "content_generation",
- amount: -50,
- balance_after: 4850,
- description: "Social media post batch",
- created_at: "2024-12-09T12:00:00Z"
- }
-]
- ↓
-Frontend Displays Timeline
-- Shows running balance
-- Color codes: Green for additions, Red for deductions
-- Filterable by type
-```
-
----
-
-## 8. Currency Conversion Flow
-
-### Flow Diagram
-
-```
-User Signs Up from Pakistan
- ↓
-Frontend Detects Country
-- navigator.language or IP geolocation
-- country_code = 'PK'
- ↓
-Sends to Backend
-POST /v1/auth/register/
-{
- ...user data,
- country: "PK"
-}
- ↓
-Backend Receives Request
- ↓
-User Selects Plan
-- Plan: Basic
-- plan.price_usd = 29.00
- ↓
-Call: convert_usd_to_local(29.00, 'PK')
- ↓
-Lookup Currency Multiplier
-```python
-CURRENCY_MULTIPLIERS = {
- 'PK': 278.0,
- 'IN': 83.0,
- 'GB': 0.79,
- ...
-}
-multiplier = CURRENCY_MULTIPLIERS.get('PK', 1.0)
-# multiplier = 278.0
-```
- ↓
-Calculate Local Amount
-- local_amount = 29.00 × 278.0
-- local_amount = 8,062.00
- ↓
-Get Currency Code
-- Call: get_currency_for_country('PK')
-- Returns: 'PKR'
- ↓
-Create Invoice with Local Currency
-- amount = 8062.00
-- currency = 'PKR'
-- metadata = {
- usd_price: 29.00,
- exchange_rate: 278.0,
- country: 'PK'
- }
- ↓
-Return to Frontend
-{
- invoice: {
- total: 8062.00,
- currency: "PKR",
- ...
- }
-}
- ↓
-Frontend Displays
-"Amount Due: PKR 8,062.00"
-```
-
-### Multi-Currency Support Table
-
-| Country | Currency | Rate | $29 Plan | $79 Plan | $199 Plan |
-|---------|----------|------|----------|----------|-----------|
-| Pakistan | PKR | 278.0 | ₨8,062 | ₨21,962 | ₨55,322 |
-| India | INR | 83.0 | ₹2,407 | ₹6,557 | ₹16,517 |
-| UK | GBP | 0.79 | £22.91 | £62.41 | £157.21 |
-| Europe | EUR | 0.92 | €26.68 | €72.68 | €183.08 |
-| Canada | CAD | 1.36 | C$39.44 | C$107.44 | C$270.64 |
-| Australia | AUD | 1.52 | A$44.08 | A$120.08 | A$302.48 |
-| USA | USD | 1.0 | $29.00 | $79.00 | $199.00 |
-
-### Currency Display Formatting
-
-```
-Call: format_currency(8062.00, 'PKR')
- ↓
-Returns: "PKR 8,062.00"
-
-Call: format_currency(29.00, 'USD')
- ↓
-Returns: "$29.00"
-
-Call: format_currency(2407.00, 'INR')
- ↓
-Returns: "₹2,407.00"
-```
-
----
-
-## 9. Authentication Flow
-
-### Registration with JWT Token Generation
-
-```
-User Submits Registration
-POST /v1/auth/register/
- ↓
-Backend: RegisterView.post()
- ↓
-Create User & Account
-(See Free Trial or Paid Signup Flow)
- ↓
-Generate Access Token
-```python
-from igny8_core.auth.utils import generate_access_token
-
-access_token = generate_access_token(user)
-# Creates JWT with:
-# - user_id
-# - account_id
-# - email
-# - role
-# - exp: 15 minutes from now
-```
- ↓
-Generate Refresh Token
-```python
-from igny8_core.auth.utils import generate_refresh_token
-
-refresh_token = generate_refresh_token(user)
-# Creates JWT with:
-# - user_id
-# - exp: 7 days from now
-```
- ↓
-Return Tokens in Response
-{
- user: {...},
- account: {...},
- tokens: {
- access: "eyJhbGciOi...",
- refresh: "eyJhbGciOi..."
- }
-}
- ↓
-Frontend Receives Response
- ↓
-authStore.setAuth() Called
- ├─ Extract tokens from response
- │ └─ Check multiple paths:
- │ - tokens?.access
- │ - data?.tokens?.access
- │ - data?.data?.tokens?.access
- ├─ Store in localStorage (synchronous)
- │ └─ localStorage.setItem('access_token', token)
- │ └─ localStorage.setItem('refresh_token', token)
- └─ Update Zustand state
- └─ set({ user, account, isAuthenticated: true })
- ↓
-User Authenticated and Logged In
-```
-
-**Key Fix Applied (Dec 9, 2024):**
-
-Problem: Users logged out immediately after signup
-- RegisterView didn't generate JWT tokens
-- Frontend couldn't find tokens in response
-- authStore set user but no tokens
-- Subsequent requests failed authentication
-
-Solution: Generate tokens like LoginView
-- Added generate_access_token(user) call
-- Added generate_refresh_token(user) call
-- Return tokens in response data
-- Frontend extracts with fallback paths
-
----
-
-### Login Flow
-
-```
-User Enters Credentials
-POST /v1/auth/login/
-{
- email: "user@example.com",
- password: "SecurePass123"
-}
- ↓
-Backend: LoginView.post()
- ↓
-Validate Credentials
- ├─ User exists with email?
- ├─ Password hash matches?
- ├─ User is_active = True?
- │ ├─ All pass → Continue
- │ └─ Any fail → Return 401 "Invalid credentials"
- ↓
-Check Account Status
- ├─ account.account_status in ['active', 'trial']?
- │ ├─ Yes → Continue
- │ └─ No → Return 403 "Account not active"
- ↓
-Generate Tokens
-- Access token (15 min)
-- Refresh token (7 days)
- ↓
-Return Response
-{
- user: {...},
- account: {...},
- tokens: {
- access: "...",
- refresh: "..."
- }
-}
- ↓
-Frontend Stores Tokens
-- localStorage persistence
-- Zustand state update
- ↓
-User Logged In
-```
-
-### Token Refresh Flow
-
-```
-Access Token Expires (15 min)
- ↓
-API Request Fails with 401
- ↓
-Frontend Detects Expiration
- ↓
-Check Refresh Token
- ├─ Refresh token exists?
- ├─ Refresh token not expired?
- │ ├─ Yes → Refresh
- │ └─ No → Force logout
- ↓
-POST /v1/auth/refresh/
-{
- refresh: "eyJhbGciOi..."
-}
- ↓
-Backend Validates Refresh Token
- ├─ Token signature valid?
- ├─ Token not expired?
- ├─ User still exists and active?
- │ ├─ All pass → Continue
- │ └─ Any fail → Return 401
- ↓
-Generate New Access Token
-- Fresh 15-minute token
-- Same claims as before
- ↓
-Return Response
-{
- access: "eyJhbGciOi...",
- refresh: "eyJhbGciOi..." (same or new)
-}
- ↓
-Frontend Updates Token
-- Replace access_token in localStorage
-- Retry failed API request
- ↓
-Request Succeeds
-```
-
-### Middleware Flow (Every Request)
-
-```
-API Request with Token
-Authorization: Bearer eyJhbGciOi...
- ↓
-Django Middleware Pipeline
- ↓
-JWTAuthenticationMiddleware
- ├─ Extract token from header
- ├─ Decode and validate JWT
- ├─ Extract user_id from claims
- ├─ Fetch User object
- ├─ Attach to request.user
- └─ Continue to next middleware
- ↓
-TenantMiddleware
- ├─ Get account_id from JWT claims
- ├─ Fetch Account object
- ├─ Attach to request.account
- ├─ Set thread-local for query filtering
- └─ Continue to view
- ↓
-View Executes
-- Has access to request.user
-- Has access to request.account
-- All queries auto-filtered by account
-```
-
----
-
-## 10. Complete End-to-End Journey
-
-### Paid User Journey (Bank Transfer Payment)
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│ Day 1: User Signup │
-└─────────────────────────────────────────────────────────────┘
- ↓
-User Visits Landing Page (Pakistan)
- ↓
-Clicks "Get Started" → Signup Form
- ↓
-Fills Form:
-- Email: owner@business.pk
-- Password: SecurePass123
-- Name: Ahmad Khan
-- Country: Pakistan
- ↓
-Selects Plan: Basic ($29/month)
- ↓
-POST /v1/auth/register/
- ↓
-Backend Creates:
-├─ Account (account_status='pending_payment')
-├─ User (role='owner')
-├─ Subscription (status='incomplete')
-└─ Invoice (PKR 8,062.00, status='pending')
- ↓
-JWT Tokens Generated and Returned
- ↓
-Frontend Redirects to Payment Instructions
- ↓
-User Sees:
-- Invoice #INV-001
-- Amount: PKR 8,062.00
-- Payment methods for Pakistan
-- Instructions for bank transfer
-
-
-┌─────────────────────────────────────────────────────────────┐
-│ Day 1: User Makes Payment │
-└─────────────────────────────────────────────────────────────┘
- ↓
-User Opens Banking App
- ↓
-Transfers PKR 8,062 to Company Account
-- Transaction ID: TXN20241209001
-- Takes screenshot of receipt
- ↓
-Returns to Platform
- ↓
-Clicks "Confirm Payment" Button
- ↓
-Payment Modal Opens
-- Shows invoice amount: PKR 8,062.00
-- Dropdown: Selects "Bank Transfer"
-- Enters Transaction ID: TXN20241209001
-- Enters Notes: "Paid via HBL mobile banking"
- ↓
-POST /v1/billing/admin/payments/confirm/
- ↓
-Backend Creates Payment:
-- status='pending_approval'
-- manual_reference='TXN20241209001'
- ↓
-Invoice Updated:
-- status='pending' → 'pending_approval'
- ↓
-User Sees Success Message:
-"Payment submitted. We'll review within 24 hours."
- ↓
-User Waits (Limited Access)
-- Can browse dashboard
-- Cannot create sites/content
-- account_status='pending_payment'
-
-
-┌─────────────────────────────────────────────────────────────┐
-│ Day 2: Admin Approves Payment │
-└─────────────────────────────────────────────────────────────┘
- ↓
-Admin Logs into Django Admin
- ↓
-Navigates: Billing → Payments
- ↓
-Filters: Status = Pending Approval
- ↓
-Sees Payment:
-- Account: Ahmad Khan (owner@business.pk)
-- Amount: PKR 8,062.00
-- Method: Bank Transfer
-- Reference: TXN20241209001
-- Notes: "Paid via HBL mobile banking"
- ↓
-Admin Verifies:
-✓ Checks bank account
-✓ Sees PKR 8,062 received
-✓ Transaction ID matches
-✓ Amount correct
- ↓
-Admin Clicks Payment → Opens Edit
- ↓
-Changes Status: "Pending Approval" → "Succeeded"
- ↓
-Clicks "Save"
- ↓
-Automatic Workflow Triggers:
-├─ Payment.status = 'succeeded'
-├─ Payment.approved_by = admin
-├─ Invoice.status = 'paid'
-├─ Subscription.status = 'active'
-├─ Subscription.current_period_end = +30 days
-├─ Account.account_status = 'active'
-└─ Credits allocated: +5000
- └─ CreditTransaction created
- ↓
-Admin Sees Success Message:
-"Payment approved. Account activated with 5000 credits."
-
-
-┌─────────────────────────────────────────────────────────────┐
-│ Day 2: User Gets Activated (Automatic) │
-└─────────────────────────────────────────────────────────────┘
- ↓
-User Refreshes Dashboard
- ↓
-API Calls Return Updated Data:
-- account.account_status = 'active'
-- account.credits = 5000
-- subscription.status = 'active'
- ↓
-UI Changes:
-- Payment pending banner disappears
-- "Create Site" button enabled
-- Credit balance shows 5000
-- All features unlocked
- ↓
-User Clicks "Create Site"
- ↓
-Opens Site Creation Wizard
- ↓
-Fills Form:
-- Name: "Digital Marketing Blog"
-- Domain: https://digitalmktg.pk
-- Industry: Marketing
-- Type: Blog
- ↓
-POST /v1/auth/sites/
- ↓
-Backend:
-├─ Checks plan limit (3 sites for Basic)
-├─ Current sites: 0
-├─ Creates site
-└─ Grants owner access
- ↓
-User Sees New Site Created
- ↓
-Proceeds to Select Sectors:
-- Selects 3 sectors:
- ├─ Content Marketing
- ├─ Social Media
- └─ SEO
- ↓
-POST /v1/auth/sites/123/select_sectors/
- ↓
-Backend Creates 3 Sector Records
- ↓
-Site Setup Complete
- ↓
-User Navigates to Content Generation
- ↓
-Generates First Blog Post
-- Cost: 100 credits
-- Deduction: 5000 → 4900
- ↓
-Credits Deducted, Content Created
- ↓
-User Actively Using Platform
-- 4900 credits remaining
-- 29 days left in subscription
-- Full access to all features
-
-
-┌─────────────────────────────────────────────────────────────┐
-│ Day 32: Subscription Renewal (Future Feature) │
-└─────────────────────────────────────────────────────────────┘
- ↓
-Celery Task: check_expiring_subscriptions
- ↓
-Detects subscription.current_period_end approaching
- ↓
-If auto_renew=True:
-├─ Create new invoice
-├─ Send payment reminder email
-└─ User repeats payment flow
- ↓
-If auto_renew=False:
-├─ Subscription expires
-├─ account_status = 'trial' or 'inactive'
-└─ User must renew manually
-```
-
----
-
-**End of Data Flow Diagrams Document**
-
-This document provides visual representation of all critical workflows in the IGNY8 multi-tenancy system as implemented on December 9, 2024.
diff --git a/docs/multi-tenancy/TENANCY-IMPLEMENTATION-GUIDE.md b/docs/multi-tenancy/TENANCY-IMPLEMENTATION-GUIDE.md
deleted file mode 100644
index b28b1b1e..00000000
--- a/docs/multi-tenancy/TENANCY-IMPLEMENTATION-GUIDE.md
+++ /dev/null
@@ -1,1584 +0,0 @@
-# Multi-Tenancy Implementation Guide
-**IGNY8 Platform - Complete Technical Documentation**
-**Last Updated:** December 9, 2024
-**Status:** ✅ Production Ready
-
----
-
-## Table of Contents
-
-1. [Architecture Overview](#1-architecture-overview)
-2. [Core Models & Relationships](#2-core-models--relationships)
-3. [Authentication System](#3-authentication-system)
-4. [Payment Processing](#4-payment-processing)
-5. [Multi-Currency System](#5-multi-currency-system)
-6. [Site & Sector Management](#6-site--sector-management)
-7. [Credit System](#7-credit-system)
-8. [Admin Workflows](#8-admin-workflows)
-9. [API Endpoints](#9-api-endpoints)
-10. [Security & Permissions](#10-security--permissions)
-
----
-
-## 1. Architecture Overview
-
-### 1.1 Multi-Tenancy Model
-
-**Hierarchy:**
-```
-Account (Tenant)
- ├─ Owner (User with role='owner')
- ├─ Plan (Subscription Tier)
- ├─ Payment Methods
- ├─ Billing Information
- ├─ Credit Balance
- ├─ Sites (1 to max_sites)
- │ └─ Sectors (up to 5 per site)
- ├─ Users (1 to max_users)
- └─ Subscription (1:1 relationship)
- ├─ Current Period
- └─ Invoices (many)
- └─ Payments (many)
-```
-
-### 1.2 Data Isolation Strategy
-
-**Database Level:**
-- All tenant-scoped models inherit from `AccountBaseModel`
-- Database column: `tenant_id` (foreign key to accounts table)
-- Automatic filtering via Django ORM queryset methods
-- No cross-tenant data access possible
-
-**Middleware Level:**
-- `TenantMiddleware` extracts account from request
-- Attaches `request.account` to every request
-- Uses JWT token claim `account_id` for identification
-- Validates user belongs to account
-
-**Permission Level:**
-- `HasTenantAccess` permission class validates account ownership
-- `IsAuthenticatedAndActive` ensures user and account are active
-- Role-based permissions: developer > owner > admin > editor > viewer
-- Superusers and developers bypass tenant isolation
-
-### 1.3 Key Design Principles
-
-**Single Source of Truth:**
-- Payment Method: `AccountPaymentMethod` model (not duplicated in Account/Subscription)
-- Period Dates: `Subscription` model only (Invoice references via FK)
-- Plan Information: `Plan` model with historical tracking in Subscription
-- Billing Information: `Account` model with snapshot in Invoice metadata
-
-**Immutability Where Needed:**
-- Invoices are immutable once created (status changes only)
-- Subscription plan locked for period (new subscription on plan change)
-- Credit transactions are append-only (no updates/deletes)
-- Payment history preserved (soft delete for data retention)
-
-**Atomic Operations:**
-- Account creation wraps user + account in transaction
-- Payment approval atomically updates invoice + subscription + account + credits
-- Subscription creation creates account + subscription + invoice + payment method
-- All database modifications use `transaction.atomic()`
-
----
-
-## 2. Core Models & Relationships
-
-### 2.1 Account Model
-
-**Location:** `backend/igny8_core/auth/models.py`
-**Database Table:** `igny8_tenants`
-**Inheritance:** `SoftDeletableModel`
-
-**Primary Fields:**
-
-| Field Category | Fields | Purpose |
-|---------------|--------|---------|
-| **Identity** | id, name, slug | Unique identification |
-| **Relationships** | owner (FK User), plan (FK Plan) | Account ownership and tier |
-| **Financial** | credits (Integer), status (CharField) | Available credits and account state |
-| **Billing Profile** | billing_email, billing_address_line1/2, billing_city, billing_state, billing_postal_code, billing_country, tax_id | Complete billing information |
-| **Payment** | stripe_customer_id | External payment gateway reference |
-| **Soft Delete** | is_deleted, deleted_at, deleted_by, delete_reason, restore_until, deletion_retention_days | Soft delete with retention period |
-| **Audit** | created_at, updated_at | Timestamp tracking |
-
-**Status Values:**
-- `trial` - Free trial period (default for free plan)
-- `active` - Paid and operational
-- `pending_payment` - Awaiting payment confirmation
-- `suspended` - Temporarily disabled
-- `cancelled` - Permanently closed
-
-**Business Logic Methods:**
-
-`is_system_account()` → Boolean
-- Checks if slug in system accounts: 'aws-admin', 'default-account'
-- Used to prevent deletion of critical accounts
-- System accounts bypass certain restrictions
-
-`soft_delete(user, reason, retention_days)` → None
-- Marks account as deleted without removing from database
-- Sets deletion timestamp and restore deadline
-- Cascades soft delete to related entities
-- Allows restoration within retention period
-
-`restore()` → None
-- Reverses soft delete if within retention period
-- Clears deletion flags and timestamps
-- Restores related entities
-
-**Property Methods:**
-
-`payment_method` → String (Read-only property)
-- Returns default payment method from `AccountPaymentMethod`
-- Fallback logic: default method → first enabled method → 'stripe'
-- Replaces deprecated payment_method field
-- Single source of truth pattern
-
----
-
-### 2.2 Plan Model
-
-**Location:** `backend/igny8_core/auth/models.py`
-**Database Table:** `igny8_plans`
-**Purpose:** Defines subscription tiers and limits
-
-**Field Categories:**
-
-| Category | Fields | Purpose |
-|----------|--------|---------|
-| **Identity** | id, name, slug | Plan identification (e.g., "Free Trial", "free") |
-| **Pricing** | price, billing_cycle, annual_discount_percent | Monthly/annual pricing structure |
-| **Display** | is_featured, features (JSON), is_active, is_internal | UI presentation and visibility |
-| **Limits** | max_users, max_sites, max_industries, max_author_profiles | Hard limits per account |
-| **Credits** | included_credits, extra_credit_price, allow_credit_topup, auto_credit_topup_threshold, auto_credit_topup_amount | Credit allocation and top-up rules |
-| **Gateway** | stripe_product_id, stripe_price_id | Payment gateway integration |
-| **Legacy** | credits_per_month (deprecated) | Backward compatibility |
-
-**Business Logic Methods:**
-
-`get_effective_credits_per_month()` → Integer
-- Returns `included_credits` (preferred) or falls back to `credits_per_month`
-- Used during account creation to allocate initial credits
-- Ensures backward compatibility with old plans
-
-`clean()` → None
-- Django model validation
-- Ensures `max_sites >= 1`
-- Ensures `included_credits >= 0`
-- Called before save operations
-
-**Standard Plan Configuration:**
-
-| Plan | Slug | Price (USD) | Credits | Sites | Users | Featured |
-|------|------|-------------|---------|-------|-------|----------|
-| Free Trial | free | 0.00 | 1,000 | 1 | 1 | No |
-| Starter | starter | 29.00 | 5,000 | 3 | 3 | No |
-| Growth | growth | 79.00 | 15,000 | 10 | 10 | Yes |
-| Scale | scale | 199.00 | 50,000 | 30 | 30 | No |
-
----
-
-### 2.3 User Model
-
-**Location:** `backend/igny8_core/auth/models.py`
-**Database Table:** `igny8_users`
-**Inheritance:** Django `AbstractUser`
-
-**Core Fields:**
-
-| Field | Type | Purpose | Notes |
-|-------|------|---------|-------|
-| id | AutoField | Primary key | Auto-increment |
-| email | EmailField | Login identifier | Unique, required |
-| username | CharField(150) | Display name | Auto-generated from email |
-| password | CharField(128) | Hashed password | Django PBKDF2 SHA256 |
-| first_name, last_name | CharField(150) | Full name | Optional |
-| account | FK(Account) | Tenant association | Nullable, CASCADE, db_column='tenant_id' |
-| role | CharField(20) | Permission level | Choices below |
-| is_active | BooleanField | Account enabled | Default: True |
-| is_staff | BooleanField | Django admin access | Default: False |
-| is_superuser | BooleanField | Full system access | Default: False |
-
-**Role Hierarchy:**
-
-| Role | Code | Capabilities | Tenant Isolation |
-|------|------|--------------|------------------|
-| Developer | developer | Full system access, all accounts | Bypassed |
-| Owner | owner | Full account access, billing, automation | Enforced |
-| Admin | admin | Content management, view billing | Enforced |
-| Editor | editor | AI content, manage clusters/tasks | Enforced |
-| Viewer | viewer | Read-only dashboards | Enforced |
-| System Bot | system_bot | Automation tasks only | Special |
-
-**Business Logic Methods:**
-
-`is_developer()` → Boolean
-- Returns True if role == 'developer'
-- Used to bypass tenant filtering
-- Grants system-wide access
-
-`is_system_account_user()` → Boolean
-- Returns True if account is system account
-- System users can perform automated tasks
-- Used by background jobs and API integrations
-
-`get_accessible_sites()` → QuerySet[Site]
-- Returns sites user can access based on role
-- Owner/Admin: All sites in account
-- Editor/Viewer: Sites with explicit SiteUserAccess grants
-- Developer: All sites across all accounts
-
-**Authentication Methods:**
-
-`set_password(raw_password)` → None
-- Django's password hashing (PBKDF2 SHA256)
-- Salted and stretched for security
-
-`check_password(raw_password)` → Boolean
-- Validates password against hash
-- Used in login flow
-
----
-
-### 2.4 Subscription Model
-
-**Location:** `backend/igny8_core/auth/models.py`
-**Database Table:** `igny8_subscriptions`
-**Relationship:** 1:1 with Account
-
-**Core Fields:**
-
-| Field | Type | Purpose | Notes |
-|-------|------|---------|-------|
-| id | AutoField | Primary key | |
-| account | OneToOneField(Account) | Tenant link | CASCADE delete |
-| plan | FK(Plan) | Subscription tier | **NEW: Added for historical tracking** |
-| status | CharField(20) | Subscription state | pending_payment/active/cancelled/expired |
-| stripe_subscription_id | CharField(255) | Stripe reference | For automated billing |
-| external_payment_id | CharField(255) | Manual payment ref | For bank transfer/wallet |
-| current_period_start | DateTimeField | Billing period start | **Single source of truth** |
-| current_period_end | DateTimeField | Billing period end | **Single source of truth** |
-| cancel_at_period_end | BooleanField | Auto-cancel flag | Default: False |
-| created_at, updated_at | DateTimeField | Audit timestamps | |
-
-**Status Flow:**
-
-```
-[Registration] → pending_payment (for paid plans)
- ↓
-[Payment Approved] → active
- ↓
-[Cancellation Requested] → active (cancel_at_period_end=True)
- ↓
-[Period Ends] → cancelled OR expired
-```
-
-**Key Changes from Original Design:**
-
-1. **Added `plan` Field:**
- - Previously relied on `account.plan` only
- - Problem: Plan changes lost historical context
- - Solution: Lock plan in subscription for billing period
- - New subscription created on plan changes
-
-2. **Removed `payment_method` Field:**
- - Moved to property that queries `AccountPaymentMethod`
- - Eliminates data duplication
- - Single source of truth pattern
-
-**Property Methods:**
-
-`payment_method` → String (Read-only)
-- Returns `self.account.payment_method`
-- Delegates to AccountPaymentMethod query
-- No data duplication
-
----
-
-### 2.5 Invoice Model
-
-**Location:** `backend/igny8_core/business/billing/models.py`
-**Database Table:** `igny8_invoices`
-**Inheritance:** `AccountBaseModel`
-
-**Core Fields:**
-
-| Field | Type | Purpose | Notes |
-|-------|------|---------|-------|
-| id | AutoField | Primary key | |
-| account | FK(Account) | Tenant | Via AccountBaseModel |
-| subscription | FK(Subscription) | Billing source | CASCADE, nullable |
-| invoice_number | CharField(50) | Unique identifier | Format: INV-{account_id}-{YYYYMM}-{seq} |
-| status | CharField(20) | Payment state | draft/pending/paid/void/uncollectible |
-| subtotal | DecimalField(10,2) | Pre-tax amount | Calculated from line_items |
-| tax | DecimalField(10,2) | Tax amount | Default: 0 |
-| total | DecimalField(10,2) | Final amount | subtotal + tax |
-| currency | CharField(3) | ISO currency code | USD/PKR/INR/GBP/EUR/CAD/AUD |
-| invoice_date | DateField | Issue date | Indexed |
-| due_date | DateField | Payment deadline | Calculated: invoice_date + grace period |
-| paid_at | DateTimeField | Payment timestamp | Nullable |
-| line_items | JSONField | Invoice items | Array of {description, amount, quantity} |
-| stripe_invoice_id | CharField(255) | Stripe reference | Nullable |
-| payment_method | CharField(50) | How paid | Historical record |
-| notes | TextField | Additional info | |
-| metadata | JSONField | Structured data | Billing snapshot, period dates, exchange rate |
-
-**Status Flow:**
-
-```
-[Created] → pending
- ↓
-[Payment Confirmed] → paid
- ↓
-[Non-Payment] → uncollectible OR void (if cancelled)
-```
-
-**Key Changes from Original Design:**
-
-1. **Removed Duplicate Fields:**
- - `billing_period_start` - Now in metadata, retrieved via `subscription.current_period_start`
- - `billing_period_end` - Now in metadata, retrieved via `subscription.current_period_end`
- - `billing_email` - Now in metadata snapshot, not separate field
-
-2. **Added Both Field Names:**
- - API returns both `total` and `total_amount` for backward compatibility
- - Frontend can use either field name
- - Migration path for existing integrations
-
-**Business Logic Methods:**
-
-`calculate_totals()` → None
-- Recalculates subtotal from line_items array
-- Sets total = subtotal + tax
-- Called before save() operations
-
-`add_line_item(description, quantity, unit_price, amount)` → None
-- Appends item to line_items JSON array
-- Does NOT recalculate totals (call calculate_totals after)
-- Used by InvoiceService during creation
-
-**Metadata Structure:**
-
-```python
-{
- 'billing_snapshot': {
- 'email': 'user@example.com',
- 'address_line1': '123 Main St',
- 'city': 'Karachi',
- 'country': 'PK',
- 'snapshot_date': '2024-12-09T10:30:00Z'
- },
- 'billing_period_start': '2024-12-01T00:00:00Z',
- 'billing_period_end': '2024-12-31T23:59:59Z',
- 'subscription_id': 42,
- 'usd_price': '29.00',
- 'exchange_rate': '278.00'
-}
-```
-
----
-
-### 2.6 Payment Model
-
-**Location:** `backend/igny8_core/business/billing/models.py`
-**Database Table:** `igny8_payments`
-**Inheritance:** `AccountBaseModel`
-
-**Core Fields:**
-
-| Field | Type | Purpose | Notes |
-|-------|------|---------|-------|
-| id | AutoField | Primary key | |
-| account | FK(Account) | Tenant | Via AccountBaseModel |
-| invoice | FK(Invoice) | Invoice paid | CASCADE |
-| amount | DecimalField(10,2) | Payment amount | Must match invoice total |
-| currency | CharField(3) | ISO code | Must match invoice currency |
-| status | CharField(20) | Payment state | See status table below |
-| payment_method | CharField(50) | How paid | stripe/paypal/bank_transfer/local_wallet |
-| stripe_payment_intent_id | CharField(255) | Stripe reference | For automated payments |
-| stripe_charge_id | CharField(255) | Stripe charge | |
-| paypal_order_id | CharField(255) | PayPal reference | For automated payments |
-| paypal_capture_id | CharField(255) | PayPal capture | |
-| manual_reference | CharField(255) | Manual payment ref | **Required for manual payments** |
-| manual_notes | TextField | User notes | Optional |
-| admin_notes | TextField | Admin comments | For approval/rejection |
-| approved_by | FK(User) | Admin who approved | SET_NULL |
-| approved_at | DateTimeField | Approval timestamp | |
-| processed_at | DateTimeField | Processing timestamp | |
-| failed_at | DateTimeField | Failure timestamp | |
-| refunded_at | DateTimeField | Refund timestamp | |
-| failure_reason | TextField | Why failed | |
-| metadata | JSONField | Additional data | proof_url, submitted_by |
-
-**Payment Status Values:**
-
-| Status | Description | Used For | Next States |
-|--------|-------------|----------|-------------|
-| pending_approval | Awaiting admin review | Manual payments (bank transfer, mobile wallet) | succeeded, failed |
-| succeeded | Completed successfully | All successful payments | refunded |
-| failed | Payment rejected | Declined cards, rejected manual payments | - |
-| refunded | Money returned | Customer refund requests | - |
-
-**Simplified Status Flow:**
-
-```
-[User Confirms Manual Payment] → pending_approval
- ↓
-[Admin Approves] → succeeded
- ↓
-[Refund Requested] → refunded
-
-[Admin Rejects] → failed
-```
-
-**Key Changes from Original Design:**
-
-1. **Removed Duplicate Reference Field:**
- - Had both `manual_reference` and `transaction_reference`
- - Kept `manual_reference` only
- - Single field for manual payment tracking
-
-2. **Streamlined Status Values:**
- - Removed: pending, processing, completed, cancelled
- - Kept: pending_approval, succeeded, failed, refunded
- - Clearer workflow for admins
-
-**Validation Logic:**
-
-`clean()` → None
-- Validates manual payments have `manual_reference`
-- Checks amount matches invoice total
-- Ensures currency matches invoice currency
-- Called before save operations
-
----
-
-### 2.7 AccountPaymentMethod Model
-
-**Location:** `backend/igny8_core/business/billing/models.py`
-**Database Table:** `igny8_account_payment_methods`
-
-**Purpose:** Single source of truth for account's payment preferences
-
-**Core Fields:**
-
-| Field | Type | Purpose | Notes |
-|-------|------|---------|-------|
-| id | AutoField | Primary key | |
-| account | FK(Account) | Tenant | CASCADE |
-| type | CharField(50) | Payment method code | stripe/paypal/bank_transfer/local_wallet |
-| display_name | CharField(255) | User-friendly name | "Credit Card (Stripe)" |
-| is_default | BooleanField | Primary method | Only one per account |
-| is_enabled | BooleanField | Currently active | Can disable temporarily |
-| is_verified | BooleanField | Verified by admin | For manual methods |
-| country_code | CharField(2) | ISO country | For country-specific methods |
-| instructions | TextField | Payment details | Bank account info, wallet number |
-| metadata | JSONField | Additional config | Provider-specific settings |
-
-**Business Logic:**
-
-`save()` → None
-- If `is_default=True`, sets all other methods to `is_default=False`
-- Ensures only one default method per account
-- Uses `update()` to avoid recursion
-
----
-
-### 2.8 PaymentMethodConfig Model
-
-**Location:** `backend/igny8_core/business/billing/models.py`
-**Database Table:** `igny8_payment_method_configs`
-
-**Purpose:** Global configuration for available payment methods
-
-**Core Fields:**
-
-| Field | Type | Purpose | Notes |
-|-------|------|---------|-------|
-| id | AutoField | Primary key | |
-| country_code | CharField(2) | ISO country or '*' | '*' = available globally |
-| payment_method | CharField(50) | Method code | stripe/paypal/bank_transfer/local_wallet |
-| display_name | CharField(255) | UI label | "Bank Transfer (Manual)" |
-| is_enabled | BooleanField | Currently available | Can disable globally |
-| instructions | TextField | Payment details | Shown to users during signup |
-| provider | CharField(100) | Gateway provider | Stripe, PayPal, Bank, JazzCash |
-| wallet_type | CharField(50) | Wallet provider | For local_wallet: JazzCash, Easypaisa |
-| sort_order | IntegerField | Display order | Lower = shown first |
-| metadata | JSONField | Config data | API keys, webhooks (encrypted) |
-| webhook_url | URLField | Webhook endpoint | For automated payments |
-| webhook_secret | CharField(255) | Webhook signature | For verification |
-| webhook_events | JSONField | Event subscriptions | Array of event types |
-
-**Standard Configurations:**
-
-| Method | Country | Enabled | Instructions |
-|--------|---------|---------|--------------|
-| stripe | * (global) | No | Will be enabled when API keys configured |
-| paypal | * (global) | No | Will be enabled when API keys configured |
-| bank_transfer | * (global) | Yes | See account details in payment confirmation |
-| local_wallet | PK | Yes | JazzCash: 0300-1234567 / Easypaisa: 0300-7654321 |
-
-**Query Methods:**
-
-`get_available_for_country(country_code)` → QuerySet
-- Returns enabled methods for country
-- Includes global methods (country_code='*')
-- Ordered by sort_order
-- Used in signup flow
-
----
-
-### 2.9 CreditTransaction Model
-
-**Location:** `backend/igny8_core/business/billing/models.py`
-**Database Table:** `igny8_credit_transactions`
-**Inheritance:** `AccountBaseModel`
-
-**Purpose:** Immutable audit trail of credit changes
-
-**Core Fields:**
-
-| Field | Type | Purpose | Notes |
-|-------|------|---------|-------|
-| id | AutoField | Primary key | |
-| account | FK(Account) | Tenant | Via AccountBaseModel |
-| payment | FK(Payment) | Source payment | **NEW: Added for tracking**, nullable |
-| transaction_type | CharField(50) | Category | subscription/topup/refund/adjustment/usage |
-| amount | IntegerField | Credit change | Positive = add, Negative = deduct |
-| balance_after | IntegerField | Resulting balance | Snapshot after this transaction |
-| description | TextField | Human readable | "Free plan credits from Free Trial" |
-| metadata | JSONField | Structured data | payment_id, subscription_id, approved_by |
-| created_at | DateTimeField | Transaction time | Immutable |
-
-**Transaction Types:**
-
-| Type | Amount Sign | Description | Example |
-|------|-------------|-------------|---------|
-| subscription | Positive | Plan credits allocated | +1000 credits from Free Trial plan |
-| topup | Positive | Manual credit purchase | +5000 credits purchased for $50 |
-| refund | Positive | Credits returned | +2000 credits from refunded payment |
-| adjustment | Either | Manual correction | +/-500 credits - admin adjustment |
-| usage | Negative | Credits consumed | -10 credits for content generation |
-
-**Key Changes:**
-
-Added `payment` foreign key:
-- Links credit allocation to payment that triggered it
-- Enables preventing duplicate credit grants
-- Used in payment approval workflow
-- Query: "Has this payment already allocated credits?"
-
-**Business Logic:**
-
-Immutable Design:
-- No update() or delete() operations
-- Append-only transaction log
-- Balance recalculated by summing all transactions
-- Maintains complete audit trail
-
----
-
-## 3. Authentication System
-
-### 3.1 Registration Flow
-
-**Endpoint:** `POST /v1/auth/register/`
-**Handler:** `RegisterView.post()` in `backend/igny8_core/auth/urls.py`
-**Permission:** `AllowAny` (public endpoint)
-
-**Request Payload Structure:**
-
-```python
-{
- # Required Fields
- 'email': String,
- 'password': String,
- 'password_confirm': String,
-
- # Optional User Fields
- 'username': String, # Auto-generated from email if not provided
- 'first_name': String,
- 'last_name': String,
-
- # Optional Account Fields
- 'account_name': String, # Auto-generated from name or email if not provided
-
- # Plan Selection
- 'plan_slug': String, # 'free' (default) | 'starter' | 'growth' | 'scale'
-
- # Billing Information (required for paid plans)
- 'billing_email': String,
- 'billing_address_line1': String,
- 'billing_address_line2': String,
- 'billing_city': String,
- 'billing_state': String,
- 'billing_postal_code': String,
- 'billing_country': String (2-letter ISO), # Required for paid plans
- 'tax_id': String,
-
- # Payment Selection (required for paid plans)
- 'payment_method': String # 'bank_transfer' | 'local_wallet' | 'stripe' | 'paypal'
-}
-```
-
-**Registration Process Logic:**
-
-Step 1: Validate Input
-- Serializer: `RegisterSerializer.validate()`
-- Check password == password_confirm
-- For paid plans: Require billing_country and payment_method
-- Convert empty strings to None for optional fields
-
-Step 2: Resolve Plan
-- If `plan_slug='free'` or not provided:
- - Plan = Free Trial
- - Status = 'trial'
- - Credits = plan.included_credits (e.g., 1000)
- - No subscription/invoice created
-- If `plan_slug` in ['starter', 'growth', 'scale']:
- - Fetch plan by slug
- - Status = 'pending_payment'
- - Credits = 0 (allocated after payment)
- - Subscription and invoice will be created
-
-Step 3: Generate Username (if not provided)
-- Extract local part from email: 'john@example.com' → 'john'
-- Check uniqueness: If exists, append counter (john1, john2, etc.)
-- Ensures no duplicate usernames
-
-Step 4: Create User (without account first)
-- Django's `User.objects.create_user()`
-- Hash password using PBKDF2 SHA256
-- Set account=None temporarily
-- Allows rolling back account creation if fails
-
-Step 5: Generate Account Slug
-- Source: account_name if provided, else first_name + last_name, else email
-- Slugify: Convert to lowercase, replace spaces with hyphens
-- Ensure uniqueness: Append counter if duplicate exists
-- Example: "John's Business" → "johns-business"
-
-Step 6: Create Account (Atomic Transaction)
-- Set owner=user (from step 4)
-- Set plan from step 2
-- Set credits (1000 for free, 0 for paid)
-- Set status ('trial' for free, 'pending_payment' for paid)
-- Save all billing information to account fields
-- Generate billing_email = billing_email OR email
-
-Step 7: Link User to Account
-- Update user.account = account
-- Save user record
-- Completes circular reference
-
-Step 8: Log Initial Credits (Free Trial Only)
-- Create CreditTransaction record
-- Type = 'subscription'
-- Amount = plan.included_credits
-- Description = "Free plan credits from {plan.name}"
-- Metadata includes plan_slug, registration=True, trial=True
-
-Step 9: Create Subscription (Paid Plans Only)
-- Create Subscription record
-- Status = 'pending_payment'
-- Plan = selected plan (locked for this subscription)
-- Current period = now to now + 30 days
-- Payment method = from request
-
-Step 10: Create Invoice (Paid Plans Only)
-- Function: `InvoiceService.create_subscription_invoice()`
-- Convert USD price to local currency
-- Create line item with converted price
-- Status = 'pending'
-- Due date = invoice_date + grace period (7 days)
-
-Step 11: Create AccountPaymentMethod (Paid Plans Only)
-- Type = selected payment method
-- Display name from lookup table
-- Is_default = True
-- Is_enabled = True
-- Instructions = from PaymentMethodConfig
-
-Step 12: Generate JWT Tokens
-- Access token: `generate_access_token(user, account)`
-- Refresh token: `generate_refresh_token(user, account)`
-- Include claims: user_id, account_id, role
-- Expiry: access=1 hour, refresh=7 days
-
-Step 13: Return Response
-- Success response with user data and tokens
-- Frontend stores tokens in localStorage
-- User automatically logged in
-
-**Key Fix Applied (Dec 9, 2024):**
-
-Problem: RegisterView wasn't generating tokens
-- Original code only returned user data
-- No tokens in response
-- Frontend couldn't authenticate subsequent requests
-- User immediately logged out
-
-Solution: Added token generation to RegisterView
-- Generate access and refresh tokens
-- Return in response: `data.tokens.access` and `data.tokens.refresh`
-- Matches LoginView response structure
-- Users stay logged in after registration
-
----
-
-### 3.2 Login Flow
-
-**Endpoint:** `POST /v1/auth/login/`
-**Handler:** `LoginView.post()` in `backend/igny8_core/auth/urls.py`
-**Permission:** `AllowAny`
-
-**Request Payload:**
-
-```python
-{
- 'email': String, # User's email address
- 'password': String # Plain text password (hashed by backend)
-}
-```
-
-**Login Process Logic:**
-
-Step 1: Validate Credentials
-- Serializer: `LoginSerializer.is_valid()`
-- Validates email format
-- Password required (not validated yet)
-
-Step 2: Fetch User
-- Query: `User.objects.select_related('account', 'account__plan').get(email=email)`
-- Optimized query: Pre-loads account and plan data
-- Raises DoesNotExist if email not found
-
-Step 3: Check Password
-- Django's `user.check_password(password)`
-- Compares hashed password
-- Returns False if incorrect
-
-Step 4: Validate User Status
-- Check `user.is_active == True`
-- Inactive users cannot login
-- Returns error: "User account is disabled"
-
-Step 5: Validate Account Status
-- Check account exists: `user.account is not None`
-- Check account status in ['trial', 'active', 'pending_payment']
-- Suspended/cancelled accounts cannot login
-- Returns error: "Account is {status}"
-
-Step 6: Generate Tokens
-- Access token with user_id, account_id, role claims
-- Refresh token with same claims
-- Calculate expiry timestamps
-
-Step 7: Return Response
-- User data (via UserSerializer)
-- Access and refresh tokens
-- Token expiry timestamps
-
----
-
-### 3.3 Token Structure
-
-**JWT Claims:**
-
-Access Token:
-```python
-{
- 'user_id': Integer,
- 'account_id': Integer,
- 'email': String,
- 'role': String,
- 'exp': Timestamp, # Now + 1 hour
- 'iat': Timestamp, # Issued at
- 'type': 'access'
-}
-```
-
-Refresh Token:
-```python
-{
- 'user_id': Integer,
- 'account_id': Integer,
- 'exp': Timestamp, # Now + 7 days
- 'iat': Timestamp,
- 'type': 'refresh'
-}
-```
-
-**Token Refresh Flow:**
-
-Endpoint: `POST /v1/auth/refresh/`
-Process:
-1. Validate refresh token signature
-2. Check expiry (must not be expired)
-3. Extract user_id and account_id
-4. Fetch user and account from database
-5. Validate user.is_active and account status
-6. Generate new access token
-7. Return new access token (refresh token stays same)
-
----
-
-### 3.4 Frontend Token Handling
-
-**Storage Strategy:**
-
-Dual Storage Approach:
-- Zustand persist middleware: Stores in `localStorage['auth-storage']`
-- Direct localStorage keys: `access_token` and `refresh_token`
-
-Reason for Dual Storage:
-- Zustand persist is asynchronous
-- API calls happen immediately after login/register
-- Direct keys available synchronously
-- No race condition between persist and first API call
-
-**Token Extraction Logic (Fixed Dec 9, 2024):**
-
-Frontend: `authStore.ts`
-```typescript
-Function: register() and login()
-
-// Extract from response
-const responseData = data.data || data
-const tokens = responseData.tokens || {}
-const newToken = tokens.access || responseData.access ||
- data.data?.tokens?.access || data.tokens?.access
-
-// Store in Zustand (async)
-set({ token: newToken, refreshToken: newRefreshToken, ... })
-
-// CRITICAL FIX: Store synchronously for immediate API calls
-localStorage.setItem('access_token', newToken)
-localStorage.setItem('refresh_token', newRefreshToken)
-```
-
-**API Interceptor:**
-
-Function: `fetchAPI()` in `services/api.ts`
-
-Authorization Header:
-```typescript
-const token = localStorage.getItem('access_token') ||
- useAuthStore.getState().token
-
-headers['Authorization'] = `Bearer ${token}`
-```
-
-401 Handling:
-1. Attempt token refresh with refresh_token
-2. If refresh succeeds: Retry original request with new token
-3. If refresh fails: Clear auth state and redirect to /signin
-
-403 Handling:
-1. Check error message for authentication keywords
-2. If auth error: Force logout and redirect
-3. If permission error: Show error to user
-
----
-
-## 4. Payment Processing
-
-### 4.1 Payment Workflow Overview
-
-**Manual Payment Flow (Bank Transfer / Mobile Wallet):**
-
-```
-User Signs Up (Paid Plan)
- ↓
-Account Created (status='pending_payment')
- ↓
-Subscription Created (status='pending_payment')
- ↓
-Invoice Created (status='pending', with local currency amount)
- ↓
-User Shown Payment Instructions
- ↓
-User Makes Payment Externally (bank or wallet)
- ↓
-User Submits Payment Confirmation (with transaction reference)
- ↓
-Payment Record Created (status='pending_approval')
- ↓
-Admin Reviews Payment in Django Admin
- ↓
-Admin Approves Payment (changes status to 'succeeded')
- ↓
-AUTOMATIC WORKFLOW TRIGGERED:
- - Invoice status → 'paid'
- - Subscription status → 'active'
- - Account status → 'active'
- - Credits allocated based on plan
- ↓
-User Can Now Use Platform
-```
-
-**Automated Payment Flow (Stripe / PayPal - Future):**
-
-```
-User Signs Up (Paid Plan)
- ↓
-Account Created (status='pending_payment')
- ↓
-Subscription Created (status='pending_payment')
- ↓
-Invoice Created (status='pending')
- ↓
-User Enters Card/PayPal Details
- ↓
-Payment Gateway Processes Payment
- ↓
-Webhook Received: payment.succeeded
- ↓
-Payment Record Created (status='succeeded')
- ↓
-SAME AUTOMATIC WORKFLOW AS MANUAL
- ↓
-User Can Use Platform Immediately
-```
-
----
-
-### 4.2 Invoice Creation Service
-
-**Service:** `InvoiceService` in `backend/igny8_core/business/billing/services/invoice_service.py`
-
-**Method:** `create_subscription_invoice(subscription, billing_period_start, billing_period_end)`
-
-**Purpose:** Creates invoice with currency conversion for subscription billing
-
-**Process Logic:**
-
-Step 1: Extract Account and Plan
-- Get account from subscription.account
-- Get plan from subscription.plan (new field added Dec 9)
-- Validate plan exists
-
-Step 2: Snapshot Billing Information
-- Create billing_snapshot dictionary from account fields:
- - email (from billing_email or owner.email)
- - address_line1, address_line2
- - city, state, postal_code, country
- - tax_id
- - snapshot_date (current timestamp)
-- Stored in invoice.metadata for historical record
-- Account billing info can change later without affecting invoice
-
-Step 3: Calculate Invoice and Due Dates
-- invoice_date = today's date
-- due_date = invoice_date + INVOICE_DUE_DATE_OFFSET
-- Default offset: 7 days
-- Configurable in billing config
-
-Step 4: Determine Currency
-- Function: `get_currency_for_country(account.billing_country)`
-- Maps country codes to currencies:
- - PK → PKR, IN → INR
- - GB → GBP, EU countries → EUR
- - CA → CAD, AU → AUD
- - US and others → USD
-- Returns 3-letter ISO currency code
-
-Step 5: Convert Price to Local Currency
-- Function: `convert_usd_to_local(usd_amount, country_code)`
-- Applies currency multiplier from CURRENCY_MULTIPLIERS table:
- - PKR: ×278.0 (1 USD = 278 PKR)
- - INR: ×83.0
- - GBP: ×0.79
- - EUR: ×0.92
- - CAD: ×1.36
- - AUD: ×1.52
-- Formula: local_price = usd_price × multiplier
-- Example: $29 × 278 = PKR 8,062
-
-Step 6: Create Invoice Record
-- Set account, subscription
-- Generate invoice_number: `INV-{account.id}-{YYYYMM}-{sequence}`
-- Set status='pending'
-- Set currency from step 4
-- Set invoice_date and due_date from step 3
-- Store metadata with billing_snapshot and period dates
-
-Step 7: Add Line Item
-- Description: "{plan.name} Plan - {month_year}"
- - Example: "Starter Plan - Dec 2024"
-- Quantity: 1
-- Unit price: converted local price
-- Amount: same as unit price
-- Appended to invoice.line_items JSON array
-
-Step 8: Calculate Totals
-- Function: `invoice.calculate_totals()`
-- Sums all line_items amounts → subtotal
-- Adds tax (currently 0) → total
-- Saves calculated amounts to invoice
-
-Step 9: Store Exchange Rate Metadata
-- Original USD price stored in metadata
-- Exchange rate stored for reference
-- Enables audit trail of currency conversion
-- Example metadata:
- ```python
- {
- 'usd_price': '29.00',
- 'exchange_rate': '278.00',
- 'subscription_id': 42,
- 'billing_period_start': '2024-12-01T00:00:00Z',
- 'billing_period_end': '2024-12-31T23:59:59Z'
- }
- ```
-
-Step 10: Return Created Invoice
-- Invoice saved to database
-- Returns invoice object
-- Used in subscription creation flow
-
----
-
-### 4.3 Payment Confirmation Flow
-
-**Endpoint:** `POST /v1/billing/admin/payments/confirm/`
-**Handler:** `AdminPaymentViewSet.confirm_payment()` in `backend/igny8_core/business/billing/views.py`
-**Permission:** `IsAuthenticatedAndActive`
-
-**Request Payload:**
-
-```python
-{
- 'invoice_id': Integer, # Required
- 'payment_method': String, # Required: bank_transfer | local_wallet
- 'amount': Decimal, # Required: Must match invoice.total
- 'manual_reference': String, # Required: Transaction ID from bank/wallet
- 'manual_notes': String, # Optional: Additional info from user
- 'proof_url': String (URL) # Optional: Receipt/screenshot URL
-}
-```
-
-**Validation Process:**
-
-Step 1: Validate Payload
-- Serializer: `PaymentConfirmationSerializer`
-- Check all required fields present
-- Validate payment_method in ['bank_transfer', 'local_wallet']
-- Validate amount is positive decimal with 2 decimal places
-- Validate manual_reference not empty
-- Validate proof_url is valid URL format (if provided)
-
-Step 2: Fetch and Validate Invoice
-- Query invoice by id
-- Ensure invoice belongs to request.account (tenant isolation)
-- If not found or wrong account: Return 404
-
-Step 3: Check for Existing Payment
-- Query Payment table for invoice
-- Filter: status in ['pending_approval', 'succeeded']
-- If exists with status='succeeded':
- - Return error: "Invoice already paid"
-- If exists with status='pending_approval':
- - Return error: "Payment confirmation already pending approval (Payment ID: {id})"
-
-Step 4: Validate Amount Matches Invoice
-- Compare payment amount to invoice.total
-- Must match exactly (including decimals)
-- If mismatch: Return error with expected amount and currency
-
-Step 5: Create Payment Record
-- Set account from request.account
-- Set invoice from step 2
-- Set amount and currency from invoice
-- Set status='pending_approval'
-- Set payment_method from request
-- Set manual_reference and manual_notes from request
-- Set metadata with proof_url and submitted_by email
-- Save to database
-
-Step 6: Log Payment Submission
-- Log to application logger
-- Include: Payment ID, Invoice number, Account ID, Reference
-- Used for audit trail and debugging
-
-Step 7: Send Email Notification (Optional)
-- Service: `BillingEmailService.send_payment_confirmation_email()`
-- Send to user's billing_email
-- Subject: "Payment Confirmation Received"
-- Body: Payment details, next steps, estimated review time
-
-Step 8: Return Success Response
-- Include payment_id for tracking
-- Include invoice_id and invoice_number
-- Include status='pending_approval'
-- Include formatted amount and currency
-
----
-
-### 4.4 Payment Approval Workflow
-
-**Location:** Django Admin → Billing → Payments
-**Handler:** `PaymentAdmin.save_model()` in `backend/igny8_core/modules/billing/admin.py`
-
-**Trigger:** Admin changes payment status from 'pending_approval' to 'succeeded'
-
-**Automatic Workflow (Atomic Transaction):**
-
-Step 1: Detect Status Change
-- Compare current status to previous status
-- If changed to 'succeeded' and was not 'succeeded' before:
- - Trigger approval workflow
-- If no change: Just save, no workflow
-
-Step 2: Set Approval Metadata
-- approved_by = current admin user
-- approved_at = current timestamp
-- processed_at = current timestamp
-- Save payment record first
-
-Step 3: Update Invoice Status
-- Fetch invoice from payment.invoice
-- If invoice.status != 'paid':
- - Set invoice.status = 'paid'
- - Set invoice.paid_at = current timestamp
- - Save invoice
-
-Step 4: Update Subscription Status
-- Get subscription from invoice.subscription OR account.subscription
-- If subscription.status != 'active':
- - Set subscription.status = 'active'
- - Set subscription.external_payment_id = payment.manual_reference
- - Save subscription
-
-Step 5: Update Account Status
-- Get account from payment.account
-- If account.status != 'active':
- - Set account.status = 'active'
- - Save account
-
-Step 6: Allocate Credits (Check for Duplicates First)
-- Query CreditTransaction table
-- Filter: account=account, metadata__payment_id=payment.id
-- If exists: Skip credit allocation (prevents duplicates)
-- If not exists:
- - Get credits_to_add from subscription.plan.included_credits OR account.plan.included_credits
- - If credits_to_add > 0:
- - Call `CreditService.add_credits()`
-
-Step 7: Add Credits via CreditService
-- Function: `CreditService.add_credits(account, amount, transaction_type, description, metadata)`
-- Create CreditTransaction record
-- Calculate new balance: current_balance + amount
-- Update account.credits = new_balance
-- Metadata includes:
- - subscription_id
- - invoice_id
- - payment_id (for duplicate detection)
- - approved_by (admin email)
-
-Step 8: Show Admin Success Message
-- Django admin message framework
-- Success message: "✓ Payment approved: Account activated, {credits} credits added"
-- Shows plan name, invoice number, and credit amount
-
-Step 9: Error Handling
-- If any step fails: Rollback entire transaction (atomic)
-- Show error message in admin
-- Payment stays in 'pending_approval' status
-- Admin can retry or investigate issue
-
-**Key Fix Applied (Dec 9, 2024):**
-
-Problem: Manual status change didn't trigger workflow
-- Original code only set approved_by field
-- No invoice/subscription/account updates
-- No credit allocation
-- Admin had to manually activate everything
-
-Solution: Enhanced save_model() with full workflow
-- Detects status changes
-- Runs complete approval process
-- All updates in atomic transaction
-- Prevents duplicate credit allocation
-
----
-
-## 5. Multi-Currency System
-
-### 5.1 Currency Configuration
-
-**Location:** `backend/igny8_core/business/billing/utils/currency.py`
-
-**Currency Multipliers Table:**
-
-| Country Code | Currency | Multiplier | Example Conversion |
-|--------------|----------|------------|-------------------|
-| PK | PKR | 278.0 | $29 → PKR 8,062 |
-| IN | INR | 83.0 | $29 → INR 2,407 |
-| GB | GBP | 0.79 | $29 → £22.91 |
-| EU (multiple) | EUR | 0.92 | $29 → €26.68 |
-| CA | CAD | 1.36 | $29 → CAD 39.44 |
-| AU | AUD | 1.52 | $29 → AUD 44.08 |
-| US, others | USD | 1.0 | $29 → $29.00 |
-
-**Function:** `convert_usd_to_local(usd_amount, country_code)`
-
-Logic:
-1. Get multiplier from CURRENCY_MULTIPLIERS dict
-2. Default to 1.0 if country not in table (uses USD)
-3. Calculate: local_amount = usd_amount × multiplier
-4. Return as Decimal with 2 decimal places
-
-**Function:** `get_currency_for_country(country_code)`
-
-Returns 3-letter ISO currency code based on country:
-- Maps country codes to currencies
-- Default: USD for unmapped countries
-
-**Function:** `format_currency(amount, currency_code)`
-
-Returns formatted string for display:
-- PKR 8,062.00
-- $29.00
-- €26.68
-
----
-
-### 5.2 Invoice Currency Handling
-
-**Invoice Creation:**
-- Detects user's billing_country from account
-- Converts plan price from USD to local currency
-- Stores both amounts:
- - invoice.total (in local currency)
- - metadata.usd_price (original USD price)
- - metadata.exchange_rate (multiplier used)
-
-**API Response:**
-- Returns both `total` and `total_amount` fields
-- Frontend can use either field name
-- Currency code included in `currency` field
-
-**Payment Validation:**
-- Payment amount must match invoice.total exactly
-- Currency must match invoice.currency
-- No currency conversion during payment confirmation
-
----
-
-## 6. Site & Sector Management
-
-### 6.1 Site Creation
-
-**Endpoint:** `POST /v1/auth/sites/`
-**Handler:** `SiteViewSet.create()` in `backend/igny8_core/auth/views.py`
-**Permission:** `IsAuthenticated` (account status not required)
-
-**Request Payload:**
-
-```python
-{
- 'name': String, # Required: Site display name
- 'domain': String, # Optional: Website URL
- 'description': String, # Optional
- 'industry': Integer, # Required: FK to Industry
- 'is_active': Boolean, # Default: True
- 'hosting_type': String, # wordpress/custom/static
- 'site_type': String # blog/ecommerce/corporate
-}
-```
-
-**Validation Process:**
-
-Step 1: Check Plan Limits
-- Get account from request.account (middleware)
-- Get max_sites from account.plan.max_sites
-- Count existing active sites for account
-- If count >= max_sites: Return error "Site limit reached"
-
-Step 2: Auto-Generate Slug
-- If slug not provided: Generate from name
-- Slugify: Convert to lowercase, replace spaces with hyphens
-- Ensure uniqueness within account
-- Example: "Tech Blog" → "tech-blog"
-
-Step 3: Validate and Format Domain
-- If domain provided:
- - Strip whitespace
- - If empty string: Set to None
- - If starts with http://: Replace with https://
- - If no protocol: Add https://
- - Validate URL format
-- If domain not provided or empty: Set to None
-
-Step 4: Create Site Record
-- Set account from request.account (automatic)
-- Set all fields from validated data
-- Save to database
-
-Step 5: Grant Creator Access (Owner/Admin Only)
-- If user role in ['owner', 'admin']:
- - Create SiteUserAccess record
- - Set user=request.user
- - Set site=newly created site
- - Set granted_by=request.user
-
-Step 6: Return Created Site
-- Serializer includes related counts
-- Returns site with industry name and slug
-- Includes sectors_count=0 (new site has no sectors)
-
-**Key Fix Applied (Dec 9, 2024):**
-
-Problem: Site creation failed with empty domain
-- Domain field validation rejected empty strings
-- Frontend sent empty string when field left blank
-- Users couldn't create sites without domain
-
-Solution: Allow empty domain values
-- Modified validation to convert empty string to None
-- Accepts None, empty string, or valid URL
-- Allows sites without domains
-
----
-
-### 6.2 Sector Management
-
-**Sector Creation Endpoint:** `POST /v1/auth/sites/{site_id}/select_sectors/`
-**Handler:** `SiteViewSet.select_sectors()` in `backend/igny8_core/auth/views.py`
-
-**Request Payload:**
-
-```python
-{
- 'industry_slug': String, # Must match site.industry.slug
- 'sector_slugs': [String] # Array of IndustrySector slugs
-}
-```
-
-**Process Logic:**
-
-Step 1: Validate Site Ownership
-- Ensure site belongs to request.account
-- Check user has access to site
-
-Step 2: Validate Industry Match
-- Fetch industry by slug
-- Ensure industry matches site.industry
-- Prevent cross-industry sector assignment
-
-Step 3: Check Sector Limit
-- Max sectors per site: 5 (hard-coded)
-- Count existing active sectors for site
-- Calculate available slots
-- If sector_slugs length > available: Return error
-
-Step 4: Fetch Industry Sectors
-- Query IndustrySector by slugs and industry
-- Validate all requested sectors exist
-- Ensure sectors belong to correct industry
-
-Step 5: Create or Update Sectors
-- For each industry_sector:
- - Check if Sector already exists for site
- - If exists: Update is_active=True
- - If not exists: Create new Sector
- - Auto-generate sector name and slug
- - Set account=site.account (automatic)
-
-Step 6: Return Results
-- Count of created sectors
-- Count of updated sectors
-- Array of sector objects with details
-
----
-
-## 7. Credit System
-
-### 7.1 Credit Allocation
-
-**Service:** `CreditService` in `backend/igny8_core/business/billing/services/credit_service.py`
-
-**Method:** `add_credits(account, amount, transaction_type, description, metadata)`
-
-**Process:**
-
-Step 1: Validate Amount
-- Must be positive integer
-- No fractional credits allowed
-
-Step 2: Calculate New Balance
-- Fetch current balance from account.credits
-- New balance = current + amount
-
-Step 3: Create Transaction Record
-- Type = transaction_type ('subscription' for plan credits)
-- Amount = credit amount being added
-- Balance_after = new calculated balance
-- Description = human-readable text
-- Metadata = structured data (payment_id, etc.)
-
-Step 4: Update Account Balance
-- Set account.credits = new balance
-- Save account record
-
-Step 5: Return Transaction
-- Returns created CreditTransaction object
-
----
-
-### 7.2 Credit Deduction
-
-**Method:** `deduct_credits(account, amount, transaction_type, description, metadata)`
-
-**Process:**
-
-Similar to add_credits but:
-- Amount is positive (converted to negative internally)
-- Checks sufficient balance before deduction
-- Raises InsufficientCreditsError if balance < amount
-- Transaction record has negative amount
-- Balance_after = current - amount
-
----
-
-## 8. Admin Workflows
-
-### 8.1 Payment Approval (Django Admin)
-
-**Location:** Admin → Billing → Payments
-
-**Process:**
-
-Option 1: Bulk Action
-1. Select payment checkboxes
-2. Choose "Approve selected manual payments" from Actions dropdown
-3. Click "Go"
-4. Automatic workflow runs for each payment
-5. Success message shows details
-
-Option 2: Individual Edit
-1. Click payment to open edit page
-2. Change Status dropdown from "Pending Approval" to "Succeeded"
-3. Add admin notes (optional)
-4. Click "Save"
-5. Automatic workflow runs on save
-6. Success message confirms activation
-
-**Admin Interface Shows:**
-- Invoice number
-- Account name
-- Amount and currency
-- Payment method
-- Manual reference (transaction ID from user)
-- Manual notes (user's comments)
-- Status with color coding
-- Approved by and timestamp (after approval)
-
----
-
-### 8.2 Account Management
-
-**Admin Can:**
-
-View Account Details:
-- Plan and status
-- Credit balance
-- Billing information
-- Owner and users
-- Sites and sectors
-- Payment history
-
-Modify Account:
-- Change plan (creates new subscription)
-- Adjust credit balance (creates adjustment transaction)
-- Update billing information
-- Change account status
-- Add/remove users
-
-Soft Delete Account:
-- Mark as deleted with retention period
-- All data preserved during retention
-- Can restore within period
-- Hard delete after retention expires
-
----
-
-## 9. API Endpoints Summary
-
-### 9.1 Authentication Endpoints
-
-| Method | Endpoint | Permission | Purpose |
-|--------|----------|------------|---------|
-| POST | /v1/auth/register/ | AllowAny | User registration |
-| POST | /v1/auth/login/ | AllowAny | User login |
-| POST | /v1/auth/refresh/ | AllowAny | Refresh access token |
-| GET | /v1/auth/me/ | IsAuthenticated | Get current user |
-| POST | /v1/auth/change-password/ | IsAuthenticated | Change password |
-
-### 9.2 Billing Endpoints
-
-| Method | Endpoint | Permission | Purpose |
-|--------|----------|------------|---------|
-| GET | /v1/billing/admin/payment-methods/ | AllowAny | Get payment methods by country |
-| GET | /v1/billing/plans/ | AllowAny | List subscription plans |
-| GET | /v1/billing/invoices/ | IsAuthenticatedAndActive | List user's invoices |
-| GET | /v1/billing/payments/ | IsAuthenticatedAndActive | List user's payments |
-| POST | /v1/billing/admin/payments/confirm/ | IsAuthenticatedAndActive | Confirm manual payment |
-
-### 9.3 Site & Sector Endpoints
-
-| Method | Endpoint | Permission | Purpose |
-|--------|----------|------------|---------|
-| GET | /v1/auth/sites/ | IsAuthenticated | List user's sites |
-| POST | /v1/auth/sites/ | IsAuthenticated | Create site |
-| GET | /v1/auth/sites/{id}/ | IsAuthenticatedAndActive | Get site details |
-| POST | /v1/auth/sites/{id}/select_sectors/ | IsAuthenticatedAndActive | Add sectors to site |
-| GET | /v1/auth/industries/ | AllowAny | List available industries |
-
----
-
-## 10. Security & Permissions
-
-### 10.1 Permission Classes
-
-**IsAuthenticatedAndActive:**
-- Requires valid JWT token
-- Checks user.is_active == True
-- Used for most authenticated endpoints
-
-**HasTenantAccess:**
-- Validates request.account matches user.account
-- Ensures tenant isolation
-- Bypassed for developers and superusers
-
-**IsEditorOrAbove:**
-- Requires role in ['developer', 'owner', 'admin', 'editor']
-- Blocks 'viewer' and 'system_bot' roles
-- Used for content modification
-
-**IsOwnerOrAdmin:**
-- Requires role in ['developer', 'owner', 'admin']
-- Used for account management and billing
-
-### 10.2 Data Isolation
-
-**Query Filtering:**
-- All models inherit from AccountBaseModel
-- Automatic account filtering in querysets
-- Middleware sets request.account
-- Impossible to query cross-tenant data
-
-**API Security:**
-- JWT tokens include account_id claim
-- Tokens validated on every request
-- Expired tokens rejected
-- Refresh tokens for long sessions
-
----
-
-**End of Implementation Guide**
-
-This document provides complete technical details of the IGNY8 multi-tenancy system as implemented on December 9, 2024.
diff --git a/docs/package-backup/BACKUP-SYSTEM.md b/docs/package-backup/BACKUP-SYSTEM.md
deleted file mode 100644
index b2245a8c..00000000
--- a/docs/package-backup/BACKUP-SYSTEM.md
+++ /dev/null
@@ -1,199 +0,0 @@
-# IGNY8 Application Packaging & Backup System
-
-## Overview
-
-This system creates portable, clean packages of the IGNY8 application containing only source code (no dependencies or generated artifacts).
-
-## Components
-
-### 1. Packaging Script
-**Location**: `/data/app/igny8/scripts/package_app.sh`
-
-**What it does**:
-- Creates compressed archive of application source code
-- Excludes: `node_modules/`, `.venv/`, `dist/`, `*.sql`, `*.log`, build artifacts
-- Includes: Source code, Docker configs, documentation
-- Generates SHA256 checksum for verification
-- Auto-cleans packages older than 7 days
-- Package size: ~44 MB (compressed)
-
-**Manual Usage**:
-```bash
-/data/app/igny8/scripts/package_app.sh
-```
-
-### 2. Automated Backup Tasks
-**Location**: `/data/app/igny8/backend/igny8_core/tasks/backup.py`
-
-**Celery Tasks**:
-
-1. **`backup.create_daily_app_package`**
- - Runs daily at 00:00 UTC
- - Creates full application package
- - Logs success/failure
- - Returns status dict
-
-2. **`backup.cleanup_old_packages`**
- - Runs weekly (Monday at 01:00 UTC)
- - Removes packages older than 30 days
- - Keeps recent backups safe
-
-### 3. Celery Beat Schedule
-**Location**: `/data/app/igny8/backend/igny8_core/celery.py`
-
-Configured schedules:
-```python
-'daily-app-package-backup': {
- 'task': 'backup.create_daily_app_package',
- 'schedule': crontab(hour=0, minute=0), # Daily at midnight
-},
-'weekly-package-cleanup': {
- 'task': 'backup.cleanup_old_packages',
- 'schedule': crontab(hour=1, minute=0, day_of_week=1), # Monday 01:00
-},
-```
-
-## Backup Storage
-
-**Location**: `/data/backups/igny8/`
-
-**Files created**:
-```
-/data/backups/igny8/
-├── igny8-app-20251210_161527.tar.gz # Compressed package
-├── igny8-app-20251210_161527.tar.gz.sha256 # Checksum file
-├── igny8-app-20251211_000000.tar.gz
-├── igny8-app-20251211_000000.tar.gz.sha256
-└── ... (7-30 days of backups retained)
-```
-
-## Package Contents
-
-### ✅ INCLUDED (Source code only - ~56 MB uncompressed):
-- `backend/igny8_core/` - Django application
-- `backend/manage.py`, `requirements.txt`
-- `frontend/src/`, `frontend/public/`
-- `frontend/package.json`, config files
-- `docs/`, `README.md`
-- Dockerfiles, docker-compose files
-
-### ❌ EXCLUDED (Auto-generated - will be rebuilt):
-- `backend/.venv/` - Python virtual environment
-- `frontend/node_modules/` - NPM dependencies
-- `frontend/dist/` - Build output
-- `*.sql`, `*.sqlite3` - Database files
-- `logs/` - Runtime logs
-- `celerybeat-schedule` - Celery state
-- `staticfiles/` - Collected static files
-- `__pycache__/`, `*.pyc` - Python cache
-
-## Restoration Process
-
-To restore from a package on a new server:
-
-```bash
-# 1. Extract package
-cd /data/app
-tar -xzf /path/to/igny8-app-YYYYMMDD_HHMMSS.tar.gz
-
-# 2. Verify checksum (optional but recommended)
-sha256sum -c igny8-app-YYYYMMDD_HHMMSS.tar.gz.sha256
-
-# 3. Follow INSTALLATION.md to:
-# - Build Docker images (installs all dependencies)
-# - Start services
-# - Run migrations
-```
-
-## Monitoring
-
-**Check backup status**:
-```bash
-# List recent backups
-ls -lh /data/backups/igny8/
-
-# View Celery Beat schedule
-docker exec igny8_celery_beat celery -A igny8_core inspect scheduled
-
-# View Celery logs
-docker logs igny8_celery_beat
-docker logs igny8_celery_worker
-```
-
-**Verify backup worked**:
-```bash
-# Check if backup ran
-ls -lt /data/backups/igny8/ | head -5
-
-# Verify package integrity
-cd /data/backups/igny8/
-sha256sum -c igny8-app-*.tar.gz.sha256
-```
-
-## Retention Policy
-
-- **Daily backups**: Kept for 7 days in packaging script
-- **Long-term backups**: Kept for 30 days by cleanup task
-- **Manual backups**: Never auto-deleted (run script manually with different output dir)
-
-## Troubleshooting
-
-**Backup didn't run at midnight**:
-```bash
-# Check Celery Beat is running
-docker ps | grep celery_beat
-
-# Check Beat logs
-docker logs igny8_celery_beat
-
-# Manually trigger backup
-docker exec igny8_celery_worker celery -A igny8_core call backup.create_daily_app_package
-```
-
-**Insufficient disk space**:
-```bash
-# Check disk usage
-df -h /data
-
-# Clean old backups manually
-find /data/backups/igny8/ -name "*.tar.gz" -mtime +30 -delete
-```
-
-**Package too large**:
-- Check no large files accidentally included
-- Verify `.git` folder is excluded
-- Ensure `node_modules`, `.venv` excluded
-
-## Security Notes
-
-1. **Packages contain source code** - store securely
-2. **No secrets in package** - `.env` is excluded
-3. **Checksum verification** - always verify SHA256 before restoring
-4. **Backup the backups** - Consider copying to remote storage
-
-## Quick Reference
-
-| Action | Command |
-|--------|---------|
-| Create backup now | `/data/app/igny8/scripts/package_app.sh` |
-| List backups | `ls -lh /data/backups/igny8/` |
-| Verify package | `sha256sum -c package.tar.gz.sha256` |
-| Extract package | `tar -xzf package.tar.gz` |
-| Check schedule | `docker exec igny8_celery_beat celery -A igny8_core inspect scheduled` |
-| View logs | `docker logs igny8_celery_beat` |
-
-## Configuration
-
-To change backup schedule, edit `/data/app/igny8/backend/igny8_core/celery.py`:
-
-```python
-'daily-app-package-backup': {
- 'task': 'backup.create_daily_app_package',
- 'schedule': crontab(hour=0, minute=0), # Change time here
-},
-```
-
-Then restart Celery:
-```bash
-docker restart igny8_celery_beat igny8_celery_worker
-```
diff --git a/docs/package-backup/INSTALLATION.md b/docs/package-backup/INSTALLATION.md
deleted file mode 100644
index 65cd0dc6..00000000
--- a/docs/package-backup/INSTALLATION.md
+++ /dev/null
@@ -1,431 +0,0 @@
-# IGNY8 Application - Installation Guide
-
-**Complete step-by-step installation on a clean Ubuntu server**
-
----
-
-## Prerequisites
-
-- **Clean Ubuntu 22.04 LTS or later** (stable version)
-- **Minimum Requirements**: 4GB RAM, 20GB disk space, 2 CPU cores
-- **Root or sudo access**
-- **Internet connection**
-
----
-
-## Installation Steps
-
-### 1. Initial System Setup
-
-```bash
-# Update system
-sudo apt update && sudo apt upgrade -y
-
-# Install required system packages
-sudo apt install -y \
- git \
- curl \
- wget \
- ca-certificates \
- gnupg \
- lsb-release
-```
-
----
-
-### 2. Install Docker & Docker Compose
-
-```bash
-# Add Docker's official GPG key
-sudo mkdir -p /etc/apt/keyrings
-curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
-
-# Set up Docker repository
-echo \
- "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
- $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
-
-# Install Docker Engine
-sudo apt update
-sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
-
-# Verify installation
-docker --version
-docker compose version
-
-# Add current user to docker group (optional - for non-root usage)
-sudo usermod -aG docker $USER
-newgrp docker
-```
-
----
-
-### 3. Install Portainer (Optional - for GUI management)
-
-```bash
-# Create Docker network
-docker network create igny8_net
-
-# Create Portainer volume
-docker volume create portainer_data
-
-# Run Portainer
-docker run -d \
- --name portainer \
- --restart always \
- -p 9443:9443 \
- -p 8000:8000 \
- -v /var/run/docker.sock:/var/run/docker.sock \
- -v portainer_data:/data \
- --network igny8_net \
- portainer/portainer-ce:latest
-
-# Access Portainer at: https://YOUR_SERVER_IP:9443
-```
-
----
-
-### 4. Get IGNY8 Application
-
-**Option A: Clone from Git Repository**
-```bash
-# Create application directory
-sudo mkdir -p /data/app
-cd /data/app
-
-# Clone repository
-git clone igny8
-cd igny8
-```
-
-**Option B: Upload Application Package**
-```bash
-# Create application directory
-sudo mkdir -p /data/app
-cd /data/app
-
-# Upload igny8.tar.gz to server, then extract
-tar -xzf igny8.tar.gz
-cd igny8
-```
-
----
-
-### 5. Configure Environment Variables
-
-```bash
-# Create environment file
-cat > .env << 'EOF'
-# Database Configuration
-DB_HOST=postgres
-DB_NAME=igny8_db
-DB_USER=igny8
-DB_PASSWORD=CHANGE_THIS_PASSWORD
-
-# Redis Configuration
-REDIS_HOST=redis
-REDIS_PORT=6379
-
-# Django Settings
-DEBUG=False
-SECRET_KEY=CHANGE_THIS_TO_RANDOM_50_CHAR_STRING
-ALLOWED_HOSTS=*
-
-# Security
-USE_SECURE_COOKIES=True
-USE_SECURE_PROXY_HEADER=True
-
-# Application URLs
-VITE_BACKEND_URL=https://api.yourdomain.com/api
-EOF
-
-# Generate Django secret key
-python3 -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())' >> .env.secret
-```
-
----
-
-### 6. Prepare Application Structure
-
-**What gets installed automatically (NO manual work needed):**
-
-✅ **Backend (Python packages)**: Installed inside Docker container from `requirements.txt`
-- Django, Celery, DRF, PostgreSQL drivers, etc.
-- No local Python venv needed
-
-✅ **Frontend (Node packages)**: Installed inside Docker container from `package.json`
-- React, Vite, TailwindCSS, etc.
-- No local node_modules needed
-
-✅ **Database**: PostgreSQL runs in Docker container
-
-✅ **Cache**: Redis runs in Docker container
-
-**Your IGNY8 folder should contain ONLY:**
-```
-igny8/
-├── backend/
-│ ├── igny8_core/ # Django application code
-│ ├── manage.py # Django management
-│ ├── requirements.txt # Python dependencies
-│ └── Dockerfile # Backend container build
-├── frontend/
-│ ├── src/ # React application code
-│ ├── public/ # Static assets
-│ ├── package.json # Node dependencies
-│ └── Dockerfile.dev # Frontend container build
-├── docker-compose.app.yml # Application stack definition
-├── README.md
-└── docs/
-
-# These should NOT be present (automatically generated):
-❌ backend/.venv/ # Will be built in Docker
-❌ frontend/node_modules/ # Will be built in Docker
-❌ frontend/dist/ # Will be built in Docker
-❌ *.sql, *.sqlite3 # Database backups
-❌ logs/ # Runtime logs
-```
-
----
-
-### 7. Build Docker Images
-
-```bash
-cd /data/app/igny8
-
-# Build backend image
-cd backend
-docker build -t igny8-backend:latest -f Dockerfile .
-
-# Build frontend dev image
-cd ../frontend
-docker build -t igny8-frontend-dev:latest -f Dockerfile.dev .
-
-# Build marketing dev image (if needed)
-docker build -t igny8-marketing-dev:latest -f Dockerfile.marketing.dev .
-
-cd ..
-```
-
----
-
-### 8. Start Infrastructure Services
-
-```bash
-# Create infrastructure stack (Postgres, Redis, Caddy, etc.)
-cd /data/app
-
-# Start infrastructure services
-docker compose -f docker-compose.yml up -d
-
-# Verify infrastructure is running
-docker ps
-```
-
----
-
-### 9. Start IGNY8 Application
-
-```bash
-# Start application stack
-cd /data/app/igny8
-docker compose -f docker-compose.app.yml up -d
-
-# Check all containers are running
-docker ps -a
-
-# View logs
-docker logs igny8_backend
-docker logs igny8_frontend
-docker logs igny8_celery_worker
-```
-
----
-
-### 10. Initialize Database
-
-```bash
-# Run migrations
-docker exec igny8_backend python manage.py migrate
-
-# Create superuser
-docker exec -it igny8_backend python manage.py createsuperuser
-
-# Collect static files (if needed)
-docker exec igny8_backend python manage.py collectstatic --noinput
-```
-
----
-
-### 11. Verify Installation
-
-**Check services:**
-```bash
-# Backend API
-curl http://localhost:8011/api/v1/system/status/
-
-# Frontend
-curl http://localhost:8021
-
-# Access application
-# Backend API: http://YOUR_SERVER_IP:8011
-# Frontend App: http://YOUR_SERVER_IP:8021
-# Marketing: http://YOUR_SERVER_IP:8023
-```
-
-**Check container health:**
-```bash
-docker ps --format "table {{.Names}}\t{{.Status}}"
-```
-
----
-
-## What Happens Automatically vs. Manually
-
-### ✅ AUTOMATIC (Docker handles everything):
-
-1. **Python environment setup**: Docker builds venv inside container
-2. **Install Python packages**: From `requirements.txt`
-3. **Node.js environment setup**: Docker installs Node in container
-4. **Install npm packages**: From `package.json`
-5. **Build frontend**: Vite builds in dev mode
-6. **Database setup**: PostgreSQL container starts
-7. **Cache setup**: Redis container starts
-8. **Networking**: Docker creates networks
-
-### 🔧 MANUAL (You must do):
-
-1. **Install Docker** on the host machine
-2. **Clone/upload** the IGNY8 application folder
-3. **Create `.env`** file with passwords and secrets
-4. **Build Docker images** (`docker build`)
-5. **Start services** (`docker compose up`)
-6. **Run database migrations** (`docker exec ... migrate`)
-7. **Create admin user** (`docker exec ... createsuperuser`)
-
----
-
-## Post-Installation
-
-### Set up SSL/HTTPS (Production)
-
-```bash
-# Update Caddyfile with your domain
-# Edit /data/app/igny8/frontend/Caddyfile
-# Caddy will automatically get SSL certificates from Let's Encrypt
-```
-
-### Set up backups
-
-```bash
-# Database backup script
-cat > /data/app/backup.sh << 'EOF'
-#!/bin/bash
-DATE=$(date +%Y%m%d_%H%M%S)
-docker exec igny8_postgres pg_dump -U igny8 igny8_db > /data/backups/pg/igny8_$DATE.sql
-EOF
-
-chmod +x /data/app/backup.sh
-
-# Add to crontab for daily backups
-crontab -e
-# Add: 0 2 * * * /data/app/backup.sh
-```
-
----
-
-## Updating the Application
-
-```bash
-# Pull latest code
-cd /data/app/igny8
-git pull origin main
-
-# Rebuild images
-docker compose -f docker-compose.app.yml build
-
-# Restart services
-docker compose -f docker-compose.app.yml down
-docker compose -f docker-compose.app.yml up -d
-
-# Run new migrations
-docker exec igny8_backend python manage.py migrate
-```
-
----
-
-## Troubleshooting
-
-**Containers won't start:**
-```bash
-# Check logs
-docker logs igny8_backend
-docker logs igny8_postgres
-
-# Check container status
-docker ps -a
-```
-
-**Database connection errors:**
-```bash
-# Verify postgres is running
-docker ps | grep postgres
-
-# Check network
-docker network inspect igny8_net
-```
-
-**Port conflicts:**
-```bash
-# Check what's using the port
-sudo lsof -i :8011
-sudo lsof -i :8021
-```
-
----
-
-## Summary: Fresh Ubuntu to Running IGNY8
-
-**Time estimate: 15-30 minutes**
-
-1. ✅ Install Docker (5 min)
-2. ✅ Install Portainer - optional (2 min)
-3. ✅ Clone/upload IGNY8 app (2 min)
-4. ✅ Create `.env` file (3 min)
-5. ✅ Build Docker images (5-10 min - downloads dependencies)
-6. ✅ Start infrastructure (2 min)
-7. ✅ Start application (2 min)
-8. ✅ Initialize database (3 min)
-9. ✅ Verify and test (2 min)
-
-**Total manual commands: ~20 commands**
-**Everything else: Automated by Docker**
-
----
-
-## Files You Need to Package
-
-**Minimum files to transfer to new server:**
-```
-igny8/
-├── backend/
-│ ├── igny8_core/ ← Your Django code
-│ ├── manage.py
-│ ├── requirements.txt ← Python deps list
-│ └── Dockerfile
-├── frontend/
-│ ├── src/ ← Your React code
-│ ├── public/
-│ ├── package.json ← Node deps list
-│ └── Dockerfile.dev
-├── docker-compose.app.yml ← Stack definition
-├── .env ← Secrets (create on new server)
-└── README.md
-
-Total size: ~10-20 MB (without node_modules, .venv, dist)
-```
-
-**DO NOT include:**
-- `.venv/`, `node_modules/`, `dist/`, `*.sql`, `logs/`, `celerybeat-schedule`
-
-These are automatically created by Docker during build.
diff --git a/docs/package-backup/PACKAGING-SETUP-COMPLETE.md b/docs/package-backup/PACKAGING-SETUP-COMPLETE.md
deleted file mode 100644
index 7bd7185f..00000000
--- a/docs/package-backup/PACKAGING-SETUP-COMPLETE.md
+++ /dev/null
@@ -1,159 +0,0 @@
-# IGNY8 Application Packaging & Backup - Setup Complete ✅
-
-## What Was Created
-
-### 1. Packaging Script
-**File**: `/data/app/igny8/scripts/package_app.sh`
-- ✅ Creates portable application packages
-- ✅ Excludes all generated artifacts (node_modules, .venv, dist, logs, etc.)
-- ✅ Generates SHA256 checksums for verification
-- ✅ Auto-cleans old backups (7+ days)
-- ✅ Package size: ~44 MB (compressed from ~56 MB source)
-
-### 2. Automated Backup Tasks
-**File**: `/data/app/igny8/backend/igny8_core/tasks/backup.py`
-- ✅ `backup.create_daily_app_package` - Daily backup task
-- ✅ `backup.cleanup_old_packages` - Weekly cleanup task
-- ✅ Full error handling and logging
-
-### 3. Celery Beat Schedule
-**File**: `/data/app/igny8/backend/igny8_core/celery.py`
-- ✅ Daily backup at 00:00 UTC
-- ✅ Weekly cleanup on Mondays at 01:00 UTC
-
-### 4. Documentation
-- ✅ `/data/app/igny8/INSTALLATION.md` - Complete installation guide
-- ✅ `/data/app/igny8/docs/BACKUP-SYSTEM.md` - Backup system documentation
-
-## First Backup Created
-
-```
-📦 Package: /data/backups/igny8/igny8-app-20251210_161527.tar.gz
-📏 Size: 44 MB
-🔐 SHA256: 5aa8fe458bcb75d1f4a455746a484015a81147bbfa8e8b1285e99195e2deacbd
-```
-
-## How It Works
-
-### Automatic Daily Backups (00:00 UTC)
-1. Celery Beat triggers `backup.create_daily_app_package` at midnight
-2. Task executes `/data/app/igny8/scripts/package_app.sh`
-3. Script creates compressed archive with date stamp
-4. Package saved to `/data/backups/igny8/`
-5. SHA256 checksum file generated
-6. Old backups (7+ days) auto-deleted
-
-### What Gets Packaged
-**INCLUDED** (~56 MB source):
-- `backend/igny8_core/` - All Django code
-- `backend/manage.py`, `requirements.txt`
-- `frontend/src/`, `public/` - All React code
-- `frontend/package.json`, build configs
-- `docs/`, `README.md`
-- Dockerfiles, docker-compose files
-
-**EXCLUDED** (auto-generated):
-- `node_modules/` - NPM dependencies (297 MB)
-- `.venv/` - Python virtual environment (140 MB)
-- `dist/` - Build outputs
-- `*.sql`, `*.sqlite3` - Databases
-- `logs/` - Runtime logs
-- Cache files, compiled files
-
-### Restoration Process
-```bash
-# On new server:
-1. Extract: tar -xzf igny8-app-YYYYMMDD_HHMMSS.tar.gz
-2. Verify: sha256sum -c igny8-app-YYYYMMDD_HHMMSS.tar.gz.sha256
-3. Follow INSTALLATION.md to deploy
-```
-
-## Testing & Verification
-
-### Manual Test (Already Done ✅)
-```bash
-/data/app/igny8/scripts/package_app.sh
-# Result: Package created successfully at /data/backups/igny8/
-```
-
-### Verify Celery Tasks
-```bash
-# Restart Celery to load new tasks
-docker restart igny8_celery_worker igny8_celery_beat
-
-# Check scheduled tasks
-docker exec igny8_celery_beat celery -A igny8_core inspect scheduled
-
-# View Beat logs
-docker logs igny8_celery_beat
-
-# Manually trigger backup (for testing)
-docker exec igny8_celery_worker celery -A igny8_core call backup.create_daily_app_package
-```
-
-### Monitor Backups
-```bash
-# List all backups
-ls -lh /data/backups/igny8/
-
-# Check latest backup
-ls -lt /data/backups/igny8/ | head -3
-
-# Verify checksum
-cd /data/backups/igny8/
-sha256sum -c igny8-app-*.tar.gz.sha256
-```
-
-## Next Steps
-
-1. **Wait for first automated backup** (will run at 00:00 UTC tonight)
-2. **Verify backup runs successfully**:
- ```bash
- # Check tomorrow morning
- ls -lt /data/backups/igny8/
- ```
-3. **Optional: Add remote backup** (copy to S3, Google Drive, etc.)
-
-## Retention Policy
-
-- **Packaging script**: Deletes backups > 7 days old
-- **Cleanup task**: Deletes backups > 30 days old (weekly check)
-- **Result**: 7-30 days of backups retained automatically
-
-## Package Portability
-
-✅ **Portable** - Package contains only source code
-✅ **Small** - 44 MB compressed (vs ~500+ MB with dependencies)
-✅ **Clean** - No generated files, logs, or secrets
-✅ **Verified** - SHA256 checksum ensures integrity
-✅ **Self-contained** - Everything needed to rebuild app
-
-## Deployment to New Server
-
-From the package, you get a clean IGNY8 installation:
-
-1. Extract package (44 MB)
-2. Install Docker
-3. Build images (Docker installs dependencies automatically)
-4. Start services
-5. Initialize database
-6. **Ready to run!**
-
-**Dependencies installed automatically by Docker**:
-- Python packages from `requirements.txt`
-- Node packages from `package.json`
-- PostgreSQL, Redis containers
-- All build tools and dependencies
-
-## Summary
-
-✅ **Automated daily backups** at midnight
-✅ **Portable packages** - only source code
-✅ **Auto-cleanup** - keeps 7-30 days
-✅ **Checksum verification** - ensures integrity
-✅ **Easy restoration** - extract and deploy
-✅ **Documentation** - complete guides created
-
-**Total disk usage for backups**: ~44 MB × 7-30 days = **308 MB - 1.3 GB**
-
-Much better than storing everything (would be 10+ GB with node_modules, venv, etc.)!
diff --git a/docs/package-backup/UNDER-OBSERVATION.md b/docs/package-backup/UNDER-OBSERVATION.md
deleted file mode 100644
index bad1ced9..00000000
--- a/docs/package-backup/UNDER-OBSERVATION.md
+++ /dev/null
@@ -1,118 +0,0 @@
-# UNDER OBSERVATION
-
-## Issue: User Logged Out During Image Prompt Generation (Dec 10, 2025)
-
-### Original Problem
-User performed workflow: auto-cluster → generate ideas → queue to writer → generate content → generate image prompt. During image prompt generation (near completion), user was automatically logged out.
-
-### Investigation Timeline
-
-**Initial Analysis:**
-- Suspected backend container restarts invalidating sessions
-- Docker ps showed all containers up 19+ minutes - NO RESTARTS during incident
-- Backend logs showed: `[IsAuthenticatedAndActive] DENIED: User not authenticated` and `Client error: Authentication credentials were not provided`
-- Token was not being sent with API requests
-
-**Root Cause Identified:**
-The logout was NOT caused by backend issues or container restarts. It was caused by **frontend state corruption during HMR (Hot Module Reload)** triggered by code changes made to fix an unrelated useLocation() error.
-
-**What Actually Happened:**
-
-1. **Commit 5fb3687854d9aadfc5d604470f3712004b23243c** - Already had proper fix for useLocation() error (Suspense outside Routes)
-
-2. **Additional "fixes" applied on Dec 10, 2025:**
- - Changed `cacheDir: "/tmp/vite-cache"` in vite.config.ts
- - Moved BrowserRouter above ErrorBoundary in main.tsx
- - Added `watch.interval: 100` and `fs.strict: false`
-
-3. **These changes triggered:**
- - Vite cache stored in /tmp got wiped on container operations
- - Full rebuild with HMR
- - Component tree restructuring (BrowserRouter position change)
- - Auth store (Zustand persist) lost state during rapid unmount/remount cycle
- - Frontend started making API calls WITHOUT Authorization header
- - Backend correctly rejected unauthenticated requests
- - Frontend logout() triggered
-
-### Fix Applied
-**Reverted the problematic changes:**
-- Removed `cacheDir: "/tmp/vite-cache"` - let Vite use default node_modules/.vite
-- Restored BrowserRouter position inside ErrorBoundary/ThemeProvider (original structure)
-- Removed `watch.interval` and `fs.strict` additions
-
-**Kept the actual fixes:**
-- Backend: Removed `IsSystemAccountOrDeveloper` from IntegrationSettingsViewSet class-level permissions
-- Backend: Auto-cluster `extra_data` → `debug_info` parameter fix
-- Frontend: Suspense wrapping Routes (from commit 5fb3687) - THIS was the real useLocation() fix
-
-### What to Watch For
-
-**1. useLocation() Error After Container Restarts**
-- **Symptom:** "useLocation() may be used only in the context of a component"
-- **Where:** Keywords page, other planner/writer module pages (50-60% of pages)
-- **If it happens:**
- - Check if Vite cache is stale
- - Clear node_modules/.vite inside frontend container: `docker compose exec igny8_frontend rm -rf /app/node_modules/.vite`
- - Restart frontend container
- - DO NOT change cacheDir or component tree structure
-
-**2. Auth State Loss During Development**
-- **Symptom:** Random logouts during active sessions, "Authentication credentials were not provided"
-- **Triggers:**
- - HMR with significant component tree changes
- - Rapid container restarts during development
- - Changes to context provider order in main.tsx
-- **Prevention:**
- - Avoid restructuring main.tsx component tree
- - Test auth persistence after any main.tsx changes
- - Monitor browser console for localStorage errors during HMR
-
-**3. Permission Errors for Normal Users**
-- **Symptom:** "You do not have permission to perform this action" for valid users with complete account setup
-- **Check:**
- - Backend logs for permission class debug output: `[IsAuthenticatedAndActive]`, `[IsViewerOrAbove]`, `[HasTenantAccess]`
- - Verify user has role='owner' and is_active=True
- - Ensure viewset doesn't have `IsSystemAccountOrDeveloper` at class level for endpoints normal users need
-
-**4. Celery Task Progress Polling 403 Errors**
-- **Symptom:** Task progress endpoint returns 403 for normal users
-- **Root cause:** ViewSet class-level permissions blocking action-level overrides
-- **Solution:** Ensure IntegrationSettingsViewSet permission_classes doesn't include IsSystemAccountOrDeveloper
-
-### Lessons Learned
-
-1. **Don't layer fixes on top of fixes** - Identify root cause first
-2. **Vite cache location matters** - /tmp gets wiped, breaking HMR state persistence
-3. **Component tree structure is fragile** - Moving BrowserRouter breaks auth rehydration timing
-4. **Container uptime ≠ code stability** - HMR can cause issues without restart
-5. **Permission debugging** - Added logging to permission classes was critical for diagnosis
-6. **The original fix was already correct** - Commit 5fb3687 had it right, additional "improvements" broke it
-
-### Files Modified (Reverted)
-- `frontend/vite.config.ts` - Removed cacheDir and watch config changes
-- `frontend/src/main.tsx` - Restored original component tree structure
-
-### Files Modified (Kept)
-- `backend/igny8_core/modules/system/integration_views.py` - Removed IsSystemAccountOrDeveloper
-- `backend/igny8_core/modules/planner/views.py` - Fixed extra_data → debug_info
-- `backend/igny8_core/api/permissions.py` - Added debug logging (can be removed later)
-
-### Status
-**RESOLVED** - Auth state stable, backend permissions correct, useLocation fix preserved.
-
-**ADDITIONAL FIX (Dec 10, 2025 - Evening):**
-1. **Permission Fix**: Fixed image generation task progress polling 403 errors
- - Root cause: `IsSystemAccountOrDeveloper` was still in class-level permissions
- - Solution: Moved to `get_permissions()` method to allow action-level overrides
- - `task_progress` and `get_image_generation_settings` now accessible to all authenticated users
- - Save/test operations still restricted to system accounts
-
-2. **System Account Fallback**: Fixed "Image generation settings not found" for normal users
- - Root cause: IntegrationSettings are account-specific - normal users don't have their own settings
- - Only super user account (aws-admin) has configured API keys
- - Solution: Added fallback to system account (aws-admin) settings in `process_image_generation_queue` task
- - When user's account doesn't have IntegrationSettings, falls back to system account
- - Allows normal users to use centralized API keys managed by super users
- - Files modified: `backend/igny8_core/ai/tasks.py`
-
-**Monitor for 48 hours** - Watch for any recurrence of useLocation errors or auth issues after container restarts. Test image generation with normal user accounts (paid-2).
diff --git a/frontend/src/components/auth/SignUpForm.tsx b/frontend/src/components/auth/SignUpForm.tsx
index 259b85a9..dff1e72a 100644
--- a/frontend/src/components/auth/SignUpForm.tsx
+++ b/frontend/src/components/auth/SignUpForm.tsx
@@ -129,7 +129,7 @@ export default function SignUpForm({ planDetails: planDetailsProp, planLoading:
{planSlug && paidPlans.includes(planSlug)
? `You're signing up for the ${planSlug} plan. You'll be taken to billing to complete payment.`
- : "No credit card required. 100 AI credits to get started."}
+ : "No credit card required. Start creating content today."}
{isPaidPlan
? `Complete the ${totalSteps}-step process to activate your subscription.`
- : 'No credit card required. 1000 AI credits to get started.'}
+ : 'No credit card required. Start creating content today.'}