423 lines
15 KiB
Markdown
423 lines
15 KiB
Markdown
# 🔷 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)
|