Converts the analytics dashboard from mocked UI theatre into real data. Every performance chart now aggregates from live deal activity; all 4 report generators produce real rows; PDF/Excel exports work; scheduled reports are cron-ready.
Foundation (Phase A)
- Migration
f7a8b9c0d1e2createsanalytics_snapshots— daily per-(workspace, campaign, channel) rollups with idempotent unique-key upsert backend/services/analytics/snapshot_builder.py— aggregates scheduling deals + marketplace deals, writes buyer spend-side + seller revenue-side rows per dealPOST /analytics/admin/rollup— SA-only cron-compatible endpoint that rebuilds snapshots
Live performance endpoints (Phase B)
All 6 /performance/* endpoints now read from analytics_snapshots:
/performance,/performance/channels,/funnel,/heatmap,/gauges,/waterfall- No more
random.uniform()mocks - All gated with
require_roles(ADVERTISER, AGENCY_ADMIN, SUPER_ADMIN)(previously only/performancewas gated — 5 leaked) /performanceresponse includesprevious_periodsummary for real delta badges
Real report generators (Phase C)
- 4 generators rewritten against snapshot data: campaign performance, cross-channel, attribution (with fallback), custom KPI
POST /reports/{id}/generatereturns populateddataand updatessize_bytes,row_count- Attribution falls back to snapshot channel rollup when
attribution_modelsis empty
Exports + scheduling (Phase D)
- PDF via WeasyPrint + Jinja template
backend/templates/analytics_report.html - Excel via
openpyxl(added to requirements) POST /analytics/reports/{id}/exportacceptsformat=csv|pdf|xlsxPOST /admin/analytics/run-scheduled— SA endpoint that picks up daily/weekly/monthly reports due to run, generates them, emails recipients via existingemail_service, advancesnext_run_at
Polish (Phase E)
- Migration
a9b0c1d2e3f4addsformula_json JSONBtocustom_kpisso the KPI formula builder round-trips cleanly GET /analytics/attribution/channel-timeseries— real daily revenue per channel (replaces the fake 3-point synthesized series)- Attribution page uses real
previous_perioddeltas (removes hardcodedpreviousValue * 0.85)
Verification (live)
- Rollup wrote 34 snapshots from existing deals
- Aggregated: 417,300 impressions, ₹24,640 spend
- Advertiser
/performance?dateFrom=2026-04-01&dateTo=2026-04-22returns real numbers - PDF (
%PDF-1.7magic), XLSX (PK..magic), CSV all produce valid bytes
Top-left brand text
Sidebar header changed from Advertise.net to Advertise.Network.
Honest caveats
- Impressions/clicks derived from deal pricing + 2% CTR fallback — no real ad-platform telemetry yet. The
sourcecolumn on snapshots is designed to swap in Meta/Google/TikTok feeds without schema change. - Data is sparse (1 completed scheduling deal in test data) — numbers shown are real but small.
---

