diff --git a/src/app/dashboard/data/page.tsx b/src/app/dashboard/data/page.tsx new file mode 100644 index 0000000..8f01011 --- /dev/null +++ b/src/app/dashboard/data/page.tsx @@ -0,0 +1,130 @@ +'use client'; + +import Link from 'next/link'; +import { useQuery } from '@tanstack/react-query'; +import { apiFetch } from '../../../lib/api'; +import type { SavedSegment, AiRequest } from '../../../lib/api'; +import { useSession } from '../../../components/session-provider'; + +const B = '/dashboard'; + +interface DataModule { + label: string; + href: string; + status: 'live' | 'planned' | 'a3' | 'a4'; + desc: string; + count?: number; +} + +export default function DataOverviewPage() { + const { activeTenant } = useSession(); + const tenantId = activeTenant?.tenantId ?? ''; + const opts = { enabled: Boolean(tenantId), staleTime: 60_000 }; + + const { data: segments = [] } = useQuery({ + queryKey: ['data-segments', tenantId], + queryFn: () => apiFetch('/v1/segments', { tenantId }), + ...opts, + }); + const { data: aiRequests = [] } = useQuery({ + queryKey: ['data-ai-requests', tenantId], + queryFn: () => apiFetch('/v1/ai-requests?limit=200', { tenantId }), + ...opts, + }); + + const DATA_MODULES: DataModule[] = [ + { label: 'Dataset Registry', href: `${B}/data/datasets`, status: 'planned', desc: 'Licență, scop permis, jurisdicție, PII, retenție, opt-out, checksum.' }, + { label: 'Ingestion Jobs', href: `${B}/data/ingestion`, status: 'planned', desc: 'Pipeline Apollo existent pe server — monitorizare din UI în lucru.' }, + { label: 'Data Quality', href: `${B}/data/quality`, status: 'planned', desc: 'Completitudine, duplicate, rejects, quarantine.' }, + { label: 'Entity Resolution', href: `${B}/data/entities`, status: 'planned', desc: 'Legarea reversibilă de entități — fără merge distructiv.' }, + { label: 'Companies Database', href: `${B}/data/companies`, status: 'planned', desc: 'Companii canonice cu surse și confidence.' }, + { label: 'Contacts Database', href: `${B}/data/contacts`, status: 'planned', desc: 'Contacte canonice cu opt-out și date permise.' }, + { label: 'Enrichment', href: `${B}/data/enrichment`, status: 'planned', desc: 'Crawler + enrichment rulează pe server — UI în lucru.' }, + { label: 'Segments Builder', href: `${B}/data/segments`, status: 'planned', desc: 'Builder de segmente admin cu preview și export control.' }, + { label: 'Data Sources', href: `${B}/data/sources`, status: 'planned', desc: 'Inventar surse cu provenance.' }, + { label: 'Compliance', href: `${B}/data/compliance`, status: 'planned', desc: 'Temei legal, retenție, suppression list.' }, + { label: 'Export Control', href: `${B}/data/export-control`, status: 'planned', desc: 'Exporturi bulk auditate și limitate.' }, + ]; + + const PLATFORM_STATUS = [ + { label: 'ClickHouse', value: '147M+ rânduri', color: 'text-signal-ok', desc: 'sursa B2B principală' }, + { label: 'Apollo Pipeline', value: 'live', color: 'text-signal-ok', desc: 'ingestie continuă' }, + { label: 'Intelligence API', value: 'live', color: 'text-signal-ok', desc: 'company search + contact match' }, + { label: 'Hermes AI', value: 'live', color: 'text-signal-ok', desc: 'orchestrare AI cu learning per tenant' }, + { label: 'Memory Graph', value: 'live', color: 'text-signal-ok', desc: 'Apache AGE — facts/entities/relations' }, + { label: 'Paperless-ngx', value: 'server', color: 'text-signal-warn', desc: 'rulează, neconectat la ceo-api' }, + { label: 'ERPNext', value: 'server', color: 'text-signal-warn', desc: 'rulează, adapter în lucru' }, + ]; + + return ( +
+
+

Data Overview

+

+ Starea platformei de date — surse, pipeline-uri și capabilități. +

+
+ + {/* Platform status */} +
+

+ Status platformă +

+
+ {PLATFORM_STATUS.map((s) => ( +
+

{s.label}

+

{s.value}

+

{s.desc}

+
+ ))} +
+
+ + {/* Counters from live data */} +
+
+

Segmente salvate

+

{segments.length}

+ + Gestionează → + +
+
+

Cereri AI procesate

+

{aiRequests.length}

+ + Istoric → + +
+
+

Companii indexate

+

147M+

+ + Caută → + +
+
+ + {/* Data modules list */} +
+

+ Module de date ({DATA_MODULES.filter((m) => m.status === 'live').length}/{DATA_MODULES.length} live) +

+
    + {DATA_MODULES.map((mod) => ( +
  • +
    +

    {mod.label}

    +

    {mod.desc}

    +
    + + în lucru + +
  • + ))} +
+
+
+ ); +}