# Reporting and analytics scaling

**Principle:** OLTP stays fast; heavy read models and analytics use **isolation** (replicas, snapshots, exports, warehouses).

---

## 1. Export scalability rules

1. **One export row per request** — track status; avoid duplicate concurrent exports for the same logical report where product allows dedupe.
2. **Handlers** must stream or chunk reads; never `->get()` an entire tenant’s transactional history without bounds.
3. **After-commit dispatch** — avoid queue work for exports that will never exist in DB (see export manager stabilization).
4. **Tenant context** — job must carry `tenantId` and enter `TenantContext` in `handle()`.

---

## 2. Reporting isolation strategies

| Tier | Use case | Latency |
|------|----------|---------|
| In-app dashboards | Operational counts | Seconds (cache-backed) |
| Admin business metrics | Cross-tenant aggregates | Minutes acceptable |
| BI / data warehouse | Finance, HR analytics | Hours (ETL) |
| Payroll finalized snapshots | Compliance / payslip support | Immutable boundary |

**Avoid:** running ad-hoc BI queries on production primary during peak local business hours without guardrails.

---

## 3. Snapshot-based analytics recommendations

- **Payroll:** finalized periods + `payroll_employee_snapshots` are the canonical “point-in-time” inputs for payroll analytics.
- **Attendance:** daily aggregates (rolled up per tenant/day) reduce scan cost if dashboard metrics become hot.
- **Subscriptions / billing audit:** `platform_audit_events` supports operational analytics; consider read-optimized rollups if volume grows.

---

## 4. Operational metrics page

- Internal `BusinessMetricsService` provides coarse counters; not a substitute for Prometheus/Grafana but safe for v1 ops reviews.

---

## References

- `app/Modules/Admin/Operations/Services/BusinessMetricsService.php`
- `app/Modules/Exports/Jobs/ExportProcessorJob.php`
- [ADR 0002: Immutable payroll snapshots](../architecture/adr/0002-immutable-payroll-snapshots.md)
