feat(cc-051): Data Overview platform status page

This commit is contained in:
admin-valentin 2026-08-01 10:09:31 +00:00
parent 56faae7eab
commit c400226479

View file

@ -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<SavedSegment[]>('/v1/segments', { tenantId }),
...opts,
});
const { data: aiRequests = [] } = useQuery({
queryKey: ['data-ai-requests', tenantId],
queryFn: () => apiFetch<AiRequest[]>('/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 (
<div className="max-w-5xl space-y-6">
<div>
<h1 className="font-display text-2xl font-semibold text-ink">Data Overview</h1>
<p className="mt-1 text-sm text-ink-faint">
Starea platformei de date surse, pipeline-uri și capabilități.
</p>
</div>
{/* Platform status */}
<section className="card p-5">
<h2 className="mb-4 text-xs font-semibold uppercase tracking-wider text-ink-faint">
Status platformă
</h2>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
{PLATFORM_STATUS.map((s) => (
<div key={s.label} className="rounded-lg border border-paper-sunken p-3">
<p className="text-xs font-semibold text-ink">{s.label}</p>
<p className={`mt-0.5 font-mono text-[11px] font-semibold ${s.color}`}>{s.value}</p>
<p className="mt-0.5 text-[10px] text-ink-line">{s.desc}</p>
</div>
))}
</div>
</section>
{/* Counters from live data */}
<div className="grid grid-cols-3 gap-4">
<div className="card p-5">
<p className="text-xs font-medium text-ink-faint">Segmente salvate</p>
<p className="mt-1 font-display text-2xl font-semibold text-ink">{segments.length}</p>
<Link href={`${B}/segments`} className="mt-1 text-xs text-bronze-deep hover:underline">
Gestionează
</Link>
</div>
<div className="card p-5">
<p className="text-xs font-medium text-ink-faint">Cereri AI procesate</p>
<p className="mt-1 font-display text-2xl font-semibold text-ink">{aiRequests.length}</p>
<Link href={`${B}/ai/history`} className="mt-1 text-xs text-bronze-deep hover:underline">
Istoric
</Link>
</div>
<div className="card p-5">
<p className="text-xs font-medium text-ink-faint">Companii indexate</p>
<p className="mt-1 font-display text-2xl font-semibold text-ink">147M+</p>
<Link href={`${B}/companies`} className="mt-1 text-xs text-bronze-deep hover:underline">
Caută
</Link>
</div>
</div>
{/* Data modules list */}
<section>
<h2 className="mb-3 text-xs font-semibold uppercase tracking-wider text-ink-faint">
Module de date ({DATA_MODULES.filter((m) => m.status === 'live').length}/{DATA_MODULES.length} live)
</h2>
<ul className="space-y-2">
{DATA_MODULES.map((mod) => (
<li key={mod.label} className="card flex items-center gap-4 px-4 py-3 opacity-70">
<div className="min-w-0 flex-1">
<p className="text-sm font-medium text-ink">{mod.label}</p>
<p className="mt-0.5 text-xs text-ink-faint">{mod.desc}</p>
</div>
<span className="shrink-0 rounded-full bg-paper-sunken px-2 py-0.5 text-[10px] font-medium text-ink-line">
în lucru
</span>
</li>
))}
</ul>
</section>
</div>
);
}