Limits
What’s not in BI
Scope is intentionally narrow — BI is the canvas for analyst-built dashboards over your warehouse, not a Looker / Tableau replacement.
Hard contract — won’t change
- Read-only. Inherited from DB Engine. No widget can write back to the source DB.
- One connection per widget. No cross-connection joins inside a single widget.
Roadmap
These are documented intent — not committed scope. Surface them if they’re blocking you.
- Per-tenant dashboard templates — clone a stock dashboard (“Clinic A/R overview”, “Coverage health”, “ABA panel productivity”) instead of building from scratch.
- Scheduled refresh — auto-refresh on a cron (currently manual / lazy). Plumb through APScheduler or a CronJob worker.
- Cross-filtering — clicking a bar in widget A filters every widget on the same connection. Needs a per-dashboard filter state and a SQL rewriter pass.
- Drill-through — clicking a chart datum opens the underlying rows in a side panel.
- Snapshot dashboards — capture data + spec + layout at a point in time so emails can link to a stable view.
- Per-breakpoint layouts —
lg / md / sm / xs / xxsdistinct positions. Current behaviour is single layout with auto-collapse.
Off the roadmap
- Operational replacement. Use
/admin/coverage,/admin/eligibility,/admin/denials, etc. for the practice’s own purpose-built queues. BI is not the place to rebuild those. - ML / forecasting widgets. Predictive charts are a separate roadmap; BI is descriptive.
- Write-back from widgets. Read-only by contract.
- Custom chart kinds. Recharts kinds are the locked list — line / area / bar / stacked-bar / donut / scatter / kpi / table. Adding a kind is a contract change; surface the request.
Performance caps
- Per dashboard: ~20 widgets comfortable; beyond that, refresh-all parallelism hits warehouse rate limits.
- Per widget result: 100k rows max (inherited from
db.run_sql). - Per widget refresh: 30s statement timeout (inherited).