feat: consolidate schema and fix frontend type errors

This commit is contained in:
cawcenter
2025-12-13 22:00:00 -05:00
parent 987958c8b9
commit a924d90de5
4 changed files with 2025 additions and 6 deletions

274
SCHEMA_REFERENCE.md Normal file
View File

@@ -0,0 +1,274 @@
# Spark Platform - Database Schema Reference
This document serves as the **Single Source of Truth** for the Spark Platform database schema. It consolidates all core systems, engines, and analytics modules.
## 1. Core System
### `sites`
Managed WordPress instances.
- **id** (UUID): Primary Key
- **name** (String): Site Name
- **url** (String): Full URL (e.g., https://example.com)
- **wp_username** (String): Admin username
- **wp_app_password** (String): Application Password
- **domain_age_years** (Integer): Age of domain for velocity calculation
- **status** (String): `active` | `paused` | `archived`
- **created_at** (Timestamp)
- **updated_at** (Timestamp)
### `globals`
Site-wide settings and branding.
- **id** (UUID): Primary Key
- **site** (M2O -> sites): Owner site
- **site_name** (String)
- **site_tagline** (String)
- **logo** (Image)
- **favicon** (Image)
- **primary_color** (String)
- **secondary_color** (String)
- **footer_text** (Text)
- **social_links** (JSON)
- **scripts_head** (Text)
- **scripts_body** (Text)
### `navigation`
Site menus.
- **id** (UUID)
- **site** (M2O -> sites)
- **label** (String)
- **url** (String)
- **target** (String): `_self` | `_blank`
- **parent** (M2O -> navigation): For nested menus
- **sort** (Integer)
---
## 2. Content Factory (SEO Engine)
### `campaign_masters`
Controls content generation campaigns.
- **id** (UUID)
- **site_id** (M2O -> sites)
- **name** (String)
- **headline_spintax_root** (Text): Root spintax for titles
- **niche_variables** (JSON): Key/Value pairs for replacement
- **location_mode** (String): `none` | `state` | `county` | `city`
- **location_target** (String)
- **batch_count** (Integer)
- **target_word_count** (Integer): Default 1500
- **velocity_mode** (String): `RAMP_UP` | `CONSISTENT`
- **backdate_start** (Date)
- **backdate_end** (Date)
- **status** (String): `active` | `paused` | `completed`
### `generated_articles`
The central content unit (replaces/aliases `posts` for SEO).
- **id** (UUID)
- **site_id** (M2O -> sites)
- **campaign_id** (M2O -> campaign_masters)
- **title** (String)
- **slug** (String)
- **html_content** (Text): Full rendered HTML
- **schema_json** (JSON): FAQ, Article, Product schema
- **meta_desc** (Text)
- **meta_title** (String)
- **featured_image** (Image)
- **generation_hash** (String): For duplicate checks
- **is_published** (Boolean)
- **status** (String): `queued` | `processing` | `qc` | `approved` | `published`
- **sitemap_status** (String): `ghost` | `queued` | `indexed`
- **date_created** (Timestamp)
- **date_published** (Timestamp)
### `headline_inventory`
Pre-generated titles awaiting content.
- **id** (UUID)
- **campaign** (M2O -> campaign_masters)
- **final_title_text** (String)
- **status** (String): `available` | `used`
- **used_on_article** (M2O -> generated_articles)
### `content_fragments`
Reusable content blocks (intros, outros, CTAs).
- **id** (UUID)
- **campaign** (M2O -> campaign_masters)
- **fragment_type** (String)
- **content_body** (Text)
- **word_count** (Integer)
### `production_queue`
Manages generation schedule and velocity.
- **id** (UUID)
- **site** (M2O -> sites)
- **campaign** (M2O -> campaign_masters)
- **status** (String): `test_batch` | `pending` | `active` | `completed`
- **total_requested** (Integer)
- **completed_count** (Integer)
- **velocity_mode** (String)
- **schedule_data** (JSON): Array of planned dates
---
## 3. Cartesian Engine (Advanced Logic)
### `generation_jobs`
Batch jobs for Cartesian product generation.
- **id** (UUID)
- **site_id** (M2O -> sites)
- **target_quantity** (Integer)
- **status** (String): `Pending` | `Processing` | `Complete`
- **filters** (JSON)
- **current_offset** (Integer)
### `cartesian_patterns`
Logic patterns for data combinations.
- **id** (UUID)
- **pattern_key** (String): Unique key
- **pattern_type** (String)
- **formula** (String): Logic formula
- **data** (JSON)
### `spintax_dictionaries`
Global spintax terms.
- **id** (UUID)
- **category** (String): e.g., "power_words"
- **data** (JSON): Array of strings
---
## 4. Intelligence Library
### `avatar_intelligence`
User personas for targeted content.
- **id** (UUID)
- **avatar_key** (String)
- **base_name** (String)
- **wealth_cluster** (String)
- **business_niches** (JSON)
- **data** (JSON): Pain points, desires, etc.
### `avatar_variants`
Variations of personas.
- **id** (UUID)
- **avatar_key** (String)
- **variant_type** (String)
- **data** (JSON)
### `geo_intelligence`
Location data clusters.
- **id** (UUID)
- **cluster_key** (String)
- **data** (JSON): Demographics, local keywords
### `offer_blocks`
Universal and personalized offer content.
- **id** (UUID)
- **block_type** (String)
- **avatar_key** (String)
- **data** (JSON)
### `quality_flags`
Content quality control issues.
- **id** (UUID)
- **site** (M2O -> sites)
- **batch_id** (String)
- **article_a** (String)
- **article_b** (String)
- **collision_text** (Text)
- **similarity_score** (Float)
- **status** (String): `pending` | `resolved` | `ignored`
---
## 5. Analytics & Tracking
### `events`
Custom user interactions.
- **id** (UUID)
- **site** (M2O -> sites)
- **event_name** (String)
- **event_category** (String)
- **event_label** (String)
- **event_value** (Integer)
- **page_path** (String)
- **session_id** (String)
- **visitor_id** (String)
- **metadata** (JSON)
- **timestamp** (Timestamp)
### `pageviews`
Traffic logging.
- **id** (UUID)
- **site** (M2O -> sites)
- **page_path** (String)
- **page_title** (String)
- **referrer** (String)
- **user_agent** (String)
- **ip_address** (String)
- **device_type** (String)
- **browser** (String)
- **os** (String)
- **utm_source** (String)
- **utm_medium** (String)
- **utm_campaign** (String)
- **is_bot** (Boolean)
- **bot_name** (String)
- **timestamp** (Timestamp)
### `conversions`
Goal completions.
- **id** (UUID)
- **site** (M2O -> sites)
- **lead** (M2O -> leads)
- **conversion_type** (String)
- **value** (Float)
- **currency** (String)
- **source** (String)
- **sent_to_google** (Boolean)
- **sent_to_facebook** (Boolean)
### `site_analytics`
Analytics configuration per site.
- **id** (UUID)
- **site** (M2O -> sites)
- **google_ads_id** (String)
- **google_ads_conversion_label** (String)
- **fb_pixel_id** (String)
- **fb_access_token** (String)
---
## 6. Infrastructure
### `hub_pages`
Programmatic internal linking hubs.
- **id** (UUID)
- **site** (M2O -> sites)
- **title** (String)
- **slug** (String)
- **parent_hub** (M2O -> hub_pages)
- **level** (Integer)
- **articles_count** (Integer)
- **schema_json** (JSON)
### `link_targets`
Internal linking destinations.
- **id** (UUID)
- **site** (M2O -> sites)
- **target_url** (String)
- **anchor_text** (String)
- **anchor_variations** (JSON)
- **priority** (Integer)
- **is_active** (Boolean)
- **is_hub** (Boolean)
### `work_log`
System audit trail.
- **id** (UUID)
- **site** (M2O -> sites)
- **action** (String)
- **entity_type** (String)
- **entity_id** (String)
- **details** (JSON)
- **user** (String)
- **timestamp** (Timestamp)

101
complete-schema-setup.sh Executable file
View File

@@ -0,0 +1,101 @@
#!/bin/bash
# Spark Platform - Complete Schema Setup Script
# Usage: ./complete-schema-setup.sh [DIRECTUS_URL] [TOKEN]
# Defaults to hardcoded values if not provided
DIRECTUS_URL=${1:-"https://spark.jumpstartscaling.com"}
TOKEN=${2:-"oGn-0AZjenB900pfzQYH8zCbFwGw7flU"}
SCHEMA_FILE="unified_schema.json"
echo "🚀 Starting Complete Schema Setup..."
echo "Target: $DIRECTUS_URL"
echo ""
if [ ! -f "$SCHEMA_FILE" ]; then
echo "❌ Error: $SCHEMA_FILE not found!"
exit 1
fi
# Dependency check
if ! command -v jq &> /dev/null; then
echo "❌ Error: jq is required but not installed."
exit 1
fi
# Function to create a collection
create_collection() {
local name=$1
local meta=$2
echo "📦 Checking collection: $name"
# Construct payload
local payload=$(jq -n \
--arg name "$name" \
--argjson meta "$meta" \
'{collection: $name, meta: $meta, schema: {}}')
# Try to create
response=$(curl -s -k -x POST "$DIRECTUS_URL/collections" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$payload")
if echo "$response" | grep -q "errors"; then
echo " → Exists or Error: $(echo $response | jq -r '.errors[0].message')"
else
echo " → Created successfully"
fi
}
# Function to create a field
create_field() {
local collection=$1
local field_name=$2
local field_def=$3
echo " 🔹 Field: $field_name"
response=$(curl -s -k -X POST "$DIRECTUS_URL/fields/$collection" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$field_def")
if echo "$response" | grep -q "errors"; then
# Ignore "field already exists" errors silently-ish
err=$(echo $response | jq -r '.errors[0].message')
if [[ "$err" != *"already exists"* ]]; then
echo " ⚠️ Error: $err"
fi
else
echo " → Created"
fi
}
# Main Loop over JSON
count=$(jq '. | length' $SCHEMA_FILE)
for ((i=0; i<$count; i++)); do
# Get collection details
name=$(jq -r ".[$i].collection" $SCHEMA_FILE)
meta=$(jq ".[$i].meta" $SCHEMA_FILE)
# Create Collection
create_collection "$name" "$meta"
# Get fields count
field_count=$(jq ".[$i].fields | length" $SCHEMA_FILE)
for ((j=0; j<$field_count; j++)); do
field_name=$(jq -r ".[$i].fields[$j].field" $SCHEMA_FILE)
field_def=$(jq ".[$i].fields[$j]" $SCHEMA_FILE)
# Create Field
create_field "$name" "$field_name" "$field_def"
done
echo ""
done
echo "✅ Schema Setup Complete!"

View File

@@ -47,6 +47,7 @@ export interface Post {
published_at?: string;
category?: string;
author?: string;
meta_title?: string;
seo_title?: string;
seo_description?: string;
date_created?: string;
@@ -132,6 +133,9 @@ export interface ImageTemplate {
id: string;
name: string;
svg_template: string;
svg_source?: string;
is_default?: boolean;
preview?: string;
}
export interface LocationState {
@@ -254,11 +258,15 @@ export interface GeneratedArticle {
due_date?: string;
seo_score?: number;
generation_hash: string;
meta_title?: string;
meta_desc?: string;
is_published?: boolean;
sync_status?: string;
schema_json?: Record<string, any>;
is_test_batch?: boolean;
date_created?: string;
date_updated?: string;
date_published?: string;
}
@@ -303,6 +311,9 @@ export interface FormSubmission {
date_created?: string;
}
/**
* Full Spark Platform Schema for Directus SDK
*/
/**
* Full Spark Platform Schema for Directus SDK
*/
@@ -314,7 +325,7 @@ export interface SparkSchema {
navigation: Navigation[];
authors: Author[];
// Legacy SEO Engine (Keep for compatibility if needed)
// SEO Engine
campaign_masters: CampaignMaster[];
headline_inventory: HeadlineInventory[];
content_fragments: ContentFragment[];
@@ -322,8 +333,10 @@ export interface SparkSchema {
locations_states: LocationState[];
locations_counties: LocationCounty[];
locations_cities: LocationCity[];
production_queue: ProductionQueueItem[];
quality_flags: QualityFlag[];
// New Cartesian Engine
// Cartesian Engine
generation_jobs: GenerationJob[];
article_templates: ArticleTemplate[];
avatars: Avatar[];
@@ -336,26 +349,131 @@ export interface SparkSchema {
offer_blocks_personalized: OfferBlockPersonalized[];
generated_articles: GeneratedArticle[];
// CRM & Forms
leads: Lead[];
newsletter_subscribers: NewsletterSubscriber[];
forms: Form[];
form_submissions: FormSubmission[];
// Infrastructure & Analytics
link_targets: LinkTarget[];
hub_pages: HubPage[];
work_log: WorkLog[];
events: AnalyticsEvent[];
pageviews: PageView[];
conversions: Conversion[];
site_analytics: SiteAnalyticsConfig[];
}
export interface ProductionQueueItem {
id: string;
site: string | Site;
campaign: string | CampaignMaster;
status: 'test_batch' | 'pending' | 'active' | 'completed' | 'paused';
total_requested: number;
completed_count: number;
velocity_mode: string;
schedule_data: any[]; // JSON
date_created?: string;
}
export interface QualityFlag {
id: string;
site: string | Site;
batch_id?: string;
article_a: string;
article_b: string;
collision_text: string;
similarity_score: number;
status: 'pending' | 'resolved' | 'ignored';
date_created?: string;
}
export interface HubPage {
id: string;
site: string | Site;
title: string;
slug: string;
parent_hub?: string | HubPage;
level: number;
articles_count: number;
schema_json?: Record<string, any>;
date_created?: string;
}
export interface AnalyticsEvent {
id: string;
site: string | Site;
event_name: string;
event_category?: string;
event_label?: string;
event_value?: number;
page_path: string;
session_id?: string;
visitor_id?: string;
metadata?: Record<string, any>;
timestamp?: string;
}
export interface PageView {
id: string;
site: string | Site;
page_path: string;
page_title?: string | null;
referrer?: string | null;
user_agent?: string | null;
device_type?: string | null;
browser?: string | null;
os?: string | null;
utm_source?: string | null;
utm_medium?: string | null;
utm_campaign?: string | null;
utm_content?: string | null;
utm_term?: string | null;
is_bot?: boolean;
bot_name?: string | null;
session_id?: string | null;
visitor_id?: string | null;
timestamp?: string;
}
export interface Conversion {
id: string;
site: string | Site;
lead?: string | Lead;
conversion_type: string;
value?: number;
currency?: string;
source?: string;
campaign?: string;
gclid?: string;
fbclid?: string;
sent_to_google?: boolean;
sent_to_facebook?: boolean;
date_created?: string;
}
export interface SiteAnalyticsConfig {
id: string;
site: string | Site;
google_ads_id?: string;
google_ads_conversion_label?: string;
fb_pixel_id?: string;
fb_access_token?: string;
}
export interface WorkLog {
id: number;
site?: number;
site?: number | string; // Relaxed type
action: string;
entity_type?: string;
entity_id?: string | number;
details?: string;
details?: string | Record<string, any>; // Relaxed to allow JSON object
level?: string;
status?: string;
timestamp?: string; // Directus uses date_created
timestamp?: string;
date_created?: string;
user?: string; // user ID
user?: string;
}
export interface LinkTarget {
@@ -370,3 +488,4 @@ export interface LinkTarget {
is_hub?: boolean;
max_per_article?: number;
}

1525
unified_schema.json Normal file

File diff suppressed because it is too large Load Diff