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

@@ -204,6 +204,94 @@ export const createContentPageConfig = (
<SourceBadge source={(row.source as ContentSource) || 'igny8'} />
),
},
// Stage 3: Metadata columns
{
key: 'entity_type',
label: 'Entity Type',
sortable: true,
sortField: 'entity_type',
width: '120px',
defaultVisible: true,
render: (value: string, row: Content) => {
const entityType = value || row.entity_type;
if (!entityType) {
return <span className="text-gray-400 dark:text-gray-500">-</span>;
}
const typeLabels: Record<string, string> = {
'blog_post': 'Blog Post',
'article': 'Article',
'product': 'Product',
'service': 'Service',
'taxonomy': 'Taxonomy',
'page': 'Page',
};
return (
<Badge color="info" size="sm" variant="light">
{typeLabels[entityType] || entityType}
</Badge>
);
},
},
{
key: 'cluster',
label: 'Cluster',
sortable: false,
width: '150px',
defaultVisible: true,
render: (_value: any, row: Content) => {
const clusterName = row.cluster_name;
if (!clusterName) {
return <span className="text-gray-400 dark:text-gray-500">-</span>;
}
return (
<Badge color="primary" size="sm" variant="light">
{clusterName}
</Badge>
);
},
},
{
key: 'cluster_role',
label: 'Role',
sortable: true,
sortField: 'cluster_role',
width: '100px',
defaultVisible: false,
render: (value: string, row: Content) => {
const role = value || row.cluster_role;
if (!role) {
return <span className="text-gray-400 dark:text-gray-500">-</span>;
}
const roleColors: Record<string, 'primary' | 'success' | 'warning'> = {
'hub': 'primary',
'supporting': 'success',
'attribute': 'warning',
};
return (
<Badge color={roleColors[role] || 'primary'} size="sm" variant="light">
{role.charAt(0).toUpperCase() + role.slice(1)}
</Badge>
);
},
},
{
key: 'taxonomy',
label: 'Taxonomy',
sortable: false,
width: '150px',
defaultVisible: false,
render: (_value: any, row: Content) => {
const taxonomyName = row.taxonomy_name;
if (!taxonomyName) {
return <span className="text-gray-400 dark:text-gray-500">-</span>;
}
return (
<Badge color="purple" size="sm" variant="light">
{taxonomyName}
</Badge>
);
},
},
{
key: 'sync_status',
label: 'Sync Status',
@@ -349,6 +437,21 @@ export const createContentPageConfig = (
{ value: 'publish', label: 'Publish' },
],
},
// Stage 3: Entity type filter
{
key: 'entity_type',
label: 'Entity Type',
type: 'select',
options: [
{ value: '', label: 'All Types' },
{ value: 'blog_post', label: 'Blog Post' },
{ value: 'article', label: 'Article' },
{ value: 'product', label: 'Product' },
{ value: 'service', label: 'Service' },
{ value: 'taxonomy', label: 'Taxonomy' },
{ value: 'page', label: 'Page' },
],
},
{
key: 'source',
label: 'Source',