16 controllers still used request.user.sub (Auth0 ID) instead of request.userContext.userId (UUID) after the user_id column migration, causing 500 errors on all authenticated endpoints including dashboard. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ownership Costs Feature
Tracks vehicle ownership costs including insurance, registration, tax, inspection, parking, and other costs.
Database Schema
ownership_costs (
id UUID PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
vehicle_id UUID NOT NULL REFERENCES vehicles(id) ON DELETE CASCADE,
document_id UUID NULL REFERENCES documents(id) ON DELETE CASCADE,
cost_type VARCHAR(32) NOT NULL CHECK (cost_type IN ('insurance', 'registration', 'tax', 'inspection', 'parking', 'other')),
amount DECIMAL(10, 2) NOT NULL CHECK (amount > 0),
description VARCHAR(200),
period_start DATE,
period_end DATE,
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
)
API Endpoints
POST /ownership-costs
Create a new ownership cost record.
Auth: Required (JWT)
Request Body:
{
"vehicleId": "uuid",
"documentId": "uuid (optional)",
"costType": "insurance | registration | tax | inspection | parking | other",
"amount": 150.00,
"description": "Auto insurance premium (optional)",
"periodStart": "2024-01-01 (optional)",
"periodEnd": "2024-12-31 (optional)",
"notes": "Additional notes (optional)"
}
Response: 201 Created
{
"id": "uuid",
"userId": "string",
"vehicleId": "uuid",
"documentId": "uuid",
"costType": "insurance",
"amount": 150.00,
"description": "Auto insurance premium",
"periodStart": "2024-01-01",
"periodEnd": "2024-12-31",
"notes": "Additional notes",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
GET /ownership-costs
List all ownership costs for the authenticated user.
Auth: Required (JWT)
Query Parameters:
vehicleId(optional): Filter by vehicle UUIDcostType(optional): Filter by cost typedocumentId(optional): Filter by document UUID
Response: 200 OK
[
{
"id": "uuid",
"userId": "string",
"vehicleId": "uuid",
"costType": "insurance",
"amount": 150.00,
"description": "Auto insurance premium",
"periodStart": "2024-01-01",
"periodEnd": "2024-12-31",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
]
GET /ownership-costs/:id
Get a specific ownership cost record.
Auth: Required (JWT)
Response: 200 OK (same as POST response)
Errors:
- 404 Not Found: Cost not found or not owned by user
PUT /ownership-costs/:id
Update an ownership cost record.
Auth: Required (JWT)
Request Body: (all fields optional)
{
"documentId": "uuid",
"costType": "insurance",
"amount": 160.00,
"description": "Updated description",
"periodStart": "2024-01-01",
"periodEnd": "2024-12-31",
"notes": "Updated notes"
}
Response: 200 OK (same as POST response)
Errors:
- 404 Not Found: Cost not found or not owned by user
DELETE /ownership-costs/:id
Delete an ownership cost record.
Auth: Required (JWT)
Response: 204 No Content
Errors:
- 404 Not Found: Cost not found or not owned by user
Cost Types
| Type | Description |
|---|---|
| insurance | Auto insurance premiums |
| registration | Vehicle registration fees |
| tax | Property or excise taxes |
| inspection | State inspection fees |
| parking | Parking permits, monthly fees |
| other | Other ownership costs |
Authorization
All endpoints enforce user scoping - users can only access their own ownership cost records. Vehicle ownership is verified before creating records.
Integration with Other Features
- Documents: Optional document_id links costs to supporting documents
- Vehicles: vehicle_id foreign key with CASCADE delete
- TCO Calculation: Service provides
getVehicleOwnershipCosts()for total cost of ownership aggregation