Technical Dashboard Aggregate Design (Task 4.2)
Date: 2026-04-26
Status: Approved (conversation-level), pending file review gate
1) Goal
Implement backend aggregate for GET /dashboard/technical so Technical users only see:
- Assigned ticket queue
- Internal ticket queue (tickets created by technical user)
- Today route
- Device diagnostics
- Parts needed
- Maintenance history
- Service report state
The response must not include business-sensitive metrics (cost/revenue/FCR/survival/staff performance/daily log detail).
2) Current State
TechnicalDashboardServiceis placeholder-only and returns empty sections + count from placeholder permission service.DashboardPermissionServiceticket methods are stubs:getTechnicalAssignedTicketIdsreturns[]assertTicketAssignedToTechnicalandassertInternalTicketCreatedByTechnicalthrow unavailable errors
DashboardQueryServicehas owner/staff/admin/super-admin real query logic but technical remains empty.- Ticket foundation exists (Task 4.1):
ticketstable + enums + entity/serviceTickethas scope fields (organizationId,farmId,pondId,deviceId) and technical metadata (assignedTechnicalId,createdByTechnicalId).
3) Options Considered
Option A (recommended): Extend existing DashboardQueryService
Add technical query methods into current query service and keep orchestration in TechnicalDashboardService.
Pros
- Consistent with existing dashboard architecture
- Minimal module churn
- Reuses established filtering/aggregation style
Cons
dashboard-query.service.tsgets larger
Option B: New TechnicalDashboardQueryService
Create a dedicated technical query service and inject it into technical dashboard service.
Pros
- Better isolation for technical domain
Cons
- Extra abstraction now, little immediate value
- More files/wiring for current scope
4) Selected Design
Use Option A and add focused technical query methods in DashboardQueryService, with strict ticket-scope filtering in service-level orchestration.
4.1 Service orchestration
TechnicalDashboardService.getDashboard(currentUser) will:
- Assert role is
TECHNICAL - Resolve
organizationId - Resolve both ticket scopes:
- assigned ticket IDs (
assignedTechnicalId = currentUser.userId) - internal ticket IDs (
createdByTechnicalId = currentUser.userIdandtype = INTERNAL_MAINTENANCE)
- assigned ticket IDs (
- Build sections only from union/intersection required by each section
- Return typed response with
generatedAt,scope: own,kpis,sections
4.2 Permission scope service
Implement missing ticket scope methods in DashboardPermissionService using Ticket repository:
getTechnicalAssignedTicketIds(currentUser): Promise<string[]>getTechnicalInternalTicketIds(currentUser): Promise<string[]>(new helper)assertTicketAssignedToTechnical(ticketId, userId)assertInternalTicketCreatedByTechnical(ticketId, userId)
All methods must enforce organization scoping and technical ownership/assignment constraints.
4.3 Query layer additions
Add technical-specific aggregate methods in DashboardQueryService:
buildTechnicalSections(params)getTechnicalAssignedTicketQueue(...)getTechnicalInternalTicketQueue(...)getTechnicalTodayRoute(...)getTechnicalDeviceDiagnostics(...)getTechnicalPartsNeeded(...)getTechnicalMaintenanceHistory(...)getTechnicalServiceReportState(...)
Each query must filter by:
organizationId- ticket scope IDs (assigned/internal)
- nullable relation safety (device/pond/farm may be null)
4.4 DTO contract
Update technical-dashboard-response.dto.ts from empty array placeholders to explicit item DTOs for each section, with stable API fields and ISO timestamps.
4.5 Data sensitivity guardrails
Do not include fields representing:
- cost / revenue / profit
- FCR / survival / biomass business KPIs
- staff performance
- daily log details outside ticket context
Keep output operational and maintenance-centric only.
5) File-Level Change Plan
backend/src/dashboard/services/technical-dashboard.service.ts- Replace placeholder implementation with real orchestration.
backend/src/dashboard/dashboard-permission.service.ts- Implement technical ticket scope methods.
backend/src/dashboard/dashboard-permission.service.spec.ts- Add tests for technical scope resolution and forbidden checks.
backend/src/dashboard/dashboard-query.service.ts- Add technical aggregate query methods.
backend/src/dashboard/dto/technical-dashboard-response.dto.ts- Define concrete DTO item structures.
backend/src/dashboard/services/technical-dashboard.service.spec.ts- Add service tests for assigned/internal/forbidden/sensitive-data boundaries.
6) Test Strategy
Required tests (minimum):
- Assigned tickets visible for owning technical user
- Internal tickets visible only when created by current technical user
- Forbidden cross-technical access for ticket not assigned/not created by current user
- Device diagnostics limited to ticket scope
- Today route limited to ticket scope
- Sensitive business metrics absent from technical response
Verification commands:
bun run backend:test -- src/dashboard/services/technical-dashboard.service.spec.tsbun run backend:test -- src/dashboard/dashboard-permission.service.spec.tsbun run check
7) Out of Scope
- Ticket workflow redesign (Task 4.1 already established)
- Frontend Technical dashboard UI (Task 4.3)
- Super Admin ticket/workload integration UI (Task 4.4)
- Redis/performance caching decisions (Phase 5)
8) Risks and Mitigations
Risk: Null
pondId/deviceIdtickets break joins
Mitigation: Left joins + explicit nullable mapping in DTOs.Risk: Scope leakage across technical users
Mitigation: Centralized permission methods + unit tests for forbidden paths.Risk: Overloading query service file
Mitigation: Add technical methods as compact, isolated private/public blocks; keep signatures strict.