feat: Total Cost of Ownership (TCO) per Vehicle #28

Merged
egullickson merged 11 commits from issue-15-add-tco-feature into main 2026-01-14 03:08:35 +00:00
Owner

Summary

  • Add Total Cost of Ownership (TCO) calculation and display for vehicles
  • Track purchase price, insurance costs, registration costs alongside fuel and maintenance
  • Display lifetime total and cost per mile/km on vehicle detail page

Changes

Database (M1)

  • Migration adds 7 new columns to vehicles table with CHECK constraints

Backend (M2-M5)

  • CostInterval type and PAYMENTS_PER_YEAR constant
  • TCO fields in Vehicle types and repository mapRow()
  • getVehicleMaintenanceCosts() method in maintenance service
  • getTCO() service method with cost normalization
  • GET /api/vehicles/:id/tco endpoint

Frontend (M6-M7)

  • "Ownership Costs" section in VehicleForm
  • TCODisplay component showing lifetime total and cost breakdown
  • Mobile-responsive with 44px touch targets

Test plan

  • Create vehicle with TCO fields populated
  • Enable TCO display toggle
  • Verify TCO shows on vehicle detail page
  • Verify cost breakdown shows correct values
  • Test on mobile viewport (320px)
  • Test on desktop viewport (1920px)
  • Verify API returns 404 for non-existent vehicle
  • Verify division by zero guard (new vehicle with 0 months)

Fixes #15

🤖 Generated with Claude Code

## Summary - Add Total Cost of Ownership (TCO) calculation and display for vehicles - Track purchase price, insurance costs, registration costs alongside fuel and maintenance - Display lifetime total and cost per mile/km on vehicle detail page ## Changes ### Database (M1) - Migration adds 7 new columns to vehicles table with CHECK constraints ### Backend (M2-M5) - `CostInterval` type and `PAYMENTS_PER_YEAR` constant - TCO fields in Vehicle types and repository mapRow() - `getVehicleMaintenanceCosts()` method in maintenance service - `getTCO()` service method with cost normalization - `GET /api/vehicles/:id/tco` endpoint ### Frontend (M6-M7) - "Ownership Costs" section in VehicleForm - TCODisplay component showing lifetime total and cost breakdown - Mobile-responsive with 44px touch targets ## Test plan - [ ] Create vehicle with TCO fields populated - [ ] Enable TCO display toggle - [ ] Verify TCO shows on vehicle detail page - [ ] Verify cost breakdown shows correct values - [ ] Test on mobile viewport (320px) - [ ] Test on desktop viewport (1920px) - [ ] Verify API returns 404 for non-existent vehicle - [ ] Verify division by zero guard (new vehicle with 0 months) Fixes #15 🤖 Generated with [Claude Code](https://claude.com/claude-code)
egullickson added 7 commits 2026-01-13 02:06:39 +00:00
Add database columns for Total Cost of Ownership:
- purchase_price, purchase_date
- insurance_cost, insurance_interval
- registration_cost, registration_interval
- tco_enabled toggle

Includes CHECK constraints for interval values and non-negative costs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CostInterval type and PAYMENTS_PER_YEAR constant
- Add 7 TCO fields to Vehicle, CreateVehicleRequest, UpdateVehicleRequest
- Update VehicleResponse and Body types
- Update mapRow() with snake_case to camelCase mapping
- Update create(), update(), batchInsert() for new fields
- Add Zod validation for TCO fields with interval enum

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add MaintenanceCostStats interface
- Add getVehicleMaintenanceCosts() method to maintenance service
- Validates numeric cost values and throws on invalid data

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TCOResponse interface
- Add getTCO() method aggregating all cost sources
- Add normalizeRecurringCost() with division-by-zero guard
- Integrate FuelLogsService and MaintenanceService for cost data
- Respect user preferences for distance unit and currency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add GET /api/vehicles/:id/tco route
- Add getTCO controller method with error handling
- Returns 200 with TCO data, 404 for not found, 403 for unauthorized

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CostInterval type and TCOResponse interface
- Add TCO fields to Vehicle, CreateVehicleRequest, UpdateVehicleRequest
- Add "Ownership Costs" section to VehicleForm with:
  - Purchase price and date
  - Insurance cost and interval
  - Registration cost and interval
  - TCO display toggle
- Add getTCO API method
- Mobile-responsive grid layout with 44px touch targets

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat: add TCO display component (refs #15)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 5m41s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 29s
Deploy to Staging / Verify Staging (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 5s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
9e8f9a1932
- Create TCODisplay component showing lifetime cost and cost per distance
- Display cost breakdown (purchase, insurance, registration, fuel, maintenance)
- Integrate into VehicleDetailPage right-justified next to vehicle details
- Responsive layout: stacks vertically on mobile, side-by-side on desktop
- Only shows when tcoEnabled is true

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
egullickson added 1 commit 2026-01-13 02:32:26 +00:00
fix: add TCO unit tests and fix blocking issues (refs #15)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 4m34s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 28s
Deploy to Staging / Verify Staging (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
5c93150a58
Quality Review Fixes:
- Add comprehensive unit tests for getTCO() method (12 test cases)
- Add tests for normalizeRecurringCost() via getTCO integration
- Add future date validation guard in calculateMonthsOwned()
- Fix pre-existing unused React import in VehicleLimitDialog.test.tsx
- Fix pre-existing test parameter types in vehicles.service.test.ts

Test Coverage:
- Vehicle not found / unauthorized access
- Missing optional TCO fields handling
- Zero odometer (costPerDistance = 0)
- Monthly/semi-annual/annual cost normalization
- Division by zero guard (new purchase)
- Future purchase date handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
egullickson added 2 commits 2026-01-13 13:59:31 +00:00
- Create ownership_costs table for recurring vehicle costs
- Add backend feature capsule with types, repository, service, routes
- Update TCO calculation to use ownership_costs (with fallback to legacy vehicle fields)
- Add taxCosts and otherCosts to TCO response
- Create frontend ownership-costs feature with form, list, API, hooks
- Update TCODisplay to show all cost types

This implements a more flexible approach to tracking recurring ownership costs
(insurance, registration, tax, other) with explicit date ranges and optional
document association.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat: integrate ownership-costs UI into vehicle detail pages (refs #15)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 4m43s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 38s
Deploy to Staging / Verify Staging (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
cb93e3ccc5
- Add OwnershipCostsList to desktop VehicleDetailPage
- Add OwnershipCostsList to mobile VehicleDetailMobile
- Users can now view, add, edit, and delete recurring costs directly
  from the vehicle detail view
egullickson added 1 commit 2026-01-13 14:16:55 +00:00
fix: add ownership-costs to migration order and improve error handling (refs #15)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 4m41s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 38s
Deploy to Staging / Verify Staging (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
395670c3bd
- Add 'features/ownership-costs' to MIGRATION_ORDER in run-all.ts
- Improve OwnershipCostsList error display to not block the page
- Show friendly message when feature needs migration
egullickson merged commit 5f07123646 into main 2026-01-14 03:08:35 +00:00
egullickson deleted branch issue-15-add-tco-feature 2026-01-14 03:08:36 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: egullickson/motovaultpro#28