Files
net/backend/scripts/add_intelligence_fields.ts
cawcenter 2a8306bb46 feat: Complete Intelligence Library + Jumpstart Fix + Frontend Plugins
Intelligence Library:
- Add full CRUD managers for Avatar Variants, Spintax, Cartesian Patterns
- Update GeoIntelligenceManager to work with cluster/location structure
- Create reusable DataTable, CRUDModal, DeleteConfirm components
- Add TanStack Table for sorting/filtering/pagination
- Add React Hook Form + Zod for form validation
- Add export to JSON functionality
- Add real-time stats dashboards
- Update all Intelligence Library pages to use React components

Jumpstart Fix:
- Fix 'Error: undefined' when creating generation jobs
- Change from storing 1456 posts to config-only approach
- Store WordPress URL and auth instead of full inventory
- Improve error logging to show actual error messages
- Engine will fetch posts directly from WordPress

Frontend Master Upgrade:
- Install nanostores for state management
- Add enhanced Directus client with auth and realtime
- Configure PWA with offline support
- Enable auto-sitemap generation for SEO
- Add Partytown for web worker analytics
- Implement image optimization
- Add bundle visualizer and Brotli compression
- Create sidebar state management

Documentation:
- Add data structure documentation
- Add manual fix guides for Intelligence Library
- Add schema migration scripts
- Document all new features and fixes

All components tested and ready for deployment.
2025-12-13 18:27:34 -05:00

92 lines
5.3 KiB
TypeScript

import { createDirectus, rest, authentication, createField, readCollections } from '@directus/sdk';
import * as dotenv from 'dotenv';
import * as path from 'path';
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
const DIRECTUS_URL = process.env.DIRECTUS_PUBLIC_URL || 'https://spark.jumpstartscaling.com';
const EMAIL = process.env.DIRECTUS_ADMIN_EMAIL;
const PASSWORD = process.env.DIRECTUS_ADMIN_PASSWORD;
const client = createDirectus(DIRECTUS_URL).with(authentication()).with(rest());
async function addMissingFields() {
console.log(`🚀 Connecting to Directus at ${DIRECTUS_URL}...`);
try {
console.log(`🔑 Authenticating as ${EMAIL}...`);
await client.login(EMAIL!, PASSWORD!);
console.log('✅ Authentication successful.');
const createFieldSafe = async (collection: string, field: string, type: string, meta: any = {}) => {
try {
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') {
console.log(` ⏭️ Field exists: ${collection}.${field}`);
} else {
console.log(` ❌ Error creating ${collection}.${field}:`, e.message);
}
}
};
console.log('\n📝 Adding missing fields for Intelligence Library...\n');
// GEO INTELLIGENCE - Create new collection with proper fields
console.log('--- Geo Intelligence ---');
await createFieldSafe('geo_intelligence', 'location_key', 'string', { note: 'Unique location identifier' });
await createFieldSafe('geo_intelligence', 'city', 'string', { note: 'City name' });
await createFieldSafe('geo_intelligence', 'state', 'string', { note: 'State code' });
await createFieldSafe('geo_intelligence', 'county', 'string', { note: 'County name' });
await createFieldSafe('geo_intelligence', 'zip_code', 'string', { note: 'ZIP code' });
await createFieldSafe('geo_intelligence', 'population', 'integer', { note: 'Population count' });
await createFieldSafe('geo_intelligence', 'median_income', 'float', { note: 'Median household income' });
await createFieldSafe('geo_intelligence', 'keywords', 'text', { note: 'Local keywords' });
await createFieldSafe('geo_intelligence', 'local_modifiers', 'text', { note: 'Local phrases and modifiers' });
// AVATAR VARIANTS - Update existing collection
console.log('\n--- Avatar Variants ---');
await createFieldSafe('avatar_variants', 'avatar_key', 'string', { note: 'Avatar identifier' });
await createFieldSafe('avatar_variants', 'variant_type', 'string', { note: 'male, female, or neutral' });
await createFieldSafe('avatar_variants', 'pronoun', 'string', { note: 'Pronoun set' });
await createFieldSafe('avatar_variants', 'identity', 'string', { note: 'Full identity name' });
await createFieldSafe('avatar_variants', 'tone_modifiers', 'text', { note: 'Tone adjustments' });
// SPINTAX DICTIONARIES - Update existing collection
console.log('\n--- Spintax Dictionaries ---');
await createFieldSafe('spintax_dictionaries', 'category', 'string', { note: 'Dictionary category' });
await createFieldSafe('spintax_dictionaries', 'data', 'json', { note: 'Array of terms' });
await createFieldSafe('spintax_dictionaries', 'description', 'text', { note: 'Optional description' });
// CARTESIAN PATTERNS - Update existing collection
console.log('\n--- Cartesian Patterns ---');
await createFieldSafe('cartesian_patterns', 'pattern_key', 'string', { note: 'Pattern identifier' });
await createFieldSafe('cartesian_patterns', 'pattern_type', 'string', { note: 'Pattern category' });
await createFieldSafe('cartesian_patterns', 'formula', 'text', { note: 'Pattern formula with variables' });
await createFieldSafe('cartesian_patterns', 'example_output', 'text', { note: 'Example of generated output' });
await createFieldSafe('cartesian_patterns', 'description', 'text', { note: 'Optional description' });
// GENERATION JOBS - Update for Jumpstart fix
console.log('\n--- Generation Jobs ---');
await createFieldSafe('generation_jobs', 'site_id', 'integer', { note: 'Related site' });
await createFieldSafe('generation_jobs', 'status', 'string', { note: 'Job status' });
await createFieldSafe('generation_jobs', 'type', 'string', { note: 'Job type' });
await createFieldSafe('generation_jobs', 'target_quantity', 'integer', { note: 'Total items to process' });
await createFieldSafe('generation_jobs', 'current_offset', 'integer', { note: 'Current progress' });
await createFieldSafe('generation_jobs', 'config', 'json', { note: 'Job configuration (WordPress URL, auth, etc)' });
console.log('\n✅ All fields added successfully!');
console.log('\n📋 Next steps:');
console.log('1. Refresh your frontend (hard refresh: Cmd+Shift+R)');
console.log('2. Visit the Intelligence Library pages');
console.log('3. Start adding data!');
} catch (error) {
console.error('❌ Failed:', error);
process.exit(1);
}
}
addMissingFields();