feat(weeks2-3): data ingestion, geospatial launcher, intelligence endpoints
This commit is contained in:
166
src/lib/data/dataValidator.ts
Normal file
166
src/lib/data/dataValidator.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* Data Validation Schemas for God Mode
|
||||
* Uses Zod for runtime type safety
|
||||
*/
|
||||
|
||||
// ============================================================
|
||||
// INGESTION PAYLOAD SCHEMA
|
||||
// ============================================================
|
||||
|
||||
export const IngestionPayloadSchema = z.object({
|
||||
data: z.string().min(1, 'Data cannot be empty'),
|
||||
format: z.enum(['csv', 'json']),
|
||||
tableName: z.string()
|
||||
.regex(/^[a-zA-Z0-9_]+$/, 'Table name must be alphanumeric with underscores only')
|
||||
.min(1, 'Table name required'),
|
||||
columnMapping: z.record(z.string(), z.string()).optional(),
|
||||
validateOnly: z.boolean().optional().default(false)
|
||||
});
|
||||
|
||||
export type IngestionPayload = z.infer<typeof IngestionPayloadSchema>;
|
||||
|
||||
// ============================================================
|
||||
// TARGET ROW SCHEMAS (Flexible for different data types)
|
||||
// ============================================================
|
||||
|
||||
// Basic target schema (city-based content)
|
||||
export const CityTargetSchema = z.object({
|
||||
city_name: z.string().min(1),
|
||||
state: z.string().length(2).optional(),
|
||||
county: z.string().optional(),
|
||||
lat: z.number().min(-90).max(90).optional(),
|
||||
lng: z.number().min(-180).max(180).optional(),
|
||||
population: z.number().optional(),
|
||||
zip: z.string().optional()
|
||||
});
|
||||
|
||||
// Competitor URL target
|
||||
export const CompetitorTargetSchema = z.object({
|
||||
url: z.string().url(),
|
||||
domain: z.string(),
|
||||
industry: z.string().optional(),
|
||||
target_keywords: z.array(z.string()).optional()
|
||||
});
|
||||
|
||||
// Generic flexible target (catchall)
|
||||
export const GenericTargetSchema = z.record(z.string(), z.union([
|
||||
z.string(),
|
||||
z.number(),
|
||||
z.boolean(),
|
||||
z.null()
|
||||
]));
|
||||
|
||||
// ============================================================
|
||||
// GENERATION JOB SCHEMAS
|
||||
// ============================================================
|
||||
|
||||
export const GenerationJobDataSchema = z.object({
|
||||
job_type: z.enum(['generate_post', 'publish', 'assemble', 'geo_campaign']),
|
||||
site_id: z.string().uuid().optional(),
|
||||
target_data: z.record(z.any()),
|
||||
campaign_id: z.string().uuid().optional(),
|
||||
priority: z.number().min(0).max(10).default(5)
|
||||
});
|
||||
|
||||
export type GenerationJobData = z.infer<typeof GenerationJobDataSchema>;
|
||||
|
||||
// ============================================================
|
||||
// GEOSPATIAL SCHEMAS
|
||||
// ============================================================
|
||||
|
||||
export const GeoPointSchema = z.tuple([z.number(), z.number()]); // [lat, lng]
|
||||
|
||||
export const GeoBoundarySchema = z.object({
|
||||
type: z.literal('Polygon'),
|
||||
coordinates: z.array(z.array(GeoPointSchema))
|
||||
});
|
||||
|
||||
export const GeoCampaignSchema = z.object({
|
||||
boundary: GeoBoundarySchema,
|
||||
campaign_type: z.enum(['local_article', 'service_area', 'competitor_targeting']),
|
||||
density: z.enum(['low', 'medium', 'high', 'insane']).default('medium'),
|
||||
template_id: z.string().uuid().optional(),
|
||||
site_id: z.string().uuid(),
|
||||
target_count: z.number().min(1).max(100000).optional()
|
||||
});
|
||||
|
||||
export type GeoCampaign = z.infer<typeof GeoCampaignSchema>;
|
||||
|
||||
// ============================================================
|
||||
// PROMPT TESTING SCHEMA
|
||||
// ============================================================
|
||||
|
||||
export const PromptTestSchema = z.object({
|
||||
prompt: z.string().min(10, 'Prompt too short'),
|
||||
variables: z.record(z.string(), z.string()).default({}),
|
||||
model: z.enum(['gpt-4', 'gpt-4-turbo', 'gpt-3.5-turbo', 'claude-3-opus']).default('gpt-4'),
|
||||
max_tokens: z.number().min(100).max(8000).default(1000),
|
||||
temperature: z.number().min(0).max(2).default(0.7)
|
||||
});
|
||||
|
||||
export type PromptTest = z.infer<typeof PromptTestSchema>;
|
||||
|
||||
// ============================================================
|
||||
// SPINTAX VALIDATION SCHEMA
|
||||
// ============================================================
|
||||
|
||||
export const SpintaxPatternSchema = z.object({
|
||||
pattern: z.string().min(1),
|
||||
validate_recursion: z.boolean().default(true),
|
||||
max_depth: z.number().min(1).max(10).default(3)
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// SYSTEM CONFIG SCHEMA
|
||||
// ============================================================
|
||||
|
||||
export const SystemConfigSchema = z.object({
|
||||
throttle_delay_ms: z.number().min(0).max(10000).default(0),
|
||||
max_concurrency: z.number().min(1).max(1000).default(128),
|
||||
max_cost_per_hour: z.number().min(0).max(10000).default(100),
|
||||
enable_auto_throttle: z.boolean().default(true),
|
||||
memory_threshold_pct: z.number().min(50).max(99).default(90)
|
||||
});
|
||||
|
||||
export type SystemConfig = z.infer<typeof SystemConfigSchema>;
|
||||
|
||||
// ============================================================
|
||||
// HELPER FUNCTIONS
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Validate and parse ingestion payload
|
||||
*/
|
||||
export function validateIngestionPayload(payload: unknown): IngestionPayload {
|
||||
return IngestionPayloadSchema.parse(payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate city target data
|
||||
*/
|
||||
export function validateCityTarget(data: unknown) {
|
||||
return CityTargetSchema.parse(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate generation job data
|
||||
*/
|
||||
export function validateJobData(data: unknown): GenerationJobData {
|
||||
return GenerationJobDataSchema.parse(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate geospatial campaign
|
||||
*/
|
||||
export function validateGeoCampaign(data: unknown): GeoCampaign {
|
||||
return GeoCampaignSchema.parse(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate prompt test data
|
||||
*/
|
||||
export function validatePromptTest(data: unknown) {
|
||||
return PromptTestSchema.parse(data);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { pool } from './db';
|
||||
import { pool } from '../db';
|
||||
|
||||
/**
|
||||
* Migration System for God Mode
|
||||
@@ -90,7 +90,7 @@ export async function getMigrationStatus(): Promise<{
|
||||
`);
|
||||
|
||||
return {
|
||||
tables: result.rows.map(r => r.table_name)
|
||||
tables: result.rows.map((r: { table_name: string }) => r.table_name)
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user