fix: before admin stations removal

This commit is contained in:
Eric Gullickson
2025-12-24 17:20:11 -06:00
parent 96ee43ea94
commit 8ef6b3d853
32 changed files with 1258 additions and 176 deletions

View File

@@ -27,6 +27,7 @@ import { adminRoutes } from './features/admin/api/admin.routes';
import { notificationsRoutes } from './features/notifications';
import { userProfileRoutes } from './features/user-profile';
import { onboardingRoutes } from './features/onboarding';
import { userPreferencesRoutes } from './features/user-preferences';
import { pool } from './core/config/database';
async function buildApp(): Promise<FastifyInstance> {
@@ -84,7 +85,7 @@ async function buildApp(): Promise<FastifyInstance> {
status: 'healthy',
timestamp: new Date().toISOString(),
environment: process.env['NODE_ENV'],
features: ['admin', 'auth', 'onboarding', 'vehicles', 'documents', 'fuel-logs', 'stations', 'maintenance', 'platform', 'notifications', 'user-profile']
features: ['admin', 'auth', 'onboarding', 'vehicles', 'documents', 'fuel-logs', 'stations', 'maintenance', 'platform', 'notifications', 'user-profile', 'user-preferences']
});
});
@@ -94,7 +95,7 @@ async function buildApp(): Promise<FastifyInstance> {
status: 'healthy',
scope: 'api',
timestamp: new Date().toISOString(),
features: ['admin', 'auth', 'onboarding', 'vehicles', 'documents', 'fuel-logs', 'stations', 'maintenance', 'platform', 'notifications', 'user-profile']
features: ['admin', 'auth', 'onboarding', 'vehicles', 'documents', 'fuel-logs', 'stations', 'maintenance', 'platform', 'notifications', 'user-profile', 'user-preferences']
});
});
@@ -132,6 +133,7 @@ async function buildApp(): Promise<FastifyInstance> {
await app.register(adminRoutes, { prefix: '/api' });
await app.register(notificationsRoutes, { prefix: '/api' });
await app.register(userProfileRoutes, { prefix: '/api' });
await app.register(userPreferencesRoutes, { prefix: '/api' });
// 404 handler
app.setNotFoundHandler(async (_request, reply) => {

View File

@@ -50,7 +50,7 @@ export const adminRoutes: FastifyPluginAsync = async (fastify) => {
// Initialize catalog dependencies
const platformCacheService = new PlatformCacheService(cacheService);
const catalogService = new VehicleCatalogService(pool, platformCacheService);
const catalogImportService = new CatalogImportService(pool);
const catalogImportService = new CatalogImportService(pool, platformCacheService);
const catalogController = new CatalogController(catalogService);
catalogController.setImportService(catalogImportService);

View File

@@ -5,9 +5,9 @@
import { Pool } from 'pg';
import { logger } from '../../../core/logging/logger';
import { PlatformCacheService } from '../../platform/domain/platform-cache.service';
export interface ImportRow {
action: 'add' | 'update' | 'delete';
year: number;
make: string;
model: string;
@@ -25,7 +25,6 @@ export interface ImportPreviewResult {
previewId: string;
toCreate: ImportRow[];
toUpdate: ImportRow[];
toDelete: ImportRow[];
errors: ImportError[];
valid: boolean;
}
@@ -33,7 +32,6 @@ export interface ImportPreviewResult {
export interface ImportApplyResult {
created: number;
updated: number;
deleted: number;
errors: ImportError[];
}
@@ -50,7 +48,10 @@ export interface ExportRow {
const previewCache = new Map<string, { data: ImportPreviewResult; expiresAt: number }>();
export class CatalogImportService {
constructor(private pool: Pool) {}
constructor(
private pool: Pool,
private platformCacheService?: PlatformCacheService
) {}
/**
* Parse CSV content and validate without applying changes
@@ -59,7 +60,6 @@ export class CatalogImportService {
const previewId = uuidv4();
const toCreate: ImportRow[] = [];
const toUpdate: ImportRow[] = [];
const toDelete: ImportRow[] = [];
const errors: ImportError[] = [];
const lines = csvContent.trim().split('\n');
@@ -68,7 +68,6 @@ export class CatalogImportService {
previewId,
toCreate,
toUpdate,
toDelete,
errors: [{ row: 0, error: 'CSV must have a header row and at least one data row' }],
valid: false,
};
@@ -78,15 +77,14 @@ export class CatalogImportService {
const header = this.parseCSVLine(lines[0]);
const headerLower = header.map(h => h.toLowerCase().trim());
// Validate required headers
const requiredHeaders = ['action', 'year', 'make', 'model', 'trim'];
// Validate required headers (no action column required - matches export format)
const requiredHeaders = ['year', 'make', 'model', 'trim'];
for (const required of requiredHeaders) {
if (!headerLower.includes(required)) {
return {
previewId,
toCreate,
toUpdate,
toDelete,
errors: [{ row: 1, error: `Missing required header: ${required}` }],
valid: false,
};
@@ -95,7 +93,6 @@ export class CatalogImportService {
// Find column indices
const colIndices = {
action: headerLower.indexOf('action'),
year: headerLower.indexOf('year'),
make: headerLower.indexOf('make'),
model: headerLower.indexOf('model'),
@@ -113,7 +110,6 @@ export class CatalogImportService {
const rowNum = i + 1;
try {
const action = values[colIndices.action]?.toLowerCase().trim();
const year = parseInt(values[colIndices.year], 10);
const make = values[colIndices.make]?.trim();
const model = values[colIndices.model]?.trim();
@@ -121,12 +117,6 @@ export class CatalogImportService {
const engineName = colIndices.engineName >= 0 ? values[colIndices.engineName]?.trim() || null : null;
const transmissionType = colIndices.transmissionType >= 0 ? values[colIndices.transmissionType]?.trim() || null : null;
// Validate action
if (!['add', 'update', 'delete'].includes(action)) {
errors.push({ row: rowNum, error: `Invalid action: ${action}. Must be add, update, or delete` });
continue;
}
// Validate year
if (isNaN(year) || year < 1900 || year > 2100) {
errors.push({ row: rowNum, error: `Invalid year: ${values[colIndices.year]}` });
@@ -148,7 +138,6 @@ export class CatalogImportService {
}
const row: ImportRow = {
action: action as 'add' | 'update' | 'delete',
year,
make,
model,
@@ -157,7 +146,7 @@ export class CatalogImportService {
transmissionType,
};
// Check if record exists for validation
// Check if record exists to determine create vs update (upsert logic)
const existsResult = await this.pool.query(
`SELECT id FROM vehicle_options
WHERE year = $1 AND make = $2 AND model = $3 AND trim = $4
@@ -166,26 +155,11 @@ export class CatalogImportService {
);
const exists = (existsResult.rowCount || 0) > 0;
if (action === 'add' && exists) {
errors.push({ row: rowNum, error: `Record already exists: ${year} ${make} ${model} ${trim}` });
continue;
}
if ((action === 'update' || action === 'delete') && !exists) {
errors.push({ row: rowNum, error: `Record not found: ${year} ${make} ${model} ${trim}` });
continue;
}
// Sort into appropriate bucket
switch (action) {
case 'add':
toCreate.push(row);
break;
case 'update':
toUpdate.push(row);
break;
case 'delete':
toDelete.push(row);
break;
// Auto-detect: if exists -> update, else -> create
if (exists) {
toUpdate.push(row);
} else {
toCreate.push(row);
}
} catch (error: any) {
errors.push({ row: rowNum, error: error.message || 'Parse error' });
@@ -196,7 +170,6 @@ export class CatalogImportService {
previewId,
toCreate,
toUpdate,
toDelete,
errors,
valid: errors.length === 0,
};
@@ -230,7 +203,6 @@ export class CatalogImportService {
const result: ImportApplyResult = {
created: 0,
updated: 0,
deleted: 0,
errors: [],
};
@@ -247,7 +219,7 @@ export class CatalogImportService {
const engineResult = await client.query(
`INSERT INTO engines (name, fuel_type)
VALUES ($1, 'Gas')
ON CONFLICT (LOWER(name)) DO UPDATE SET name = EXCLUDED.name
ON CONFLICT ((lower(name))) DO UPDATE SET name = EXCLUDED.name
RETURNING id`,
[row.engineName]
);
@@ -260,7 +232,7 @@ export class CatalogImportService {
const transResult = await client.query(
`INSERT INTO transmissions (type)
VALUES ($1)
ON CONFLICT (LOWER(type)) DO UPDATE SET type = EXCLUDED.type
ON CONFLICT ((lower(type))) DO UPDATE SET type = EXCLUDED.type
RETURNING id`,
[row.transmissionType]
);
@@ -289,7 +261,7 @@ export class CatalogImportService {
const engineResult = await client.query(
`INSERT INTO engines (name, fuel_type)
VALUES ($1, 'Gas')
ON CONFLICT (LOWER(name)) DO UPDATE SET name = EXCLUDED.name
ON CONFLICT ((lower(name))) DO UPDATE SET name = EXCLUDED.name
RETURNING id`,
[row.engineName]
);
@@ -302,7 +274,7 @@ export class CatalogImportService {
const transResult = await client.query(
`INSERT INTO transmissions (type)
VALUES ($1)
ON CONFLICT (LOWER(type)) DO UPDATE SET type = EXCLUDED.type
ON CONFLICT ((lower(type))) DO UPDATE SET type = EXCLUDED.type
RETURNING id`,
[row.transmissionType]
);
@@ -323,41 +295,21 @@ export class CatalogImportService {
}
}
// Process deletes
for (const row of preview.toDelete) {
try {
await client.query(
`DELETE FROM vehicle_options
WHERE year = $1 AND make = $2 AND model = $3 AND trim = $4`,
[row.year, row.make, row.model, row.trim]
);
result.deleted++;
} catch (error: any) {
result.errors.push({ row: 0, error: `Failed to delete ${row.year} ${row.make} ${row.model} ${row.trim}: ${error.message}` });
}
}
await client.query('COMMIT');
// Log the import action
await this.pool.query(
`INSERT INTO platform_change_log (change_type, resource_type, resource_id, old_value, new_value, changed_by)
VALUES ('CREATE', 'import', $1, NULL, $2, $3)`,
[
previewId,
JSON.stringify({ created: result.created, updated: result.updated, deleted: result.deleted }),
changedBy,
]
);
// Remove preview from cache
previewCache.delete(previewId);
// Invalidate vehicle data cache so dropdowns reflect new data
if (this.platformCacheService) {
await this.platformCacheService.invalidateVehicleData();
logger.debug('Vehicle data cache invalidated after import');
}
logger.info('Catalog import completed', {
previewId,
created: result.created,
updated: result.updated,
deleted: result.deleted,
errors: result.errors.length,
changedBy,
});

View File

@@ -0,0 +1,113 @@
/**
* @ai-summary Fastify route handlers for user preferences API
* @ai-context HTTP request/response handling for unit system and currency preferences
*/
import { FastifyRequest, FastifyReply } from 'fastify';
import { UserPreferencesRepository } from '../../../core/user-preferences/data/user-preferences.repository';
import { UpdateUserPreferencesRequest } from '../../../core/user-preferences/user-preferences.types';
import { pool } from '../../../core/config/database';
import { logger } from '../../../core/logging/logger';
export class UserPreferencesController {
private repository: UserPreferencesRepository;
constructor() {
this.repository = new UserPreferencesRepository(pool);
}
async getPreferences(request: FastifyRequest, reply: FastifyReply) {
try {
const userId = (request as any).user.sub;
let preferences = await this.repository.findByUserId(userId);
// Create default preferences if none exist
if (!preferences) {
preferences = await this.repository.create({
userId,
unitSystem: 'imperial',
currencyCode: 'USD',
timeZone: 'UTC',
});
}
return reply.code(200).send({
id: preferences.id,
userId: preferences.userId,
unitSystem: preferences.unitSystem,
currencyCode: preferences.currencyCode,
timeZone: preferences.timeZone,
createdAt: preferences.createdAt,
updatedAt: preferences.updatedAt,
});
} catch (error) {
logger.error('Error getting user preferences', { error, userId: (request as any).user?.sub });
return reply.code(500).send({
error: 'Internal server error',
message: 'Failed to get preferences',
});
}
}
async updatePreferences(
request: FastifyRequest<{ Body: UpdateUserPreferencesRequest }>,
reply: FastifyReply
) {
try {
const userId = (request as any).user.sub;
const { unitSystem, currencyCode, timeZone } = request.body;
// Validate unitSystem if provided
if (unitSystem && !['imperial', 'metric'].includes(unitSystem)) {
return reply.code(400).send({
error: 'Bad Request',
message: 'unitSystem must be either "imperial" or "metric"',
});
}
// Validate currencyCode if provided (basic 3-letter check)
if (currencyCode && !/^[A-Z]{3}$/.test(currencyCode)) {
return reply.code(400).send({
error: 'Bad Request',
message: 'currencyCode must be a 3-letter ISO currency code',
});
}
// Check if preferences exist, create if not
let preferences = await this.repository.findByUserId(userId);
if (!preferences) {
preferences = await this.repository.create({
userId,
unitSystem: unitSystem || 'imperial',
currencyCode: currencyCode || 'USD',
timeZone: timeZone || 'UTC',
});
} else {
const updated = await this.repository.update(userId, {
unitSystem,
currencyCode,
timeZone,
});
if (updated) {
preferences = updated;
}
}
return reply.code(200).send({
id: preferences.id,
userId: preferences.userId,
unitSystem: preferences.unitSystem,
currencyCode: preferences.currencyCode,
timeZone: preferences.timeZone,
createdAt: preferences.createdAt,
updatedAt: preferences.updatedAt,
});
} catch (error) {
logger.error('Error updating user preferences', { error, userId: (request as any).user?.sub });
return reply.code(500).send({
error: 'Internal server error',
message: 'Failed to update preferences',
});
}
}
}

View File

@@ -0,0 +1,28 @@
/**
* @ai-summary Fastify routes for user preferences API
* @ai-context Route definitions for unit system, currency, and timezone preferences
*/
import { FastifyInstance, FastifyPluginOptions } from 'fastify';
import { FastifyPluginAsync } from 'fastify';
import { UserPreferencesController } from './user-preferences.controller';
import { UpdateUserPreferencesRequest } from '../../../core/user-preferences/user-preferences.types';
export const userPreferencesRoutes: FastifyPluginAsync = async (
fastify: FastifyInstance,
_opts: FastifyPluginOptions
) => {
const controller = new UserPreferencesController();
// GET /api/user/preferences - Get user preferences (creates defaults if none)
fastify.get('/user/preferences', {
preHandler: [fastify.authenticate],
handler: controller.getPreferences.bind(controller),
});
// PUT /api/user/preferences - Update user preferences
fastify.put<{ Body: UpdateUserPreferencesRequest }>('/user/preferences', {
preHandler: [fastify.authenticate],
handler: controller.updatePreferences.bind(controller),
});
};

View File

@@ -0,0 +1,6 @@
/**
* @ai-summary User preferences feature entry point
* @ai-context Exports routes for unit system, currency, and timezone preferences
*/
export { userPreferencesRoutes } from './api/user-preferences.routes';

View File

@@ -0,0 +1,74 @@
groupname | variable | value | itempatternid | itemvinschemaid | itemkeys | itemelementid | itemattributeid | itemcreatedon | itemwmiid | code | datatype | decode | itemsource | itemtobeqced
-----------------------------------------------------+-----------------------------------------------+-----------------------------------------------------------------------------------------------------------------+---------------+-----------------+--------------+---------------+-----------------------------------------------------------------------------------------------------------------+-------------------------+-----------+-------------------------------------+----------+--------------+----------------------------------+--------------
| Possible Values | | | | | 144 | | | | PossibleValues | string | Decoding | Corrections |
| Suggested VIN | | | | | 142 | | | | SuggestedVIN | string | Decoding | Corrections |
| Error Text | 0 - VIN decoded clean. Check Digit (9th position) is correct | | | | 191 | 0 - VIN decoded clean. Check Digit (9th position) is correct | | | ErrorText | string | Decoding | Corrections |
| Vehicle Descriptor | 5J8YE1H0*SL | | | | 196 | 5J8YE1H0*SL | | | VehicleDescriptor | string | Decoding | Corrections |
| Error Code | 0 | | | | 143 | 0 | | | ErrorCode | lookup | Decoding | Corrections |
| Additional Error Text | | | | | 156 | | | | AdditionalErrorText | string | Decoding | Corrections |
General | Vehicle Type | MULTIPURPOSE PASSENGER VEHICLE (MPV) | | | 5J8 | 39 | 7 | 2015-03-27 15:31:28.273 | 2105 | VehicleType | lookup | WMI | VehType |
General | Make | ACURA | 2074168 | 26929 | Y[ED]*H | 26 | 475 | | | Make | lookup | WMI, Pattern | pattern - model |
General | Manufacturer Name | AMERICAN HONDA MOTOR CO., INC. | | | 5J8 | 27 | 988 | | 2105 | Manufacturer | lookup | WMI | Manu. Name |
General | Model Year | 2025 | | | ***X*|Y | 29 | 2025 | | | ModelYear | int | WMI, Input | ModelYear |
General | Model | MDX | 2074168 | 26929 | Y[ED]*H | 28 | 2147 | 2024-05-21 10:17:20.287 | 2105 | Model | lookup | Pattern | Pattern |
General | Plant City | EAST LIBERTY | 2117059 | 27341 | *****|*L | 31 | EAST LIBERTY | 2024-08-27 07:36:52.53 | 2105 | PlantCity | string | Pattern | Pattern |
General | Plant State | OHIO | 2117056 | 27341 | *****|*[ALY] | 77 | OHIO | 2024-08-27 07:35:26.557 | 2105 | PlantState | string | Pattern | Pattern |
General | Plant Country | UNITED STATES (USA) | 2117055 | 27341 | *****|*[ALY] | 75 | 6 | 2024-08-27 07:35:26.54 | 2105 | PlantCountry | lookup | Pattern | Pattern |
General | Trim | SH-AWD A-Spec | 2074202 | 26929 | YE1H0 | 38 | SH-AWD A-Spec | 2024-05-21 10:24:09.057 | 2105 | Trim | string | Pattern | Pattern |
Exterior / Body | Body Class | Sport Utility Vehicle (SUV)/Multi-Purpose Vehicle (MPV) | 2074165 | 26929 | Y[ED]*H | 5 | 7 | 2024-05-21 10:17:20.143 | 2105 | BodyClass | lookup | Pattern | Pattern |
Exterior / Body | Doors | 5 | 2074166 | 26929 | Y[ED]*H | 14 | 5 | 2024-05-21 10:17:20.223 | 2105 | Doors | int | Pattern | Pattern |
Exterior / Dimension | Gross Vehicle Weight Rating From | Class 1D: 5,001 - 6,000 lb (2,268 - 2,722 kg) | 2074167 | 26929 | Y[ED]*H | 25 | 13 | 2024-05-21 10:17:20.27 | 2105 | GVWR | lookup | Pattern | Pattern |
Exterior / Dimension | Gross Vehicle Weight Rating To | Class 1D: 5,001 - 6,000 lb (2,268 - 2,722 kg) | 2074180 | 26929 | Y[ED]*H | 190 | 13 | 2024-05-21 10:17:20.63 | 2105 | GVWR_to | lookup | Pattern | Pattern |
Exterior / Trailer | Trailer Type Connection | Not Applicable | | | | 116 | 0 | 2019-12-21 20:26:30.583 | | TrailerType | lookup | Pattern | Default |
Exterior / Trailer | Trailer Body Type | Not Applicable | | | | 117 | 0 | 2019-12-21 20:26:30.583 | | TrailerBodyType | lookup | Pattern | Default |
Exterior / Motorcycle | Motorcycle Suspension Type | Not Applicable | | | | 152 | 0 | 2019-12-21 20:26:30.583 | | MotorcycleSuspensionType | lookup | Pattern | Default |
Exterior / Motorcycle | Motorcycle Chassis Type | Not Applicable | | | | 153 | 0 | 2019-12-21 20:26:30.583 | | MotorcycleChassisType | lookup | Pattern | Default |
Exterior / Motorcycle | Custom Motorcycle Type | Not Applicable | | | | 151 | 0 | 2019-12-21 20:26:30.583 | | CustomMotorcycleType | lookup | Pattern | Default |
Exterior / Bus | Bus Floor Configuration Type | Not Applicable | | | | 148 | 0 | 2019-12-21 20:26:30.583 | | BusFloorConfigType | lookup | Pattern | Default |
Exterior / Bus | Bus Type | Not Applicable | | | | 149 | 0 | 2019-12-21 20:26:30.583 | | BusType | lookup | Pattern | Default |
Mechanical / Transmission | Transmission Speeds | 10 | 2074171 | 26929 | Y[ED]*H | 63 | 10 | 2024-05-21 10:17:20.343 | 2105 | TransmissionSpeeds | int | Pattern | Pattern |
Mechanical / Transmission | Transmission Style | Automatic | 2074169 | 26929 | Y[ED]*H | 37 | 2 | 2024-05-21 10:17:20.303 | 2105 | TransmissionStyle | lookup | Pattern | Pattern |
Mechanical / Drivetrain | Drive Type | 4WD/4-Wheel Drive/4x4 | 2074181 | 26929 | YE1 | 15 | 2 | 2024-05-21 10:18:30.127 | 2105 | DriveType | lookup | Pattern | Pattern |
Engine | Other Engine Info | Direct Fuel Injection | 2074214 | 26929 | Y[ED][19] | 129 | Direct Fuel Injection | 2024-05-21 10:42:05.407 | 2105 | OtherEngineInfo | string | Pattern | Pattern |
Engine | Displacement (CC) | 3500.0 | 2074206 | 26929 | Y[ED][19] | 11 | 3500.0 | | 2105 | DisplacementCC | decimal | Pattern | Conversion 4: 3.5 * 1000 |
Engine | Displacement (CI) | 213.5831043315629938 | 2074206 | 26929 | Y[ED][19] | 12 | 213.5831043315629938 | | 2105 | DisplacementCI | decimal | Pattern | Conversion 7: 3.5 / 0.016387064 |
Engine | Engine Number of Cylinders | 6 | 2074205 | 26929 | Y[ED][19] | 9 | 6 | 2024-05-21 10:42:05.137 | 2105 | EngineCylinders | int | Pattern | Pattern |
Engine | Displacement (L) | 3.5 | 2074206 | 26929 | Y[ED][19] | 13 | 3.5 | 2024-05-21 10:42:05.157 | 2105 | DisplacementL | decimal | Pattern | Pattern |
Engine | Engine Stroke Cycles | 4 | 2074207 | 26929 | Y[ED][19] | 17 | 4 | 2024-05-21 10:42:05.287 | 2105 | EngineCycles | int | Pattern | Pattern |
Engine | Engine Model | J35Y5 | 2074208 | 26929 | Y[ED][19] | 18 | J35Y5 | 2024-05-21 10:42:05.303 | 2105 | EngineModel | string | Pattern | Pattern |
Engine | Fuel Type - Primary | Gasoline | 2074209 | 26929 | Y[ED][19] | 24 | 4 | 2024-05-21 10:42:05.32 | 2105 | FuelTypePrimary | lookup | Pattern | Pattern |
Engine | Valve Train Design | Single Overhead Cam (SOHC) | 2074210 | 26929 | Y[ED][19] | 62 | 4 | 2024-05-21 10:42:05.337 | 2105 | ValveTrainDesign | lookup | Pattern | Pattern |
Engine | Engine Configuration | V-Shaped | 2074211 | 26929 | Y[ED][19] | 64 | 2 | 2024-05-21 10:42:05.353 | 2105 | EngineConfiguration | lookup | Pattern | Pattern |
Engine | Engine Brake (hp) From | 290 | 2074212 | 26929 | Y[ED][19] | 71 | 290 | 2024-05-21 10:42:05.37 | 2105 | EngineHP | decimal | Pattern | Pattern |
Engine | Cooling Type | Water | 2074213 | 26929 | Y[ED][19] | 122 | 2 | 2024-05-21 10:42:05.39 | 2105 | CoolingType | lookup | Pattern | Pattern |
Engine | Engine Manufacturer | Honda | 2074215 | 26929 | Y[ED][19] | 146 | Honda | 2024-05-21 10:42:05.423 | 2105 | EngineManufacturer | string | Pattern | Pattern |
Passive Safety System | Other Restraint System Info | Front: Seat Belts, Mid/Rear: Seat Belt and Side Curtain Air Bag (Outer positions) / Seat Belt (Center position) | 2074179 | 26929 | Y[ED]*H | 121 | Front: Seat Belts, Mid/Rear: Seat Belt and Side Curtain Air Bag (Outer positions) / Seat Belt (Center position) | 2024-05-21 10:17:20.61 | 2105 | OtherRestraintSystemInfo | string | Pattern | Pattern |
Passive Safety System | Seat Belt Type | Manual | 2074174 | 26929 | Y[ED]*H | 79 | 1 | 2024-05-21 10:17:20.393 | 2105 | SeatBeltsAll | lookup | Pattern | Pattern |
Passive Safety System / Air Bag Location | Side Air Bag Locations | 1st Row (Driver and Passenger) | 2074178 | 26929 | Y[ED]*H | 107 | 3 | 2024-05-21 10:17:20.593 | 2105 | AirBagLocSide | lookup | Pattern | Pattern |
Passive Safety System / Air Bag Location | Knee Air Bag Locations | 1st Row (Driver and Passenger) | 2074173 | 26929 | Y[ED]*H | 69 | 3 | 2024-05-21 10:17:20.377 | 2105 | AirBagLocKnee | lookup | Pattern | Pattern |
Passive Safety System / Air Bag Location | Front Air Bag Locations | 1st Row (Driver and Passenger) | 2074172 | 26929 | Y[ED]*H | 65 | 3 | 2024-05-21 10:17:20.36 | 2105 | AirBagLocFront | lookup | Pattern | Pattern |
Passive Safety System / Air Bag Location | Curtain Air Bag Locations | 1st and 2nd and 3rd Rows | 2074170 | 26929 | Y[ED]*H | 55 | 5 | 2024-05-21 10:17:20.327 | 2105 | AirBagLocCurtain | lookup | Pattern | Pattern |
Active Safety System | Keyless Ignition | Standard | 16875 | 5601 | | 176 | 1 | 2025-04-03 14:07:35.83 | | KeylessIgnition | lookup | Pattern | Vehicle Specs |
Active Safety System | Electronic Stability Control (ESC) | Standard | 16875 | 5601 | | 99 | 1 | 2025-04-03 14:07:35.587 | | ESC | lookup | Pattern | Vehicle Specs |
Active Safety System | Tire Pressure Monitoring System (TPMS) Type | Direct | 16875 | 5601 | | 168 | 1 | 2025-04-03 14:07:35.767 | | TPMS | lookup | Pattern | Vehicle Specs |
Active Safety System | Event Data Recorder (EDR) | Standard | 16875 | 5601 | | 175 | 1 | 2025-04-03 14:07:35.817 | | EDR | lookup | Pattern | Vehicle Specs |
Active Safety System | Auto-Reverse System for Windows and Sunroofs | Standard | 16875 | 5601 | | 172 | 1 | 2025-04-03 14:07:35.803 | | AutoReverseSystem | lookup | Pattern | Vehicle Specs |
Active Safety System | Anti-lock Braking System (ABS) | Standard | 16875 | 5601 | | 86 | 1 | 2025-04-03 14:07:35.56 | | ABS | lookup | Pattern | Vehicle Specs |
Active Safety System | Traction Control | Standard | 16875 | 5601 | | 100 | 1 | 2025-04-03 14:07:35.6 | | TractionControl | lookup | Pattern | Vehicle Specs |
Active Safety System / Maintaining Safe Distance | Adaptive Cruise Control (ACC) | Standard | 16875 | 5601 | | 81 | 1 | 2025-04-03 14:07:35.55 | | AdaptiveCruiseControl | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Forward Collision Warning (FCW) | Standard | 16875 | 5601 | | 101 | 1 | 2025-04-03 14:07:35.613 | | ForwardCollisionWarning | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Dynamic Brake Support (DBS) | Standard | 16875 | 5601 | | 170 | 1 | 2025-04-03 14:07:35.78 | | DynamicBrakeSupport | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Pedestrian Automatic Emergency Braking (PAEB) | Standard | 16875 | 5601 | | 171 | 1 | 2025-04-03 14:07:35.79 | | PedestrianAutomaticEmergencyBraking | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Crash Imminent Braking (CIB) | Standard | 16875 | 5601 | | 87 | 1 | 2025-04-03 14:07:35.573 | | CIB | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Lane Keeping Assistance (LKA) | Standard | 16875 | 5601 | | 103 | 1 | 2025-04-03 14:07:35.64 | | LaneKeepSystem | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Lane Departure Warning (LDW) | Standard | 16875 | 5601 | | 102 | 1 | 2025-04-03 14:07:35.627 | | LaneDepartureWarning | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Lane Centering Assistance | Standard | 16875 | 5601 | | 194 | 1 | 2025-04-03 14:07:36.043 | | LaneCenteringAssistance | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Blind Spot Intervention (BSI) | Standard | 16875 | 5601 | | 193 | 1 | 2025-04-03 14:07:36.03 | | BlindSpotIntervention | lookup | Pattern | Vehicle Specs |
Active Safety System / Backing Up and Parking | Rear Automatic Emergency Braking | Standard | 16875 | 5601 | | 192 | 1 | 2025-04-03 14:07:36.01 | | RearAutomaticEmergencyBraking | lookup | Pattern | Vehicle Specs |
Active Safety System / Backing Up and Parking | Rear Cross Traffic Alert | Standard | 16875 | 5601 | | 183 | 1 | 2025-04-03 14:07:35.897 | | RearCrossTrafficAlert | lookup | Pattern | Vehicle Specs |
Active Safety System / Backing Up and Parking | Backup Camera | Standard | 16875 | 5601 | | 104 | 1 | 2025-04-03 14:07:35.753 | | RearVisibilitySystem | lookup | Pattern | Vehicle Specs |
Active Safety System / Lighting Technologies | Headlamp Light Source | LED | 16875 | 5601 | | 178 | 3 | 2025-04-03 14:07:35.863 | | LowerBeamHeadlampLightSource | lookup | Pattern | Vehicle Specs |
Active Safety System / Lighting Technologies | Daytime Running Light (DRL) | Standard | 16875 | 5601 | | 177 | 1 | 2025-04-03 14:07:35.843 | | DaytimeRunningLight | lookup | Pattern | Vehicle Specs |
Active Safety System / Lighting Technologies | Semiautomatic Headlamp Beam Switching | Standard | 16875 | 5601 | | 179 | 1 | 2025-04-03 14:07:35.88 | | SemiautomaticHeadlampBeamSwitching | lookup | Pattern | Vehicle Specs |
(70 rows)

64
data/vehicle-etl/BMW.txt Normal file
View File

@@ -0,0 +1,64 @@
groupname | variable | value | itempatternid | itemvinschemaid | itemkeys | itemelementid | itemattributeid | itemcreatedon | itemwmiid | code | datatype | decode | itemsource | itemtobeqced
-----------------------------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+---------------+-----------------+----------+---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------+-----------+-------------------------------------+----------+--------------+----------------------------------+--------------
| Possible Values | | | | | 144 | | | | PossibleValues | string | Decoding | Corrections |
| Additional Error Text | | | | | 156 | | | | AdditionalErrorText | string | Decoding | Corrections |
| Vehicle Descriptor | 5YM13ET0*R9 | | | | 196 | 5YM13ET0*R9 | | | VehicleDescriptor | string | Decoding | Corrections |
| Error Code | 0 | | | | 143 | 0 | | | ErrorCode | lookup | Decoding | Corrections |
| Error Text | 0 - VIN decoded clean. Check Digit (9th position) is correct | | | | 191 | 0 - VIN decoded clean. Check Digit (9th position) is correct | | | ErrorText | string | Decoding | Corrections |
| Suggested VIN | | | | | 142 | | | | SuggestedVIN | string | Decoding | Corrections |
General | Vehicle Type | MULTIPURPOSE PASSENGER VEHICLE (MPV) | | | 5YM | 39 | 7 | 2015-03-11 13:50:19.203 | 2020 | VehicleType | lookup | WMI | VehType |
General | Plant State | SOUTH CAROLINA | 1765033 | 23981 | *****|*9 | 77 | SOUTH CAROLINA | 2022-06-22 14:28:01.55 | 2020 | PlantState | string | Pattern | Pattern |
General | Plant Country | UNITED STATES (USA) | 1765032 | 23981 | *****|*9 | 75 | 6 | 2022-06-22 14:28:01.55 | 2020 | PlantCountry | lookup | Pattern | Pattern |
General | Plant City | GREER | 1765031 | 23981 | *****|*9 | 31 | GREER | 2022-06-22 14:28:01.55 | 2020 | PlantCity | string | Pattern | Pattern |
General | Manufacturer Name | BMW MANUFACTURER CORPORATION / BMW NORTH AMERICA | | | 5YM | 27 | 968 | | 2020 | Manufacturer | lookup | WMI | Manu. Name |
General | Make | BMW | 1895508 | 25151 | 13ET0 | 26 | 452 | | | Make | lookup | WMI, Pattern | pattern - model |
General | Model | X5 | 1895508 | 25151 | 13ET0 | 28 | 1717 | 2023-03-09 15:43:52.33 | 2020 | Model | lookup | Pattern | Pattern | f
General | Trim | X5 M Competition | 2031372 | 25151 | 13ET0 | 38 | X5 M Competition | 2024-02-20 12:44:30.22 | 2020 | Trim | string | Pattern | Pattern | f
General | Model Year | 2024 | | | ***X*|Y | 29 | 2024 | | | ModelYear | int | WMI, Input | ModelYear |
Exterior / Body | Doors | 4 | 1895505 | 25151 | 13ET0 | 14 | 4 | 2023-03-09 15:43:52.28 | 2020 | Doors | int | Pattern | Pattern | f
Exterior / Body | Body Class | Sport Utility Vehicle (SUV)/Multi-Purpose Vehicle (MPV) | 1895502 | 25151 | 13ET0 | 5 | 7 | 2023-03-09 15:43:52.227 | 2020 | BodyClass | lookup | Pattern | Pattern | f
Exterior / Dimension | Gross Vehicle Weight Rating From | Class 2E: 6,001 - 7,000 lb (2,722 - 3,175 kg) | 1895507 | 25151 | 13ET0 | 25 | 14 | 2023-03-09 15:43:52.313 | 2020 | GVWR | lookup | Pattern | Pattern | f
Exterior / Trailer | Trailer Body Type | Not Applicable | | | | 117 | 0 | 2019-12-21 20:26:30.583 | | TrailerBodyType | lookup | Pattern | Default |
Exterior / Trailer | Trailer Type Connection | Not Applicable | | | | 116 | 0 | 2019-12-21 20:26:30.583 | | TrailerType | lookup | Pattern | Default |
Exterior / Motorcycle | Motorcycle Chassis Type | Not Applicable | | | | 153 | 0 | 2019-12-21 20:26:30.583 | | MotorcycleChassisType | lookup | Pattern | Default |
Exterior / Motorcycle | Custom Motorcycle Type | Not Applicable | | | | 151 | 0 | 2019-12-21 20:26:30.583 | | CustomMotorcycleType | lookup | Pattern | Default |
Exterior / Motorcycle | Motorcycle Suspension Type | Not Applicable | | | | 152 | 0 | 2019-12-21 20:26:30.583 | | MotorcycleSuspensionType | lookup | Pattern | Default |
Exterior / Bus | Bus Type | Not Applicable | | | | 149 | 0 | 2019-12-21 20:26:30.583 | | BusType | lookup | Pattern | Default |
Exterior / Bus | Bus Floor Configuration Type | Not Applicable | | | | 148 | 0 | 2019-12-21 20:26:30.583 | | BusFloorConfigType | lookup | Pattern | Default |
Engine | Engine Number of Cylinders | 8 | 1895503 | 25151 | 13ET0 | 9 | 8 | 2023-03-09 15:43:52.243 | 2020 | EngineCylinders | int | Pattern | Pattern | f
Engine | Displacement (CC) | 4400.0 | 1895504 | 25151 | 13ET0 | 11 | 4400.0 | | 2020 | DisplacementCC | decimal | Pattern | Conversion 4: 4.4 * 1000 |
Engine | Displacement (CI) | 268.5044740168220494 | 1895504 | 25151 | 13ET0 | 12 | 268.5044740168220494 | | 2020 | DisplacementCI | decimal | Pattern | Conversion 7: 4.4 / 0.016387064 |
Engine | Displacement (L) | 4.4 | 1895504 | 25151 | 13ET0 | 13 | 4.4 | 2023-03-09 15:43:52.26 | 2020 | DisplacementL | decimal | Pattern | Pattern | f
Engine | Fuel Type - Primary | Gasoline | 1895506 | 25151 | 13ET0 | 24 | 4 | 2023-03-09 15:43:52.297 | 2020 | FuelTypePrimary | lookup | Pattern | Pattern | f
Engine | Engine Brake (hp) From | 617 | 1895513 | 25151 | 13ET0 | 71 | 617 | 2023-03-09 15:43:52.537 | 2020 | EngineHP | decimal | Pattern | Pattern | f
Passive Safety System | Seat Belt Type | Manual | 1895515 | 25151 | 13ET0 | 79 | 1 | 2023-03-09 15:43:52.57 | 2020 | SeatBeltsAll | lookup | Pattern | Pattern | f
Passive Safety System | Other Restraint System Info | Seat Belt: All positions / Pretensioners, Side Airbags, Head Inflatable Restraint: Front Row & Rear Outboard Driver-side, Rear Outboard Passenger-side | 1895520 | 25151 | 13ET0 | 121 | Seat Belt: All positions / Pretensioners, Side Airbags, Head Inflatable Restraint: Front Row & Rear Outboard Driver-side, Rear Outboard Passenger-side | 2023-03-09 15:43:52.77 | 2020 | OtherRestraintSystemInfo | string | Pattern | Pattern | f
Passive Safety System | Pretensioner | Yes | 1895514 | 25151 | 13ET0 | 78 | 1 | 2023-03-09 15:43:52.553 | 2020 | Pretensioner | lookup | Pattern | Pattern | f
Passive Safety System / Air Bag Location | Knee Air Bag Locations | 1st Row (Driver and Passenger) | 1895512 | 25151 | 13ET0 | 69 | 3 | 2023-03-09 15:43:52.517 | 2020 | AirBagLocKnee | lookup | Pattern | Pattern | f
Passive Safety System / Air Bag Location | Side Air Bag Locations | 1st and 2nd Rows | 1895519 | 25151 | 13ET0 | 107 | 4 | 2023-03-09 15:43:52.633 | 2020 | AirBagLocSide | lookup | Pattern | Pattern | f
Passive Safety System / Air Bag Location | Curtain Air Bag Locations | 1st and 2nd Rows | 1895510 | 25151 | 13ET0 | 55 | 4 | 2023-03-09 15:43:52.483 | 2020 | AirBagLocCurtain | lookup | Pattern | Pattern | f
Passive Safety System / Air Bag Location | Front Air Bag Locations | 1st Row (Driver and Passenger) | 1895511 | 25151 | 13ET0 | 65 | 3 | 2023-03-09 15:43:52.5 | 2020 | AirBagLocFront | lookup | Pattern | Pattern | f
Active Safety System | Tire Pressure Monitoring System (TPMS) Type | Direct | 14937 | 4656 | | 168 | 1 | 2024-03-12 13:41:17.253 | | TPMS | lookup | Pattern | Vehicle Specs |
Active Safety System | Anti-lock Braking System (ABS) | Standard | 14937 | 4656 | | 86 | 1 | 2024-03-12 13:41:17.01 | | ABS | lookup | Pattern | Vehicle Specs |
Active Safety System | Keyless Ignition | Standard | 14937 | 4656 | | 176 | 1 | 2024-03-12 13:41:17.317 | | KeylessIgnition | lookup | Pattern | Vehicle Specs |
Active Safety System | Auto-Reverse System for Windows and Sunroofs | Standard | 14937 | 4656 | | 172 | 1 | 2024-03-12 13:41:17.3 | | AutoReverseSystem | lookup | Pattern | Vehicle Specs |
Active Safety System | Electronic Stability Control (ESC) | Standard | 14937 | 4656 | | 99 | 1 | 2024-03-12 13:41:17.05 | | ESC | lookup | Pattern | Vehicle Specs |
Active Safety System | Traction Control | Standard | 14937 | 4656 | | 100 | 1 | 2024-03-12 13:41:17.183 | | TractionControl | lookup | Pattern | Vehicle Specs |
Active Safety System / Maintaining Safe Distance | Adaptive Cruise Control (ACC) | Optional | 14937 | 4656 | | 81 | 3 | 2024-03-12 13:41:16.993 | | AdaptiveCruiseControl | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Dynamic Brake Support (DBS) | Standard | 14937 | 4656 | | 170 | 1 | 2024-03-12 13:41:17.267 | | DynamicBrakeSupport | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Forward Collision Warning (FCW) | Standard | 14937 | 4656 | | 101 | 1 | 2024-03-12 13:41:17.2 | | ForwardCollisionWarning | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Crash Imminent Braking (CIB) | Standard | 14937 | 4656 | | 87 | 1 | 2024-03-12 13:41:17.02 | | CIB | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Pedestrian Automatic Emergency Braking (PAEB) | Standard | 14937 | 4656 | | 171 | 1 | 2024-03-12 13:41:17.28 | | PedestrianAutomaticEmergencyBraking | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Lane Centering Assistance | Optional | 14937 | 4656 | | 194 | 3 | 2024-03-12 13:41:17.543 | | LaneCenteringAssistance | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Blind Spot Warning (BSW) | Standard | 14937 | 4656 | | 88 | 1 | 2024-03-12 13:41:17.037 | | BlindSpotMon | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Lane Keeping Assistance (LKA) | Optional | 14937 | 4656 | | 103 | 5 | 2024-03-12 13:41:17.227 | | LaneKeepSystem | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Blind Spot Intervention (BSI) | Optional | 14937 | 4656 | | 193 | 3 | 2024-03-12 13:41:17.53 | | BlindSpotIntervention | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Lane Departure Warning (LDW) | Standard | 14937 | 4656 | | 102 | 1 | 2024-03-12 13:41:17.213 | | LaneDepartureWarning | lookup | Pattern | Vehicle Specs |
Active Safety System / Backing Up and Parking | Rear Automatic Emergency Braking | Standard | 14937 | 4656 | | 192 | 1 | 2024-03-12 13:41:17.517 | | RearAutomaticEmergencyBraking | lookup | Pattern | Vehicle Specs |
Active Safety System / Backing Up and Parking | Rear Cross Traffic Alert | Optional | 14937 | 4656 | | 183 | 2 | 2024-03-12 13:41:17.503 | | RearCrossTrafficAlert | lookup | Pattern | Vehicle Specs |
Active Safety System / Backing Up and Parking | Backup Camera | Standard | 14937 | 4656 | | 104 | 1 | 2024-03-12 13:41:17.24 | | RearVisibilitySystem | lookup | Pattern | Vehicle Specs |
Active Safety System / Lighting Technologies | Semiautomatic Headlamp Beam Switching | Standard | 14937 | 4656 | | 179 | 1 | 2024-03-12 13:41:17.49 | | SemiautomaticHeadlampBeamSwitching | lookup | Pattern | Vehicle Specs |
Active Safety System / Lighting Technologies | Daytime Running Light (DRL) | Standard | 14937 | 4656 | | 177 | 1 | 2024-03-12 13:41:17.33 | | DaytimeRunningLight | lookup | Pattern | Vehicle Specs |
Active Safety System / Lighting Technologies | Headlamp Light Source | LED | 14937 | 4656 | | 178 | 3 | 2024-03-12 13:41:17.477 | | LowerBeamHeadlampLightSource | lookup | Pattern | Vehicle Specs |
(60 rows)

68
data/vehicle-etl/GMC.txt Normal file
View File

@@ -0,0 +1,68 @@
groupname | variable | value | itempatternid | itemvinschemaid | itemkeys | itemelementid | itemattributeid | itemcreatedon | itemwmiid | code | datatype | decode | itemsource | itemtobeqced
-----------------------------------------------------+-----------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+---------------+-----------------+----------------+---------------+------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------+-----------+-------------------------------------+----------+--------------+----------------------------------+--------------
| Suggested VIN | | | | | 142 | | | | SuggestedVIN | string | Decoding | Corrections |
| Error Text | 0 - VIN decoded clean. Check Digit (9th position) is correct | | | | 191 | 0 - VIN decoded clean. Check Digit (9th position) is correct | | | ErrorText | string | Decoding | Corrections |
| Additional Error Text | The Model Year decoded for this VIN may be incorrect. If you know the Model year, please enter it and decode again to get more accurate information. | | | | 156 | The Model Year decoded for this VIN may be incorrect. If you know the Model year, please enter it and decode again to get more accurate information. | | | AdditionalErrorText | string | Decoding | Corrections |
| Error Code | 0 | | | | 143 | 0 | | | ErrorCode | lookup | Decoding | Corrections |
| Vehicle Descriptor | 3GTUUFEL*PG | | | | 196 | 3GTUUFEL*PG | | | VehicleDescriptor | string | Decoding | Corrections |
| Possible Values | | | | | 144 | | | | PossibleValues | string | Decoding | Corrections |
General | Manufacturer Name | GENERAL MOTORS LLC | | | 3GT | 27 | 984 | | 2066 | Manufacturer | lookup | WMI | Manu. Name |
General | Model Year | 2023 | | | ***X*|Y | 29 | 2023 | | | ModelYear | int | WMI, Input | ModelYear |
General | Make | GMC | 1947758 | 25646 | [NPRUV][HU] | 26 | 472 | | | Make | lookup | WMI, Pattern | pattern - model |
General | Plant City | SILAO | 1947761 | 25646 | *****|*G | 31 | SILAO | 2023-07-11 14:39:30.503 | 2066 | PlantCity | string | Pattern | Pattern |
General | Series | 1500 | 1947762 | 25646 | [NPRUV][HU] | 34 | 1500 | 2023-07-11 14:39:30.503 | 2066 | Series | string | Pattern | Pattern |
General | Trim | AT4X | 1947769 | 25646 | *UF | 38 | AT4X | 2023-07-11 14:39:30.503 | 2066 | Trim | string | Pattern | Pattern |
General | Plant Country | MEXICO | 1947783 | 25646 | *****|*G | 75 | 12 | 2023-07-11 14:39:30.503 | 2066 | PlantCountry | lookup | Pattern | Pattern |
General | Plant State | GUANAJUATO | 1947786 | 25646 | *****|*G | 77 | GUANAJUATO | 2023-07-11 14:39:30.503 | 2066 | PlantState | string | Pattern | Pattern |
General | Vehicle Type | TRUCK | | | 3GT | 39 | 3 | 2015-03-24 15:16:38.563 | 2066 | VehicleType | lookup | WMI | VehType |
General | Model | Sierra | 1947758 | 25646 | [NPRUV][HU] | 28 | 1857 | 2023-07-11 14:46:06.22 | 2066 | Model | lookup | Pattern | Pattern |
Exterior / Body | Body Class | Pickup | 1947732 | 25646 | [NPRUV][HU] | 5 | 60 | 2023-07-11 14:46:06.22 | 2066 | BodyClass | lookup | Pattern | Pattern |
Exterior / Dimension | Gross Vehicle Weight Rating From | Class 2F: 7,001 - 8,000 lb (3,175 - 3,629 kg) | 1947756 | 25646 | [UV][HU] | 25 | 15 | 2023-07-11 14:46:18.457 | 2066 | GVWR | lookup | Pattern | Pattern |
Exterior / Trailer | Trailer Body Type | Not Applicable | | | | 117 | 0 | 2019-12-21 20:26:30.583 | | TrailerBodyType | lookup | Pattern | Default |
Exterior / Trailer | Trailer Type Connection | Not Applicable | | | | 116 | 0 | 2019-12-21 20:26:30.583 | | TrailerType | lookup | Pattern | Default |
Exterior / Motorcycle | Motorcycle Chassis Type | Not Applicable | | | | 153 | 0 | 2019-12-21 20:26:30.583 | | MotorcycleChassisType | lookup | Pattern | Default |
Exterior / Motorcycle | Custom Motorcycle Type | Not Applicable | | | | 151 | 0 | 2019-12-21 20:26:30.583 | | CustomMotorcycleType | lookup | Pattern | Default |
Exterior / Motorcycle | Motorcycle Suspension Type | Not Applicable | | | | 152 | 0 | 2019-12-21 20:26:30.583 | | MotorcycleSuspensionType | lookup | Pattern | Default |
Exterior / Bus | Bus Type | Not Applicable | | | | 149 | 0 | 2019-12-21 20:26:30.583 | | BusType | lookup | Pattern | Default |
Exterior / Bus | Bus Floor Configuration Type | Not Applicable | | | | 148 | 0 | 2019-12-21 20:26:30.583 | | BusFloorConfigType | lookup | Pattern | Default |
Mechanical / Drivetrain | Drive Type | 4WD/4-Wheel Drive/4x4 | 1947745 | 25646 | [NPRUV]U[A-J9] | 15 | 2 | 2023-07-11 14:39:30.503 | 2066 | DriveType | lookup | Pattern | Pattern |
Mechanical / Brake | Brake System Type | Hydraulic | 1947772 | 25646 | [NPRUV][HU] | 42 | 2 | 2023-07-11 14:46:06.22 | 2066 | BrakeSystemType | lookup | Pattern | Pattern |
Engine | Other Engine Info | DI DFM, ALUM, GEN 5 | 1947794 | 25646 | *[HU]**L | 129 | DI DFM, ALUM, GEN 5 | 2023-07-11 14:39:30.503 | 2066 | OtherEngineInfo | string | Pattern | Pattern |
Engine | Displacement (CI) | 378.3472133873401605 | 1947739 | 25646 | *[HU]**L | 12 | 378.3472133873401605 | | 2066 | DisplacementCI | decimal | Pattern | Conversion 7: 6.2 / 0.016387064 |
Engine | Engine Configuration | V-Shaped | 1947780 | 25646 | *[HU]**L | 64 | 2 | 2023-07-11 14:39:30.503 | 2066 | EngineConfiguration | lookup | Pattern | Pattern |
Engine | Fuel Type - Primary | Gasoline | 1947755 | 25646 | *[HU]**L | 24 | 4 | 2023-07-11 14:39:30.503 | 2066 | FuelTypePrimary | lookup | Pattern | Pattern |
Engine | Engine Model | L87 | 1947746 | 25646 | *[HU]**L | 18 | L87 | 2023-07-11 14:39:30.503 | 2066 | EngineModel | string | Pattern | Pattern |
Engine | Displacement (L) | 6.2 | 1947739 | 25646 | *[HU]**L | 13 | 6.2 | 2023-07-11 14:39:30.503 | 2066 | DisplacementL | decimal | Pattern | Pattern |
Engine | Engine Number of Cylinders | 8 | 1947733 | 25646 | *[HU]**L | 9 | 8 | 2023-07-11 14:39:30.503 | 2066 | EngineCylinders | int | Pattern | Pattern |
Engine | Displacement (CC) | 6200.0 | 1947739 | 25646 | *[HU]**L | 11 | 6200.0 | | 2066 | DisplacementCC | decimal | Pattern | Conversion 4: 6.2 * 1000 |
Passive Safety System | Seat Belt Type | Manual | 1947788 | 25646 | *[HU]*E | 79 | 1 | 2023-07-11 14:39:30.503 | 2066 | SeatBeltsAll | lookup | Pattern | Pattern |
Passive Safety System | Other Restraint System Info | AY0 - Active Manual Belts | 1947793 | 25646 | *[HU]*E | 121 | AY0 - Active Manual Belts | 2023-07-11 14:39:30.503 | 2066 | OtherRestraintSystemInfo | string | Pattern | Pattern |
Passive Safety System / Air Bag Location | Curtain Air Bag Locations | All Rows | 1947773 | 25646 | *[HU]*E | 55 | 6 | 2023-07-11 14:39:30.503 | 2066 | AirBagLocCurtain | lookup | Pattern | Pattern |
Passive Safety System / Air Bag Location | Front Air Bag Locations | 1st Row (Driver and Passenger) | 1947781 | 25646 | *[HU]*E | 65 | 3 | 2023-07-11 14:39:30.503 | 2066 | AirBagLocFront | lookup | Pattern | Pattern |
Passive Safety System / Air Bag Location | Side Air Bag Locations | 1st Row (Driver and Passenger) | 1947792 | 25646 | *[HU]*E | 107 | 3 | 2023-07-11 14:39:30.503 | 2066 | AirBagLocSide | lookup | Pattern | Pattern |
Active Safety System | Auto-Reverse System for Windows and Sunroofs | Optional | 13609 | 4140 | | 172 | 3 | 2024-01-31 16:04:17.207 | | AutoReverseSystem | lookup | Pattern | Vehicle Specs | f
Active Safety System | Electronic Stability Control (ESC) | Standard | 13609 | 4140 | | 99 | 1 | 2024-01-31 16:04:16.897 | | ESC | lookup | Pattern | Vehicle Specs | f
Active Safety System | Anti-lock Braking System (ABS) | Standard | 13609 | 4140 | | 86 | 1 | 2024-01-31 16:04:16.85 | | ABS | lookup | Pattern | Vehicle Specs | f
Active Safety System | Traction Control | Standard | 13609 | 4140 | | 100 | 1 | 2024-01-31 16:04:16.91 | | TractionControl | lookup | Pattern | Vehicle Specs | f
Active Safety System | Keyless Ignition | Standard | 13609 | 4140 | | 176 | 1 | 2024-01-31 16:04:17.257 | | KeylessIgnition | lookup | Pattern | Vehicle Specs | f
Active Safety System | Tire Pressure Monitoring System (TPMS) Type | Direct | 13609 | 4140 | | 168 | 1 | 2024-01-31 16:04:17.157 | | TPMS | lookup | Pattern | Vehicle Specs | f
Active Safety System | Event Data Recorder (EDR) | Standard | 13609 | 4140 | | 175 | 1 | 2024-01-31 16:04:17.24 | | EDR | lookup | Pattern | Vehicle Specs | f
Active Safety System / Maintaining Safe Distance | Adaptive Cruise Control (ACC) | Optional | 13609 | 4140 | | 81 | 3 | 2024-01-31 16:04:16.837 | | AdaptiveCruiseControl | lookup | Pattern | Vehicle Specs | f
Active Safety System / Forward Collision Prevention | Dynamic Brake Support (DBS) | Standard | 13609 | 4140 | | 170 | 1 | 2024-01-31 16:04:17.173 | | DynamicBrakeSupport | lookup | Pattern | Vehicle Specs | f
Active Safety System / Forward Collision Prevention | Crash Imminent Braking (CIB) | Standard | 13609 | 4140 | | 87 | 1 | 2024-01-31 16:04:16.863 | | CIB | lookup | Pattern | Vehicle Specs | f
Active Safety System / Forward Collision Prevention | Pedestrian Automatic Emergency Braking (PAEB) | Standard | 13609 | 4140 | | 171 | 1 | 2024-01-31 16:04:17.19 | | PedestrianAutomaticEmergencyBraking | lookup | Pattern | Vehicle Specs | f
Active Safety System / Forward Collision Prevention | Forward Collision Warning (FCW) | Standard | 13609 | 4140 | | 101 | 1 | 2024-01-31 16:04:16.923 | | ForwardCollisionWarning | lookup | Pattern | Vehicle Specs | f
Active Safety System / Lane and Side Assist | Lane Keeping Assistance (LKA) | Standard | 13609 | 4140 | | 103 | 1 | 2024-01-31 16:04:17.103 | | LaneKeepSystem | lookup | Pattern | Vehicle Specs | f
Active Safety System / Lane and Side Assist | Lane Departure Warning (LDW) | Standard | 13609 | 4140 | | 102 | 1 | 2024-01-31 16:04:16.94 | | LaneDepartureWarning | lookup | Pattern | Vehicle Specs | f
Active Safety System / Lane and Side Assist | Blind Spot Warning (BSW) | Optional | 13609 | 4140 | | 88 | 3 | 2024-01-31 16:04:16.88 | | BlindSpotMon | lookup | Pattern | Vehicle Specs | f
Active Safety System / Backing Up and Parking | Rear Automatic Emergency Braking | Optional | 13609 | 4140 | | 192 | 3 | 2024-01-31 16:04:17.487 | | RearAutomaticEmergencyBraking | lookup | Pattern | Vehicle Specs | f
Active Safety System / Backing Up and Parking | Backup Camera | Standard | 13609 | 4140 | | 104 | 1 | 2024-01-31 16:04:17.12 | | RearVisibilitySystem | lookup | Pattern | Vehicle Specs | f
Active Safety System / Backing Up and Parking | Rear Cross Traffic Alert | Optional | 13609 | 4140 | | 183 | 2 | 2024-01-31 16:04:17.47 | | RearCrossTrafficAlert | lookup | Pattern | Vehicle Specs | f
Active Safety System / Backing Up and Parking | Parking Assist | Optional | 13609 | 4140 | | 105 | 3 | 2024-01-31 16:04:17.14 | | ParkAssist | lookup | Pattern | Vehicle Specs | f
Active Safety System / 911 Notification | Automatic Crash Notification (ACN) / Advanced Automatic Crash Notification (AACN) | Standard | 13609 | 4140 | | 174 | 1 | 2024-01-31 16:04:17.22 | | CAN_AACN | lookup | Pattern | Vehicle Specs | f
Active Safety System / Lighting Technologies | Headlamp Light Source | LED | 13609 | 4140 | | 178 | 3 | 2024-01-31 16:04:17.427 | | LowerBeamHeadlampLightSource | lookup | Pattern | Vehicle Specs | f
Active Safety System / Lighting Technologies | Adaptive Driving Beam (ADB) | Standard | 13609 | 4140 | | 180 | 1 | 2024-01-31 16:04:17.453 | | AdaptiveDrivingBeam | lookup | Pattern | Vehicle Specs | f
Active Safety System / Lighting Technologies | Daytime Running Light (DRL) | Standard | 13609 | 4140 | | 177 | 1 | 2024-01-31 16:04:17.273 | | DaytimeRunningLight | lookup | Pattern | Vehicle Specs | f
Active Safety System / Lighting Technologies | Semiautomatic Headlamp Beam Switching | Standard | 13609 | 4140 | | 179 | 1 | 2024-01-31 16:04:17.44 | | SemiautomaticHeadlampBeamSwitching | lookup | Pattern | Vehicle Specs | f
(64 rows)

View File

@@ -0,0 +1,79 @@
groupname | variable | value | itempatternid | itemvinschemaid | itemkeys | itemelementid | itemattributeid | itemcreatedon | itemwmiid | code | datatype | decode | itemsource | itemtobeqced
-----------------------------------------------------+--------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+---------------+-----------------+----------+---------------+----------------------------------------------------------------------------------------------------------------------------+-------------------------+-----------+-------------------------------------+----------+--------------+--------------------------------+--------------
| Error Text | 0 - VIN decoded clean. Check Digit (9th position) is correct | | | | 191 | 0 - VIN decoded clean. Check Digit (9th position) is correct | | | ErrorText | string | Decoding | Corrections |
| Additional Error Text | | | | | 156 | | | | AdditionalErrorText | string | Decoding | Corrections |
| Error Code | 0 | | | | 143 | 0 | | | ErrorCode | lookup | Decoding | Corrections |
| Possible Values | | | | | 144 | | | | PossibleValues | string | Decoding | Corrections |
| Vehicle Descriptor | 2HGFE4F8*SH | | | | 196 | 2HGFE4F8*SH | | | VehicleDescriptor | string | Decoding | Corrections |
| Suggested VIN | | | | | 142 | | | | SuggestedVIN | string | Decoding | Corrections |
General | Plant City | ALLISTON | 2123543 | 27387 | *****|*H | 31 | ALLISTON | 2024-09-16 08:37:51.523 | 2096 | PlantCity | string | Pattern | Pattern |
General | Trim | Sport Hybrid / Sport Touring Hybrid | 2086003 | 27007 | FE4F8 | 38 | Sport Hybrid / Sport Touring Hybrid | 2024-06-17 10:36:46.323 | 2096 | Trim | string | Pattern | Pattern |
General | Plant Country | CANADA | 2123544 | 27387 | *****|*H | 75 | 1 | 2024-09-16 08:37:51.54 | 2096 | PlantCountry | lookup | Pattern | Pattern |
General | Plant State | ONTARIO | 2123545 | 27387 | *****|*H | 77 | ONTARIO | 2024-09-16 08:37:51.553 | 2096 | PlantState | string | Pattern | Pattern |
General | Model Year | 2025 | | | ***X*|Y | 29 | 2025 | | | ModelYear | int | WMI, Input | ModelYear |
General | Manufacturer Name | HONDA OF CANADA MFG., A DIVISION OF HONDA CANADA INC. | | | 2HG | 27 | 990 | | 2096 | Manufacturer | lookup | WMI | Manu. Name |
General | Make | HONDA | 2086001 | 27007 | FE4F8 | 26 | 474 | | | Make | lookup | WMI, Pattern | pattern - model |
General | Vehicle Type | PASSENGER CAR | | | 2HG | 39 | 2 | 2015-03-26 16:57:39.147 | 2096 | VehicleType | lookup | WMI | VehType |
General | Model | Civic | 2086001 | 27007 | FE4F8 | 28 | 1863 | 2024-06-17 10:36:46.287 | 2096 | Model | lookup | Pattern | Pattern |
Exterior / Body | Doors | 4 | 2085995 | 27007 | FE4F8 | 14 | 4 | 2024-06-17 10:36:46.163 | 2096 | Doors | int | Pattern | Pattern |
Exterior / Body | Body Class | Sedan/Saloon | 2085992 | 27007 | FE4F8 | 5 | 13 | 2024-06-17 10:36:45.88 | 2096 | BodyClass | lookup | Pattern | Pattern |
Exterior / Dimension | Gross Vehicle Weight Rating From | Class 1C: 4,001 - 5,000 lb (1,814 - 2,268 kg) | 2086000 | 27007 | FE4F8 | 25 | 12 | 2024-06-17 10:36:46.267 | 2096 | GVWR | lookup | Pattern | Pattern |
Exterior / Dimension | Gross Vehicle Weight Rating To | Class 1C: 4,001 - 5,000 lb (1,814 - 2,268 kg) | 2086015 | 27007 | FE4F8 | 190 | 12 | 2024-06-17 10:36:46.713 | 2096 | GVWR_to | lookup | Pattern | Pattern |
Exterior / Truck | Bed Type | Not Applicable | | | | 3 | 0 | 2019-12-21 20:26:30.583 | | BedType | lookup | Pattern | Default |
Exterior / Truck | Cab Type | Not Applicable | | | | 4 | 0 | 2019-12-21 20:26:30.583 | | BodyCabType | lookup | Pattern | Default |
Exterior / Trailer | Trailer Body Type | Not Applicable | | | | 117 | 0 | 2019-12-21 20:26:30.583 | | TrailerBodyType | lookup | Pattern | Default |
Exterior / Trailer | Trailer Type Connection | Not Applicable | | | | 116 | 0 | 2019-12-21 20:26:30.583 | | TrailerType | lookup | Pattern | Default |
Exterior / Motorcycle | Motorcycle Suspension Type | Not Applicable | | | | 152 | 0 | 2019-12-21 20:26:30.583 | | MotorcycleSuspensionType | lookup | Pattern | Default |
Exterior / Motorcycle | Custom Motorcycle Type | Not Applicable | | | | 151 | 0 | 2019-12-21 20:26:30.583 | | CustomMotorcycleType | lookup | Pattern | Default |
Exterior / Motorcycle | Motorcycle Chassis Type | Not Applicable | | | | 153 | 0 | 2019-12-21 20:26:30.583 | | MotorcycleChassisType | lookup | Pattern | Default |
Exterior / Bus | Bus Floor Configuration Type | Not Applicable | | | | 148 | 0 | 2019-12-21 20:26:30.583 | | BusFloorConfigType | lookup | Pattern | Default |
Exterior / Bus | Bus Type | Not Applicable | | | | 149 | 0 | 2019-12-21 20:26:30.583 | | BusType | lookup | Pattern | Default |
Mechanical / Transmission | Transmission Style | Electronic Continuously Variable (e-CVT) | 2086002 | 27007 | FE4F8 | 37 | 4 | 2024-06-17 10:36:46.307 | 2096 | TransmissionStyle | lookup | Pattern | Pattern |
Mechanical / Drivetrain | Drive Type | 4x2 | 2085996 | 27007 | FE4F8 | 15 | 7 | 2024-06-17 10:36:46.18 | 2096 | DriveType | lookup | Pattern | Pattern |
Mechanical / Battery | EV Drive Unit | Single Motor | 2086065 | 27007 | FE4F8 | 72 | 2 | 2024-06-17 10:59:49.297 | 2096 | EVDriveUnit | lookup | Pattern | Pattern |
Engine | Engine Manufacturer | Honda | 2086014 | 27007 | FE4F8 | 146 | Honda | 2024-06-17 10:36:46.69 | 2096 | EngineManufacturer | string | Pattern | Pattern |
Engine | Displacement (CC) | 2000 | 2085994 | 27007 | FE4F8 | 11 | 2000 | | 2096 | DisplacementCC | decimal | Pattern | Conversion 4: 2 * 1000 |
Engine | Displacement (CI) | 122.0474881894645679 | 2085994 | 27007 | FE4F8 | 12 | 122.0474881894645679 | | 2096 | DisplacementCI | decimal | Pattern | Conversion 7: 2 / 0.016387064 |
Engine | Engine Number of Cylinders | 4 | 2085993 | 27007 | FE4F8 | 9 | 4 | 2024-06-17 10:36:45.96 | 2096 | EngineCylinders | int | Pattern | Pattern |
Engine | Displacement (L) | 2 | 2085994 | 27007 | FE4F8 | 13 | 2 | 2024-06-17 10:36:46.023 | 2096 | DisplacementL | decimal | Pattern | Pattern |
Engine | Engine Stroke Cycles | 4 | 2085997 | 27007 | FE4F8 | 17 | 4 | 2024-06-17 10:36:46.203 | 2096 | EngineCycles | int | Pattern | Pattern |
Engine | Engine Model | LFC3 | 2085998 | 27007 | FE4F8 | 18 | LFC3 | 2024-06-17 10:36:46.223 | 2096 | EngineModel | string | Pattern | Pattern |
Engine | Fuel Type - Primary | Gasoline | 2085999 | 27007 | FE4F8 | 24 | 4 | 2024-06-17 10:36:46.247 | 2096 | FuelTypePrimary | lookup | Pattern | Pattern |
Engine | Valve Train Design | Dual Overhead Cam (DOHC) | 2086004 | 27007 | FE4F8 | 62 | 2 | 2024-06-17 10:36:46.343 | 2096 | ValveTrainDesign | lookup | Pattern | Pattern |
Engine | Engine Configuration | In-Line | 2086005 | 27007 | FE4F8 | 64 | 1 | 2024-06-17 10:36:46.363 | 2096 | EngineConfiguration | lookup | Pattern | Pattern |
Engine | Fuel Type - Secondary | Electric | 2086006 | 27007 | FE4F8 | 66 | 2 | 2024-06-17 10:36:46.527 | 2096 | FuelTypeSecondary | lookup | Pattern | Pattern |
Engine | Engine Brake (hp) From | 141 | 2086007 | 27007 | FE4F8 | 71 | 141 | 2024-06-17 10:36:46.543 | 2096 | EngineHP | decimal | Pattern | Pattern |
Engine | Cooling Type | Water | 2086011 | 27007 | FE4F8 | 122 | 2 | 2024-06-17 10:36:46.63 | 2096 | CoolingType | lookup | Pattern | Pattern |
Engine | Electrification Level | Strong HEV (Hybrid Electric Vehicle) | 2086012 | 27007 | FE4F8 | 126 | 2 | 2024-06-17 10:36:46.65 | 2096 | ElectrificationLevel | lookup | Pattern | Pattern |
Engine | Other Engine Info | Direct Fuel Injection / Motor: 135kW | 2086013 | 27007 | FE4F8 | 129 | Direct Fuel Injection / Motor: 135kW | 2024-06-17 10:36:46.67 | 2096 | OtherEngineInfo | string | Pattern | Pattern |
Passive Safety System | Other Restraint System Info | Front: Seat Belt / Rear: Seat Belt , Side Air Bag and Side Curtain Air Bag (Outer positions) / Seat Belt (Center position) | 2083833 | 27007 | FE[24]F | 121 | Front: Seat Belt / Rear: Seat Belt , Side Air Bag and Side Curtain Air Bag (Outer positions) / Seat Belt (Center position) | 2024-06-17 10:20:27.853 | 2096 | OtherRestraintSystemInfo | string | Pattern | Pattern |
Passive Safety System | Seat Belt Type | Manual | 2083828 | 27007 | FE[24]F | 79 | 1 | 2024-06-17 10:20:27.853 | 2096 | SeatBeltsAll | lookup | Pattern | Pattern |
Passive Safety System / Air Bag Location | Side Air Bag Locations | 1st and 2nd Rows | 2083832 | 27007 | FE[24]F | 107 | 4 | 2024-06-17 10:20:27.853 | 2096 | AirBagLocSide | lookup | Pattern | Pattern |
Passive Safety System / Air Bag Location | Knee Air Bag Locations | 1st Row (Driver and Passenger) | 2083826 | 27007 | FE[24]F | 69 | 3 | 2024-06-17 10:05:30.837 | 2096 | AirBagLocKnee | lookup | Pattern | Pattern |
Passive Safety System / Air Bag Location | Front Air Bag Locations | 1st Row (Driver and Passenger) | 2083825 | 27007 | FE[24]F | 65 | 3 | 2024-06-17 10:05:30.837 | 2096 | AirBagLocFront | lookup | Pattern | Pattern |
Passive Safety System / Air Bag Location | Curtain Air Bag Locations | 1st and 2nd Rows | 2083822 | 27007 | FE[24]F | 55 | 4 | 2024-06-17 10:05:30.837 | 2096 | AirBagLocCurtain | lookup | Pattern | Pattern |
Active Safety System | Anti-lock Braking System (ABS) | Standard | 16871 | 5597 | | 86 | 1 | 2025-04-03 14:40:02.47 | | ABS | lookup | Pattern | Vehicle Specs |
Active Safety System | Traction Control | Standard | 16871 | 5597 | | 100 | 1 | 2025-04-03 14:40:02.52 | | TractionControl | lookup | Pattern | Vehicle Specs |
Active Safety System | Automatic Pedestrian Alerting Sound (for Hybrid and EV only) | Standard | 17451 | 5597 | | 173 | 1 | 2025-04-01 10:29:03.217 | | AutomaticPedestrianAlertingSound | lookup | Pattern | Vehicle Specs |
Active Safety System | Tire Pressure Monitoring System (TPMS) Type | Indirect | 16871 | 5597 | | 168 | 2 | 2025-04-03 14:40:02.6 | | TPMS | lookup | Pattern | Vehicle Specs |
Active Safety System | Keyless Ignition | Standard | 16871 | 5597 | | 176 | 1 | 2025-04-03 14:40:02.793 | | KeylessIgnition | lookup | Pattern | Vehicle Specs |
Active Safety System | Electronic Stability Control (ESC) | Standard | 16871 | 5597 | | 99 | 1 | 2025-04-03 14:40:02.503 | | ESC | lookup | Pattern | Vehicle Specs |
Active Safety System | Auto-Reverse System for Windows and Sunroofs | Standard | 16871 | 5597 | | 172 | 1 | 2025-04-03 14:40:02.763 | | AutoReverseSystem | lookup | Pattern | Vehicle Specs |
Active Safety System | Event Data Recorder (EDR) | Standard | 16871 | 5597 | | 175 | 1 | 2025-04-03 14:40:02.78 | | EDR | lookup | Pattern | Vehicle Specs |
Active Safety System / Maintaining Safe Distance | Adaptive Cruise Control (ACC) | Standard | 16871 | 5597 | | 81 | 1 | 2025-04-03 14:40:02.337 | | AdaptiveCruiseControl | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Forward Collision Warning (FCW) | Standard | 16871 | 5597 | | 101 | 1 | 2025-04-03 14:40:02.537 | | ForwardCollisionWarning | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Dynamic Brake Support (DBS) | Standard | 16871 | 5597 | | 170 | 1 | 2025-04-03 14:40:02.61 | | DynamicBrakeSupport | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Crash Imminent Braking (CIB) | Standard | 16871 | 5597 | | 87 | 1 | 2025-04-03 14:40:02.487 | | CIB | lookup | Pattern | Vehicle Specs |
Active Safety System / Forward Collision Prevention | Pedestrian Automatic Emergency Braking (PAEB) | Standard | 16871 | 5597 | | 171 | 1 | 2025-04-03 14:40:02.627 | | PedestrianAutomaticEmergencyBraking | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Lane Keeping Assistance (LKA) | Standard | 16871 | 5597 | | 103 | 1 | 2025-04-03 14:40:02.567 | | LaneKeepSystem | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Blind Spot Intervention (BSI) | Standard | 17451 | 5597 | | 193 | 1 | 2025-04-01 10:29:03.243 | | BlindSpotIntervention | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Blind Spot Warning (BSW) | Standard | 17451 | 5597 | | 88 | 1 | 2025-04-01 10:29:03.203 | | BlindSpotMon | lookup | Pattern | Vehicle Specs |
Active Safety System / Lane and Side Assist | Lane Departure Warning (LDW) | Standard | 16871 | 5597 | | 102 | 1 | 2025-04-03 14:40:02.55 | | LaneDepartureWarning | lookup | Pattern | Vehicle Specs |
Active Safety System / Backing Up and Parking | Backup Camera | Standard | 16871 | 5597 | | 104 | 1 | 2025-04-03 14:40:02.583 | | RearVisibilitySystem | lookup | Pattern | Vehicle Specs |
Active Safety System / Backing Up and Parking | Rear Automatic Emergency Braking | Standard | 16871 | 5597 | | 192 | 1 | 2025-04-03 14:40:02.877 | | RearAutomaticEmergencyBraking | lookup | Pattern | Vehicle Specs |
Active Safety System / Backing Up and Parking | Rear Cross Traffic Alert | Standard | 17451 | 5597 | | 183 | 1 | 2025-04-01 10:29:03.23 | | RearCrossTrafficAlert | lookup | Pattern | Vehicle Specs |
Active Safety System / Lighting Technologies | Semiautomatic Headlamp Beam Switching | Standard | 16871 | 5597 | | 179 | 1 | 2025-04-03 14:40:02.843 | | SemiautomaticHeadlampBeamSwitching | lookup | Pattern | Vehicle Specs |
Active Safety System / Lighting Technologies | Daytime Running Light (DRL) | Standard | 16871 | 5597 | | 177 | 1 | 2025-04-03 14:40:02.81 | | DaytimeRunningLight | lookup | Pattern | Vehicle Specs |
Active Safety System / Lighting Technologies | Headlamp Light Source | LED | 16871 | 5597 | | 178 | 3 | 2025-04-03 14:40:02.83 | | LowerBeamHeadlampLightSource | lookup | Pattern | Vehicle Specs |
(75 rows)

View File

@@ -33,9 +33,8 @@ Step 1: Fetch Data from VehAPI
python3 vehapi_fetch_snapshot.py --min-year 2020 --max-year 2020
# Full ETL workflow
# Full ETL workflow with cached results
./reset_database.sh # Clear old data
python3 vehapi_fetch_snapshot.py # Fetch from API
python3 etl_generate_sql.py --snapshot-path snapshots/*.sqlite # Generate SQL
./import_data.sh # Import to Postgres
docker compose exec mvp-redis redis-cli FLUSHALL # Flush Redis Cache for front end

View File

@@ -0,0 +1,514 @@
# vPIC ETL Implementation Plan v2
## Overview
Extract vehicle dropdown data from NHTSA vPIC database for MY2022+ to supplement existing VehAPI data. This revised plan uses a make-specific extraction approach with proper VIN schema parsing.
## Key Changes from v1
1. **Limit to VehAPI makes only** - Only extract the 48 makes that exist in VehAPI data
2. **VIN schema-based extraction** - Extract directly from VIN patterns, not defs_model
3. **Proper field formatting** - Match VehAPI display string formats
4. **Make-specific logic** - Handle different manufacturers' data patterns
## Critical Discovery: WMI Linkage
**Must use `wmi_make` junction table (many-to-many), NOT `wmi.makeid` (one-to-many):**
```sql
-- CORRECT: via wmi_make (finds all makes including Toyota, Hyundai, etc.)
FROM vpic.make m
JOIN vpic.wmi_make wm ON wm.makeid = m.id
JOIN vpic.wmi w ON w.id = wm.wmiid
-- WRONG: via wmi.makeid (misses many major brands)
FROM vpic.make m
JOIN vpic.wmi w ON w.makeid = m.id
```
---
## Make Availability Summary
| Status | Count | Makes |
|--------|-------|-------|
| **Available (2022+ schemas)** | 46 | See table below |
| **No 2022+ data** | 2 | Hummer (discontinued 2010), Scion (discontinued 2016) |
---
## Per-Make Analysis
### Group 1: Japanese Manufacturers (Honda/Acura, Toyota/Lexus, Nissan/Infiniti)
| Make | VehAPI Name | vPIC Name | Schemas (2022+) | Status |
|------|-------------|-----------|-----------------|--------|
| Acura | Acura | Acura | 48 | Ready |
| Honda | Honda | Honda | 238 | Ready |
| Lexus | Lexus | Lexus | 90 | Ready |
| Toyota | Toyota | Toyota | 152 | Ready |
| Infiniti | INFINITI | Infiniti | 76 | Ready |
| Nissan | Nissan | Nissan | 85 | Ready |
| Mazda | Mazda | Mazda | 37 | Ready |
| Mitsubishi | Mitsubishi | Mitsubishi | 11 | Ready |
| Subaru | Subaru | Subaru | 75 | Ready |
| Isuzu | Isuzu | Isuzu | 11 | Ready |
### Group 2: Korean Manufacturers (Hyundai/Kia/Genesis)
| Make | VehAPI Name | vPIC Name | Schemas (2022+) | Status |
|------|-------------|-----------|-----------------|--------|
| Genesis | Genesis | Genesis | 74 | Ready |
| Hyundai | Hyundai | Hyundai | 177 | Ready |
| Kia | Kia | Kia | 72 | Ready |
### Group 3: American - GM (Chevrolet, GMC, Buick, Cadillac)
| Make | VehAPI Name | vPIC Name | Schemas (2022+) | Status |
|------|-------------|-----------|-----------------|--------|
| Buick | Buick | Buick | 20 | Ready |
| Cadillac | Cadillac | Cadillac | 50 | Ready |
| Chevrolet | Chevrolet | Chevrolet | 185 | Ready |
| GMC | GMC | GMC | 107 | Ready |
| Oldsmobile | Oldsmobile | Oldsmobile | 1 | Limited |
| Pontiac | Pontiac | Pontiac | 5 | Limited (2022-2024) |
### Group 4: American - Stellantis (Chrysler, Dodge, Jeep, Ram, Fiat)
| Make | VehAPI Name | vPIC Name | Schemas (2022+) | Status |
|------|-------------|-----------|-----------------|--------|
| Chrysler | Chrysler | Chrysler | 81 | Ready |
| Dodge | Dodge | Dodge | 86 | Ready |
| FIAT | FIAT | Fiat | 91 | Ready (case diff) |
| Jeep | Jeep | Jeep | 81 | Ready |
| RAM | RAM | Ram | 81 | Ready (case diff) |
| Plymouth | Plymouth | Plymouth | 4 | Limited |
### Group 5: American - Ford
| Make | VehAPI Name | vPIC Name | Schemas (2022+) | Status |
|------|-------------|-----------|-----------------|--------|
| Ford | Ford | Ford | 108 | Ready |
| Lincoln | Lincoln | Lincoln | 21 | Ready |
| Mercury | Mercury | Mercury | 0 | No data (discontinued 2011) |
### Group 6: American - EV Startups
| Make | VehAPI Name | vPIC Name | Schemas (2022+) | Status |
|------|-------------|-----------|-----------------|--------|
| Polestar | Polestar | Polestar | 12 | Ready |
| Rivian | Rivian | RIVIAN | 10 | Ready (case diff) |
| Tesla | Tesla | Tesla | 14 | Ready |
### Group 7: German Manufacturers
| Make | VehAPI Name | vPIC Name | Schemas (2022+) | Status |
|------|-------------|-----------|-----------------|--------|
| Audi | Audi | Audi | 55 | Ready |
| BMW | BMW | BMW | 61 | Ready |
| Mercedes-Benz | Mercedes-Benz | Mercedes-Benz | 39 | Ready |
| MINI | MINI | MINI | 10 | Ready |
| Porsche | Porsche | Porsche | 23 | Ready |
| smart | smart | smart | 5 | Ready |
| Volkswagen | Volkswagen | Volkswagen | 134 | Ready |
### Group 8: European Luxury
| Make | VehAPI Name | vPIC Name | Schemas (2022+) | Status |
|------|-------------|-----------|-----------------|--------|
| Bentley | Bentley | Bentley | 48 | Ready |
| Ferrari | Ferrari | Ferrari | 9 | Ready |
| Jaguar | Jaguar | Jaguar | 17 | Ready |
| Lamborghini | Lamborghini | Lamborghini | 10 | Ready |
| Lotus | Lotus | Lotus | 5 | Ready |
| Maserati | Maserati | Maserati | 19 | Ready |
| McLaren | McLaren | McLaren | 4 | Ready |
| Volvo | Volvo | Volvo | 80 | Ready |
### Group 9: Discontinued (No 2022+ Data)
| Make | VehAPI Name | Reason | Action |
|------|-------------|--------|--------|
| Hummer | Hummer | Discontinued 2010 (new EV under GMC) | Skip - use existing VehAPI |
| Scion | Scion | Discontinued 2016 | Skip - use existing VehAPI |
| Saab | Saab | Discontinued 2012 | Limited schemas (9) |
| Mercury | Mercury | Discontinued 2011 | No schemas |
---
## Extraction Architecture
### Data Flow
```
vPIC VIN Schemas → Pattern Extraction → Format Transformation → SQLite Pairs
Filter by:
- 48 VehAPI makes only
- Year >= 2022
- Vehicle types (exclude motorcycles, trailers, buses)
```
### Core Query Strategy
For each allowed make:
1. Find WMIs linked to that make
2. Get VIN schemas for years 2022+
3. Extract from patterns:
- Model (from schema name or pattern)
- Trim (Element: Trim)
- Displacement (Element: DisplacementL)
- Horsepower (Element: EngineHP)
- Cylinders (Element: EngineCylinders)
- Engine Config (Element: EngineConfiguration)
- Transmission Style (Element: TransmissionStyle)
- Transmission Speeds (Element: TransmissionSpeeds)
---
## Acura Extraction Template
This pattern applies to Honda/Acura and similar well-structured manufacturers.
### Sample VIN Schema: Acura MDX 2025 (schema_id: 26929)
| Element | Code | Values |
|---------|------|--------|
| Trim | Trim | MDX, Technology, SH-AWD, SH-AWD Technology, SH-AWD A-Spec, SH-AWD Advance, SH-AWD A-Spec Advance, SH-AWD TYPE S ADVANCE |
| Displacement | DisplacementL | 3.5, 3.0 |
| Horsepower | EngineHP | 290, 355 |
| Cylinders | EngineCylinders | 6 |
| Engine Config | EngineConfiguration | V-Shaped |
| Trans Style | TransmissionStyle | Automatic |
| Trans Speeds | TransmissionSpeeds | 10 |
### Output Format
**Engine Display** (match VehAPI):
```
{DisplacementL}L {EngineHP} hp V{EngineCylinders}
→ "3.5L 290 hp V6"
```
**Transmission Display** (match VehAPI):
```
{TransmissionSpeeds}-Speed {TransmissionStyle}
→ "10-Speed Automatic"
```
### Extraction SQL Template
```sql
WITH schema_data AS (
SELECT DISTINCT
vs.id AS schema_id,
vs.name AS schema_name,
wvs.yearfrom,
COALESCE(wvs.yearto, 2027) AS yearto,
m.name AS make_name
FROM vpic.wmi w
JOIN vpic.make m ON w.makeid = m.id
JOIN vpic.wmi_vinschema wvs ON w.id = wvs.wmiid
JOIN vpic.vinschema vs ON wvs.vinschemaid = vs.id
WHERE LOWER(m.name) IN ('acura', 'honda', ...) -- VehAPI makes
AND wvs.yearfrom >= 2022 OR (wvs.yearto >= 2022)
),
trim_data AS (
SELECT DISTINCT sd.schema_id, p.attributeid AS trim
FROM schema_data sd
JOIN vpic.pattern p ON p.vinschemaid = sd.schema_id
JOIN vpic.element e ON p.elementid = e.id
WHERE e.code = 'Trim'
),
engine_data AS (
SELECT DISTINCT
sd.schema_id,
MAX(CASE WHEN e.code = 'DisplacementL' THEN p.attributeid END) AS displacement,
MAX(CASE WHEN e.code = 'EngineHP' THEN p.attributeid END) AS hp,
MAX(CASE WHEN e.code = 'EngineCylinders' THEN p.attributeid END) AS cylinders,
MAX(CASE WHEN e.code = 'EngineConfiguration' THEN ec.name END) AS config
FROM schema_data sd
JOIN vpic.pattern p ON p.vinschemaid = sd.schema_id
JOIN vpic.element e ON p.elementid = e.id
LEFT JOIN vpic.engineconfiguration ec ON e.code = 'EngineConfiguration'
AND p.attributeid ~ '^[0-9]+$' AND ec.id = CAST(p.attributeid AS INT)
WHERE e.code IN ('DisplacementL', 'EngineHP', 'EngineCylinders', 'EngineConfiguration')
GROUP BY sd.schema_id, p.keys -- Group by VIN pattern position
),
trans_data AS (
SELECT DISTINCT
sd.schema_id,
t.name AS style,
MAX(CASE WHEN e.code = 'TransmissionSpeeds' THEN p.attributeid END) AS speeds
FROM schema_data sd
JOIN vpic.pattern p ON p.vinschemaid = sd.schema_id
JOIN vpic.element e ON p.elementid = e.id
LEFT JOIN vpic.transmission t ON e.code = 'TransmissionStyle'
AND p.attributeid ~ '^[0-9]+$' AND t.id = CAST(p.attributeid AS INT)
WHERE e.code IN ('TransmissionStyle', 'TransmissionSpeeds')
GROUP BY sd.schema_id, t.name
)
SELECT ...
```
---
## Allowed Makes (48 from VehAPI)
```python
ALLOWED_MAKES = [
'Acura', 'Audi', 'Bentley', 'BMW', 'Buick', 'Cadillac', 'Chevrolet',
'Chrysler', 'Dodge', 'Ferrari', 'FIAT', 'Ford', 'Genesis', 'GMC',
'Honda', 'Hummer', 'Hyundai', 'INFINITI', 'Isuzu', 'Jaguar', 'Jeep',
'Kia', 'Lamborghini', 'Lexus', 'Lincoln', 'Lotus', 'Maserati', 'Mazda',
'McLaren', 'Mercedes-Benz', 'Mercury', 'MINI', 'Mitsubishi', 'Nissan',
'Oldsmobile', 'Plymouth', 'Polestar', 'Pontiac', 'Porsche', 'RAM',
'Rivian', 'Saab', 'Scion', 'smart', 'Subaru', 'Tesla', 'Toyota',
'Volkswagen', 'Volvo'
]
```
Note: Some makes may have different names in vPIC (case variations, abbreviations).
---
## Implementation Steps
### Phase 1: Rewrite vpic_extract.py
**File:** `vpic_extract.py`
Core extraction query (uses wmi_make junction table):
```sql
WITH base AS (
SELECT DISTINCT
m.name AS make_name,
vs.id AS schema_id,
vs.name AS schema_name,
generate_series(
GREATEST(wvs.yearfrom, 2022),
COALESCE(wvs.yearto, EXTRACT(YEAR FROM NOW()) + 2)
)::INT AS year
FROM vpic.make m
JOIN vpic.wmi_make wm ON wm.makeid = m.id
JOIN vpic.wmi w ON w.id = wm.wmiid
JOIN vpic.wmi_vinschema wvs ON w.id = wvs.wmiid
JOIN vpic.vinschema vs ON wvs.vinschemaid = vs.id
WHERE LOWER(m.name) IN ({allowed_makes})
AND (wvs.yearfrom >= 2022 OR wvs.yearto >= 2022)
)
SELECT ...
```
**Key functions to implement:**
1. `extract_model_from_schema_name(schema_name)` - Parse "Acura MDX Schema..." → "MDX"
2. `get_schema_patterns(schema_id)` - Get all pattern data for a schema
3. `format_engine_display(disp, hp, cyl, config)` - Format as "3.5L 290 hp V6"
4. `format_trans_display(style, speeds)` - Format as "10-Speed Automatic"
5. `generate_trans_records(has_data, style, speeds)` - Return 1 or 2 records
**Make name normalization:**
```python
MAKE_MAPPING = {
'INFINITI': 'INFINITI', # VehAPI uses all-caps
'FIAT': 'FIAT',
'RAM': 'RAM',
'RIVIAN': 'Rivian', # vPIC uses all-caps, normalize
# ... etc
}
```
### Phase 2: Test Extraction
Test with validated VINs:
```bash
source .venv/bin/activate
python3 vpic_extract.py --test-vin 5J8YE1H05SL018611 # Acura MDX
python3 vpic_extract.py --test-vin 5TFJA5DB4SX327537 # Toyota Tundra
python3 vpic_extract.py --test-vin 3GTUUFEL6PG140748 # GMC Sierra
```
### Phase 3: Full Extraction
```bash
python3 vpic_extract.py --min-year 2022 --output-dir snapshots/vpic-2025-12
```
### Phase 4: Merge & Import
```bash
# Merge vPIC with existing VehAPI data
sqlite3 snapshots/merged/snapshot.sqlite "
CREATE TABLE pairs(...);
ATTACH 'snapshots/vehicle-drop-down.sqlite' AS db1;
ATTACH 'snapshots/vpic-2025-12/snapshot.sqlite' AS db2;
INSERT OR IGNORE INTO pairs SELECT * FROM db1.pairs WHERE year < 2022;
INSERT OR IGNORE INTO pairs SELECT * FROM db2.pairs;
"
# Generate SQL and import
python3 etl_generate_sql.py --snapshot-path snapshots/merged/snapshot.sqlite
./import_data.sh
```
---
## Files to Modify
| File | Changes |
|------|---------|
| `vpic_extract.py` | Complete rewrite: VIN schema extraction, dual-record trans logic |
| `README.md` | Already updated with workflow |
---
## Success Criteria
1. Extract all 41 makes with 2022+ VIN schemas
2. ~2,500-5,000 unique vehicle configurations (Year/Make/Model/Trim/Engine)
3. Transmission: Use vPIC data where available (7 makes), dual-record elsewhere
4. Output format matches VehAPI: "3.5L 290 hp V6" / "10-Speed Automatic"
5. Merge preserves 2015-2021 VehAPI data
6. QA validation passes after import
---
## Make Analysis Status (All Families Validated)
| Family | Makes | Status | Trans Data | Strategy |
|--------|-------|--------|------------|----------|
| Honda/Acura | Acura, Honda | VALIDATED | YES (93-97%) | Use vPIC trans data |
| Toyota/Lexus | Toyota, Lexus | VALIDATED | PARTIAL (Toyota 23%, Lexus 0%) | Dual-record for Lexus |
| Nissan/Infiniti | Nissan, Infiniti, Mitsubishi | VALIDATED | LOW (5%) | Dual-record |
| GM | Chevrolet, GMC, Buick, Cadillac | VALIDATED | LOW (0-7%) | Dual-record |
| Stellantis | Chrysler, Dodge, Jeep, Ram, Fiat | VALIDATED | NONE (0%) | Dual-record |
| Ford | Ford, Lincoln | VALIDATED | NONE (0%) | Dual-record |
| VW Group | Volkswagen, Audi, Porsche, Bentley, Lamborghini | VALIDATED | MIXED (0-84%) | VW/Audi use vPIC; others dual-record |
| BMW | BMW, MINI | VALIDATED | NONE (0%) | Dual-record |
| Mercedes | Mercedes-Benz, smart | VALIDATED | YES (52%) | Use vPIC trans data |
| Hyundai/Kia/Genesis | Hyundai, Kia, Genesis | VALIDATED | NONE (0%) | Dual-record |
| Subaru | Subaru | VALIDATED | YES (64%) | Use vPIC trans data |
| Mazda | Mazda | VALIDATED | LOW (11%) | Dual-record |
| Volvo | Volvo, Polestar | VALIDATED | LOW (3%/0%) | Dual-record |
| Exotics | Ferrari, Maserati, Jaguar, Lotus, McLaren | VALIDATED | MIXED | Per-make handling |
| EV | Tesla, Rivian | VALIDATED | NONE (0%) | Dual-record (though EVs don't have "manual") |
### Special Cases
1. **Electric Vehicles** (Tesla, Rivian, Polestar): Don't have manual transmissions
- Still create dual-record for consistency with dropdown
- User can select "Automatic" (single-speed EV)
2. **Luxury Exotics** (Ferrari, Lamborghini, etc.): Mix of automated manual/DCT
- Dual-record covers all options
---
## CRITICAL FINDING: Transmission Data Availability
**Most manufacturers do NOT encode transmission info in VINs.**
### VIN Decode Validation Results (12 Families)
| Family | VIN | Make | Model | Year | Trim | Engine | Trans |
|--------|-----|------|-------|------|------|--------|-------|
| Honda/Acura | 5J8YE1H05SL018611 | ACURA | MDX | 2025 | SH-AWD A-Spec | 3.5L V6 290hp | 10-Spd Auto |
| Honda/Acura | 2HGFE4F88SH315466 | HONDA | Civic | 2025 | Sport Hybrid | 2.0L I4 141hp | e-CVT |
| Toyota/Lexus | 5TFJA5DB4SX327537 | TOYOTA | Tundra | 2025 | Limited | 3.4L V6 389hp | 10-Spd Auto |
| Nissan/Infiniti | 5N1AL1FW9TC332353 | INFINITI | QX60 | 2026 | Luxe | 2.0L (no cyl/hp) | **MISSING** |
| GM | 3GTUUFEL6PG140748 | GMC | Sierra | 2023 | AT4X | 6.2L V8 (no hp) | **MISSING** |
| Stellantis | 1C4HJXEG7PW506480 | JEEP | Wrangler | 2023 | Sahara | 3.6L V6 285hp | **MISSING** |
| Ford | 1FTFW4L59SFC03038 | FORD | F-150 | 2025 | Tremor | 5.0L V8 (no hp) | **MISSING** |
| VW Group | WVWEB7CD9RW229116 | VOLKSWAGEN | Golf R | 2024 | **MISSING** | 2.0L 4cyl 315hp | Auto (no spd) |
| BMW | 5YM13ET06R9S31554 | BMW | X5 | 2024 | X5 M Competition | 4.4L 8cyl 617hp | **MISSING** |
| Mercedes | W1KAF4HB1SR287126 | MERCEDES-BENZ | C-Class | 2025 | C300 4MATIC | 2.0L I4 255hp | 9-Spd Auto |
| Hyundai/Kia | 5XYRLDJC0SG336002 | KIA | Sorento | 2025 | S | 2.5L 4cyl 191hp | **MISSING** |
| Subaru | JF1VBAF67P9806852 | SUBARU | WRX | 2023 | Premium | 2.4L 4cyl 271hp | 6-Spd Manual |
| Mazda | JM3KFBCL3R0522361 | MAZDA | CX-5 | 2024 | Preferred Pkg | 2.5L I4 187hp | 6-Spd Auto |
| Volvo | YV4M12RJ9S1094167 | VOLVO | XC60 | 2025 | Core | 2.0L 4cyl 247hp | 8-Spd Auto |
### Transmission Data Coverage in vPIC Schemas
| Coverage | Makes | Trans Schemas / Total |
|----------|-------|----------------------|
| **HIGH (>40%)** | Honda, Acura, Subaru, Audi, VW, Mercedes, Jaguar | 225/233, 42/45, 47/74, 46/55, 47/132, 13/25, 17/17 |
| **LOW (<10%)** | Chevrolet, Cadillac, Nissan, Infiniti, Mazda, Volvo | 4/164, 7/43, 4/82, 4/74, 4/36, 2/72 |
| **NONE (0%)** | GMC, Buick, Ford, Lincoln, Jeep, Dodge, Chrysler, Ram, Fiat, BMW, MINI, Porsche, Hyundai, Kia, Genesis, Lexus, Tesla, Rivian, Polestar | 0% |
### Makes WITHOUT Transmission Data (22 of 41 makes = 54%)
- **ALL Stellantis**: Chrysler, Dodge, Jeep, Ram, Fiat
- **ALL Ford**: Ford, Lincoln
- **ALL Korean**: Hyundai, Kia, Genesis
- **ALL BMW Group**: BMW, MINI
- **GM (partial)**: GMC, Buick (Chevy/Cadillac have minimal)
- **Others**: Lexus, Porsche, Bentley, Lamborghini, Tesla, Rivian, Polestar
---
## Extraction Strategy (SELECTED)
### Dual-Record Strategy for Missing Transmission Data
When transmission data is NOT available from vPIC:
- **Create TWO records** for each vehicle configuration
- One with `trans_display = "Automatic"`, `trans_canon = "automatic"`
- One with `trans_display = "Manual"`, `trans_canon = "manual"`
This ensures:
- All transmission options available in dropdown for user selection
- User can select the correct transmission type
- No false "Unknown" values that break filtering
### Implementation Logic
```python
def generate_trans_records(has_trans_data: bool, trans_style: str, trans_speeds: str):
if has_trans_data:
# Use actual vPIC data
return [(format_trans_display(trans_style, trans_speeds),
canonicalize_trans(trans_style))]
else:
# Generate both options
return [
("Automatic", "automatic"),
("Manual", "manual")
]
```
### Expected Output Growth
For makes without trans data, record count approximately doubles:
- GMC Sierra AT4X + 6.2L V8 → 2 records (Auto + Manual)
- Ford F-150 Tremor + 5.0L V8 → 2 records (Auto + Manual)
This is acceptable as it provides complete dropdown coverage.
---
## Validated Extraction Examples
### Acura MDX 2025 (VIN: 5J8YE1H05SL018611)
- **vPIC**: Make=ACURA, Model=MDX, Trim=SH-AWD A-Spec, Engine=3.5L V6 290hp, Trans=10-Speed Automatic
- **Output**: `3.5L 290 hp V6` | `10-Speed Automatic`
### Honda Civic 2025 (VIN: 2HGFE4F88SH315466)
- **vPIC**: Make=HONDA, Model=Civic, Trim=Sport Hybrid / Sport Touring Hybrid, Engine=2L I4 141hp, Trans=e-CVT
- **Output**: `2.0L 141 hp I4` | `Electronic Continuously Variable (e-CVT)`
### Toyota Tundra 2025 (VIN: 5TFJA5DB4SX327537)
- **vPIC**: Make=TOYOTA, Model=Tundra, Trim=Limited, Engine=3.4L V6 389hp, Trans=10-Speed Automatic
- **Output**: `3.4L 389 hp V6` | `10-Speed Automatic`
### Mercedes C-Class 2025 (VIN: W1KAF4HB1SR287126)
- **vPIC**: Make=MERCEDES-BENZ, Model=C-Class, Trim=C300 4MATIC, Engine=2.0L I4 255hp, Trans=9-Speed Automatic
- **Output**: `2.0L 255 hp I4` | `9-Speed Automatic`
### Subaru WRX 2023 (VIN: JF1VBAF67P9806852)
- **vPIC**: Make=SUBARU, Model=WRX, Trim=Premium, Engine=2.4L 4cyl 271hp, Trans=6-Speed Manual
- **Output**: `2.4L 271 hp 4cyl` | `6-Speed Manual`
### Mazda CX-5 2024 (VIN: JM3KFBCL3R0522361)
- **vPIC**: Make=MAZDA, Model=CX-5, Trim=Preferred Package, Engine=2.5L I4 187hp, Trans=6-Speed Automatic
- **Output**: `2.5L 187 hp I4` | `6-Speed Automatic`
### Volvo XC60 2025 (VIN: YV4M12RJ9S1094167)
- **vPIC**: Make=VOLVO, Model=XC60, Trim=Core, Engine=2.0L 4cyl 247hp, Trans=8-Speed Automatic
- **Output**: `2.0L 247 hp 4cyl` | `8-Speed Automatic`

View File

@@ -19,18 +19,17 @@ comprehensive spec.md - containing requirements, architecture decisions, data mo
You are a senior software engineer specializsing in NodeJS, Typescript, front end and back end development. You will be delegating tasks to the platform-agent, feature-agent, first-frontend-agent and quality-agent when appropriate.
*** ACTION ***
- You will be fixing a workflow logic in the new user sign up wizard.
- Make no assumptions.
- Ask clarifying questions.
- Ultrathink
- You will be removing functionality that was never implemented.
*** CONTEXT ***
- This is a modern web app for managing a vehicle fleet. It has both a desktop and mobile versions of the site that both need to maintain feature parity. It's currently deployed via docker compose but in the future will be deployed via k8s.
- Read README.md CLAUDE.md and AI-INDEX.md and follow relevant instructions to understand this code repository in the context of this change.
- When a new user signs up, they are immediately redirected to https://motovaultpro.com/verify-email which is supposed to send them through a new user wizard.
- The user is also allowed to login before the email is confirmed. There are API errors but the login is allowed.
- It should not even let people login without a verified email.
- The new user wizard exists. It worked in the past. Recent user changes must have broken the workflow.
- There is a "station management" section for admin users that was never implemented and needs to be removed.
- The route is located at https://motovaultpro.com/garage/settings/admin/stations
- Remove the front end and any associated routes or logic in the code.
*** CHANGES TO IMPLEMENT ***
- Research this code base and ask iterative questions to compile a complete plan.
@@ -52,4 +51,31 @@ You are a senior software engineer specializsing in NodeJS, Typescript, front en
- The secrets architecture is based of a future state of being deployed into k8s. Right now it's in docker compose with files that are copied in via the pipeline.
*** ACTION - CHANGES TO IMPLEMENT ***
- Replicate the same secrets process that's implemented with the Google API and Auth0 API keys.
- Replicate the same secrets process that's implemented with the Google API and Auth0 API keys.
*** ROLE ***
- You are a senior DBA with expert knowledge in Postgres SQL.
*** ACTION ***
- Make no assumptions.
- Ask clarifying questions.
- Ultrathink
- You will be implementing an ETL process that takes a export of the NHTSA vPIC database in Postgres and transforming it for use in this application.
*** CONTEXT ***
- This is a modern web app for managing a vehicle fleet. It has both a desktop and mobile versions of the site that both need to maintain feature parity. It's currently deployed via docker compose but in the future will be deployed via k8s.
- Read README.md CLAUDE.md and AI-INDEX.md and follow relevant instructions to understand this code repository in the context of this change.
- There is an existing database import process in this directory. This process works and should not be changed.
- The source database from the NHTSA vPIC dataset is located in the @vpic-source directory
- Deep research needs to be conducted on how to execute this ETL process.
- The source database is designed for VIN decoding only.
- Example VIN: 2025 Honda Civic Hybrid - 2HGFE4F88SH315466
- Example VIN: 2023 GMC Sierra 1500 AT4x - 3GTUUFEL6PG140748
- Example VIN: 2017 Chevrolet Corvette Z06 - 1G1YU3D64H5602799
*** CHANGES TO IMPLEMENT ***
- Research this code base and ask iterative questions to compile a complete plan.
- generate a project plan
- break into bite-sized tasks and milestones

View File

@@ -1,9 +1,9 @@
/**
* @ai-summary React context for unit system preferences
* @ai-context Provides unit preferences and conversion functions throughout the app
* @ai-summary React context for unit system preferences with backend sync
* @ai-context Provides unit preferences, conversion functions, and currency symbol throughout the app
*/
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import React, { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react';
import { UnitSystem, UnitPreferences } from './units.types';
import { safeStorage } from '../utils/safe-storage';
import {
@@ -18,22 +18,27 @@ import {
getVolumeUnit,
getFuelEfficiencyUnit
} from './units.utils';
import { usePreferences, useUpdatePreferences } from '../../features/settings/hooks/usePreferences';
import { useAuth0 } from '@auth0/auth0-react';
interface UnitsContextType {
unitSystem: UnitSystem;
setUnitSystem: (system: UnitSystem) => void;
preferences: UnitPreferences;
currencySymbol: string;
currencyCode: string;
isLoading: boolean;
// Conversion functions
convertDistance: (miles: number) => number;
convertVolume: (gallons: number) => number;
convertFuelEfficiency: (mpg: number) => number;
// Formatting functions
formatDistance: (miles: number, precision?: number) => string;
formatVolume: (gallons: number, precision?: number) => string;
formatFuelEfficiency: (mpg: number, precision?: number) => string;
formatPrice: (pricePerGallon: number, currency?: string, precision?: number) => string;
formatPrice: (pricePerGallon: number, precision?: number) => string;
}
const UnitsContext = createContext<UnitsContextType | undefined>(undefined);
@@ -43,34 +48,78 @@ interface UnitsProviderProps {
initialSystem?: UnitSystem;
}
export const UnitsProvider: React.FC<UnitsProviderProps> = ({
children,
initialSystem = 'imperial'
}) => {
const [unitSystem, setUnitSystem] = useState<UnitSystem>(initialSystem);
// Load unit preference from storage on mount
useEffect(() => {
try {
const stored = safeStorage.getItem('motovaultpro-unit-system');
if (stored === 'imperial' || stored === 'metric') {
setUnitSystem(stored);
}
} catch (error) {
console.warn('[Units] Failed to load unit system preference:', error);
}
}, []);
// Currency symbol mapping
const getCurrencySymbol = (system: UnitSystem): string => {
return system === 'metric' ? '\u20AC' : '$'; // EUR or USD
};
// Save unit preference to storage when changed
const handleSetUnitSystem = (system: UnitSystem) => {
setUnitSystem(system);
const getCurrencyCode = (system: UnitSystem): string => {
return system === 'metric' ? 'EUR' : 'USD';
};
export const UnitsProvider: React.FC<UnitsProviderProps> = ({
children,
initialSystem = 'imperial'
}) => {
const [unitSystem, setUnitSystemState] = useState<UnitSystem>(initialSystem);
const [hasInitialized, setHasInitialized] = useState(false);
const { isAuthenticated } = useAuth0();
const { data: backendPreferences, isLoading: preferencesLoading } = usePreferences();
const updatePreferencesMutation = useUpdatePreferences();
// Load unit preference from localStorage on mount (fallback)
useEffect(() => {
if (!hasInitialized) {
try {
const stored = safeStorage.getItem('motovaultpro-unit-system');
if (stored === 'imperial' || stored === 'metric') {
setUnitSystemState(stored);
}
} catch (error) {
console.warn('[Units] Failed to load unit system preference from storage:', error);
}
}
}, [hasInitialized]);
// Sync with backend preferences when they load (takes priority over localStorage)
useEffect(() => {
if (backendPreferences?.unitSystem && !hasInitialized) {
setUnitSystemState(backendPreferences.unitSystem);
// Also update localStorage to keep them in sync
try {
safeStorage.setItem('motovaultpro-unit-system', backendPreferences.unitSystem);
} catch (error) {
console.warn('[Units] Failed to sync unit system to storage:', error);
}
setHasInitialized(true);
}
}, [backendPreferences, hasInitialized]);
// Mark as initialized when not authenticated (localStorage is the source of truth)
useEffect(() => {
if (!isAuthenticated && !hasInitialized) {
setHasInitialized(true);
}
}, [isAuthenticated, hasInitialized]);
// Handle unit system change with backend sync
const handleSetUnitSystem = useCallback((system: UnitSystem) => {
setUnitSystemState(system);
// Always save to localStorage (offline fallback)
try {
safeStorage.setItem('motovaultpro-unit-system', system);
} catch (error) {
console.warn('[Units] Failed to save unit system preference:', error);
}
};
// Sync to backend if authenticated
if (isAuthenticated) {
updatePreferencesMutation.mutate({ unitSystem: system });
}
}, [isAuthenticated, updatePreferencesMutation]);
// Generate preferences object based on current system
const preferences: UnitPreferences = {
system: unitSystem,
@@ -78,29 +127,36 @@ export const UnitsProvider: React.FC<UnitsProviderProps> = ({
volume: getVolumeUnit(unitSystem),
fuelEfficiency: getFuelEfficiencyUnit(unitSystem),
};
// Currency based on unit system
const currencySymbol = getCurrencySymbol(unitSystem);
const currencyCode = getCurrencyCode(unitSystem);
// Conversion functions using current unit system
const convertDistance = (miles: number) => convertDistanceBySystem(miles, unitSystem);
const convertVolume = (gallons: number) => convertVolumeBySystem(gallons, unitSystem);
const convertFuelEfficiency = (mpg: number) => convertFuelEfficiencyBySystem(mpg, unitSystem);
const convertDistance = useCallback((miles: number) => convertDistanceBySystem(miles, unitSystem), [unitSystem]);
const convertVolume = useCallback((gallons: number) => convertVolumeBySystem(gallons, unitSystem), [unitSystem]);
const convertFuelEfficiency = useCallback((mpg: number) => convertFuelEfficiencyBySystem(mpg, unitSystem), [unitSystem]);
// Formatting functions using current unit system
const formatDistance = (miles: number, precision?: number) =>
formatDistanceBySystem(miles, unitSystem, precision);
const formatVolume = (gallons: number, precision?: number) =>
formatVolumeBySystem(gallons, unitSystem, precision);
const formatFuelEfficiency = (mpg: number, precision?: number) =>
formatFuelEfficiencyBySystem(mpg, unitSystem, precision);
const formatPrice = (pricePerGallon: number, currency?: string, precision?: number) =>
formatPriceBySystem(pricePerGallon, unitSystem, currency, precision);
const formatDistance = useCallback((miles: number, precision?: number) =>
formatDistanceBySystem(miles, unitSystem, precision), [unitSystem]);
const formatVolume = useCallback((gallons: number, precision?: number) =>
formatVolumeBySystem(gallons, unitSystem, precision), [unitSystem]);
const formatFuelEfficiency = useCallback((mpg: number, precision?: number) =>
formatFuelEfficiencyBySystem(mpg, unitSystem, precision), [unitSystem]);
const formatPrice = useCallback((pricePerGallon: number, precision?: number) =>
formatPriceBySystem(pricePerGallon, unitSystem, currencyCode, precision), [unitSystem, currencyCode]);
const value: UnitsContextType = {
unitSystem,
setUnitSystem: handleSetUnitSystem,
preferences,
currencySymbol,
currencyCode,
isLoading: preferencesLoading && isAuthenticated,
convertDistance,
convertVolume,
convertFuelEfficiency,
@@ -123,4 +179,4 @@ export const useUnits = (): UnitsContextType => {
throw new Error('useUnits must be used within a UnitsProvider');
}
return context;
};
};

View File

@@ -6,7 +6,7 @@
export type UnitSystem = 'imperial' | 'metric';
export type DistanceUnit = 'miles' | 'km';
export type VolumeUnit = 'gallons' | 'liters';
export type FuelEfficiencyUnit = 'mpg' | 'kml';
export type FuelEfficiencyUnit = 'mpg' | 'l100km';
export interface UnitPreferences {
system: UnitSystem;

View File

@@ -10,9 +10,8 @@ const MILES_TO_KM = 1.60934;
const KM_TO_MILES = 0.621371;
const GALLONS_TO_LITERS = 3.78541;
const LITERS_TO_GALLONS = 0.264172;
// For km/L conversion
const MPG_TO_KML = 1.60934 / 3.78541; // ≈ 0.425144
const KML_TO_MPG = 3.78541 / 1.60934; // ≈ 2.352145
// For L/100km conversion (inverse relationship: lower L/100km = better efficiency)
const MPG_TO_L100KM_FACTOR = 235.214;
// Distance Conversions
export function convertDistance(value: number, fromUnit: DistanceUnit, toUnit: DistanceUnit): number {
@@ -58,24 +57,24 @@ export function convertVolumeBySystem(gallons: number, toSystem: UnitSystem): nu
return gallons;
}
// Fuel Efficiency Conversions
// Fuel Efficiency Conversions (L/100km is inverse: lower = better)
export function convertFuelEfficiency(value: number, fromUnit: FuelEfficiencyUnit, toUnit: FuelEfficiencyUnit): number {
if (fromUnit === toUnit) return value;
if (fromUnit === 'mpg' && toUnit === 'kml') {
return value * MPG_TO_KML;
if (fromUnit === 'mpg' && toUnit === 'l100km') {
return value === 0 ? 0 : MPG_TO_L100KM_FACTOR / value;
}
if (fromUnit === 'kml' && toUnit === 'mpg') {
return value * KML_TO_MPG;
if (fromUnit === 'l100km' && toUnit === 'mpg') {
return value === 0 ? 0 : MPG_TO_L100KM_FACTOR / value;
}
return value;
}
export function convertFuelEfficiencyBySystem(mpg: number, toSystem: UnitSystem): number {
if (toSystem === 'metric') {
return convertFuelEfficiency(mpg, 'mpg', 'kml');
return convertFuelEfficiency(mpg, 'mpg', 'l100km');
}
return mpg;
}
@@ -111,15 +110,15 @@ export function formatVolume(value: number, unit: VolumeUnit, precision = 2): st
export function formatFuelEfficiency(value: number, unit: FuelEfficiencyUnit, precision = 1): string {
if (typeof value !== 'number' || isNaN(value)) {
return unit === 'mpg' ? '0 MPG' : '0 km/L';
return unit === 'mpg' ? '0 MPG' : '0 L/100km';
}
const rounded = parseFloat(value.toFixed(precision));
if (unit === 'mpg') {
return `${rounded} MPG`;
} else {
return `${rounded} km/L`;
return `${rounded} L/100km`;
}
}
@@ -168,8 +167,8 @@ export function formatVolumeBySystem(gallons: number, system: UnitSystem, precis
export function formatFuelEfficiencyBySystem(mpg: number, system: UnitSystem, precision = 1): string {
if (system === 'metric') {
const kml = convertFuelEfficiencyBySystem(mpg, system);
return formatFuelEfficiency(kml, 'kml', precision);
const l100km = convertFuelEfficiencyBySystem(mpg, system);
return formatFuelEfficiency(l100km, 'l100km', precision);
}
return formatFuelEfficiency(mpg, 'mpg', precision);
}
@@ -192,5 +191,5 @@ export function getVolumeUnit(system: UnitSystem): VolumeUnit {
}
export function getFuelEfficiencyUnit(system: UnitSystem): FuelEfficiencyUnit {
return system === 'metric' ? 'kml' : 'mpg';
return system === 'metric' ? 'l100km' : 'mpg';
}

View File

@@ -350,7 +350,7 @@ export const useImportApply = () => {
onSuccess: (result) => {
queryClient.invalidateQueries({ queryKey: ['catalogSearch'] });
toast.success(
`Import completed: ${result.created} created, ${result.updated} updated, ${result.deleted} deleted`
`Import completed: ${result.created} created, ${result.updated} updated`
);
},
onError: (error: ApiError) => {

View File

@@ -462,9 +462,6 @@ export const AdminCatalogMobileScreen: React.FC = () => {
<div className="bg-blue-100 text-blue-800 px-3 py-2 rounded-lg">
<strong>{importPreview.toUpdate.length}</strong> to update
</div>
<div className="bg-red-100 text-red-800 px-3 py-2 rounded-lg">
<strong>{importPreview.toDelete.length}</strong> to delete
</div>
</div>
{/* Errors */}

View File

@@ -181,7 +181,6 @@ export interface CatalogSearchResponse {
// Catalog import types
export interface ImportRow {
action: 'add' | 'update' | 'delete';
year: number;
make: string;
model: string;
@@ -199,7 +198,6 @@ export interface ImportPreviewResult {
previewId: string;
toCreate: ImportRow[];
toUpdate: ImportRow[];
toDelete: ImportRow[];
errors: ImportError[];
valid: boolean;
}
@@ -207,7 +205,6 @@ export interface ImportPreviewResult {
export interface ImportApplyResult {
created: number;
updated: number;
deleted: number;
errors: ImportError[];
}

View File

@@ -1,15 +1,15 @@
import React from 'react';
import { Card, CardContent, Typography, Box, Chip } from '@mui/material';
import { UnitSystem } from '../types/fuel-logs.types';
import { useUnits } from '../../../core/units/UnitsContext';
interface Props {
fuelUnits?: number;
costPerUnit?: number;
calculatedCost: number;
unitSystem?: UnitSystem;
}
export const CostCalculator: React.FC<Props> = ({ fuelUnits, costPerUnit, calculatedCost, unitSystem = 'imperial' }) => {
export const CostCalculator: React.FC<Props> = ({ fuelUnits, costPerUnit, calculatedCost }) => {
const { unitSystem, currencySymbol } = useUnits();
const unitLabel = unitSystem === 'imperial' ? 'gallons' : 'liters';
// Ensure we have valid numbers
@@ -30,8 +30,8 @@ export const CostCalculator: React.FC<Props> = ({ fuelUnits, costPerUnit, calcul
<Chip label="Real-time" size="small" color="primary" variant="outlined" />
</Box>
<Box display="flex" justifyContent="space-between" alignItems="center">
<Typography variant="body2">{safeUnits.toFixed(3)} {unitLabel} × ${safeCostPerUnit.toFixed(3)}</Typography>
<Typography variant="h6" color="primary.main" fontWeight={700}>${safeCost.toFixed(2)}</Typography>
<Typography variant="body2">{safeUnits.toFixed(3)} {unitLabel} x {currencySymbol}{safeCostPerUnit.toFixed(3)}</Typography>
<Typography variant="h6" color="primary.main" fontWeight={700}>{currencySymbol}{safeCost.toFixed(2)}</Typography>
</Box>
</CardContent>
</Card>

View File

@@ -12,8 +12,8 @@ interface Props {
}
export const DistanceInput: React.FC<Props> = ({ type, value, onChange, unitSystem = 'imperial', error, disabled }) => {
const units = unitSystem === 'imperial' ? 'miles' : 'kilometers';
const label = type === 'odometer' ? `Odometer (${units})` : `Trip Distance (${units})`;
const units = unitSystem === 'imperial' ? 'miles' : 'km';
const label = type === 'odometer' ? 'Odometer' : 'Trip Distance';
return (
<Box>
<TextField

View File

@@ -157,7 +157,7 @@ const FuelLogFormComponent: React.FC<{ onSuccess?: () => void; initial?: Partial
)} />
</Grid>
{/* Row 2: Date/Time | MPG/km/L */}
{/* Row 2: Date/Time | MPG/L/100km */}
<Grid item xs={12} sm={6}>
<Controller name="dateTime" control={control} render={({ field }) => (
<DateTimePicker
@@ -182,7 +182,7 @@ const FuelLogFormComponent: React.FC<{ onSuccess?: () => void; initial?: Partial
</Grid>
<Grid item xs={12} sm={6}>
<TextField
label={`${userSettings?.unitSystem === 'metric' ? 'km/L' : 'MPG'}`}
label={`${userSettings?.unitSystem === 'metric' ? 'L/100km' : 'MPG'}`}
value={calculatedEfficiency > 0 ? calculatedEfficiency.toFixed(3) : ''}
fullWidth
InputProps={{
@@ -283,7 +283,7 @@ const FuelLogFormComponent: React.FC<{ onSuccess?: () => void; initial?: Partial
)} />
</Grid>
<Grid item xs={12}>
<CostCalculator fuelUnits={fuelUnits} costPerUnit={costPerUnit} calculatedCost={calculatedCost} unitSystem={userSettings?.unitSystem} />
<CostCalculator fuelUnits={fuelUnits} costPerUnit={costPerUnit} calculatedCost={calculatedCost} />
</Grid>
<Grid item xs={12}>
<Controller name="locationData" control={control} render={({ field }) => (

View File

@@ -31,7 +31,7 @@ interface FuelLogsListProps {
export const FuelLogsList: React.FC<FuelLogsListProps> = ({ logs, onEdit, onDelete }) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
const { unitSystem, convertDistance, convertVolume } = useUnits();
const { unitSystem, convertDistance, convertVolume, currencySymbol } = useUnits();
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [logToDelete, setLogToDelete] = useState<FuelLogResponse | null>(null);
const [isDeleting, setIsDeleting] = useState(false);
@@ -145,7 +145,7 @@ export const FuelLogsList: React.FC<FuelLogsListProps> = ({ logs, onEdit, onDele
if (unitSystem === 'metric') {
const km = convertDistance(miles);
const liters = convertVolume(gallons);
if (liters > 0) localEffLabel = `${(km / liters).toFixed(1)} km/L`;
if (km > 0) localEffLabel = `${((liters / km) * 100).toFixed(1)} L/100km`;
} else {
localEffLabel = `${(miles / gallons).toFixed(1)} MPG`;
}
@@ -173,8 +173,8 @@ export const FuelLogsList: React.FC<FuelLogsListProps> = ({ logs, onEdit, onDele
gap: isMobile ? 0.5 : 1
}}>
<ListItemText
primary={`${dateText} $${totalCost}`}
secondary={`${fuelUnits} @ $${costPerUnit} ${distanceText}`}
primary={`${dateText} \u2013 ${currencySymbol}${totalCost}`}
secondary={`${fuelUnits} @ ${currencySymbol}${costPerUnit} \u2022 ${distanceText}`}
sx={{ flex: 1, minWidth: 0 }}
/>
{(log.efficiency && typeof log.efficiency === 'number' && !isNaN(log.efficiency) && log.efficiencyLabel) || localEffLabel ? (
@@ -262,7 +262,7 @@ export const FuelLogsList: React.FC<FuelLogsListProps> = ({ logs, onEdit, onDele
</Typography>
{logToDelete && (
<Typography variant="body2" color="text.secondary" sx={{ mt: 1 }}>
{new Date(logToDelete.dateTime).toLocaleString()} - ${logToDelete.totalCost.toFixed(2)}
{new Date(logToDelete.dateTime).toLocaleString()} - {currencySymbol}{logToDelete.totalCost.toFixed(2)}
</Typography>
)}
</DialogContent>

View File

@@ -4,7 +4,7 @@ import { FuelLogResponse } from '../types/fuel-logs.types';
import { useUnits } from '../../../core/units/UnitsContext';
export const FuelStatsCard: React.FC<{ logs?: FuelLogResponse[] }> = ({ logs }) => {
const { unitSystem } = useUnits();
const { unitSystem, currencySymbol } = useUnits();
const stats = useMemo(() => {
if (!logs || logs.length === 0) return { count: 0, totalUnits: 0, totalCost: 0 };
@@ -37,7 +37,7 @@ export const FuelStatsCard: React.FC<{ logs?: FuelLogResponse[] }> = ({ logs })
</Grid>
<Grid item xs={4}>
<Typography variant="overline" color="text.secondary">Total Cost</Typography>
<Typography variant="h6">${(typeof stats.totalCost === 'number' && !isNaN(stats.totalCost) ? stats.totalCost : 0).toFixed(2)}</Typography>
<Typography variant="h6">{currencySymbol}{(typeof stats.totalCost === 'number' && !isNaN(stats.totalCost) ? stats.totalCost : 0).toFixed(2)}</Typography>
</Grid>
</Grid>
</CardContent>

View File

@@ -4,7 +4,7 @@ import { UnitSystem } from '../types/fuel-logs.types';
export const UnitSystemDisplay: React.FC<{ unitSystem?: UnitSystem; showLabel?: string }> = ({ unitSystem, showLabel }) => {
if (!unitSystem) return null;
const label = unitSystem === 'imperial' ? 'Imperial (miles, gallons, MPG)' : 'Metric (km, liters, km/L)';
const label = unitSystem === 'imperial' ? 'Imperial (miles, gallons, MPG)' : 'Metric (km, liters, L/100km)';
return (
<Typography variant="caption" color="text.secondary">
{showLabel ? `${showLabel} ` : ''}{label}

View File

@@ -0,0 +1,13 @@
/**
* @ai-summary API client for user preferences endpoints
* @ai-context Handles unit system, currency, and timezone preferences sync
*/
import { apiClient } from '../../../core/api/client';
import { UserPreferences, UpdatePreferencesRequest } from '../types/preferences.types';
export const preferencesApi = {
getPreferences: () => apiClient.get<UserPreferences>('/user/preferences'),
updatePreferences: (data: UpdatePreferencesRequest) =>
apiClient.put<UserPreferences>('/user/preferences', data),
};

View File

@@ -0,0 +1,61 @@
/**
* @ai-summary React hooks for user preferences management
* @ai-context Handles unit system, currency, and timezone preference sync with backend
*/
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useAuth0 } from '@auth0/auth0-react';
import { preferencesApi } from '../api/preferences.api';
import { UpdatePreferencesRequest } from '../types/preferences.types';
import toast from 'react-hot-toast';
interface ApiError {
response?: {
data?: {
error?: string;
message?: string;
};
};
message?: string;
}
export const usePreferences = () => {
const { isAuthenticated, isLoading } = useAuth0();
return useQuery({
queryKey: ['user-preferences'],
queryFn: async () => {
const response = await preferencesApi.getPreferences();
return response.data;
},
enabled: isAuthenticated && !isLoading,
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 10 * 60 * 1000, // 10 minutes cache time
retry: (failureCount, error: any) => {
// Retry 401s a few times (auth token might be refreshing)
if (error?.response?.status === 401 && failureCount < 3) {
return true;
}
return false;
},
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
refetchOnWindowFocus: false,
refetchOnMount: false,
});
};
export const useUpdatePreferences = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: UpdatePreferencesRequest) => preferencesApi.updatePreferences(data),
onSuccess: (response) => {
queryClient.setQueryData(['user-preferences'], response.data);
// Don't show toast for unit system changes - context handles UI feedback
},
onError: (error: ApiError) => {
const message = error.response?.data?.message || error.response?.data?.error || 'Failed to update preferences';
toast.error(message);
},
});
};

View File

@@ -1,5 +1,6 @@
import { useState, useEffect } from 'react';
import { useSettingsPersistence, SettingsState } from './useSettingsPersistence';
import { useUnits } from '../../../core/units/UnitsContext';
const defaultSettings: SettingsState = {
darkMode: false,
@@ -13,10 +14,12 @@ const defaultSettings: SettingsState = {
export const useSettings = () => {
const { loadSettings, saveSettings } = useSettingsPersistence();
const { unitSystem: contextUnitSystem, setUnitSystem: setContextUnitSystem } = useUnits();
const [settings, setSettings] = useState<SettingsState>(defaultSettings);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Load settings from localStorage on mount
useEffect(() => {
try {
setIsLoading(true);
@@ -33,6 +36,13 @@ export const useSettings = () => {
}
}, [loadSettings]);
// Sync unitSystem from context (which may load from backend)
useEffect(() => {
if (contextUnitSystem && contextUnitSystem !== settings.unitSystem) {
setSettings(prev => ({ ...prev, unitSystem: contextUnitSystem }));
}
}, [contextUnitSystem, settings.unitSystem]);
const updateSetting = <K extends keyof SettingsState>(
key: K,
value: SettingsState[K]
@@ -42,6 +52,11 @@ export const useSettings = () => {
const newSettings = { ...settings, [key]: value };
setSettings(newSettings);
saveSettings(newSettings);
// Sync unitSystem changes to context (which syncs to backend)
if (key === 'unitSystem' && typeof value === 'string') {
setContextUnitSystem(value as 'imperial' | 'metric');
}
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to save settings');
}

View File

@@ -367,7 +367,7 @@ export const MobileSettingsScreen: React.FC = () => {
<div>
<p className="font-medium text-slate-800">Unit System</p>
<p className="text-sm text-slate-500">
Currently using {settings.unitSystem === 'imperial' ? 'Miles & Gallons' : 'Kilometers & Liters'}
Currently using {settings.unitSystem === 'imperial' ? 'Miles, Gallons, MPG, USD' : 'Km, Liters, L/100km, EUR'}
</p>
</div>
<button

View File

@@ -0,0 +1,22 @@
/**
* @ai-summary Type definitions for user preferences
* @ai-context Types for unit system, currency, and timezone preferences
*/
import { UnitSystem } from '../../../core/units/units.types';
export interface UserPreferences {
id: string;
userId: string;
unitSystem: UnitSystem;
currencyCode: string;
timeZone: string;
createdAt: string;
updatedAt: string;
}
export interface UpdatePreferencesRequest {
unitSystem?: UnitSystem;
currencyCode?: string;
timeZone?: string;
}

View File

@@ -324,7 +324,7 @@ export const SettingsPage: React.FC = () => {
<ListItem>
<ListItemText
primary="Units for distance and capacity"
secondary="Choose between Imperial (miles, gallons) or Metric (kilometers, liters)"
secondary="Imperial: miles, gallons, MPG, USD | Metric: km, liters, L/100km, EUR"
sx={{ pl: 7 }}
/>
<ListItemSecondaryAction>

View File

@@ -525,9 +525,6 @@ export const AdminCatalogPage: React.FC = () => {
<Typography>
<strong>To Update:</strong> {importPreview.toUpdate.length}
</Typography>
<Typography>
<strong>To Delete:</strong> {importPreview.toDelete.length}
</Typography>
</Box>
{/* Errors */}