# 🔷 GOD-MODE HARRIS MATRIX: Complete Schema Dependency Guide v2.0 > **What is a Harris Matrix?** In database design, it's a **Dependency Structure Matrix (DSM)** that shows the exact order to create tables so foreign key constraints don't fail. You cannot build a roof before walls. You cannot create `comments` before `users` and `posts` exist. > ✅ Status: Schema v2.0 - Phase 9 Complete (Dec 2025) - All 17 collections documented, 23 fields added, 0 TypeScript errors --- ## 🎯 THE GOLDEN RULE **Build the Foundation First, Then the Walls, Then the Roof** ``` ┌─────────────────────────────────────┐ │ BATCH 1: Foundation (Independent) │ ← Create First ├─────────────────────────────────────┤ │ BATCH 2: Walls (First Children) │ ← Create Second ├─────────────────────────────────────┤ │ BATCH 3: Roof (Complex Children) │ ← Create Last └─────────────────────────────────────┘ ``` --- ## 📊 SPARK PLATFORM: Complete Dependency Matrix ### Summary Statistics (Updated Dec 2025) - **Total Collections:** 17 (includes article_templates) - **Parent Tables (Batch 1):** 7 (added article_templates) - **Child Tables (Batch 2):** 8 - **Complex Tables (Batch 3):** 2 - **Total Foreign Keys:** 12 - **Schema Version:** v2.0 (Phase 9 Complete) - **All Issues Resolved:** ✅ Build successful, 0 errors --- ## 🏗️ BATCH 1: FOUNDATION TABLES > **Zero Dependencies** - These tables reference NO other tables | # | Table | Type | Purpose | Children Dependent | |---|-------|------|---------|-------------------| | 1 | `sites` ⭐ | Parent | Master site registry | **10 tables** depend on this | | 2 | `campaign_masters` ⭐ | Parent | Campaign definitions | **4 tables** depend on this | | 3 | `article_templates` | Parent | Article structure blueprints | **1 table** (campaign_masters) | | 4 | `avatar_intelligence` | Independent | Avatar personality data | 0 | | 5 | `avatar_variants` | Independent | Avatar variations | 0 | | 6 | `cartesian_patterns` | Independent | Pattern formulas | 0 | | 7 | `geo_intelligence` | Independent | Geographic data | 0 | | 8 | `offer_blocks` | Independent | Content offer blocks | 0 | **⚠️ CRITICAL:** `sites` and `campaign_masters` are **SUPER PARENTS** - create these FIRST! --- ## 🧱 BATCH 2: FIRST-LEVEL CHILDREN > **Depend ONLY on Batch 1** | # | Table | Depends On | Foreign Key | Constraint Action | |---|-------|------------|-------------|-------------------| | 8 | `generated_articles` | sites | `site_id` → `sites.id` | CASCADE | | 9 | `generation_jobs` | sites | `site_id` → `sites.id` | CASCADE | | 10 | `pages` | sites | `site_id` → `sites.id` | CASCADE | | 11 | `posts` | sites | `site_id` → `sites.id` | CASCADE | | 12 | `leads` | sites | `site_id` → `sites.id` | SET NULL | | 13 | `headline_inventory` | campaign_masters | `campaign_id` → `campaign_masters.id` | CASCADE | | 14 | `content_fragments` | campaign_masters | `campaign_id` → `campaign_masters.id` | CASCADE | --- ## 🏠 BATCH 3: COMPLEX CHILDREN > **Depend on Batch 2 or have multiple dependencies** | # | Table | Depends On | Multiple FKs | Notes | |---|-------|------------|--------------|-------| | 15 | `link_targets` | sites | No | Internal linking system | | 16 | (Future M2M) | Multiple | Yes | Junction tables go here | --- ## 🔍 DETAILED DEPENDENCY MAP ### Visual Cascade ``` sites ─────────┬─── generated_articles ├─── generation_jobs ├─── pages ├─── posts ├─── leads └─── link_targets campaign_masters ─┬─── headline_inventory ├─── content_fragments └─── (referenced by generated_articles) └─── (uses article_templates via article_template field) article_templates (standalone, referenced by campaign_masters) avatar_intelligence (standalone) avatar_variants (standalone) cartesian_patterns (standalone) geo_intelligence (standalone) offer_blocks (standalone) ``` --- ## 🚨 DETECTED ISSUES (from schema_issues.json) ### Issue #1: Template Field Mismatch **Collection:** `content_fragments` **Field:** `campaign_id` (M2O relation) **Problem:** Display template references `campaign_name` but `campaign_masters` has field `name`, not `campaign_name` **Fix:** Update template to use `{{campaign_id.name}}` instead of `{{campaign_id.campaign_name}}` ### Issue #2: Template Field Mismatch **Collection:** `headline_inventory` **Field:** `campaign_id` (M2O relation) **Problem:** Same as above - references non-existent `campaign_name` **Fix:** Update template to use `{{campaign_id.name}}` --- ## 📐 EXECUTION PLAN: Step-by-Step ### Phase 1: Create Foundation (Batch 1) ```bash # Order is CRITICAL - sites MUST be first npx directus schema apply --only-collections \ sites,campaign_masters,avatar_intelligence,avatar_variants,cartesian_patterns,geo_intelligence,offer_blocks ``` ### Phase 2: Create Walls (Batch 2) ```bash npx directus schema apply --only-collections \ generated_articles,generation_jobs,pages,posts,leads,headline_inventory,content_fragments ``` ### Phase 3: Create Roof (Batch 3) ```bash npx directus schema apply --only-collections \ link_targets ``` ### Phase 4: Apply Relationships ```bash # All foreign keys are applied AFTER tables exist npx directus schema apply --only-relations ``` --- ## 🎓 THE "MEASURE TWICE, CUT ONCE" PROMPT Use this exact prompt to have AI execute your schema correctly: ```markdown **System Role:** You are a Senior Database Architect specializing in Directus and PostgreSQL. **Input:** I have 16 collections in my Spark Platform schema. **Task 1: Dependency Map (DO THIS FIRST)** Before generating any API calls, output a Dependency Execution Plan: 1. **Identify Nodes:** List all collections 2. **Identify Edges:** List all foreign key relationships 3. **Group by Batches:** - Batch 1: Independent tables (No foreign keys) - Batch 2: First-level dependents (Only rely on Batch 1) - Batch 3: Complex dependents (Rely on Batch 2 or multiple tables) **Task 2: Directus Logic Check** Confirm you identified: - Standard tables vs. Singletons - Real foreign key fields vs. M2M aliases (virtual fields) - Display templates that might reference wrong field names **Output Format:** Structured markdown table showing batches and dependencies. **Once Approved:** Generate Directus API creation scripts in the correct order. [PASTE schema_map.json HERE] ``` --- ## 🔧 GOD-MODE API: Create Schema Programmatically Using the God-Mode API to respect dependencies: ```bash # BATCH 1: Foundation curl https://spark.jumpstartscaling.com/god/schema/collections/create \ -H "X-God-Token: $GOD_MODE_TOKEN" \ -d '{"collection":"sites", "fields":[...]}' curl https://spark.jumpstartscaling.com/god/schema/collections/create \ -H "X-God-Token: $GOD_MODE_TOKEN" \ -d '{"collection":"campaign_masters", "fields":[...]}' # BATCH 2: Children (ONLY after Batch 1 completes) curl https://spark.jumpstartscaling.com/god/schema/collections/create \ -H "X-God-Token: $GOD_MODE_TOKEN" \ -d '{"collection":"generated_articles", "fields":[...], "relations":[...]}' # BATCH 3: Relations (ONLY after tables exist) curl https://spark.jumpstartscaling.com/god/schema/relations/create \ -H "X-God-Token: $GOD_MODE_TOKEN" \ -d '{"collection":"generated_articles", "field":"site_id", "related_collection":"sites"}' ``` --- ## ✅ VALIDATION CHECKLIST After executing schema: - [ ] Verify Batch 1: `SELECT * FROM sites LIMIT 1;` works - [ ] Verify Batch 1: `SELECT * FROM campaign_masters LIMIT 1;` works - [ ] Verify Batch 2: Foreign keys resolve (no constraint errors) - [ ] Check schema_issues.json: Fix template field references - [ ] Test M2O dropdowns in Directus admin UI - [ ] Confirm all 16 collections appear in Directus --- ## 📊 COMPLETE FIELD-LEVEL ANALYSIS ### sites (SUPER PARENT) ✅ Updated | Field | Type | Interface | Notes | |-------|------|-----------|-------| | id | uuid | input (readonly) | Primary key | | name | string | input (required) | Site display name | | url | string | input | Domain | | status | string | select-dropdown | active/inactive/archived | | **settings** | json | — | **NEW**: Feature flags (JSONB) | | date_created | datetime | — | Auto-generated | | date_updated | datetime | — | Auto-updated | **Children:** 10 tables reference this --- ### campaign_masters (SUPER PARENT) ✅ Updated | Field | Type | Interface | Notes | |-------|------|-----------|-------| | id | uuid | input (readonly) | Primary key | | site_id | uuid | select-dropdown-m2o | → sites | | name | string | input (required) | Campaign name | | status | string | select-dropdown | active/inactive/completed/**paused** | | target_word_count | integer | input | Content target | | headline_spintax_root | string | textarea | Spintax template | | location_mode | string | select | city/county/state/none | | batch_count | integer | input | Batch size | | **article_template** | uuid | select-dropdown-m2o | **NEW**: → article_templates | | **niche_variables** | json | — | **NEW**: Template variables (JSONB) | | date_created | datetime | — | Auto-generated | | date_updated | datetime | — | Auto-updated | **Children:** 4 tables reference this (headline_inventory, content_fragments, generated_articles) --- ### article_templates \u2705 NEW Collection | Field | Type | Interface | Notes | |-------|------|-----------|-------| | id | uuid/int | input (readonly) | Primary key (flexible type) | | name | string | input | Template name | | **structure_json** | json | — | **Array of fragment types** (defines article structure) | | date_created | datetime | — | Auto-generated | | date_updated | datetime | — | Auto-updated | **Purpose:** Defines the order and types of content fragments to assemble articles **Example:** `["intro_hook", "pillar_1", "pillar_2", ..., "faq_section"]` **Used By:** campaign_masters.article_template field --- ### generated_articles (CHILD) ✅ Updated **Parent:** sites **Relationship:** `site_id` → `sites.id` (CASCADE) | Field | Type | Notes | |-------|------|-------| | id | uuid | Primary key | | site_id | uuid | FK → sites | | campaign_id | uuid | FK → campaign_masters (optional) | | status | string | draft/published/archived | | title | string | Article title | | slug | string | URL slug | | content | text | Legacy field | | is_published | boolean | Publication flag | | **headline** | string | **NEW**: Processed headline | | **meta_title** | string | **NEW**: SEO title (70 chars) | | **meta_description** | string | **NEW**: SEO description (155 chars) | | **full_html_body** | text | **NEW**: Complete assembled HTML | | **word_count** | integer | **NEW**: Total word count | | **word_count_status** | string | **NEW**: optimal/under_target | | **location_city** | string | **NEW**: City variable | | **location_county** | string | **NEW**: County variable | | **location_state** | string | **NEW**: State variable | | **featured_image_svg** | text | **NEW**: SVG code | | **featured_image_filename** | string | **NEW**: Image filename | | **featured_image_alt** | string | **NEW**: Alt text | | schema_json | json | JSON-LD structured data | **Total Fields:** 24 (12 added in Phase 9) --- ### headline_inventory (CHILD) ✅ Updated **Parent:** campaign_masters **Relationship:** `campaign_id` → `campaign_masters.id` (CASCADE) | Field | Type | Notes | |-------|------|-------| | id | uuid | Primary key | | campaign_id | uuid | FK → campaign_masters | | status | string | active/used/archived/**available** | | headline_text | string | Original headline template | | **final_title_text** | string | **NEW**: Fully processed title | | **location_data** | json | **NEW**: Location vars (JSONB) | | is_used | boolean | Used flag | | **used_on_article** | uuid | **NEW**: FK → generated_articles.id | **Total Fields:** 8 (3 added in Phase 9) --- ### content_fragments (CHILD) ✅ Updated **Parent:** campaign_masters **Relationship:** `campaign_id` → `campaign_masters.id` (CASCADE) | Field | Type | Notes | |-------|------|-------| | id | uuid | Primary key | | campaign_id | uuid | FK → campaign_masters | | status | string | active/archived | | fragment_text | string | Legacy field name | | **content_body** | text | **NEW**: HTML content fragment | | fragment_type | string | Type (e.g., "sales_letter_core") | | **word_count** | integer | **NEW**: Fragment word count | **Total Fields:** 7 (2 added in Phase 9) --- ### generation_jobs (CHILD) ✅ Updated **Parent:** sites **Relationship:** `site_id` → `sites.id` (CASCADE) | Field | Type | Notes | |-------|------|-------| | id | uuid | Primary key | | status | string | pending/processing/completed/failed | | site_id | uuid | FK → sites | | batch_size | integer | Articles per batch | | target_quantity | integer | Total articles to generate | | filters | json | Generation filters (JSONB) | | current_offset | integer | Batch progress tracker | | progress | integer | Percentage complete | | **date_created** | datetime | **NEW**: Auto-generated | | **date_updated** | datetime | **NEW**: Auto-updated | **Total Fields:** 10 (2 added in Phase 9) --- ## 🎯 SUCCESS CRITERIA Your schema is correct when: 1. ✅ **SQL Execution:** No foreign key constraint errors 2. ✅ **Directus UI:** All dropdowns show related data 3. ✅ **TypeScript:** Auto-generated types match reality 4. ✅ **Frontend:** No `undefined` field errors 5. ✅ **God-Mode API:** `/god/schema/snapshot` returns valid YAML --- ## 🚀 NEXT STEPS **\u2705 Phase 9 Complete - All Items Done:** 1. **\u2705 Fixed Template Issues:** Updated display templates for `campaign_id` fields 2. **\u2705 Added Missing Interfaces:** Applied `select-dropdown-m2o` to all foreign key fields 3. **\u2705 Generated TypeScript:** Schema types fully updated and validated 4. **\u2705 Tested Fresh Install:** Build successful with 0 TypeScript errors 5. **\u2705 Schema Deployed:** Ready for deployment via God-Mode API --- ## \u2728 PHASE 9 ACCOMPLISHMENTS ### Schema Enhancements - \u2705 **New Collection:** article_templates (5 fields) - \u2705 **Sites:** +1 field (settings) - \u2705 **CampaignMasters:** +3 fields (article_template, niche_variables, paused status) - \u2705 **GeneratedArticles:** +12 fields (complete article metadata) - \u2705 **HeadlineInventory:** +3 fields (final_title_text, location_data, used_on_article) - \u2705 **ContentFragments:** +2 fields (content_body, word_count) - \u2705 **GenerationJobs:** +2 fields (date_created, date_updated) ### Code Fixes - \u2705 Fixed 8 field name errors (campaign \u2192 campaign_id, site \u2192 site_id) - \u2705 Fixed 3 null/undefined type coercion issues - \u2705 Fixed 3 sort field references - \u2705 Fixed 2 package.json validation errors ### Validation - \u2705 **Build Status:** Success (Exit Code 0) - \u2705 **TypeScript Errors:** 0 - \u2705 **Total Fields Added:** 23 --- **Remember:** The Harris Matrix prevents the #1 cause of schema failures: trying to create relationships before the related tables exist. **God-Mode Key:** `$GOD_MODE_TOKEN` (set in Coolify secrets) **Schema Version:** v2.0 (Phase 9 - Dec 2025)