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

  • TechnicalDashboardService is placeholder-only and returns empty sections + count from placeholder permission service.
  • DashboardPermissionService ticket methods are stubs:
    • getTechnicalAssignedTicketIds returns []
    • assertTicketAssignedToTechnical and assertInternalTicketCreatedByTechnical throw unavailable errors
  • DashboardQueryService has owner/staff/admin/super-admin real query logic but technical remains empty.
  • Ticket foundation exists (Task 4.1):
    • tickets table + enums + entity/service
    • Ticket has scope fields (organizationId, farmId, pondId, deviceId) and technical metadata (assignedTechnicalId, createdByTechnicalId).

3) Options Considered

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.ts gets 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:

  1. Assert role is TECHNICAL
  2. Resolve organizationId
  3. Resolve both ticket scopes:
    • assigned ticket IDs (assignedTechnicalId = currentUser.userId)
    • internal ticket IDs (createdByTechnicalId = currentUser.userId and type = INTERNAL_MAINTENANCE)
  4. Build sections only from union/intersection required by each section
  5. 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):

  1. Assigned tickets visible for owning technical user
  2. Internal tickets visible only when created by current technical user
  3. Forbidden cross-technical access for ticket not assigned/not created by current user
  4. Device diagnostics limited to ticket scope
  5. Today route limited to ticket scope
  6. Sensitive business metrics absent from technical response

Verification commands:

  • bun run backend:test -- src/dashboard/services/technical-dashboard.service.spec.ts
  • bun run backend:test -- src/dashboard/dashboard-permission.service.spec.ts
  • bun 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/deviceId tickets 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.