Implement Stage 3: Enhance content metadata and validation features

- Added entity metadata fields to the Tasks model, including entity_type, taxonomy, and cluster_role.
- Updated CandidateEngine to prioritize content relevance based on cluster mappings.
- Introduced metadata completeness scoring in ContentAnalyzer.
- Enhanced validation services to check for entity type and mapping completeness.
- Updated frontend components to display and validate new metadata fields.
- Implemented API endpoints for content validation and metadata persistence.
- Migrated existing data to populate new metadata fields for Tasks and Content.
This commit is contained in:
IGNY8 VPS (Salman)
2025-11-19 19:21:30 +00:00
parent 38f6026e73
commit bae9ea47d8
33 changed files with 2388 additions and 73 deletions

View File

@@ -1,21 +1,61 @@
/**
* Step 1: Business Details
* Site type selection, hosting detection, brand inputs
*
* Supports both:
* - Stage 1 Wizard: data, onChange, metadata, selectedSectors
* - Stage 2 Workflow: blueprintId
*/
import { useState, useEffect } from 'react';
import { useBuilderWorkflowStore } from '../../../../store/builderWorkflowStore';
import { fetchSiteBlueprintById, updateSiteBlueprint, SiteBlueprint } from '../../../../services/api';
import { Card, CardDescription, CardTitle } from '../../../../components/ui/card';
import ButtonWithTooltip from '../../../../components/ui/button/ButtonWithTooltip';
import Input from '../../../../components/ui/input/Input';
import Input from '../../../../components/form/input/InputField';
import Alert from '../../../../components/ui/alert/Alert';
import { Loader2 } from 'lucide-react';
import type { BuilderFormData, SiteBuilderMetadata } from '../../../../types/siteBuilder';
interface BusinessDetailsStepProps {
blueprintId: number;
// Stage 1 Wizard props
interface Stage1Props {
data: BuilderFormData;
onChange: <K extends keyof BuilderFormData>(key: K, value: BuilderFormData[K]) => void;
metadata?: SiteBuilderMetadata;
selectedSectors?: Array<{ id: number; name: string }>;
blueprintId?: never;
}
export default function BusinessDetailsStep({ blueprintId }: BusinessDetailsStepProps) {
// Stage 2 Workflow props
interface Stage2Props {
blueprintId: number;
data?: never;
onChange?: never;
metadata?: never;
selectedSectors?: never;
}
type BusinessDetailsStepProps = Stage1Props | Stage2Props;
export function BusinessDetailsStep(props: BusinessDetailsStepProps) {
// Check if this is Stage 2 (has blueprintId)
const isStage2 = 'blueprintId' in props && props.blueprintId !== undefined;
// Stage 2 implementation
if (isStage2) {
return <BusinessDetailsStepStage2 blueprintId={props.blueprintId} />;
}
// Stage 1 implementation
return <BusinessDetailsStepStage1
data={props.data}
onChange={props.onChange}
metadata={props.metadata}
selectedSectors={props.selectedSectors}
/>;
}
// Stage 2 Workflow Component
function BusinessDetailsStepStage2({ blueprintId }: { blueprintId: number }) {
const { context, completeStep, loading } = useBuilderWorkflowStore();
const [blueprint, setBlueprint] = useState<SiteBlueprint | null>(null);
const [formData, setFormData] = useState({
@@ -154,3 +194,88 @@ export default function BusinessDetailsStep({ blueprintId }: BusinessDetailsStep
</Card>
);
}
// Stage 1 Wizard Component
function BusinessDetailsStepStage1({
data,
onChange,
metadata,
selectedSectors
}: {
data: BuilderFormData;
onChange: <K extends keyof BuilderFormData>(key: K, value: BuilderFormData[K]) => void;
metadata?: SiteBuilderMetadata;
selectedSectors?: Array<{ id: number; name: string }>;
}) {
return (
<Card variant="surface" padding="lg">
<div className="space-y-4">
<div>
<p className="text-xs uppercase tracking-wider text-gray-500 dark:text-white/50">
Business context
</p>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
Business details
</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">
These details help the AI understand what kind of site we are building.
</p>
</div>
<div>
<label className="block text-sm font-medium mb-2">Site name</label>
<Input
value={data.siteName}
onChange={(e) => onChange('siteName', e.target.value)}
placeholder="Acme Robotics"
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium mb-2">Business type</label>
<Input
value={data.businessType}
onChange={(e) => onChange('businessType', e.target.value)}
placeholder="B2B SaaS platform"
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">Industry</label>
<Input
value={data.industry}
onChange={(e) => onChange('industry', e.target.value)}
placeholder="Supply chain automation"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium mb-2">Target audience</label>
<Input
value={data.targetAudience}
onChange={(e) => onChange('targetAudience', e.target.value)}
placeholder="Operations leaders at fast-scaling eCommerce brands"
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">Hosting preference</label>
<select
value={data.hostingType}
onChange={(e) => onChange('hostingType', e.target.value as BuilderFormData['hostingType'])}
className="w-full px-3 py-2 border rounded-md"
>
<option value="igny8_sites">IGNY8 Sites</option>
<option value="wordpress">WordPress</option>
<option value="shopify">Shopify</option>
<option value="multi">Multiple destinations</option>
</select>
</div>
</div>
</Card>
);
}
// Also export as default for WorkflowWizard compatibility
export default BusinessDetailsStep;