feat(reports): add project + client report types end to end (PMS-179) #147

Merged
longjacksonle merged 1 commit from feat/pms-179-project-client-reports into main 2026-06-09 22:42:06 +02:00

What

Add two new tenant-scoped report types, projects and clients, end to end. Subtask of PMS-93: the SPA reports landing page advertises Projects and Clients report categories that previously had no backend, so those surfaces rendered an honest "not available yet" notice.

Endpoints

  • GET /api/v1/reports/projects - project-delivery aggregate: projects grouped by status; total budget hours / amount vs actual hours / amount (actuals summed from time_entries linked to a project); task completion (total vs completed via task_statuses.is_completed); overdue project count (target_end_date in the past, status not completed / cancelled).
  • GET /api/v1/reports/clients - CMDB / contract aggregate: company counts (all / active); asset totals with breakdown by type and by status; assets whose warranty expires within 90 days; active and renewing-within-90-days contract counts.

Both are added to the GET /reports registry so a client can discover them, gain CSV export through the existing generic /reports/{report}/export path, and are guarded by RequireReports (same as the tickets and time reports).

Tests

tests/reports.rs gains projects_report_aggregates, clients_report_aggregates, and clients_report_is_tenant_scoped. All five reports tests pass; 115 lib tests, clippy --all-targets -- -D warnings, and cargo fmt --check are clean.

Out of scope

The custom report builder stays unimplemented. PMS-93 explicitly rejected an ad-hoc query builder for v1 (injection / performance risk).

🤖 Generated with Claude Code

## What Add two new tenant-scoped report types, **projects** and **clients**, end to end. Subtask of PMS-93: the SPA reports landing page advertises Projects and Clients report categories that previously had no backend, so those surfaces rendered an honest "not available yet" notice. ## Endpoints - `GET /api/v1/reports/projects` - project-delivery aggregate: projects grouped by status; total budget hours / amount vs actual hours / amount (actuals summed from `time_entries` linked to a project); task completion (total vs completed via `task_statuses.is_completed`); overdue project count (`target_end_date` in the past, status not completed / cancelled). - `GET /api/v1/reports/clients` - CMDB / contract aggregate: company counts (all / active); asset totals with breakdown by type and by status; assets whose warranty expires within 90 days; active and renewing-within-90-days contract counts. Both are added to the `GET /reports` registry so a client can discover them, gain CSV export through the existing generic `/reports/{report}/export` path, and are guarded by `RequireReports` (same as the tickets and time reports). ## Tests `tests/reports.rs` gains `projects_report_aggregates`, `clients_report_aggregates`, and `clients_report_is_tenant_scoped`. All five reports tests pass; 115 lib tests, `clippy --all-targets -- -D warnings`, and `cargo fmt --check` are clean. ## Out of scope The custom **report builder** stays unimplemented. PMS-93 explicitly rejected an ad-hoc query builder for v1 (injection / performance risk). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(reports): add project + client report types end to end (PMS-179)
All checks were successful
E2E (staging) / Playwright against staging (pull_request) Successful in 1m10s
Check / fmt + clippy + compile + tests (pull_request) Successful in 3m17s
Create release / Create release from merged PR (pull_request) Has been skipped
Build OCI container / Build and push mokosh-api image (push) Successful in 8m14s
148d3f6197
PMS-93 shipped the ticket / time / billing reports, but the SPA reports landing page also advertises Projects and Clients report categories that had no backend behind them, so those surfaces rendered an honest "not available yet" notice. This adds the two missing report types.

GET /api/v1/reports/projects returns a tenant-scoped project-delivery aggregate: projects grouped by status, total budget hours / amount vs actual hours / amount (actuals summed from time_entries linked to a project), task completion (total vs completed via task_statuses.is_completed), and overdue project count (target_end_date in the past, not completed or cancelled). GET /api/v1/reports/clients returns a tenant-scoped CMDB / contract aggregate: company counts (all / active), asset totals with breakdown by type and by status, assets whose warranty expires within 90 days, and active / renewing-within-90-days contract counts.

Both are added to the GET /reports registry so clients can discover them, gain CSV export via the existing generic /reports/{report}/export path, and are guarded by RequireReports like the tickets and time reports.

Tests: tests/reports.rs gains projects_report_aggregates and clients_report_aggregates (assert each figure against seeded data, plus the registry advertises both keys and CSV export returns content) and clients_report_is_tenant_scoped (a second tenant's assets never leak into this tenant's counts). All five reports tests pass; 115 lib tests, clippy --all-targets, and fmt are clean.

Out of scope: the custom report builder stays unimplemented. PMS-93 explicitly rejected an ad-hoc query builder for v1 (injection / performance risk).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/pms-179-project-client-reports 2026-06-09 22:42:06 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-server!147
No description provided.