feat: add parts catalogs integration, catalog prefetch worker, and vehicle select modal

Integrate external parts catalogs API with auth service, add BullMQ-based
catalog prefetch worker for background data caching, expand vehicles service
with shared vehicle support, and add vehicle select modal to frontend.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sase Dev
2026-02-20 18:14:36 +00:00
parent f3f3f57756
commit f1a27810db
32 changed files with 2591 additions and 118 deletions

View File

@@ -28,6 +28,7 @@ import {
} from './emex.types';
import { mapEmexResponse, createEmptyDecodedVehicle } from './emex.mapper';
import { EmexBrowserService } from './emex.browser';
import { RedisService } from '../../redis/redis.service';
// Type definition for the imported scraper module
interface EmexScraperModule {
@@ -66,6 +67,7 @@ export class EmexService {
constructor(
private configService: ConfigService,
private browserService: EmexBrowserService,
private redis: RedisService,
) {
// __dirname is apps/api/src/integrations/emex/ or dist/integrations/emex/
// Scraper lives at <monorepo-root>/scripts/emex-vin-scraper.js
@@ -82,6 +84,15 @@ export class EmexService {
this.logger.log(`EMEX Service initialized with scraper path: ${this.scraperPath}`);
}
/** Mark EMEX as actively used (5min TTL) to defer prefetch worker */
private async touchActivity(): Promise<void> {
try {
await this.redis.set("prefetch:activity:emex", String(Date.now()), 300);
} catch {
// Non-critical — don't break the request
}
}
/**
* Lazily initialize the scraper module
*/
@@ -184,6 +195,7 @@ export class EmexService {
const supported = this.isSupported(cleanVin);
this.logger.log(`Decoding VIN: ${cleanVin} (catalog supported: ${supported})`);
await this.touchActivity();
let release: (() => Promise<void>) | null = null;
@@ -375,6 +387,7 @@ export class EmexService {
}
this.logger.log(`Fetching parts from category URL: ${categoryUrl}`);
await this.touchActivity();
let release: (() => Promise<void>) | null = null;