INVESTOR DOCUMENTATION: - INVESTOR_BRIEF.md: Executive summary, capacity metrics, architecture overview - PLATFORM_CAPABILITIES.md: 5 modules, 27 subcomponents catalog - TECHNICAL_ARCHITECTURE.md: Mermaid diagrams, data flows, extension points CTO/SENIOR DEV ONBOARDING: - CTO_ONBOARDING.md: System overview, security model, operational runbook - DEVELOPER_GUIDE.md: Clone→Run→Deploy workflow, debugging - API_REFERENCE.md: 30+ endpoints with request/response specs - DATABASE_SCHEMA.md: 30+ tables in Harris Matrix order - COMPONENT_LIBRARY.md: 182 React components catalog REFERENCE: - GLOSSARY.md: 70+ platform terms defined - ADMIN_PAGES_GUIDE.md: 66 admin pages by module Style: BLUF format, zero marketing fluff, high-density tables
460 lines
14 KiB
Markdown
460 lines
14 KiB
Markdown
# DATABASE SCHEMA: Spark Platform
|
|
|
|
> **BLUF**: 30+ PostgreSQL tables in Harris Matrix order. `sites` and `campaign_masters` are super parents. All content tables FK to `site_id`.
|
|
|
|
---
|
|
|
|
## 1. Schema Creation Order
|
|
|
|
### Harris Matrix Dependency Layers
|
|
|
|
| Batch | Layer | Description |
|
|
|-------|-------|-------------|
|
|
| 1 | Foundation | Zero dependencies. Create first. |
|
|
| 2 | Walls | Depend only on Batch 1. |
|
|
| 3 | Roof | Multiple dependencies or self-referential. |
|
|
|
|
---
|
|
|
|
## 2. Batch 1: Foundation Tables
|
|
|
|
### 2.1 sites (SUPER PARENT)
|
|
|
|
**Purpose**: Multi-tenant root. All content tables reference this.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK, DEFAULT gen_random_uuid() | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'active' | active, inactive, archived |
|
|
| name | VARCHAR(255) | NOT NULL | Site display name |
|
|
| url | VARCHAR(500) | | Site domain URL |
|
|
| date_created | TIMESTAMP | DEFAULT NOW() | Creation timestamp |
|
|
| date_updated | TIMESTAMP | DEFAULT NOW() | Last update |
|
|
|
|
**Children**: 10+ tables reference via `site_id`
|
|
|
|
---
|
|
|
|
### 2.2 campaign_masters (SUPER PARENT)
|
|
|
|
**Purpose**: SEO campaign configuration.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'active' | active, inactive, completed |
|
|
| site_id | UUID | FK → sites(id) CASCADE | Owning site |
|
|
| name | VARCHAR(255) | NOT NULL | Campaign name |
|
|
| headline_spintax_root | TEXT | | Spintax template |
|
|
| target_word_count | INTEGER | DEFAULT 1500 | Target article length |
|
|
| location_mode | VARCHAR(50) | | city, county, state |
|
|
| batch_count | INTEGER | | Articles per batch |
|
|
| date_created | TIMESTAMP | DEFAULT NOW() | |
|
|
| date_updated | TIMESTAMP | DEFAULT NOW() | |
|
|
|
|
**Children**: headline_inventory, content_fragments, (ref by generated_articles)
|
|
|
|
---
|
|
|
|
### 2.3 avatar_intelligence
|
|
|
|
**Purpose**: Buyer persona profiles.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'published' | published, draft |
|
|
| base_name | VARCHAR(255) | | Persona name |
|
|
| wealth_cluster | VARCHAR(100) | | Economic profile |
|
|
| pain_points | JSONB | | Array of pain points |
|
|
| demographics | JSONB | | Demographic data |
|
|
|
|
---
|
|
|
|
### 2.4 avatar_variants
|
|
|
|
**Purpose**: Gender/style variations of avatars.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'published' | |
|
|
| name | VARCHAR(255) | | Variant name |
|
|
| prompt_modifier | TEXT | | AI prompt adjustments |
|
|
|
|
---
|
|
|
|
### 2.5 cartesian_patterns
|
|
|
|
**Purpose**: Title/hook formula combinations.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'published' | |
|
|
| name | VARCHAR(255) | | Pattern name |
|
|
| pattern_logic | TEXT | | Formula definition |
|
|
|
|
---
|
|
|
|
### 2.6 geo_intelligence
|
|
|
|
**Purpose**: Geographic targeting data.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'published' | |
|
|
| city | VARCHAR(255) | | City name |
|
|
| state | VARCHAR(255) | | State name |
|
|
| population | INTEGER | | Population count |
|
|
|
|
---
|
|
|
|
### 2.7 offer_blocks
|
|
|
|
**Purpose**: Promotional content templates.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'published' | |
|
|
| name | VARCHAR(255) | | Block name |
|
|
| html_content | TEXT | | Template HTML |
|
|
|
|
---
|
|
|
|
## 3. Batch 2: First-Level Children
|
|
|
|
### 3.1 generated_articles
|
|
|
|
**Purpose**: SEO articles created by Content Factory.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'draft' | draft, published, archived |
|
|
| site_id | UUID | FK → sites(id) CASCADE | Owning site |
|
|
| campaign_id | UUID | FK → campaign_masters(id) SET NULL | Source campaign |
|
|
| title | VARCHAR(255) | | Article title |
|
|
| content | TEXT | | Full HTML body |
|
|
| slug | VARCHAR(255) | | URL slug |
|
|
| is_published | BOOLEAN | | Publication flag |
|
|
| schema_json | JSONB | | Schema.org data |
|
|
| date_created | TIMESTAMP | DEFAULT NOW() | |
|
|
| date_updated | TIMESTAMP | | |
|
|
|
|
---
|
|
|
|
### 3.2 generation_jobs
|
|
|
|
**Purpose**: Content generation queue.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'pending' | pending, processing, completed, failed |
|
|
| site_id | UUID | FK → sites(id) CASCADE | Owning site |
|
|
| batch_size | INTEGER | DEFAULT 10 | Items per batch |
|
|
| target_quantity | INTEGER | | Total target |
|
|
| filters | JSONB | | Query filters |
|
|
| current_offset | INTEGER | | Progress marker |
|
|
| progress | INTEGER | DEFAULT 0 | Percentage |
|
|
|
|
---
|
|
|
|
### 3.3 pages
|
|
|
|
**Purpose**: Site pages (blocks-based content).
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'published' | published, draft |
|
|
| site_id | UUID | FK → sites(id) CASCADE | Owning site |
|
|
| title | VARCHAR(255) | | Page title |
|
|
| slug | VARCHAR(255) | | URL slug |
|
|
| permalink | VARCHAR(255) | | Full path |
|
|
| content | TEXT | | Legacy HTML |
|
|
| blocks | JSONB | | Block definitions |
|
|
| schema_json | JSONB | | Schema.org data |
|
|
| seo_title | VARCHAR(255) | | Meta title |
|
|
| seo_description | TEXT | | Meta description |
|
|
| seo_image | UUID | FK → directus_files | OG image |
|
|
| date_created | TIMESTAMP | | |
|
|
| date_updated | TIMESTAMP | | |
|
|
|
|
---
|
|
|
|
### 3.4 posts
|
|
|
|
**Purpose**: Blog posts.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'published' | published, draft |
|
|
| site_id | UUID | FK → sites(id) CASCADE | Owning site |
|
|
| title | VARCHAR(255) | | Post title |
|
|
| slug | VARCHAR(255) | | URL slug |
|
|
| excerpt | TEXT | | Summary text |
|
|
| content | TEXT | | Full HTML body |
|
|
| featured_image | UUID | FK → directus_files | Hero image |
|
|
| published_at | TIMESTAMP | | Publication date |
|
|
| category | VARCHAR(100) | | Post category |
|
|
| author | UUID | FK → directus_users | Author |
|
|
| schema_json | JSONB | | Schema.org data |
|
|
| date_created | TIMESTAMP | | |
|
|
| date_updated | TIMESTAMP | | |
|
|
|
|
---
|
|
|
|
### 3.5 leads
|
|
|
|
**Purpose**: Lead capture data.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'new' | new, contacted, qualified, converted |
|
|
| site_id | UUID | FK → sites(id) SET NULL | Source site |
|
|
| email | VARCHAR(255) | | Contact email |
|
|
| name | VARCHAR(255) | | Contact name |
|
|
| source | VARCHAR(100) | | Lead source |
|
|
|
|
---
|
|
|
|
### 3.6 headline_inventory
|
|
|
|
**Purpose**: Generated headline variations.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'active' | active, used, archived |
|
|
| campaign_id | UUID | FK → campaign_masters(id) CASCADE | Source campaign |
|
|
| headline_text | VARCHAR(255) | | Generated headline |
|
|
| is_used | BOOLEAN | DEFAULT FALSE | Usage flag |
|
|
|
|
---
|
|
|
|
### 3.7 content_fragments
|
|
|
|
**Purpose**: Modular content blocks for article assembly.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'active' | active, archived |
|
|
| campaign_id | UUID | FK → campaign_masters(id) CASCADE | Source campaign |
|
|
| fragment_text | TEXT | | Fragment content |
|
|
| fragment_type | VARCHAR(50) | | Pillar: intro_hook, pillar_1, etc. |
|
|
|
|
---
|
|
|
|
## 4. Batch 3: Complex Children
|
|
|
|
### 4.1 link_targets
|
|
|
|
**Purpose**: Internal linking configuration.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| status | VARCHAR(50) | DEFAULT 'active' | active, inactive |
|
|
| site_id | UUID | FK → sites(id) CASCADE | Owning site |
|
|
| target_url | VARCHAR(500) | | Link destination |
|
|
| anchor_text | VARCHAR(255) | | Link text |
|
|
| keyword_focus | VARCHAR(255) | | Target keyword |
|
|
|
|
---
|
|
|
|
### 4.2 globals
|
|
|
|
**Purpose**: Site-wide settings (singleton per site).
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| site_id | UUID | FK → sites(id) CASCADE | Owning site |
|
|
| title | VARCHAR(255) | | Site title |
|
|
| description | TEXT | | Site description |
|
|
| logo | UUID | FK → directus_files | Logo image |
|
|
|
|
---
|
|
|
|
### 4.3 navigation
|
|
|
|
**Purpose**: Site menu structure.
|
|
|
|
| Column | Type | Constraints | Description |
|
|
|--------|------|-------------|-------------|
|
|
| id | UUID | PK | Primary key |
|
|
| site_id | UUID | FK → sites(id) CASCADE | Owning site |
|
|
| label | VARCHAR(255) | NOT NULL | Link text |
|
|
| url | VARCHAR(500) | NOT NULL | Link URL |
|
|
| parent | UUID | FK → navigation(id) | Parent item |
|
|
| target | VARCHAR(20) | | _self, _blank |
|
|
| sort | INTEGER | | Display order |
|
|
|
|
---
|
|
|
|
## 5. Analytics & System Tables
|
|
|
|
### 5.1 work_log
|
|
|
|
| Column | Type | Description |
|
|
|--------|------|-------------|
|
|
| id | SERIAL | Primary key |
|
|
| site_id | UUID | Related site |
|
|
| action | VARCHAR | Action type |
|
|
| entity_type | VARCHAR | Affected entity |
|
|
| entity_id | VARCHAR | Entity UUID |
|
|
| details | JSONB | Additional data |
|
|
| level | VARCHAR | debug, info, warning, error |
|
|
| status | VARCHAR | Status text |
|
|
| timestamp | TIMESTAMP | Event time |
|
|
| user | UUID | Acting user |
|
|
|
|
---
|
|
|
|
### 5.2 forms
|
|
|
|
| Column | Type | Description |
|
|
|--------|------|-------------|
|
|
| id | UUID | Primary key |
|
|
| site_id | UUID | Owning site |
|
|
| name | VARCHAR | Form name |
|
|
| fields | JSONB | Field definitions |
|
|
| submit_action | VARCHAR | webhook, email, store |
|
|
| success_message | TEXT | Confirmation text |
|
|
| redirect_url | VARCHAR | Post-submit redirect |
|
|
|
|
---
|
|
|
|
### 5.3 form_submissions
|
|
|
|
| Column | Type | Description |
|
|
|--------|------|-------------|
|
|
| id | UUID | Primary key |
|
|
| form | UUID | FK → forms |
|
|
| data | JSONB | Submitted values |
|
|
| date_created | TIMESTAMP | Submission time |
|
|
|
|
---
|
|
|
|
### 5.4 Location Tables
|
|
|
|
**locations_states**
|
|
| Column | Type | Description |
|
|
|--------|------|-------------|
|
|
| id | UUID | Primary key |
|
|
| name | VARCHAR | State name |
|
|
| code | VARCHAR(2) | State abbreviation |
|
|
|
|
**locations_counties**
|
|
| Column | Type | Description |
|
|
|--------|------|-------------|
|
|
| id | UUID | Primary key |
|
|
| name | VARCHAR | County name |
|
|
| state | UUID | FK → locations_states |
|
|
| population | INTEGER | Population count |
|
|
|
|
**locations_cities**
|
|
| Column | Type | Description |
|
|
|--------|------|-------------|
|
|
| id | UUID | Primary key |
|
|
| name | VARCHAR | City name |
|
|
| state | UUID | FK → locations_states |
|
|
| county | UUID | FK → locations_counties |
|
|
| population | INTEGER | Population count |
|
|
|
|
---
|
|
|
|
### 5.5 Analytics Tables
|
|
|
|
**site_analytics**
|
|
| Column | Type | Description |
|
|
|--------|------|-------------|
|
|
| id | UUID | Primary key |
|
|
| site_id | UUID | FK → sites |
|
|
| google_ads_id | VARCHAR | GA4 property ID |
|
|
| fb_pixel_id | VARCHAR | Meta pixel ID |
|
|
|
|
**events**
|
|
| Column | Type | Description |
|
|
|--------|------|-------------|
|
|
| id | UUID | Primary key |
|
|
| site_id | UUID | FK → sites |
|
|
| event_name | VARCHAR | Event identifier |
|
|
| page_path | VARCHAR | URL path |
|
|
| timestamp | TIMESTAMP | Event time |
|
|
|
|
**pageviews**
|
|
| Column | Type | Description |
|
|
|--------|------|-------------|
|
|
| id | UUID | Primary key |
|
|
| site_id | UUID | FK → sites |
|
|
| page_path | VARCHAR | URL path |
|
|
| session_id | VARCHAR | Anonymous session |
|
|
| timestamp | TIMESTAMP | View time |
|
|
|
|
**conversions**
|
|
| Column | Type | Description |
|
|
|--------|------|-------------|
|
|
| id | UUID | Primary key |
|
|
| site_id | UUID | FK → sites |
|
|
| lead | UUID | FK → leads |
|
|
| conversion_type | VARCHAR | Type identifier |
|
|
| value | DECIMAL | Monetary value |
|
|
|
|
---
|
|
|
|
## 6. Relationship Diagram
|
|
|
|
```
|
|
sites ─────────────────────────────────────────────────────────┐
|
|
│ │
|
|
├── campaign_masters ─┬── headline_inventory │
|
|
│ ├── content_fragments │
|
|
│ └── (ref) generated_articles │
|
|
│ │
|
|
├── generated_articles │
|
|
├── generation_jobs │
|
|
├── pages │
|
|
├── posts │
|
|
├── leads │
|
|
├── link_targets │
|
|
├── globals (1:1) │
|
|
│ │
|
|
├── navigation (self-referential via parent) │
|
|
│ │
|
|
├── forms ─── form_submissions │
|
|
│ │
|
|
├── site_analytics │
|
|
├── events │
|
|
├── pageviews │
|
|
├── conversions ─── leads │
|
|
│ │
|
|
└── work_log │
|
|
│
|
|
locations_states ─── locations_counties ─── locations_cities ──┘
|
|
```
|
|
|
|
---
|
|
|
|
## 7. SQL Reference
|
|
|
|
Full schema: [`complete_schema.sql`](file:///Users/christopheramaya/Downloads/spark/complete_schema.sql)
|
|
|
|
Extensions required:
|
|
```sql
|
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
|
```
|
|
|
|
UUID generation:
|
|
```sql
|
|
DEFAULT gen_random_uuid()
|
|
```
|