Skip to content

Next Session: Maintenance Services Stabilization

Purpose: Use a dedicated session to stabilize all maintenance micro-services (fix type issues in queries and mutations), then add/update maintenance tests, then run tests and Yaak. Do not mix with other service tests — maintenance is skipped in the current session because of its incomplete state.


Current state (why maintenance is skipped this session)

  • Queries (maintenance/queries/index.ts) and mutations (maintenance/mutation/index.ts) have many type errors and mismatches with @/types/maintenance and the DB schema. Until these are fixed, maintenance tests would be brittle and misleading.
  • This session: All non-maintenance tests are in scope (auth, me, cache, storage, cookies, jwt, mailer, internal, system). Maintenance tests are skipped entirely.

What needs to be fixed (maintenance only)

1. Types: MaintenanceQueryParams vs usage in queries

  • Defined in @/types/maintenance/unified.ts: MaintenanceQueryFilters has status?: string[], priority?: string[], dateFrom?, dateTo? (no departmentApprovalStatus, category, dueDateFrom/dueDateTo, createdAtFrom/createdAtTo, completed).
  • Used in queries/index.ts as: params.departmentApprovalStatus, params.category, params.dueDateFrom/dueDateTo, params.createdAtFrom/createdAtTo, params.completed, and params.status/params.priority as single strings in eq().
  • Fix (choose one):
    • Option A: Extend MaintenanceQueryFilters / MaintenanceQueryParams to include all fields the query layer uses (departmentApprovalStatus, category, dueDateFrom, dueDateTo, createdAtFrom, createdAtTo, completed) and, for status/priority, either keep array and use inArray() in Drizzle or add single-value variants used by eq().
    • Option B: Change query code to use only the existing params (e.g. use dateFrom/dateTo for due-date filters, add no new filter fields) and use inArray() for status/priority when they are arrays.

2. Queries: orderDirection and ordering

  • Code uses orderDirection(maintenanceRequests.createdAt) but orderDirection is not defined.
  • Fix: Define e.g. const orderDirection = order === 'asc' ? asc : desc (where order comes from params.order) and use it in the switch. Ensure the Drizzle chain has orderBy before limit/offset if required by your Drizzle version.

3. Queries: Drizzle select chain

  • Lint reports: missing orderBy on the builder, and limit/offset type issues. Ensure the select builder is built in the order your Drizzle version expects (e.g. .where().orderBy().limit().offset()).

4. Queries: getMaintenanceRequest return and mapping

  • Return type is Promise<PopulatedMaintenanceRequest> but the function returns the result of mapMaintenanceRequestToResponse(...) which is MaintenanceRequestResponse (different shape: e.g. UserResponse vs DatabaseUser, dates as strings).
  • Fix: Either change the return type of getMaintenanceRequest to Promise<MaintenanceRequestResponse> or add a separate path that builds and returns a PopulatedMaintenanceRequest from the same data. Align with how the route layer and types in @/types/database expect the response.
  • Mapping arguments: The select result has submittedByUser, assignedToUser, approvedByUser (not approvedBy), and no Attachments in the select list. Code incorrectly uses request.Attachments and request.approvedBy. Fix to pass request.approvedByUser, and for attachments either add them to the select/join or pass [] and document that attachments are loaded elsewhere.

5. Queries: mapMaintenanceRequestToResponse and null joins

  • UserResponseData is expected for staff/technician/approvedBy; leftJoin can return null. Either allow undefined in the util signature or pass req.submittedByUser ?? undefined (and same for others) so you don’t pass null.

6. Queries: calculatePermissions and hasReadPermission

  • calculatePermissions(SessionData, request) is called with request being the raw DB row; request.status can be string | null. Ensure MaintenanceRequestData or the permission logic accepts nullable status or narrows it before use.
  • hasReadPermission(sessionData, request) is called with the same row; ensure the type for request is consistent (e.g. a type that includes joined fields and nullables from the select).

7. Queries: createMaintenanceQueryService

  • At the end of the file, createMaintenanceQueryService(env: Env, services: InitializedServices) uses Env and InitializedServices but they are not imported. Add:
    • import type { Env } from '@/types/app';
    • import type { InitializedServices } from '@/lib/services/init';

8. Mutations: input and return types

  • createMaintenanceRequest(SessionData, data: any) — replace any with a proper type (e.g. CreateMaintenanceRequest or the shape from your Zod/validation).
  • updateMaintenanceRequest(SessionData, requestId, data: any): Promise<any> — use a proper update type for data and return Promise<PopulatedMaintenanceRequest> (or the type the route layer expects).

9. Core and other maintenance modules

  • After queries and mutations are type-clean, run the linter on all maintenance modules (core, permissions, validation, utils, attachment) and fix any remaining type errors so the whole maintenance service is stable.

Order of work (next session)

  1. Fix types and implementation in maintenance only
    • Align MaintenanceQueryParams / MaintenanceQueryFilters with query usage (or the reverse).
    • Fix queries: orderDirection, select chain, getMaintenanceRequest return type and mapping (approvedByUser, Attachments), null handling for joined users, createMaintenanceQueryService imports.
    • Fix mutations: replace any with proper create/update types and return type.
    • Fix any other maintenance files (core, permissions, validation, utils, attachment) until linter is clean.
  2. Maintenance tests
    • Add/update tests per Testing Guide: e.g. queries.test.ts, mutation.test.ts (or mutations.test.ts), permissions.test.ts, validation.test.ts, attachment.test.ts, and optionally core.test.ts / index.test.ts. Use real types from @/types (SessionData, PopulatedMaintenanceRequest, MaintenanceQueryParams, etc.).
  3. Run tests and Yaak
    • Run the full test suite (including maintenance). Until then, to run only non-maintenance tests: pnpm test --run --exclude='**/maintenance/**'.
    • Run maintenance flows in Yaak/Postman to validate the lifecycle (create → approve → assign → complete) against the API.

References

  • Maintenance lifecycle (where data lives, stages): docs/architecture/systems/maintenance-lifecycle.md
  • Maintenance caching (Phase 5): same doc, “Caching (Phase 5)” section; and PHASES.md.
  • Testing structure and type-safety: docs/guides/testing.md (maintenance tests follow the same one-test-file-per-micro-service pattern).
  • Current maintenance type definitions: @/types/maintenance (unified, approve, assign, complete, status) and @/types/database (PopulatedMaintenanceRequest if used).