Commit Graph

591 Commits

Author SHA1 Message Date
2ebae468c6 Merge pull request 'fix: display purchase info and fix validation on vehicle detail (#41)' (#42) from issue-41-fix-purchase-info into main
All checks were successful
Deploy to Staging / Build Images (push) Successful in 27s
Deploy to Staging / Deploy to Staging (push) Successful in 29s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Mirror Base Images / Mirror Base Images (push) Successful in 43s
Reviewed-on: #42
2026-01-16 03:04:16 +00:00
Eric Gullickson
731d67f324 fix: add mobile responsive breakpoint to purchase info grid (refs #41)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m43s
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 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 20:56:03 -06:00
Eric Gullickson
a1d3dd965a fix: display purchase info and fix validation on vehicle detail (refs #41)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m47s
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
- Add purchase price and purchase date display to vehicle detail page
- Fix form validation to handle NaN from empty number inputs using z.preprocess

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 20:53:23 -06:00
f325ff49d0 Merge pull request 'fix: remove license plate fallback from VIN field (#39)' (#40) from issue-39-fix-vin-field-fallback into main
All checks were successful
Deploy to Staging / Build Images (push) Successful in 25s
Deploy to Staging / Deploy to Staging (push) Successful in 37s
Deploy to Staging / Verify Staging (push) Successful in 6s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Reviewed-on: #40
2026-01-16 02:35:03 +00:00
Eric Gullickson
fbc0186ea6 fix: remove license plate fallback from VIN field (refs #39)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m46s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 38s
Deploy to Staging / Verify Staging (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
The VIN Number field incorrectly showed license plate when VIN was empty.
Now displays "Not provided" for missing VIN values, matching mobile behavior.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 20:29:40 -06:00
913e084127 Merge pull request 'fix: remove legacy TCO fields from vehicle forms (refs #37)' (#38) from issue-37-remove-tco-fields into main
All checks were successful
Deploy to Staging / Build Images (push) Successful in 26s
Deploy to Staging / Deploy to Staging (push) Successful in 28s
Deploy to Staging / Verify Staging (push) Successful in 6s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Reviewed-on: #38
2026-01-16 02:11:07 +00:00
Eric Gullickson
96440104c8 fix: remove legacy TCO fields from vehicle forms (refs #37)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m42s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 29s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
- Remove CostInterval type and TCOResponse interface from frontend types
- Remove insurance/registration cost fields from VehicleForm schema and UI
- Keep purchasePrice and purchaseDate fields on vehicle form
- Remove TCODisplay component from VehicleDetailPage
- Delete TCODisplay.tsx component file
- Remove getTCO method from vehicles API client

Legacy TCO fields moved to ownership-costs feature in #29.
Backend endpoint preserved for future reporting feature.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 11:03:31 -06:00
Eric Gullickson
60aa0acbe0 chore: remove file
All checks were successful
Deploy to Staging / Build Images (push) Successful in 2m23s
Deploy to Staging / Deploy to Staging (push) Successful in 38s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 7s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
2026-01-14 21:28:57 -06:00
Eric Gullickson
4cc3083da4 chore: removed dead file
All checks were successful
Deploy to Staging / Build Images (push) Successful in 25s
Deploy to Staging / Deploy to Staging (push) Successful in 28s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
2026-01-14 21:22:30 -06:00
6fa643f6a4 Merge pull request 'fix: Standardize checkboxes to use MUI Checkbox component (#35)' (#36) from issue-35-standardize-checkboxes into main
All checks were successful
Deploy to Staging / Build Images (push) Successful in 25s
Deploy to Staging / Deploy to Staging (push) Successful in 37s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Reviewed-on: #36
2026-01-15 03:06:11 +00:00
Eric Gullickson
8c570288f9 fix: standardize checkboxes to use MUI Checkbox component (refs #35)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m41s
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
Replace raw HTML checkboxes with MUI Checkbox wrapped in FormControlLabel
for consistent styling and theme integration across:
- DocumentForm.tsx (shared vehicles + scan maintenance checkboxes)
- VehicleForm.tsx (TCO enabled checkbox)
- SignupForm.tsx (terms acceptance checkbox)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 21:01:00 -06:00
ec8e6ee5d2 Merge pull request 'feat: Document feature enhancements (#31)' (#32) from issue-31-document-enhancements into main
All checks were successful
Deploy to Staging / Build Images (push) Successful in 4m43s
Deploy to Staging / Deploy to Staging (push) Successful in 38s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Reviewed-on: #32
2026-01-15 02:35:55 +00:00
4284cd9fc5 Merge pull request 'fix: add dynamic timeout for document uploads (#33)' (#34) from issue-33-document-upload-timeout into main
All checks were successful
Deploy to Staging / Build Images (push) Successful in 25s
Deploy to Staging / Deploy to Staging (push) Successful in 28s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Reviewed-on: #34
2026-01-15 02:33:20 +00:00
Eric Gullickson
a3b119a953 fix: resolve document upload hang by fixing stream pipeline (refs #33)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m22s
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 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
The upload was hanging silently because breaking early from a
`for await` loop on a Node.js stream corrupts the stream's internal
state. The remaining stream could not be used afterward.

Changes:
- Collect ALL chunks from the file stream before processing
- Use subarray() for file type detection header (first 4100 bytes)
- Create single readable stream from complete buffer for storage
- Remove broken headerStream + remainingStream piping logic

This fixes the root cause where uploads would hang after logging
"Document upload requested" without ever completing or erroring.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 20:28:19 -06:00
Eric Gullickson
1014475c0f fix: add dynamic timeout for document uploads (refs #33)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m43s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 37s
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
Document uploads were failing with "timeout of 10000ms exceeded" error
because the global axios client timeout (10s) was too short for
medium-sized files (1-5MB).

Added calculateUploadTimeout() function that calculates timeout based on
file size: 30s base + 10s per MB. This allows uploads to complete on
slower connections while still having reasonable timeout limits.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 20:16:17 -06:00
Eric Gullickson
354ce47fc4 fix: remove debug console.log statements (refs #31)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 4m40s
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 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 19:45:51 -06:00
Eric Gullickson
bdb329f7c3 feat: add context-aware document delete from vehicle screen (refs #31)
- Created DeleteDocumentConfirmDialog with context-aware messaging:
  - Primary vehicle with no shares: Full delete
  - Shared vehicle: Remove association only
  - Primary vehicle with shares: Full delete (affects all)
- Integrated documents display in VehicleDetailPage records table
- Added delete button per document with 44px touch target
- Document deletion uses appropriate backend calls based on context
- Mobile-friendly dialog with responsive design

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 19:41:52 -06:00
Eric Gullickson
b71e2cff3c feat: add document edit functionality with multi-vehicle support (refs #31)
Implemented comprehensive document editing capabilities:

1. Created EditDocumentDialog component:
   - Responsive MUI Dialog with fullScreen on mobile
   - Wraps DocumentForm in edit mode
   - Proper close handlers with refetch

2. Enhanced DocumentForm to support edit mode:
   - Added mode prop ('create' | 'edit')
   - Pre-populate all fields from initialValues
   - Use useUpdateDocument hook when in edit mode
   - Multi-select for shared vehicles (insurance only)
   - Vehicle and document type disabled in edit mode
   - Optional file upload in edit mode
   - Dynamic button text (Create/Save Changes)

3. Updated DocumentDetailPage:
   - Added Edit button with proper touch targets
   - Integrated EditDocumentDialog
   - Refetch document on successful edit

Mobile-first implementation:
- All touch targets >= 44px
- Dialog goes fullScreen on mobile
- Form fields stack on mobile
- Shared vehicle checkboxes have min-h-[44px]
- Buttons use flex-wrap for mobile overflow

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 19:38:20 -06:00
Eric Gullickson
8968cad805 feat: display vehicle names instead of UUIDs in document views (refs #31)
- Created shared utility getVehicleLabel() for consistent vehicle display
- Updated DocumentsPage to show vehicle names with clickable links
- Added "Shared with X vehicles" indicator for multi-vehicle docs
- Updated DocumentDetailPage with vehicle name and shared vehicle list
- Updated DocumentsMobileScreen with vehicle names and "Shared" indicator
- All vehicle names link to vehicle detail pages
- Mobile-first with 44px touch targets on all links

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 19:34:02 -06:00
Eric Gullickson
e558fdf8f9 feat: add frontend document-vehicle API client and hooks (refs #31)
- Update DocumentRecord interface to include sharedVehicleIds array
- Add optional sharedVehicleIds to Create/UpdateDocumentRequest types
- Add documentsApi.listByVehicle() method for fetching by vehicle
- Add documentsApi.addSharedVehicle() for linking vehicles
- Add documentsApi.removeVehicleFromDocument() for unlinking
- Add useDocumentsByVehicle() query hook with vehicle filter
- Add useAddSharedVehicle() mutation with optimistic updates
- Add useRemoveVehicleFromDocument() mutation with optimistic updates
- Ensure query invalidation includes both documents and documents-by-vehicle keys
- Update test mocks to include sharedVehicleIds field
- Fix optimistic update in useCreateDocument to include new fields

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 19:31:03 -06:00
Eric Gullickson
5dbc17e28d feat: add document-vehicle API endpoints and context-aware delete (refs #31)
Updates documents backend service and API to support multi-vehicle insurance documents:
- Service: createDocument/updateDocument validate and handle sharedVehicleIds for insurance docs
- Service: addVehicleToDocument validates ownership and adds vehicles to shared array
- Service: removeVehicleFromDocument with context-aware delete logic:
  - Shared vehicle only: remove from array
  - Primary with no shared: soft delete document
  - Primary with shared: promote first shared to primary
- Service: getDocumentsByVehicle returns all docs for a vehicle (primary or shared)
- Controller: Added handlers for listByVehicle, addVehicle, removeVehicle with proper error handling
- Routes: Added POST/DELETE /documents/:id/vehicles/:vehicleId and GET /documents/by-vehicle/:vehicleId
- Validation: Added DocumentVehicleParamsSchema for vehicle management routes

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 19:28:00 -06:00
Eric Gullickson
57debe4252 feat: add shared_vehicle_ids schema and repository methods (refs #31)
- Add migration 004_add_shared_vehicle_ids.sql with UUID array column and GIN index
- Update DocumentRecord interface to include sharedVehicleIds field
- Add sharedVehicleIds to CreateDocumentBody and UpdateDocumentBody schemas
- Update repository mapDocumentRecord() to map shared_vehicle_ids from database
- Update insert() and batchInsert() to handle sharedVehicleIds
- Update updateMetadata() to support sharedVehicleIds updates
- Add addSharedVehicle() method using atomic array_append()
- Add removeSharedVehicle() method using atomic array_remove()
- Add listByVehicle() method to query by primary or shared vehicle

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 19:24:34 -06:00
a5d828b6c1 Merge pull request 'refactor: Link ownership-costs to documents feature (#29)' (#30) from issue-29-link-ownership-costs into main
All checks were successful
Deploy to Staging / Build Images (push) Successful in 25s
Deploy to Staging / Deploy to Staging (push) Successful in 28s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Reviewed-on: #30
2026-01-15 01:23:56 +00:00
Eric Gullickson
025ab30726 fix: add schema migration for ownership_costs table (refs #29)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m21s
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
The ownership_costs table was created with an outdated schema that had
different column names (start_date/end_date vs period_start/period_end)
and was missing the notes column. This migration aligns the database
schema with the current code expectations.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 21:51:44 -06:00
Eric Gullickson
1d95eba395 fix: resolve lint error in ownership-costs types (refs #29)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 4m37s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 37s
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
Milestone 6: Change empty interface to type alias to fix
@typescript-eslint/no-empty-object-type error

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 21:37:30 -06:00
Eric Gullickson
f0deab8210 feat: add frontend ownership-costs feature (refs #29)
Milestone 4: Complete frontend with:
- Types aligned with backend schema
- API client for CRUD operations
- React Query hooks with optimistic updates
- OwnershipCostForm with all 6 cost types
- OwnershipCostsList with edit/delete actions
- Mobile-friendly (44px touch targets)
- Full dark mode support

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 21:35:44 -06:00
Eric Gullickson
7928b87ef5 feat: integrate DocumentsService with ownership_costs (refs #29)
Milestone 2: Auto-create ownership_cost when insurance/registration
document is created with cost data (premium or cost field).

- Add OwnershipCostsService integration
- Auto-create cost on document create when amount > 0
- Sync cost changes on document update
- mapDocumentTypeToCostType() validation
- extractCostAmount() for premium/cost field extraction
- CASCADE delete handled by FK constraint

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 21:30:02 -06:00
Eric Gullickson
81b1c3dd70 feat: create ownership_costs backend feature capsule (refs #29)
Milestone 1: Complete backend feature with:
- Migration with CHECK (amount > 0) constraint
- Repository with mapRow() for snake_case -> camelCase
- Service with CRUD and vehicle authorization
- Controller with HTTP handlers
- Routes registered at /api/ownership-costs
- Validation with Zod schemas
- README with endpoint documentation

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 21:28:43 -06:00
5f07123646 Merge pull request 'feat: Total Cost of Ownership (TCO) per Vehicle' (#28) from issue-15-add-tco-feature into main
All checks were successful
Deploy to Staging / Build Images (push) Successful in 24s
Deploy to Staging / Deploy to Staging (push) Successful in 27s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Reviewed-on: #28
2026-01-14 03:08:34 +00:00
Eric Gullickson
395670c3bd 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
- 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
2026-01-13 08:15:53 -06:00
Eric Gullickson
cb93e3ccc5 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
- 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
2026-01-13 07:57:23 -06:00
Eric Gullickson
a8c4eba8d1 feat: add ownership-costs feature capsule (refs #15)
- 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>
2026-01-12 21:28:25 -06:00
Eric Gullickson
5c93150a58 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
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>
2026-01-12 20:32:15 -06:00
Eric Gullickson
9e8f9a1932 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
- 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>
2026-01-12 20:05:31 -06:00
Eric Gullickson
5e40754c68 feat: add ownership cost fields to vehicle form (refs #15)
- 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>
2026-01-12 20:04:21 -06:00
Eric Gullickson
47de6898cd feat: add TCO API endpoint (refs #15)
- 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>
2026-01-12 20:02:15 -06:00
Eric Gullickson
381f602e9f feat: add TCO calculation service (refs #15)
- 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>
2026-01-12 20:01:24 -06:00
Eric Gullickson
35fd1782b4 feat: add maintenance cost aggregation for TCO (refs #15)
- 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>
2026-01-12 19:59:41 -06:00
Eric Gullickson
8517b1ded2 feat: add TCO types and repository updates (refs #15)
- 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>
2026-01-12 19:58:59 -06:00
Eric Gullickson
b0d79a26ae feat: add TCO fields migration (refs #15)
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>
2026-01-12 19:56:30 -06:00
Eric Gullickson
9059c09d2f Merge branch 'main' of 172.30.1.72:egullickson/motovaultpro
All checks were successful
Deploy to Staging / Build Images (push) Successful in 26s
Deploy to Staging / Deploy to Staging (push) Successful in 28s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
2026-01-11 21:52:36 -06:00
Eric Gullickson
34401179bd chore: update script default 2026-01-11 21:52:23 -06:00
6f86b1e7e9 Merge pull request 'feat: Add user data import feature (Fixes #26)' (#27) from issue-26-add-user-data-import into main
All checks were successful
Deploy to Staging / Build Images (push) Successful in 24s
Deploy to Staging / Deploy to Staging (push) Successful in 37s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Reviewed-on: #27
2026-01-12 03:22:31 +00:00
Eric Gullickson
28574b0eb4 fix: preserve vehicle identity by checking ID first in merge mode (refs #26)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m21s
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
Critical fix for merge mode vehicle matching logic.

Problem:
- Vehicles with same license plate but no VIN were matched to the same existing vehicle
- Example: 2 vehicles with license plate "TEST-123" both updated the same vehicle
- Result: "Updated: 2" but only 1 vehicle in database, second vehicle overwrites first

Root Cause:
- Matching order was: VIN → license plate
- Both vehicles had no VIN and same license plate
- Both matched the same existing vehicle by license plate

Solution:
- New matching order: ID → VIN → license plate
- Preserves vehicle identity across export/import cycles
- Vehicles exported with IDs will update the same vehicle on re-import
- New vehicles (no matching ID) will be created as new records
- Security check: Verify ID belongs to same user before matching

Benefits:
- Export-modify-import workflow now works correctly
- Vehicles maintain identity across imports
- Users can safely import data with duplicate license plates
- Prevents unintended overwrites

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 21:15:30 -06:00
Eric Gullickson
62b4dc31ab debug: add comprehensive logging to vehicle import merge (refs #26)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m52s
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
Added detailed logging to diagnose import merge issues:

- Log vehicle count at merge start
- Log each vehicle being processed with VIN/make/model/year
- Log when existing vehicles are found (by VIN or license plate)
- Log successful vehicle creation with new vehicle ID
- Log errors with full context (userId, VIN, make, model, error message)
- Log merge completion with summary statistics

This will help diagnose why vehicles show as "successfully imported" but don't appear in the UI.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 21:03:20 -06:00
Eric Gullickson
f48a18287b fix: prevent vehicle duplication and enforce tier limits in merge mode (refs #26)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m20s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 28s
Deploy to Staging / Verify Staging (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Critical bug fixes for import merge mode:

1. Vehicle duplication bug (RULE 0 - CRITICAL):
   - Previous: Vehicles without VINs always inserted as new, creating duplicates
   - Fixed: Check by VIN first, then fallback to license plate matching
   - Impact: Prevents duplicate vehicles on repeated imports

2. Vehicle limit bypass (RULE 0 - CRITICAL):
   - Previous: Direct repo.create() bypassed tier-based vehicle limits
   - Fixed: Use VehiclesService.createVehicle() which enforces FOR UPDATE locking and tier checks
   - Impact: Free users properly limited to 1 vehicle, prevents limit violations

Changes:
- Added VehiclesService to import service constructor
- Updated mergeVehicles() to check VIN then license plate for matches
- Replace repo.create() with service.createVehicle() for limit enforcement
- Added VehicleLimitExceededError handling with clear error messages

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 20:54:38 -06:00
Eric Gullickson
566deae5af fix: match import button style to export button (refs #26)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m39s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 37s
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
Desktop changes:
- Replace ImportButton component with MUI Button matching Export style
- Use hidden file input with validation
- Dark red/maroon button with consistent styling

Mobile changes:
- Update both Import and Export buttons to use primary-500 style
- Consistent dark primary button appearance
- Maintains 44px touch target requirement

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 20:23:56 -06:00
Eric Gullickson
5648f4c3d0 fix: add import UI to desktop settings page (refs #26)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m38s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 37s
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
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 20:16:42 -06:00
Eric Gullickson
197927ef31 test: add integration tests and documentation (refs #26)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 4m37s
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 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 20:05:06 -06:00
Eric Gullickson
7a5579df7b feat: add frontend import UI (refs #26)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 19:58:17 -06:00