feat: consolidate schema and fix frontend type errors
This commit is contained in:
274
SCHEMA_REFERENCE.md
Normal file
274
SCHEMA_REFERENCE.md
Normal 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
101
complete-schema-setup.sh
Executable 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!"
|
||||
@@ -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
1525
unified_schema.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user