feat: real-time analytics & BI platform (issue #44) - #70
Merged
josueazc merged 23 commits intoJul 29, 2026
Conversation
AnalyticsInput/Query/Scope/Snapshot and every breakdown/series/trend shape, plus AlertRule/AlertBreach, SavedView and ScheduledReportConfig, for issue Velar-Bonds#44's analytics & BI platform.
Three parties across two countries, bonds spanning several statuses, transfers covering the full transfer funnel, and reports spanning on-time/late/missing compliance outcomes — same discipline as fixtures/provenance.ts, so the engine and API can be built and tested with no VELAR database or credentials.
New NotificationType.ANALYTICS_THRESHOLD_BREACHED, delivered through the existing NotificationsService.emit() when an alert rule breaches. Updates NotificationBell's exhaustive label map accordingly.
aggregateByBondStatus/Party/Country and aggregateValueVolume, plus computeTransferFunnel (reusing TRANSFER_LIFECYCLE_STEPS/ TERMINAL_TRANSFER_STATUSES from the provenance work instead of redefining them). No I/O, no Supabase, no Role — same discipline as provenance-engine.ts.
UTC-based day/week/month bucketing (issuance, transfer, and escrow-resolution series) plus generic trend helpers: period-over-period delta, moving average, top-N, and simple threshold anomaly detection.
compliance.ts adapts the existing computeComplianceForPeriods (reports/domain/deadlines.ts) instead of reimplementing deadline logic. alerts.ts evaluates dot-path metric rules against a snapshot, pure and I/O-free. index.ts composes everything into buildAnalyticsSnapshot, applying RBAC scope and query filters without ever importing Role.
Fixture-driven, including empty/single-item/off-path edge cases.
Timeseries/trends use small hand-crafted datasets for exact, hand-verifiable day/week/month bucketing; compliance and alerts use the shared fixture.
Covers applyScope/applyQueryFilters and buildAnalyticsSnapshot end to end over the fixture, including scoped/unscoped and empty-dataset cases, and asserts the input is never mutated.
The only place in the analytics module that touches SupabaseService.admin.from(...); maps bonds/transfers/reports rows to the @velar/types shapes the pure engine consumes, and filters out legacy free-text reports with no period_year/period_month.
Pure renderSnapshotCsv(snapshot) — fully fixture-testable, unlike the legacy exportTransfersCsv which needs live-joined Supabase rows for seller/buyer names (kept separately for drill-down compatibility).
renderAnalyticsPdf(snapshot) — pure Node, no headless browser. PDF internal object ordering isn't byte-stable across runs, so tests are structural (valid %PDF- header, re-parseable, expected page count) rather than byte-exact snapshots.
ScheduledReportGenerator + SCHEDULED_REPORT_GENERATOR DI token, same interface+stub discipline as the antivirus hook in reports/files/file-scanner.ts. ManualScheduledReportGenerator produces a CSV/PDF summary from the current snapshot on demand — no cron, no vendor.
New tables analytics_saved_views (RLS: owner) and analytics_alert_rules (RLS: tse/admin), reusing the existing set_updated_at() trigger and public.auth_role() helper. Additive only — no existing migration is touched.
resolveScope: TSE/admin see every party, emisor sees only their own party, every other role is forbidden from aggregate analytics. Adds GET /analytics/snapshot, snapshot-based CSV/PDF export, saved-views and alert-rule CRUD (@roles('tse','admin') on privileged config routes), and manual scheduled-report trigger. Legacy bond-detail drill-down routes (price-history/owners/top-bonds) and the named-transfer CSV export are kept working unchanged, moved to /legacy-export.
Service tests cover scope resolution per role, CSV/PDF export scoping, alert evaluation + notification emission, and the scheduled-report stub. Controller tests cover the legacy/new export routes and prove @roles('tse','admin') actually blocks a non-privileged role on the alert-rules routes.
secondary/secondaryContainer/secondaryFixed/tertiary/tertiaryContainer/ primaryFixedDim were declared in tokens.ts and @theme but silently stripped from the compiled CSS by Tailwind v4 (unused-theme-key pruning) since no utility class referenced them — colorVar() resolved them to an empty string, rendering black/invalid in charts. warning was missing entirely. Re-declared in the plain :root/[data-theme='dark'] blocks, which Tailwind never prunes.
First third-party UI dependency in the frontend's design system, chosen over hand-rolling 5 chart types. BarChart/LineChart/AreaChart/ PieChart/StackedBarChart, all wrapped in ChartFrame: role="img" + aria-label, a screen-reader-only <table> fallback with the same data, and a shared chartTooltipStyle/cursor so Recharts' hardcoded-white defaults follow the theme instead.
Lockfile reflects both new dependencies added on this branch (pdf-lib in apps/api, recharts in apps/web).
…ponents
lib/analytics/{query,client}.ts: pure AnalyticsQuery <-> URLSearchParams
(de)serialization (also the shape a saved view stores) and a thin
wrapper over apiFetch/apiDownload — no parallel HTTP client.
components/analytics/: KpiCard, FilterBar (date range/country/party/
status/bucket), SavedViewsMenu, ExportButtons, DrillDownPanel (reuses
the legacy price-history/owners endpoints for real drill-down), and
AnalyticsDashboard composing all of it — shared by both role pages.
Rewrites /tse/analytics in place (KPIs, filters, all 5 chart types, funnel, top-bond drill-down, compliance) and adds /partido/analytics (same component tree, party-scoped by the backend — no party/country filter shown since it's always the caller's own party). Adds the "Análisis" nav link to PartidoShell (TSEShell already had one).
BACKEND.md §10: engine file map, RBAC/data-access design, endpoints, alerting/scheduled-report stub, exports, migration, types, and how to verify locally with no credentials. FRONTEND_GUIDE.md §15: dashboard components, integration, and a colorVar() note for chart colors.
|
@KevinLatino is attempting to deploy a commit to the josueazc's projects Team on Vercel. A member of the Team first needs to authorize it. |
josueazc
added a commit
to mmongee/Velar
that referenced
this pull request
Jul 29, 2026
Resuelve conflictos con main (analytics & BI dashboard, PR Velar-Bonds#70): - apps/api/package.json: conserva pdfkit (exports de reportes) y pdf-lib (PDF de analytics); ambas librerías se usan en módulos distintos. - packages/types/types/*.d.ts: regenerados con tsc desde el src ya fusionado (ReportStatus incluye 'revisado' y 'pendiente_segunda_aprobacion'). - package-lock.json: regenerado con npm install (pdfkit, @types/pdfkit, fast-check + deps de analytics de main). Verificado: typecheck de api OK; jest src/reports (126) y src/analytics (97) en verde.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary Closes #44
Closes #44 — real-time analytics & BI platform: a pure aggregation engine over bonds/transfers/reports, time-series/trend analysis, per-party/per-country breakdowns with drill-down, saved views, threshold alerting, scheduled-report generation, and CSV/PDF export, with RBAC and an accessible dashboard UI.
Architecture mirrors the provenance engine: a pure, fixture-tested engine (
apps/api/src/analytics/engine/) with zero I/O, isolated Supabase access inAnalyticsDataService, and RBAC scoping resolved before the engine ever runs (TSE/admin see everything,emisorsees only their own party, no other role has aggregate-analytics access).computeComplianceForPeriods, doesn't reimplement it), and dot-path threshold alerting.GET /analytics/snapshot, snapshot-based CSV/PDF export (pdf-lib), saved-views CRUD, alert-rule CRUD + evaluation (emits notifications via the existingNotificationsService), and a manual scheduled-report trigger behind an interface+stub (no cron/vendor). Legacy bond-detail drill-down routes are kept working unchanged.analytics_saved_views+analytics_alert_rules, additive only./tse/analyticsrewritten, new/partido/analytics) — KPIs, 5 chart types (Recharts, the frontend's first third-party UI dependency), filter bar, drill-down, saved views, CSV/PDF export. Every chart ships an accessible<table>fallback +aria-label.secondary,tertiary,warning, etc.) were silently dropped from the compiled CSS by Tailwind's unused-theme-key pruning, since nothing had exercised them viacolorVar()before this PR's charts.Test plan
npx jestinapps/api— 238 tests (engine is pure/fixture-driven; service/controller tests mockSupabaseService/NotificationsServiceand prove RBAC, alert emission, and export-format validation)npx jestinapps/web— 41 testsnpm run buildandnpx tsc --noEmitpass in both workspaces, no live VELAR credentials requirednpx eslint .— 0 errors in both workspaces