fix: maintenance repository mapper returns numeric fields as strings, violating MaintenanceRecord type contract #241
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
backend/src/features/maintenance/data/maintenance.repository.tsmapMaintenanceRecord()(andmapMaintenanceSchedule()) pass numeric columns straight through from the raw pg row. node-postgres returnsnumeric/decimalcolumns as strings, but the TypeScript types declare them asnumber. This forces every frontend consumer to defensively coerce withNumber()or risk silent failures like the one fixed in #239 (the maintenance amount column rendering as dashes becausetypeof rec.cost === 'number'was false).Affected Fields
mapMaintenanceRecord(maintenance_records table)cost— typednumber, returned as stringodometerReading— typednumber, returned as string (suspected — same column type, not yet confirmed at runtime)mapMaintenanceSchedule(maintenance_schedules table)intervalMonths— typednumberintervalMiles— typednumberlastServiceMileage— typednumbernextDueMileage— typednumber(All
*Mileageand interval fields are likelynumeric/integerin pg and should be confirmed against the migration.)Evidence
frontend/src/features/maintenance/components/MaintenanceRecordsList.tsx:127already doesNumber(record.cost).toFixed(2)— a workaround that hides the underlying bug.Number()coercion in the vehicle summary screen consumers because the cost column was rendering empty without it. That coercion is now in two more places and should be temporary.Expected Behavior
The mapper should honor its declared TypeScript types. Numeric columns should be coerced once, in the mapper:
…and equivalent for the schedule mapper's numeric fields.
After the mapper fix, the defensive
Number()calls inMaintenanceRecordsList.tsx,VehicleDetailPage.tsx, andVehicleDetailMobile.tsxcan be removed (or left as belt-and-suspenders — but the bug at the source is gone).Investigation Areas
backend/src/features/maintenance/(orbackend/migrations/).fuel-logs,ownership-costs,documents) have the same issue. Fuel logs currently displaytotalCostas a number without frontend coercion — verify whether that's because the mapper coerces or because the column type is different.backend/src/core/db/(e.g.toNumber()) that all repos can use for numeric coercion, so this pattern is consistent.Acceptance Criteria
mapMaintenanceRecordandmapMaintenanceSchedulecoerce all numeric fields tonumber(or null) before returning.numberbut the column isnumeric/decimal./maintenance/records*return numeric fields as JSON numbers, not strings (verify withcurlor network tab).Number()coercions in maintenance frontend components (MaintenanceRecordsList,VehicleDetailPage,VehicleDetailMobile) can be removed without regressions.Out of Scope
Related