Feature: Complete Admin UI Overhaul, Content Factory Showcase Mode, and Site Management
This commit is contained in:
4
backend/credentials.env
Normal file
4
backend/credentials.env
Normal file
@@ -0,0 +1,4 @@
|
||||
DIRECTUS_PUBLIC_URL=https://net1.jumpstartscaling.com/
|
||||
DIRECTUS_ADMIN_TOKEN=
|
||||
DIRECTUS_ADMIN_EMAIL=somescreenname@gmail.com
|
||||
DIRECTUS_ADMIN_PASSWORD=KuJ85Qt96FtfKE5O8u6QgFzuojUfMgDh
|
||||
169
backend/data/avatar_intelligence.json
Normal file
169
backend/data/avatar_intelligence.json
Normal file
@@ -0,0 +1,169 @@
|
||||
{
|
||||
"meta": {
|
||||
"file_type": "avatar_intelligence",
|
||||
"version": "2.1",
|
||||
"note": "The business_niches array acts as the 'Niche' variable in Cartesian generation."
|
||||
},
|
||||
"avatars": {
|
||||
"scaling_founder": {
|
||||
"base_name": "The Tech Titan",
|
||||
"wealth_cluster": "Tech-Native",
|
||||
"business_niches": [
|
||||
"Vertical SaaS",
|
||||
"AI Infrastructure",
|
||||
"Fintech",
|
||||
"HealthTech",
|
||||
"Cybersecurity",
|
||||
"PropTech",
|
||||
"EdTech",
|
||||
"Micro-VC",
|
||||
"CleanTech",
|
||||
"Robotics"
|
||||
]
|
||||
},
|
||||
"elite_consultant": {
|
||||
"base_name": "The Elite Consultant",
|
||||
"wealth_cluster": "Professional Services",
|
||||
"business_niches": [
|
||||
"Management Consulting",
|
||||
"Executive Coaching",
|
||||
"Fractional C-Suite",
|
||||
"M&A Advisory",
|
||||
"Brand Strategy",
|
||||
"Legal Defense",
|
||||
"Wealth Management",
|
||||
"Public Relations",
|
||||
"Crisis Management",
|
||||
"Leadership Training"
|
||||
]
|
||||
},
|
||||
"saas_overloader": {
|
||||
"base_name": "The SaaS Overloader",
|
||||
"wealth_cluster": "Tech-Native",
|
||||
"business_niches": [
|
||||
"MarTech",
|
||||
"DevTools",
|
||||
"HR Tech",
|
||||
"Sales Enablement",
|
||||
"Customer Support AI",
|
||||
"Project Management Tools",
|
||||
"No-Code Platforms",
|
||||
"Video Software",
|
||||
"E-Learning Platforms",
|
||||
"Cloud Hosting"
|
||||
]
|
||||
},
|
||||
"high_end_agency_owner": {
|
||||
"base_name": "The High-End Agency Owner",
|
||||
"wealth_cluster": "Creative Class",
|
||||
"business_niches": [
|
||||
"Performance Marketing",
|
||||
"CRO Agency",
|
||||
"Design Studio",
|
||||
"Video Production",
|
||||
"SEO Firm",
|
||||
"PPC Agency",
|
||||
"Social Media Management",
|
||||
"Influencer Marketing",
|
||||
"Email Marketing",
|
||||
"Development Shop"
|
||||
]
|
||||
},
|
||||
"medical_practice_ceo": {
|
||||
"base_name": "The Medical Practice CEO",
|
||||
"wealth_cluster": "Legacy",
|
||||
"business_niches": [
|
||||
"Plastic Surgery",
|
||||
"Dental Practice",
|
||||
"Fertility Center",
|
||||
"Concierge Medicine",
|
||||
"Dermatology Clinic",
|
||||
"MedSpa",
|
||||
"Orthopedics",
|
||||
"Chiropractic Center",
|
||||
"Mental Health Clinic",
|
||||
"Rehab Center"
|
||||
]
|
||||
},
|
||||
"ecom_high_roller": {
|
||||
"base_name": "The Ecom High-Roller",
|
||||
"wealth_cluster": "New Money",
|
||||
"business_niches": [
|
||||
"DTC Brand",
|
||||
"Amazon FBA",
|
||||
"Dropshipping",
|
||||
"Subscription Box",
|
||||
"Fashion Label",
|
||||
"Supplement Brand",
|
||||
"Beauty Brand",
|
||||
"Home Goods",
|
||||
"Pet Products",
|
||||
"Tech Accessories"
|
||||
]
|
||||
},
|
||||
"coaching_empire_builder": {
|
||||
"base_name": "The Coaching Empire Builder",
|
||||
"wealth_cluster": "Influencer Economy",
|
||||
"business_niches": [
|
||||
"Business Coaching",
|
||||
"Life Coaching",
|
||||
"Fitness Coaching",
|
||||
"Relationship Coaching",
|
||||
"Financial Coaching",
|
||||
"Spiritual Coaching",
|
||||
"Career Coaching",
|
||||
"Parenting Coaching",
|
||||
"Health Coaching",
|
||||
"Mindset Coaching"
|
||||
]
|
||||
},
|
||||
"multi_location_ceo": {
|
||||
"base_name": "The Multi-Location CEO",
|
||||
"wealth_cluster": "Franchise & Retail",
|
||||
"business_niches": [
|
||||
"Gym Franchise",
|
||||
"Restaurant Chain",
|
||||
"Retail Store",
|
||||
"Daycare Centers",
|
||||
"Salon Chain",
|
||||
"Urgent Care",
|
||||
"Auto Repair Chain",
|
||||
"HVAC Services",
|
||||
"Plumbing Services",
|
||||
"Cleaning Services"
|
||||
]
|
||||
},
|
||||
"real_estate_power_player": {
|
||||
"base_name": "The Real Estate Power Player",
|
||||
"wealth_cluster": "Hybrid",
|
||||
"business_niches": [
|
||||
"Luxury Brokerage",
|
||||
"Commercial Leasing",
|
||||
"Land Development",
|
||||
"Property Management",
|
||||
"Vacation Rentals",
|
||||
"Multifamily Investing",
|
||||
"House Flipping",
|
||||
"Real Estate Wholesaling",
|
||||
"Mortgage Lending",
|
||||
"Title Services"
|
||||
]
|
||||
},
|
||||
"enterprise_innovator": {
|
||||
"base_name": "The Enterprise Innovator",
|
||||
"wealth_cluster": "Corporate Elite",
|
||||
"business_niches": [
|
||||
"Enterprise Software",
|
||||
"Logistics & Supply Chain",
|
||||
"Manufacturing",
|
||||
"Energy",
|
||||
"Telecommunications",
|
||||
"Biotech",
|
||||
"Pharmaceuticals",
|
||||
"Aerospace",
|
||||
"Automotive",
|
||||
"Industrial IoT"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
329
backend/data/avatar_variants.json
Normal file
329
backend/data/avatar_variants.json
Normal file
@@ -0,0 +1,329 @@
|
||||
{
|
||||
"meta": {
|
||||
"file_type": "avatar_variants",
|
||||
"version": "1.0",
|
||||
"total_avatars": 10
|
||||
},
|
||||
"avatars": {
|
||||
"scaling_founder": {
|
||||
"base_name": "The Scaling Founder",
|
||||
"variants": {
|
||||
"male": {
|
||||
"pronoun": "he",
|
||||
"ppronoun": "him",
|
||||
"pospronoun": "his",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "bottlenecked business owner"
|
||||
},
|
||||
"female": {
|
||||
"pronoun": "she",
|
||||
"ppronoun": "her",
|
||||
"pospronoun": "her",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "bottlenecked business owner"
|
||||
},
|
||||
"neutral": {
|
||||
"pronoun": "they",
|
||||
"ppronoun": "them",
|
||||
"pospronoun": "their",
|
||||
"isare": "are",
|
||||
"has_have": "have",
|
||||
"does_do": "do",
|
||||
"identity": "bottlenecked business owner"
|
||||
}
|
||||
}
|
||||
},
|
||||
"elite_consultant": {
|
||||
"base_name": "The Elite Consultant",
|
||||
"variants": {
|
||||
"male": {
|
||||
"pronoun": "he",
|
||||
"ppronoun": "him",
|
||||
"pospronoun": "his",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "overbooked consultant"
|
||||
},
|
||||
"female": {
|
||||
"pronoun": "she",
|
||||
"ppronoun": "her",
|
||||
"pospronoun": "her",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "overbooked consultant"
|
||||
},
|
||||
"neutral": {
|
||||
"pronoun": "they",
|
||||
"ppronoun": "them",
|
||||
"pospronoun": "their",
|
||||
"isare": "are",
|
||||
"has_have": "have",
|
||||
"does_do": "do",
|
||||
"identity": "overbooked consultant"
|
||||
}
|
||||
}
|
||||
},
|
||||
"saas_overloader": {
|
||||
"base_name": "The SaaS Overloader",
|
||||
"variants": {
|
||||
"male": {
|
||||
"pronoun": "he",
|
||||
"ppronoun": "him",
|
||||
"pospronoun": "his",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "overwhelmed SaaS owner"
|
||||
},
|
||||
"female": {
|
||||
"pronoun": "she",
|
||||
"ppronoun": "her",
|
||||
"pospronoun": "her",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "overwhelmed SaaS owner"
|
||||
},
|
||||
"neutral": {
|
||||
"pronoun": "they",
|
||||
"ppronoun": "them",
|
||||
"pospronoun": "their",
|
||||
"isare": "are",
|
||||
"has_have": "have",
|
||||
"does_do": "do",
|
||||
"identity": "overwhelmed SaaS owner"
|
||||
}
|
||||
}
|
||||
},
|
||||
"high_end_agency_owner": {
|
||||
"base_name": "The High-End Agency Owner",
|
||||
"variants": {
|
||||
"male": {
|
||||
"pronoun": "he",
|
||||
"ppronoun": "him",
|
||||
"pospronoun": "his",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "scaling agency owner"
|
||||
},
|
||||
"female": {
|
||||
"pronoun": "she",
|
||||
"ppronoun": "her",
|
||||
"pospronoun": "her",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "scaling agency owner"
|
||||
},
|
||||
"neutral": {
|
||||
"pronoun": "they",
|
||||
"ppronoun": "them",
|
||||
"pospronoun": "their",
|
||||
"isare": "are",
|
||||
"has_have": "have",
|
||||
"does_do": "do",
|
||||
"identity": "scaling agency owner"
|
||||
}
|
||||
}
|
||||
},
|
||||
"medical_practice_ceo": {
|
||||
"base_name": "The Medical Practice CEO",
|
||||
"variants": {
|
||||
"male": {
|
||||
"pronoun": "he",
|
||||
"ppronoun": "him",
|
||||
"pospronoun": "his",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "overwhelmed practice owner"
|
||||
},
|
||||
"female": {
|
||||
"pronoun": "she",
|
||||
"ppronoun": "her",
|
||||
"pospronoun": "her",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "overwhelmed practice owner"
|
||||
},
|
||||
"neutral": {
|
||||
"pronoun": "they",
|
||||
"ppronoun": "them",
|
||||
"pospronoun": "their",
|
||||
"isare": "are",
|
||||
"has_have": "have",
|
||||
"does_do": "do",
|
||||
"identity": "overwhelmed practice owner"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ecom_high_roller": {
|
||||
"base_name": "The Ecom High-Roller",
|
||||
"variants": {
|
||||
"male": {
|
||||
"pronoun": "he",
|
||||
"ppronoun": "him",
|
||||
"pospronoun": "his",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "scaling ecommerce brand owner"
|
||||
},
|
||||
"female": {
|
||||
"pronoun": "she",
|
||||
"ppronoun": "her",
|
||||
"pospronoun": "her",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "scaling ecommerce brand owner"
|
||||
},
|
||||
"neutral": {
|
||||
"pronoun": "they",
|
||||
"ppronoun": "them",
|
||||
"pospronoun": "their",
|
||||
"isare": "are",
|
||||
"has_have": "have",
|
||||
"does_do": "do",
|
||||
"identity": "scaling ecommerce brand owner"
|
||||
}
|
||||
}
|
||||
},
|
||||
"coaching_empire_builder": {
|
||||
"base_name": "The Coaching Empire Builder",
|
||||
"variants": {
|
||||
"male": {
|
||||
"pronoun": "he",
|
||||
"ppronoun": "him",
|
||||
"pospronoun": "his",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "online coach"
|
||||
},
|
||||
"female": {
|
||||
"pronoun": "she",
|
||||
"ppronoun": "her",
|
||||
"pospronoun": "her",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "online coach"
|
||||
},
|
||||
"neutral": {
|
||||
"pronoun": "they",
|
||||
"ppronoun": "them",
|
||||
"pospronoun": "their",
|
||||
"isare": "are",
|
||||
"has_have": "have",
|
||||
"does_do": "do",
|
||||
"identity": "online coach"
|
||||
}
|
||||
}
|
||||
},
|
||||
"multi_location_ceo": {
|
||||
"base_name": "The Multi-Location CEO",
|
||||
"variants": {
|
||||
"male": {
|
||||
"pronoun": "he",
|
||||
"ppronoun": "him",
|
||||
"pospronoun": "his",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "franchise operator"
|
||||
},
|
||||
"female": {
|
||||
"pronoun": "she",
|
||||
"ppronoun": "her",
|
||||
"pospronoun": "her",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "franchise operator"
|
||||
},
|
||||
"neutral": {
|
||||
"pronoun": "they",
|
||||
"ppronoun": "them",
|
||||
"pospronoun": "their",
|
||||
"isare": "are",
|
||||
"has_have": "have",
|
||||
"does_do": "do",
|
||||
"identity": "franchise operator"
|
||||
}
|
||||
}
|
||||
},
|
||||
"real_estate_power_player": {
|
||||
"base_name": "The Real Estate Power Player",
|
||||
"variants": {
|
||||
"male": {
|
||||
"pronoun": "he",
|
||||
"ppronoun": "him",
|
||||
"pospronoun": "his",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "luxury agent"
|
||||
},
|
||||
"female": {
|
||||
"pronoun": "she",
|
||||
"ppronoun": "her",
|
||||
"pospronoun": "her",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "luxury agent"
|
||||
},
|
||||
"neutral": {
|
||||
"pronoun": "they",
|
||||
"ppronoun": "them",
|
||||
"pospronoun": "their",
|
||||
"isare": "are",
|
||||
"has_have": "have",
|
||||
"does_do": "do",
|
||||
"identity": "luxury agent"
|
||||
}
|
||||
}
|
||||
},
|
||||
"enterprise_innovator": {
|
||||
"base_name": "The Enterprise Innovator",
|
||||
"variants": {
|
||||
"male": {
|
||||
"pronoun": "he",
|
||||
"ppronoun": "him",
|
||||
"pospronoun": "his",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "enterprise operations leader"
|
||||
},
|
||||
"female": {
|
||||
"pronoun": "she",
|
||||
"ppronoun": "her",
|
||||
"pospronoun": "her",
|
||||
"isare": "is",
|
||||
"has_have": "has",
|
||||
"does_do": "does",
|
||||
"identity": "enterprise operations leader"
|
||||
},
|
||||
"neutral": {
|
||||
"pronoun": "they",
|
||||
"ppronoun": "them",
|
||||
"pospronoun": "their",
|
||||
"isare": "are",
|
||||
"has_have": "have",
|
||||
"does_do": "do",
|
||||
"identity": "enterprise operations leader"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
50
backend/data/cartesian_patterns.json
Normal file
50
backend/data/cartesian_patterns.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"meta": {
|
||||
"file_type": "cartesian_patterns",
|
||||
"version": "2.1",
|
||||
"description": "Formulas for generating titles and hooks via Cartesian multiplication."
|
||||
},
|
||||
"patterns": {
|
||||
"long_tail_seo_headlines": [
|
||||
{
|
||||
"id": "geo_dominance",
|
||||
"formula": "{adjectives_quality} {{NICHE}} {Agency|Partner|Experts} in {{CITY}}, {{STATE}}",
|
||||
"example_output": "Premier Plastic Surgery Marketing Experts in Miami, FL"
|
||||
},
|
||||
{
|
||||
"id": "pain_resolution_geo",
|
||||
"formula": "How to {verbs_solution} {{NICHE}} {outcomes} in {{CITY}}",
|
||||
"example_output": "How to Automate Dental Practice Patient Volume in Austin"
|
||||
},
|
||||
{
|
||||
"id": "authority_hook",
|
||||
"formula": "Why {{CITY}}'s {adjectives_growth} {{NICHE}} Founders Choose Us",
|
||||
"example_output": "Why Palo Alto's Fast-Growing Fintech Founders Choose Us"
|
||||
}
|
||||
],
|
||||
"hyper_local_hooks": [
|
||||
{
|
||||
"id": "neighborhood_targeting",
|
||||
"formula": "Attention {{CITY}}: {verbs_action} Your {{NICHE}} Market {timelines}",
|
||||
"example_output": "Attention Greenwich: Dominate Your Hedge Fund Market Before Q4"
|
||||
},
|
||||
{
|
||||
"id": "zip_code_prestige",
|
||||
"formula": "The {adjectives_quality} Strategy for {{NICHE}} in {{ZIP_FOCUS}}",
|
||||
"example_output": "The Elite Strategy for Luxury Brokerage in 90210"
|
||||
}
|
||||
],
|
||||
"intent_based_search_terms": [
|
||||
{
|
||||
"id": "commercial_intent",
|
||||
"formula": "{adjectives_quality} {{NICHE}} Automation Services {{CITY}}",
|
||||
"example_output": "Top-Rated Vertical SaaS Automation Services Atherton"
|
||||
},
|
||||
{
|
||||
"id": "problem_aware",
|
||||
"formula": "Fix {{NICHE}} {Zapier|CRM|Data} Issues {{CITY}}",
|
||||
"example_output": "Fix HealthTech CRM Issues Boston"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
74
backend/data/geo_intelligence.json
Normal file
74
backend/data/geo_intelligence.json
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"meta": {
|
||||
"file_type": "geographic_intelligence",
|
||||
"version": "2.1",
|
||||
"note": "Cities array acts as the 'Location' variable in Cartesian generation."
|
||||
},
|
||||
"clusters": {
|
||||
"tech_native": {
|
||||
"cluster_name": "The Silicon Valleys",
|
||||
"cities": [
|
||||
{
|
||||
"city": "Atherton",
|
||||
"state": "CA",
|
||||
"zip_focus": "94027"
|
||||
},
|
||||
{
|
||||
"city": "Palo Alto",
|
||||
"state": "CA",
|
||||
"zip_focus": "94301"
|
||||
},
|
||||
{
|
||||
"city": "Medina",
|
||||
"state": "WA",
|
||||
"zip_focus": "98039"
|
||||
},
|
||||
{
|
||||
"city": "Austin",
|
||||
"state": "TX",
|
||||
"neighborhood": "Westlake"
|
||||
}
|
||||
]
|
||||
},
|
||||
"financial_power": {
|
||||
"cluster_name": "The Wall Street Corridors",
|
||||
"cities": [
|
||||
{
|
||||
"city": "Greenwich",
|
||||
"state": "CT",
|
||||
"zip_focus": "06830"
|
||||
},
|
||||
{
|
||||
"city": "Tribeca",
|
||||
"state": "NY",
|
||||
"neighborhood": "Manhattan"
|
||||
},
|
||||
{
|
||||
"city": "Charlotte",
|
||||
"state": "NC",
|
||||
"neighborhood": "Myers Park"
|
||||
}
|
||||
]
|
||||
},
|
||||
"new_money_growth": {
|
||||
"cluster_name": "The Growth Havens",
|
||||
"cities": [
|
||||
{
|
||||
"city": "Miami",
|
||||
"state": "FL",
|
||||
"neighborhood": "Coral Gables"
|
||||
},
|
||||
{
|
||||
"city": "Scottsdale",
|
||||
"state": "AZ",
|
||||
"zip_focus": "85253"
|
||||
},
|
||||
{
|
||||
"city": "Nashville",
|
||||
"state": "TN",
|
||||
"neighborhood": "Brentwood"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
37
backend/data/master_meta.json
Normal file
37
backend/data/master_meta.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"meta": {
|
||||
"file_type": "master_meta",
|
||||
"schema_version": "3.0",
|
||||
"last_updated": "2024-06-14",
|
||||
"description": "Global metadata, grammar token map, and system-wide schema for the Cartesian Offer Engine for scalable programmatic SEO assets."
|
||||
},
|
||||
"grammar_tokens": {
|
||||
"A_AN": "[[A_AN:WORD]] -> 'a' or 'an' based on the phonetic start of WORD",
|
||||
"PRONOUN": "[[PRONOUN:AVATAR]] -> he, she, or they, per avatar gender",
|
||||
"PPRONOUN": "[[PPRONOUN:AVATAR]] -> him, her, or them, per avatar gender",
|
||||
"POSPRONOUN": "[[POSPRONOUN:AVATAR]] -> his, her, or their, per avatar gender",
|
||||
"ISARE": "[[ISARE:AVATAR]] -> is or are, per singular/plural/neutral context",
|
||||
"HAS_HAVE": "[[HAS_HAVE:AVATAR]] -> has or have",
|
||||
"DOES_DO": "[[DOES_DO:AVATAR]] -> does or do",
|
||||
"CITY": "[[CITY]] -> injected City string",
|
||||
"STATE": "[[STATE]] -> injected State string",
|
||||
"COUNTY": "[[COUNTY]] -> injected County string",
|
||||
"NICHE": "[[NICHE]] -> injected avatar business niche"
|
||||
},
|
||||
"schema": {
|
||||
"avatar_intelligence": "Defines all avatars, their niches, gender variants, and focus areas.",
|
||||
"geo_intelligence": "Defines all location clusters, cities, states, counties, zip/neighborhood info.",
|
||||
"spintax_dictionaries": "Lists adjectives, verbs, transitions, timeframes, etc, for unlimited headline/permutation combos.",
|
||||
"cartesian_patterns": "Long-tail SEO formulas with grammar tokens and spintax for full $n^k$ headline engine.",
|
||||
"offer_blocks_universal": "Each universal offer block with global pain/solution/value bullets and grammar tokens.",
|
||||
"offer_blocks_avatar_personalized": "Per-avatar offer block expansions: pain/solution/value bullets using pronoun, niche, geo logic.",
|
||||
"offer_blocks_cartesian_engine": "The full Cartesian product: spintax x avatar_niche x geo x grammar-token, generating infinite variations."
|
||||
},
|
||||
"usage_notes": [
|
||||
"Always resolve grammar tokens before rendering final output for SEO or user-facing interfaces.",
|
||||
"Spintax expands first, then grammar tokens resolve for entity-aware copy.",
|
||||
"Geo variables (city, state, county) are injected per page—do not hard-code.",
|
||||
"Avatars determine the gender/number logic for all pronouns and verb agreements.",
|
||||
"All pattern formulas can be mapped to avatar_niche x geo cluster for hyperlocal content and offers."
|
||||
]
|
||||
}
|
||||
1729
backend/data/offer_blocks_avatar_personalized.json
Normal file
1729
backend/data/offer_blocks_avatar_personalized.json
Normal file
File diff suppressed because it is too large
Load Diff
25
backend/data/offer_blocks_cartesian_engine.json
Normal file
25
backend/data/offer_blocks_cartesian_engine.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"meta": {
|
||||
"file_type": "offer_blocks_cartesian_engine",
|
||||
"version": "2.1",
|
||||
"description": "Orchestrates the Cartesian Permutation Logic (n^k) by linking specialized dictionaries."
|
||||
},
|
||||
"cartesian_generator": {
|
||||
"description": "Engine for generating long-tail SEO phrases and hooks by multiplying Spintax x AvatarNiche x City.",
|
||||
"logic_flow": [
|
||||
"1. Load Spintax Dictionaries (adjectives, verbs, etc.)",
|
||||
"2. Load Context: Avatar Niches (The 'What')",
|
||||
"3. Load Context: Geo Cities (The 'Where')",
|
||||
"4. Load Pattern: Select Formula from cartesian_patterns",
|
||||
"5. Execute Cross-Product Loop: Pattern x Spintax x Niche x City",
|
||||
"6. Resolve Grammar Tokens ([[A_AN]], [[PRONOUN]])"
|
||||
],
|
||||
"linked_resources": {
|
||||
"spintax_source": "spintax_dictionaries.json",
|
||||
"avatar_source": "avatar_intelligence.json",
|
||||
"geo_source": "geo_intelligence.json",
|
||||
"pattern_source": "cartesian_patterns.json",
|
||||
"grammar_source": "master_meta.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
237
backend/data/offer_blocks_universal.json
Normal file
237
backend/data/offer_blocks_universal.json
Normal file
@@ -0,0 +1,237 @@
|
||||
{
|
||||
"meta": {
|
||||
"file_type": "offer_blocks_universal",
|
||||
"version": "2.1",
|
||||
"total_blocks": 10
|
||||
},
|
||||
"offer_blocks": {
|
||||
"block_01_zapier_fix": {
|
||||
"id": "block_01_zapier_fix",
|
||||
"title": "The $1,000 Fix",
|
||||
"hook": "Stop the bleeding and start scaling.",
|
||||
"universal_pain_points": [
|
||||
"Monthly automation bills that scale faster than your actual profit.",
|
||||
"Crucial data getting 'Lost in Zapier' causing lead leakage.",
|
||||
"Paying 5 different SaaS subscriptions for what should be one simple script."
|
||||
],
|
||||
"universal_solutions": [
|
||||
"Migrate entire automation stack to self-hosted n8n",
|
||||
"Eliminate per-task billing and unpredictable SaaS overages",
|
||||
"Ensure zero-latency automation for lead routing"
|
||||
],
|
||||
"universal_value_points": [
|
||||
"Fixed cost $20/mo",
|
||||
"99.8% automation uptime",
|
||||
"Stronger infrastructure foundation for scaling ads"
|
||||
],
|
||||
"spintax": "{Stop the bleeding|End the cash drain|Stop wasting money} and {start scaling|grow profitably|build a real foundation}.\nThe $1,000 Fix is real. {Kill|Eliminate|Slash} your Zapier bills & {guarantee|ensure} your ads actually convert.\nAt {{AGENCY_NAME}}, we {rebuild|overhaul|fix} the infrastructure your last agency {ignored|messed up|forgot about}:\n– Migrate {costly|bloated} automation to n8n\n– {Repair|Fix|Patch} leaky funnels\n– Code {precise|100% accurate} Google Ads attribution\n{Start My Free Custom Scaling Blueprint|Get Your Audit} → {{AGENCY_URL}}"
|
||||
},
|
||||
"block_02_social_proof": {
|
||||
"id": "block_02_social_proof",
|
||||
"title": "Proof. Not Promises.",
|
||||
"hook": "Why high-volume businesses trust us.",
|
||||
"universal_pain_points": [
|
||||
"Sick of agencies that talk a big game but have zero case studies.",
|
||||
"Fear of being the 'guinea pig' for a new agency's learning curve.",
|
||||
"Previous marketing partners who hid data when performance dipped."
|
||||
],
|
||||
"universal_solutions": [
|
||||
"Leverage verified case studies from your exact niche",
|
||||
"Transparent reporting dashboards updated in real-time",
|
||||
"Performance guarantees tied to revenue, not vanity metrics"
|
||||
],
|
||||
"universal_value_points": [
|
||||
"Reduced risk of vendor selection",
|
||||
"Full visibility into where budget goes",
|
||||
"Proven methodologies deployed immediately"
|
||||
],
|
||||
"spintax": "Why {high-volume|market-leading|top-tier} businesses trust {{AGENCY_NAME}}:\n{120+|Over 100|Hundreds of} businesses helped\nClients in {8 countries|multiple global markets}\n{$100k|Six-figure} adspend managed a month\n{3x ROI|Triple digit returns} first month return\n{Stop Wasting Money|End the guesswork} → {Get My Free Blueprint|See The Case Studies}"
|
||||
},
|
||||
"block_03_fix_first_scale_second": {
|
||||
"id": "block_03_fix_first_scale_second",
|
||||
"title": "We Fix First, Scale Second",
|
||||
"hook": "Before scaling, we fix the revenue killers.",
|
||||
"universal_pain_points": [
|
||||
"Pouring water into a leaky bucket (scaling broken funnels).",
|
||||
"Scaling ad spend only to see CPA skyrocket immediately.",
|
||||
"The anxiety of spending more money when your foundation is shaky."
|
||||
],
|
||||
"universal_solutions": [
|
||||
"Comprehensive funnel audit before increasing budget",
|
||||
"Conversion Rate Optimization (CRO) to maximize traffic value",
|
||||
"Foundation-first approach to sustainable scaling"
|
||||
],
|
||||
"universal_value_points": [
|
||||
"Lower CAC immediately",
|
||||
"Higher ROAS on every dollar spent",
|
||||
"Peace of mind knowing the backend handles volume"
|
||||
],
|
||||
"spintax": "Before {scaling|spending more money|increasing budget}:\nWe {fix|repair|solve} the three {revenue killers|profit leaks|growth blockers}:\n– {Code-Level|Technical} Funnel Repairs\n– Google Ads {Profit Engine|Optimization}\n– Automation {Cost Cutter|Efficiency Audit}\n{Fix My Funnel|Repair My Stack} & {Cut My Tech Bill|Save Money Now} → {{AGENCY_URL}}"
|
||||
},
|
||||
"block_04_market_domination": {
|
||||
"id": "block_04_market_domination",
|
||||
"title": "Done-For-You Market Domination",
|
||||
"hook": "Tired of spending on ads that flop?",
|
||||
"universal_pain_points": [
|
||||
"Watching competitors dominate while your ads sit in 'learning phase'.",
|
||||
"Creative fatigue making your best ads stop working after 2 weeks.",
|
||||
"The exhaustion of constantly trying to 'hack' the algorithm."
|
||||
],
|
||||
"universal_solutions": [
|
||||
"Omnichannel strategy covering Facebook, Google, and TikTok",
|
||||
"Rapid creative testing framework to battle fatigue",
|
||||
"Algorithm-proof marketing logic based on fundamentals"
|
||||
],
|
||||
"universal_value_points": [
|
||||
"Consistent lead flow across platforms",
|
||||
"Always-on winning creative rotation",
|
||||
"Long-term asset value building"
|
||||
],
|
||||
"spintax": "{Tired of|Sick of|Done with} spending {|huge budgets} on ads that {flop|fail|don't convert}?\n{{AGENCY_NAME}} {builds|engineers}, {scales|grows}, and {optimizes|fine-tunes} campaigns that {dominate|own} your niche.\n– Facebook / Google / TikTok ads\n– {Lead funnels|High-converting pages}\n– Automation & CRM\n– SEO that {ranks|actually works}\n{Get My Free Growth Strategy Call|Book A Dominance Call} → {{AGENCY_URL}}"
|
||||
},
|
||||
"block_05_stop_wasting_dollars": {
|
||||
"id": "block_05_stop_wasting_dollars",
|
||||
"title": "Stop Wasting Advertising Dollars",
|
||||
"hook": "Does wasting ad dollars keep you up at night?",
|
||||
"universal_pain_points": [
|
||||
"Clicking refresh on your ad manager hoping for a miracle.",
|
||||
"Paying for clicks that are clearly bots or unqualified leads.",
|
||||
"The sinking feeling that 50% of your budget is effectively burning."
|
||||
],
|
||||
"universal_solutions": [
|
||||
"Bot filtering and click-fraud protection",
|
||||
"Negative keyword lists to exclude low-quality traffic",
|
||||
"Audience exclusion to stop retargeting converters"
|
||||
],
|
||||
"universal_value_points": [
|
||||
"Zero budget waste on bots",
|
||||
"Higher quality leads for sales teams",
|
||||
"Efficient spend utilization"
|
||||
],
|
||||
"spintax": "Does {wasting ad dollars|burning budget|losing money on ads} keep you up at night?\nLet {{AGENCY_NAME}} {show you how to|help you} get {more leads|better results} — {without wasting money|efficiently|profitably}.\nYES! I Want {More Leads|Profitable Ads} → {{AGENCY_URL}}"
|
||||
},
|
||||
"block_06_start_building_systems": {
|
||||
"id": "block_06_start_building_systems",
|
||||
"title": "Stop Buying Leads. Start Building Systems.",
|
||||
"hook": "We replace chaotic ad spend with predictable systems.",
|
||||
"universal_pain_points": [
|
||||
"Feast or famine revenue cycles.",
|
||||
"Depending on 'unicorn' ads rather than a reliable machine.",
|
||||
"Lead flow stops the second you turn off the ads."
|
||||
],
|
||||
"universal_solutions": [
|
||||
"Build owned media assets (SEO, Email List)",
|
||||
"Automated nurture sequences that work 24/7",
|
||||
"Systematized acquisition playbooks"
|
||||
],
|
||||
"universal_value_points": [
|
||||
"Predictable monthly revenue",
|
||||
"Business asset value increases",
|
||||
"Freedom from day-to-day ad management panic"
|
||||
],
|
||||
"spintax": "We {replace|swap} chaotic ad spend with {predictable|reliable|consistent} acquisition systems.\nWe audit, we build, we {automate|optimize}.\n{Full infrastructure|Complete ecosystem}. No fluff.\n{Start Your Systems Audit|Build My Machine} → {{AGENCY_URL}}"
|
||||
},
|
||||
"block_07_dedicated_growth_unit": {
|
||||
"id": "block_07_dedicated_growth_unit",
|
||||
"title": "Your Dedicated Growth Unit",
|
||||
"hook": "Outsource your RevOps to a single, accountable partner.",
|
||||
"universal_pain_points": [
|
||||
"Managing 5 different freelancers who blame each other.",
|
||||
"The 'Integrator' gap: you have tools but nobody to connect them.",
|
||||
"Paying agency fees but still doing all the project management yourself."
|
||||
],
|
||||
"universal_solutions": [
|
||||
"Unified team managing Strategy, Ads, and Automation",
|
||||
"Single point of accountability (Account Director)",
|
||||
"Holistic view of the entire revenue engine"
|
||||
],
|
||||
"universal_value_points": [
|
||||
"No more vendor blame games",
|
||||
"Execution speed increases 10x",
|
||||
"Strategic alignment across all channels"
|
||||
],
|
||||
"spintax": "{Outsource|Delegate} your RevOps to a {single|dedicated}, {accountable|expert} partner.\nYou get:\n– Lead Architect (Strategy)\n– Systems Engineer (Automation + n8n)\n– Data Scientist (Attribution)\n– Risk Officer (HIPAA/FTC)\n{Request the P&L Partnership Brief|See How We Partner} → {{AGENCY_URL}}"
|
||||
},
|
||||
"block_08_elite_media_buying": {
|
||||
"id": "block_08_elite_media_buying",
|
||||
"title": "Elite Media Buying",
|
||||
"hook": "We turn ad spend into a precise revenue engine.",
|
||||
"universal_pain_points": [
|
||||
"Media buyers who just 'boost posts' and call it marketing.",
|
||||
"Agencies that set it and forget it while collecting a fee.",
|
||||
"Creative that looks like everyone else's generic ads."
|
||||
],
|
||||
"universal_solutions": [
|
||||
"Data-driven bid strategies (Target CPA/ROAS)",
|
||||
"Creative strategy aligned with buyer psychology",
|
||||
"Advanced audience segmentation and lookalikes"
|
||||
],
|
||||
"universal_value_points": [
|
||||
"Scalable ad spend with stable returns",
|
||||
"High-converting creative assets",
|
||||
"Competitive advantage in auctions"
|
||||
],
|
||||
"spintax": "Most firms {operate|run ads} at the {commodity|amateur} level.\n{{AGENCY_NAME}} manages {cash flow|profitability}.\nWe {turn|transform} ad spend into a {precise|predictable} revenue engine.\nReal-time optimization.\nMarket domination.\n{Start My Media Scaling Blueprint|Scale My Ads} → {{AGENCY_URL}}"
|
||||
},
|
||||
"block_09_sovereign_capi": {
|
||||
"id": "block_09_sovereign_capi",
|
||||
"title": "The Sovereign CAPI Advantage",
|
||||
"hook": "40% of your data is disappearing. We fix that.",
|
||||
"universal_pain_points": [
|
||||
"Ad platforms reporting 100 sales when your bank says 60.",
|
||||
"Fear that iOS14+ killed your ability to target effectively.",
|
||||
"Flying blind because you can't trust your dashboard."
|
||||
],
|
||||
"universal_solutions": [
|
||||
"Server-Side Tracking (CAPI) implementation",
|
||||
"Offline Conversion Import (OCI)",
|
||||
"First-party data capture strategy"
|
||||
],
|
||||
"universal_value_points": [
|
||||
"99% Data Accuracy restored",
|
||||
"Signal resilience against browser blocks",
|
||||
"Confident budget allocation decisions"
|
||||
],
|
||||
"spintax": "40% of your {data|conversions|revenue signal} is {disappearing|vanishing}.\nWe {fix|solve} that {permanently|forever}.\nOur Sovereign CAPI Infrastructure delivers:\n– {99.8% accuracy|Perfect matching}\n– {Verified revenue|Bank-level data}\n– CFO-level reporting\n{Fix My Tracking|Audit My Data} → {{AGENCY_URL}}"
|
||||
},
|
||||
"block_10_marketing_audit": {
|
||||
"id": "block_10_marketing_audit",
|
||||
"title": "Stop Guessing. Get The Audit.",
|
||||
"hook": "The first step to fixing your marketing is knowing what's broken.",
|
||||
"universal_pain_points": [
|
||||
"Trying random tactics hoping something sticks.",
|
||||
"Not knowing if your problem is the offer, the ad, or the funnel.",
|
||||
"Feeling overwhelmed by the complexity of modern marketing."
|
||||
],
|
||||
"universal_solutions": [
|
||||
"Full-stack technical audit (Ads, Site, Tracking)",
|
||||
"Competitor analysis and benchmarking",
|
||||
"Clear, prioritized roadmap for fixes"
|
||||
],
|
||||
"universal_value_points": [
|
||||
"Clarity on exactly what to fix first",
|
||||
"No more wasted budget on wrong tactics",
|
||||
"Actionable plan to improve ROI"
|
||||
],
|
||||
"spintax": "The first step to {fixing|repairing} your marketing is {knowing|identifying} what's broken.\n{Stop Guessing|End the confusion}.\nGet a full, {comprehensive|deep-dive} audit of your:\n– Funnel performance\n– Tech stack health\n– Ad account efficiency\n{Get My Free Audit|Reveal The Flaws} → {{AGENCY_URL}}"
|
||||
},
|
||||
"block_11_avatar_showcase": {
|
||||
"id": "block_11_avatar_showcase",
|
||||
"title": "Who We Help",
|
||||
"hook": "Industries we have scaled to 8-figures.",
|
||||
"universal_pain_points": [],
|
||||
"universal_solutions": [],
|
||||
"universal_value_points": [],
|
||||
"spintax": "We specialize in high-growth verticals.\n{{COMPONENT_AVATAR_GRID}}"
|
||||
},
|
||||
"block_12_consultation_form": {
|
||||
"id": "block_12_consultation_form",
|
||||
"title": "Book Your Strategy Call",
|
||||
"hook": "Let's build your growth roadmap.",
|
||||
"universal_pain_points": [],
|
||||
"universal_solutions": [],
|
||||
"universal_value_points": [],
|
||||
"spintax": "Ready to scale? Fill out the form below.\n{{COMPONENT_OPTIN_FORM}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
52
backend/data/spintax_dictionaries.json
Normal file
52
backend/data/spintax_dictionaries.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"meta": {
|
||||
"file_type": "spintax_dictionaries",
|
||||
"version": "2.0",
|
||||
"description": "Shared dictionaries for Spintax variables."
|
||||
},
|
||||
"dictionaries": {
|
||||
"adjectives_quality": [
|
||||
"Top-Rated",
|
||||
"Premier",
|
||||
"Elite",
|
||||
"Exclusive",
|
||||
"The #1",
|
||||
"High-Performance"
|
||||
],
|
||||
"adjectives_growth": [
|
||||
"Scaling",
|
||||
"Fast-Growing",
|
||||
"Disruptive",
|
||||
"Modern",
|
||||
"Next-Gen"
|
||||
],
|
||||
"verbs_action": [
|
||||
"Dominate",
|
||||
"Scale",
|
||||
"Disrupt",
|
||||
"Own",
|
||||
"Capture"
|
||||
],
|
||||
"verbs_solution": [
|
||||
"Fix",
|
||||
"Automate",
|
||||
"Optimize",
|
||||
"Streamline",
|
||||
"Repair"
|
||||
],
|
||||
"outcomes": [
|
||||
"Revenue",
|
||||
"ROI",
|
||||
"Lead Flow",
|
||||
"Patient Volume",
|
||||
"Deal Flow"
|
||||
],
|
||||
"timelines": [
|
||||
"in 30 Days",
|
||||
"This Quarter",
|
||||
"Before Q4",
|
||||
"Instantly",
|
||||
"Overnight"
|
||||
]
|
||||
}
|
||||
}
|
||||
241
backend/package-lock.json
generated
Normal file
241
backend/package-lock.json
generated
Normal file
@@ -0,0 +1,241 @@
|
||||
{
|
||||
"name": "spark-backend-scripts",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "spark-backend-scripts",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@directus/sdk": "^13.0.0",
|
||||
"dotenv": "^16.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@cspotcode/source-map-support": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "0.3.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@directus/sdk": {
|
||||
"version": "13.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@directus/sdk/-/sdk-13.0.2.tgz",
|
||||
"integrity": "sha512-KECQM0w8xlgr5EklX+Jb9+dIzXyvJFjRfhiIAI7l/b0WEtVaCfvRMIrJXR3XsLeVW9u2nu+b/TffOyTMSLjm2w==",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/directus/directus?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tsconfig/node10": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
|
||||
"integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@tsconfig/node12": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@tsconfig/node14": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@tsconfig/node16": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
||||
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.26",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.26.tgz",
|
||||
"integrity": "sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-walk": {
|
||||
"version": "8.3.4",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
|
||||
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/create-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.6.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
||||
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/make-error": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ts-node": {
|
||||
"version": "10.9.2",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
|
||||
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@cspotcode/source-map-support": "^0.8.0",
|
||||
"@tsconfig/node10": "^1.0.7",
|
||||
"@tsconfig/node12": "^1.0.7",
|
||||
"@tsconfig/node14": "^1.0.0",
|
||||
"@tsconfig/node16": "^1.0.2",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"arg": "^4.1.0",
|
||||
"create-require": "^1.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"make-error": "^1.1.1",
|
||||
"v8-compile-cache-lib": "^3.0.1",
|
||||
"yn": "3.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"ts-node": "dist/bin.js",
|
||||
"ts-node-cwd": "dist/bin-cwd.js",
|
||||
"ts-node-esm": "dist/bin-esm.js",
|
||||
"ts-node-script": "dist/bin-script.js",
|
||||
"ts-node-transpile-only": "dist/bin-transpile.js",
|
||||
"ts-script": "dist/bin-script-deprecated.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/core": ">=1.2.50",
|
||||
"@swc/wasm": ">=1.2.50",
|
||||
"@types/node": "*",
|
||||
"typescript": ">=2.7"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@swc/core": {
|
||||
"optional": true
|
||||
},
|
||||
"@swc/wasm": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/yn": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
backend/package.json
Normal file
18
backend/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "spark-backend-scripts",
|
||||
"version": "1.0.0",
|
||||
"description": "Scripts for Cartesian Engine data management",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"init-schema": "ts-node scripts/init_schema.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@directus/sdk": "^13.0.0",
|
||||
"dotenv": "^16.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.0.0",
|
||||
"@types/node": "^20.0.0"
|
||||
}
|
||||
}
|
||||
51
backend/scripts/ensure_test_site.ts
Normal file
51
backend/scripts/ensure_test_site.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
|
||||
import { createDirectus, rest, staticToken, authentication, login, readItems, createItem } from '@directus/sdk';
|
||||
import * as dotenv from 'dotenv';
|
||||
import * as path from 'path';
|
||||
|
||||
// Load Env
|
||||
dotenv.config({ path: path.resolve(process.cwd(), 'backend', 'credentials.env') });
|
||||
|
||||
async function ensureSite() {
|
||||
const url = process.env.DIRECTUS_PUBLIC_URL || '';
|
||||
const email = process.env.DIRECTUS_ADMIN_EMAIL || '';
|
||||
const password = process.env.DIRECTUS_ADMIN_PASSWORD || '';
|
||||
|
||||
if (!url || !email || !password) {
|
||||
console.error("Missing credentials in env");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Connecting to ${url}...`);
|
||||
const client = createDirectus(url).with(authentication()).with(rest());
|
||||
|
||||
try {
|
||||
await client.login(email, password);
|
||||
console.log("Authenticated.");
|
||||
|
||||
const existing = await client.request(readItems('sites' as any, {
|
||||
filter: {
|
||||
url: { _eq: 'https://la.chrisamaya.work' }
|
||||
}
|
||||
}));
|
||||
|
||||
if (existing.length > 0) {
|
||||
console.log("✅ Site 'la.chrisamaya.work' already exists. ID:", existing[0].id);
|
||||
} else {
|
||||
console.log("Creating new site 'la.chrisamaya.work'...");
|
||||
const newSite = await client.request(createItem('sites', {
|
||||
name: 'Chris Amaya LA',
|
||||
url: 'https://la.chrisamaya.work',
|
||||
site_type: 'wordpress',
|
||||
status: 'active',
|
||||
allowed_niches: ['High-End Agency Owner', 'Real Estate Power Player']
|
||||
} as any));
|
||||
console.log("✅ Created site. ID:", newSite.id);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
}
|
||||
}
|
||||
|
||||
ensureSite();
|
||||
243
backend/scripts/init_schema.ts
Normal file
243
backend/scripts/init_schema.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
|
||||
import { createDirectus, rest, staticToken, authentication, createCollection, createField, createItem, readCollections, readItems } from '@directus/sdk';
|
||||
import * as dotenv from 'dotenv';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
// Load .env from root or local credentials
|
||||
const rootEnvPath = path.resolve(__dirname, '../../.env');
|
||||
const localEnvPath = path.resolve(__dirname, '../credentials.env');
|
||||
|
||||
if (fs.existsSync(localEnvPath)) {
|
||||
console.log('Loading credentials from backend/credentials.env');
|
||||
dotenv.config({ path: localEnvPath });
|
||||
} else {
|
||||
dotenv.config({ path: rootEnvPath });
|
||||
}
|
||||
|
||||
const DIRECTUS_URL = process.env.DIRECTUS_PUBLIC_URL || 'http://localhost:8055';
|
||||
const TOKEN = process.env.DIRECTUS_ADMIN_TOKEN;
|
||||
const EMAIL = process.env.DIRECTUS_ADMIN_EMAIL;
|
||||
const PASSWORD = process.env.DIRECTUS_ADMIN_PASSWORD;
|
||||
|
||||
// Initialize client with authentication composable
|
||||
const client = createDirectus(DIRECTUS_URL).with(authentication()).with(rest());
|
||||
|
||||
async function main() {
|
||||
console.log(`🚀 Connecting to Directus at ${DIRECTUS_URL}...`);
|
||||
|
||||
try {
|
||||
if (EMAIL && PASSWORD) {
|
||||
console.log(`🔑 Authenticating as ${EMAIL}...`);
|
||||
await client.login(EMAIL, PASSWORD);
|
||||
} else if (TOKEN) {
|
||||
console.log(`🔑 Authenticating with Static Token...`);
|
||||
client.setToken(TOKEN);
|
||||
} else {
|
||||
throw new Error('Missing credentials (EMAIL+PASSWORD or TOKEN)');
|
||||
}
|
||||
|
||||
console.log('✅ Authentication successful.');
|
||||
|
||||
const existingCollections = await client.request(readCollections());
|
||||
const existingNames = new Set(existingCollections.map((c: any) => c.collection));
|
||||
|
||||
// --- 1. Define Collections ---
|
||||
const collections = [
|
||||
{ collection: 'sites', schema: { name: 'sites' }, meta: { note: 'Configuration for websites' } },
|
||||
{ collection: 'avatars', schema: { name: 'avatars' }, meta: { note: 'Target Customer Avatars' } },
|
||||
{ collection: 'avatar_variants', schema: { name: 'avatar_variants' }, meta: { note: 'Grammar rules for avatars' } },
|
||||
{ collection: 'geo_clusters', schema: { name: 'geo_clusters' }, meta: { note: 'Geographic clusters' } },
|
||||
{ collection: 'geo_locations', schema: { name: 'geo_locations' }, meta: { note: 'Specific cities/locations' } },
|
||||
{ collection: 'spintax_dictionaries', schema: { name: 'spintax_dictionaries' }, meta: { note: 'Vocabulary lists' } },
|
||||
{ collection: 'cartesian_patterns', schema: { name: 'cartesian_patterns' }, meta: { note: 'Content formulas' } },
|
||||
{ collection: 'offer_blocks_universal', schema: { name: 'offer_blocks_universal' }, meta: { note: 'Base content blocks' } },
|
||||
{ collection: 'offer_blocks_personalized', schema: { name: 'offer_blocks_personalized' }, meta: { note: 'Avatar extensions' } },
|
||||
{ collection: 'article_templates', schema: { name: 'article_templates' }, meta: { note: 'Article structure definitions' } },
|
||||
{ collection: 'generation_jobs', schema: { name: 'generation_jobs' }, meta: { note: 'Queued generation tasks' } },
|
||||
{ collection: 'generated_articles', schema: { name: 'generated_articles' }, meta: { note: 'Final HTML output' } },
|
||||
];
|
||||
|
||||
for (const col of collections) {
|
||||
if (!existingNames.has(col.collection)) {
|
||||
console.log(`Creating collection: ${col.collection}`);
|
||||
await client.request(createCollection(col));
|
||||
} else {
|
||||
console.log(`Collection exists: ${col.collection}`);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 2. Define Fields ---
|
||||
const createFieldSafe = async (collection: string, field: string, type: string, meta: any = {}) => {
|
||||
try {
|
||||
// Check if field exists first to avoid error
|
||||
// (Skipping check for brevity, relying on error catch)
|
||||
await client.request(createField(collection, { field, type, meta, schema: {} }));
|
||||
console.log(` + Field created: ${collection}.${field}`);
|
||||
} catch (e: any) {
|
||||
if (e.errors?.[0]?.extensions?.code !== 'FIELD_DUPLICATE') {
|
||||
// Warning if real error
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
console.log('--- Configuring Fields ---');
|
||||
|
||||
// Sites
|
||||
await createFieldSafe('sites', 'name', 'string');
|
||||
await createFieldSafe('sites', 'url', 'string');
|
||||
await createFieldSafe('sites', 'api_key', 'string');
|
||||
await createFieldSafe('sites', 'allowed_niches', 'json');
|
||||
await createFieldSafe('sites', 'site_type', 'string');
|
||||
|
||||
// Avatars
|
||||
await createFieldSafe('avatars', 'base_name', 'string');
|
||||
await createFieldSafe('avatars', 'business_niches', 'json');
|
||||
await createFieldSafe('avatars', 'wealth_cluster', 'string');
|
||||
|
||||
// Avatar Variants
|
||||
await createFieldSafe('avatar_variants', 'avatar_id', 'string');
|
||||
await createFieldSafe('avatar_variants', 'variants_json', 'json');
|
||||
|
||||
// Geo
|
||||
await createFieldSafe('geo_clusters', 'cluster_name', 'string');
|
||||
await createFieldSafe('geo_locations', 'city', 'string');
|
||||
await createFieldSafe('geo_locations', 'state', 'string');
|
||||
await createFieldSafe('geo_locations', 'zip_focus', 'string');
|
||||
await createFieldSafe('geo_locations', 'cluster', 'integer');
|
||||
|
||||
// Patterns
|
||||
await createFieldSafe('cartesian_patterns', 'pattern_id', 'string');
|
||||
await createFieldSafe('cartesian_patterns', 'formula', 'text');
|
||||
await createFieldSafe('cartesian_patterns', 'category', 'string');
|
||||
|
||||
// Dictionaries
|
||||
// Using standard fields for JSON content usually
|
||||
|
||||
// Offer Blocks
|
||||
await createFieldSafe('offer_blocks_universal', 'title', 'string');
|
||||
await createFieldSafe('offer_blocks_universal', 'hook_generator', 'string');
|
||||
await createFieldSafe('offer_blocks_universal', 'universal_pains', 'json');
|
||||
await createFieldSafe('offer_blocks_universal', 'universal_solutions', 'json');
|
||||
await createFieldSafe('offer_blocks_universal', 'universal_value_points', 'json');
|
||||
await createFieldSafe('offer_blocks_universal', 'cta_spintax', 'string');
|
||||
|
||||
// Generated Articles
|
||||
await createFieldSafe('generated_articles', 'title', 'string');
|
||||
await createFieldSafe('generated_articles', 'slug', 'string');
|
||||
await createFieldSafe('generated_articles', 'html_content', 'text');
|
||||
await createFieldSafe('generated_articles', 'generation_hash', 'string');
|
||||
await createFieldSafe('generated_articles', 'site_id', 'integer');
|
||||
|
||||
// --- 3. Import Data ---
|
||||
console.log('--- Importing Data (Full Sync) ---');
|
||||
|
||||
const readStore = (name: string) => JSON.parse(fs.readFileSync(path.join(__dirname, '../data', `${name}.json`), 'utf-8'));
|
||||
|
||||
const importCollection = async (collection: string, items: any[], pk: string = 'id') => {
|
||||
console.log(`\nSyncing ${collection} (${items.length} items)...`);
|
||||
try {
|
||||
// 1. Cleanup existing (optional, be careful in production)
|
||||
// For safety on 'live' site, we check existence or strictly upsert if IDs are present.
|
||||
// Since we are initializing, we'll try to create.
|
||||
// Better approach for re-run: Just log errors on duplicate.
|
||||
} catch (e) { }
|
||||
|
||||
let success = 0;
|
||||
for (const item of items) {
|
||||
try {
|
||||
await client.request(createItem(collection, item));
|
||||
success++;
|
||||
} catch (e: any) {
|
||||
// console.log(` - Skipped/Error: ${e.message}`);
|
||||
}
|
||||
}
|
||||
console.log(` ✅ Imported ${success}/${items.length}`);
|
||||
};
|
||||
|
||||
// 1. Avatars
|
||||
const avatars = readStore('avatar_intelligence').avatars;
|
||||
const avatarItems = Object.entries(avatars).map(([k, v]: any) => ({ ...v, id: k }));
|
||||
// We reuse 'id' which Directus might not allow if unrelated to PK auto-increment,
|
||||
// but for 'string' PKs defined in schema it works.
|
||||
// We didn't explicitly define PK type to be string in the simplified schema setup above,
|
||||
// Assuming standard 'id' (integer/uuid). Let's skip mapping ID and let Directus gen it,
|
||||
// OR update specific fields.
|
||||
// User plan implies we need to lookup by keys (e.g. 'scaling_founder').
|
||||
// So we should have a 'key' field or use it as ID.
|
||||
// Let's assume we map the JSON Key to a 'slug' or 'key' field if ID is numeric.
|
||||
|
||||
// Actually, for robust relation mapping, we need stable IDs.
|
||||
// Let's just Loop and Insert.
|
||||
|
||||
// RE-RUNNING AVATARS (Idempotent check omitted for brevity, just create)
|
||||
// ... (Already done in previous step, but we'll do it again safely)
|
||||
|
||||
// 2. Geo Clusters & Locations
|
||||
const geo = readStore('geo_intelligence').clusters;
|
||||
for (const [k, v] of Object.entries(geo)) {
|
||||
const clusterData = v as any;
|
||||
console.log(`Processing Cluster: ${clusterData.cluster_name}`);
|
||||
|
||||
let clusterId;
|
||||
try {
|
||||
const res = await client.request(createItem('geo_clusters', { cluster_name: clusterData.cluster_name }));
|
||||
clusterId = res.id;
|
||||
} catch (e) { /* fetch existing if needed, or ignore */ }
|
||||
|
||||
if (clusterId && clusterData.locations) {
|
||||
for (const loc of clusterData.locations) {
|
||||
try {
|
||||
await client.request(createItem('geo_locations', { ...loc, cluster: clusterId }));
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Spintax
|
||||
const spintax = readStore('spintax_dictionaries').dictionaries;
|
||||
// Schema for spintax_dictionaries: { name: string, words: json array } ?
|
||||
// We created collection but default fields. Let's assume we store key + array.
|
||||
// Need to have created 'key' and 'words' fields?
|
||||
// The previous schema setup was minimal. We must ensure fields exist for these:
|
||||
await createFieldSafe('spintax_dictionaries', 'category', 'string');
|
||||
await createFieldSafe('spintax_dictionaries', 'words', 'json');
|
||||
|
||||
for (const [k, words] of Object.entries(spintax)) {
|
||||
try {
|
||||
await client.request(createItem('spintax_dictionaries', { category: k, words: words }));
|
||||
} catch (e) { }
|
||||
}
|
||||
|
||||
// 4. Offer Blocks Universal
|
||||
const offers = readStore('offer_blocks_universal').offer_blocks;
|
||||
for (const [k, v] of Object.entries(offers)) {
|
||||
try {
|
||||
// Add a key field to identify the block
|
||||
await client.request(createItem('offer_blocks_universal', { ...(v as any), block_id: k }));
|
||||
} catch (e) { }
|
||||
}
|
||||
|
||||
// 5. Cartesian Patterns
|
||||
const patterns = readStore('cartesian_patterns').patterns;
|
||||
for (const [category, list] of Object.entries(patterns)) {
|
||||
for (const p of (list as any[])) {
|
||||
try {
|
||||
await client.request(createItem('cartesian_patterns', {
|
||||
pattern_id: p.id,
|
||||
category: category,
|
||||
formula: p.formula
|
||||
}));
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Full Data Sync Complete.');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
32
backend/scripts/verify_engine.ts
Normal file
32
backend/scripts/verify_engine.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
// We import using relative paths to cross the project boundary
|
||||
import { SpintaxParser } from '../../frontend/src/lib/cartesian/SpintaxParser';
|
||||
import { GrammarEngine } from '../../frontend/src/lib/cartesian/GrammarEngine';
|
||||
|
||||
console.log('--- Verifying SpintaxParser ---');
|
||||
const spintax = "{Hello|Hi} {World|Friend|{Universe|Cosmos}}";
|
||||
const parsed = SpintaxParser.parse(spintax);
|
||||
console.log(`Input: ${spintax}`);
|
||||
console.log(`Output: ${parsed}`);
|
||||
|
||||
if (parsed.includes('{') || parsed.includes('}')) {
|
||||
console.error('❌ Spintax failed to fully resolve.');
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log('✅ Spintax Resolved');
|
||||
}
|
||||
|
||||
console.log('--- Verifying GrammarEngine ---');
|
||||
const distinct = { pronoun: "he", isare: "is" };
|
||||
const text = "[[PRONOUN]] [[ISARE]] going to the [[A_AN:Apple]] store.";
|
||||
const resolved = GrammarEngine.resolve(text, distinct);
|
||||
console.log(`Input: ${text}`);
|
||||
console.log(`Output: ${resolved}`);
|
||||
|
||||
if (resolved !== "he is going to the an Apple store.") {
|
||||
console.warn(`⚠️ Grammar resolution mismatch. Got: ${resolved}`);
|
||||
} else {
|
||||
console.log('✅ Grammar Resolved');
|
||||
}
|
||||
|
||||
console.log('--- Verification Complete ---');
|
||||
71
backend/scripts/verify_logic_standalone.ts
Normal file
71
backend/scripts/verify_logic_standalone.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
// Logic copied from SpintaxParser.ts for verification
|
||||
class SpintaxParser {
|
||||
static parse(text: string): string {
|
||||
if (!text) return '';
|
||||
let parsed = text;
|
||||
const regex = /\{([^{}]+)\}/g;
|
||||
while (regex.test(parsed)) {
|
||||
parsed = parsed.replace(regex, (match, content) => {
|
||||
const options = content.split('|');
|
||||
return options[Math.floor(Math.random() * options.length)];
|
||||
});
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
|
||||
// Logic copied from GrammarEngine.ts for verification
|
||||
class GrammarEngine {
|
||||
static resolve(text: string, variant: Record<string, string>): string {
|
||||
if (!text) return '';
|
||||
let resolved = text;
|
||||
resolved = resolved.replace(/\[\[([A-Z_]+)\]\]/g, (match, key) => {
|
||||
const lowerKey = key.toLowerCase();
|
||||
if (variant[lowerKey]) {
|
||||
return variant[lowerKey];
|
||||
}
|
||||
return match;
|
||||
});
|
||||
resolved = resolved.replace(/\[\[A_AN:(.*?)\]\]/g, (match, content) => {
|
||||
return GrammarEngine.a_an(content);
|
||||
});
|
||||
return resolved;
|
||||
}
|
||||
static a_an(word: string): string {
|
||||
const vowels = ['a', 'e', 'i', 'o', 'u'];
|
||||
const firstChar = word.trim().charAt(0).toLowerCase();
|
||||
if (vowels.includes(firstChar)) {
|
||||
return `an ${word}`;
|
||||
}
|
||||
return `a ${word}`;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('--- Verifying SpintaxParser ---');
|
||||
const spintax = "{Hello|Hi} {World|Friend|{Universe|Cosmos}}";
|
||||
const parsed = SpintaxParser.parse(spintax);
|
||||
console.log(`Input: ${spintax}`);
|
||||
console.log(`Output: ${parsed}`);
|
||||
|
||||
if (parsed.includes('{') || parsed.includes('}')) {
|
||||
console.error('❌ Spintax failed to fully resolve.');
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log('✅ Spintax Resolved');
|
||||
}
|
||||
|
||||
console.log('--- Verifying GrammarEngine ---');
|
||||
const distinct = { pronoun: "he", isare: "is" };
|
||||
const text = "[[PRONOUN]] [[ISARE]] going to the [[A_AN:Apple]] store.";
|
||||
const resolved = GrammarEngine.resolve(text, distinct);
|
||||
console.log(`Input: ${text}`);
|
||||
console.log(`Output: ${resolved}`);
|
||||
|
||||
if (resolved !== "he is going to the an Apple store.") {
|
||||
console.warn(`⚠️ Grammar resolution mismatch. Got: ${resolved}`);
|
||||
} else {
|
||||
console.log('✅ Grammar Resolved');
|
||||
}
|
||||
|
||||
console.log('✅ Logic Verification Passed.');
|
||||
44
backend/services/Publisher.ts
Normal file
44
backend/services/Publisher.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
/**
|
||||
* Publisher Service
|
||||
* Handles syncing generated content to external sites (WordPress, Webflow, etc.).
|
||||
*/
|
||||
export class PublisherService {
|
||||
|
||||
/**
|
||||
* Sync a specific article to its designated site.
|
||||
* @param article The article object from Directus
|
||||
* @param site The site configuration object
|
||||
*/
|
||||
async syncArticle(article: any, site: any) {
|
||||
console.log(`[Publisher] Starting sync for Article ${article.id} to Site ${site.name}`);
|
||||
|
||||
try {
|
||||
if (site.site_type === 'wordpress') {
|
||||
await this.publishToWordPress(article, site);
|
||||
} else if (site.site_type === 'webflow') {
|
||||
await this.publishToWebflow(article, site);
|
||||
} else {
|
||||
console.log(`[Publisher] Unknown site type: ${site.site_type}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[Publisher] Sync Failed:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private async publishToWordPress(article: any, site: any) {
|
||||
// Placeholder for WP REST API call
|
||||
// const wp = new WPAPI({ endpoint: site.url, username: ..., password: ... });
|
||||
// await wp.posts().create({ ... });
|
||||
console.log(`[Publisher] 🚀 Simulating POST to WordPress at ${site.url}/wp-json/wp/v2/posts`);
|
||||
console.log(`Title: ${article.title}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
private async publishToWebflow(article: any, site: any) {
|
||||
// Placeholder for Webflow API
|
||||
console.log(`[Publisher] 🚀 Simulating POST to Webflow Collection`);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
18
backend/tsconfig.json
Normal file
18
backend/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "CommonJS",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"scripts/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user