# TrackGo Report Engine Config-driven reporting for `trackgo-be` (`src/modules/reports`) and `trackgo-fe` (`apps/web/src/core/report`). ## Architecture 1. **Report config** — TypeScript object per report (`shared/configs/`). Defines SQL `tableSchema`, columns, filters, and `privilegeKey`. 2. **Query builder** — `ReportQueryBuilder` compiles AG Grid `queryModel` + config into parameterized Drizzle SQL (`db.execute`). 3. **Generic UI** — `ReportProvider` loads configs for a `groupName` and renders one tab per report via `ReportTable` (AG Grid Server-Side Row Model). Persisted engine data: - `report_bookmarks` — saved filters (`FILTER_TABLE`) and table layouts (`TABLE_CONFIG`) Report rows are **never** stored; they are queried live from business tables. ## Groups and privilege keys | Group | `groupName` | Privilege key | Menu path | | --- | --- | --- | --- | | Sales reports | `sales_report` | `SALES.REPORT` | `/app/sales/reports/index` | | Logistics reports | `logistics_report` | `LOGISTICS.REPORT` | `/app/logistics/reports/index` | ## HTTP APIs | Method | Path | Body / query | | --- | --- | --- | | `GET` | `/reports/config` | `groupNames` (array or repeated) | | `POST` | `/reports/data` | `{ groupName, uniqueName, queryModel }` | | `POST` | `/reports/meta` | same as data → `{ totalRow, limit, offset }` | | `GET` | `/report-bookmarks` | list filters (`groupName`, `uniqueName`, `type`, pagination) | | `POST` | `/report-bookmarks` | create bookmark | | `PUT` | `/report-bookmarks/applied/:id` | apply | | `PUT` | `/report-bookmarks/unapplied/:id` | unapply | | `DELETE` | `/report-bookmarks/:id` | delete | All endpoints require JWT. Report data/config endpoints use `ReportPrivilegeGuard` (config `privilegeKey` + `view`). Bookmarks are scoped to `createdBy` (current user). ## Adding a report 1. Add a `ReportConfigEntity` file under `shared/configs/`. 2. Register it in `shared/configs/index.ts`. 3. No new controller or React page — the generic UI picks it up when `groupName` matches. ## TrackGo-specific notes - JSON uses **camelCase** (`groupName`, `queryModel`, `columnConfigs`). - SQL values are **bound parameters**; only config-authored fragments use `sql.raw()`. - Cell formatting uses `DateTime`, `Status`, and `Decimal` value objects. - Excel export is **not** implemented in this phase. See [report-list.md](./report-list.md) for the seven shipped reports.