feat: EMEX catalog integration — schema, data migration, backend & frontend
Some checks failed
CI / Lint, Typecheck, Test & Build (push) Has been cancelled

Redesign emex_* tables from vehicle-centric to catalog-centric structure with
junction tables (emex_vehicle_group_links, emex_vehicle_part_links). Migrate
92M+ rows from emex DB via postgres_fdw. Add EmexCatalogService for browse
and VIN pre-scraped matching, with Redis caching. Frontend catalog page now
has PL24/Emex tabs with full drill-down routes (brand → vehicle → group → parts).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 04:06:29 +00:00
parent 63f6309bf3
commit 1e8a049219
17 changed files with 1351 additions and 75 deletions

View File

@@ -41,9 +41,12 @@ import { Route as DashboardAdminCopyLogsRouteImport } from "./routes/dashboard/a
import { Route as DashboardAdminAnalyticsRouteImport } from "./routes/dashboard/admin/analytics"
import { Route as DashboardVehiclesIdIndexRouteImport } from "./routes/dashboard/vehicles_/$id/index"
import { Route as DashboardCatalogBrandNameIndexRouteImport } from "./routes/dashboard/catalog_/$brandName/index"
import { Route as DashboardCatalogEmexCatalogCodeIndexRouteImport } from "./routes/dashboard/catalog_/emex/$catalogCode/index"
import { Route as DashboardCatalogBrandNameModelIdIndexRouteImport } from "./routes/dashboard/catalog_/$brandName_/$modelId/index"
import { Route as DashboardVehiclesIdCategoriesCategoryIdRouteImport } from "./routes/dashboard/vehicles_/$id/categories_/$categoryId"
import { Route as DashboardCatalogEmexCatalogCodeVehicleIdIndexRouteImport } from "./routes/dashboard/catalog_/emex/$catalogCode_/$vehicleId/index"
import { Route as DashboardCatalogBrandNameModelIdCategoriesCategoryIdRouteImport } from "./routes/dashboard/catalog_/$brandName_/$modelId/categories_/$categoryId"
import { Route as DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRouteImport } from "./routes/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId"
const TermsRoute = TermsRouteImport.update({
id: "/terms",
@@ -208,6 +211,12 @@ const DashboardCatalogBrandNameIndexRoute =
path: "/catalog/$brandName/",
getParentRoute: () => DashboardRoute,
} as any)
const DashboardCatalogEmexCatalogCodeIndexRoute =
DashboardCatalogEmexCatalogCodeIndexRouteImport.update({
id: "/catalog_/emex/$catalogCode/",
path: "/catalog/emex/$catalogCode/",
getParentRoute: () => DashboardRoute,
} as any)
const DashboardCatalogBrandNameModelIdIndexRoute =
DashboardCatalogBrandNameModelIdIndexRouteImport.update({
id: "/catalog_/$brandName_/$modelId/",
@@ -220,12 +229,24 @@ const DashboardVehiclesIdCategoriesCategoryIdRoute =
path: "/vehicles/$id/categories/$categoryId",
getParentRoute: () => DashboardRoute,
} as any)
const DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute =
DashboardCatalogEmexCatalogCodeVehicleIdIndexRouteImport.update({
id: "/catalog_/emex/$catalogCode_/$vehicleId/",
path: "/catalog/emex/$catalogCode/$vehicleId/",
getParentRoute: () => DashboardRoute,
} as any)
const DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute =
DashboardCatalogBrandNameModelIdCategoriesCategoryIdRouteImport.update({
id: "/catalog_/$brandName_/$modelId/categories_/$categoryId",
path: "/catalog/$brandName/$modelId/categories/$categoryId",
getParentRoute: () => DashboardRoute,
} as any)
const DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute =
DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRouteImport.update({
id: "/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId",
path: "/catalog/emex/$catalogCode/$vehicleId/groups/$groupId",
getParentRoute: () => DashboardRoute,
} as any)
export interface FileRoutesByFullPath {
"/": typeof IndexRoute
@@ -261,7 +282,10 @@ export interface FileRoutesByFullPath {
"/dashboard/vehicles/$id/": typeof DashboardVehiclesIdIndexRoute
"/dashboard/vehicles/$id/categories/$categoryId": typeof DashboardVehiclesIdCategoriesCategoryIdRoute
"/dashboard/catalog/$brandName/$modelId/": typeof DashboardCatalogBrandNameModelIdIndexRoute
"/dashboard/catalog/emex/$catalogCode/": typeof DashboardCatalogEmexCatalogCodeIndexRoute
"/dashboard/catalog/$brandName/$modelId/categories/$categoryId": typeof DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute
"/dashboard/catalog/emex/$catalogCode/$vehicleId/": typeof DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute
"/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId": typeof DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute
}
export interface FileRoutesByTo {
"/": typeof IndexRoute
@@ -296,7 +320,10 @@ export interface FileRoutesByTo {
"/dashboard/vehicles/$id": typeof DashboardVehiclesIdIndexRoute
"/dashboard/vehicles/$id/categories/$categoryId": typeof DashboardVehiclesIdCategoriesCategoryIdRoute
"/dashboard/catalog/$brandName/$modelId": typeof DashboardCatalogBrandNameModelIdIndexRoute
"/dashboard/catalog/emex/$catalogCode": typeof DashboardCatalogEmexCatalogCodeIndexRoute
"/dashboard/catalog/$brandName/$modelId/categories/$categoryId": typeof DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute
"/dashboard/catalog/emex/$catalogCode/$vehicleId": typeof DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute
"/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId": typeof DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
@@ -334,7 +361,10 @@ export interface FileRoutesById {
"/dashboard/vehicles_/$id/": typeof DashboardVehiclesIdIndexRoute
"/dashboard/vehicles_/$id/categories_/$categoryId": typeof DashboardVehiclesIdCategoriesCategoryIdRoute
"/dashboard/catalog_/$brandName_/$modelId/": typeof DashboardCatalogBrandNameModelIdIndexRoute
"/dashboard/catalog_/emex/$catalogCode/": typeof DashboardCatalogEmexCatalogCodeIndexRoute
"/dashboard/catalog_/$brandName_/$modelId/categories_/$categoryId": typeof DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute
"/dashboard/catalog_/emex/$catalogCode_/$vehicleId/": typeof DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute
"/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId": typeof DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
@@ -372,7 +402,10 @@ export interface FileRouteTypes {
| "/dashboard/vehicles/$id/"
| "/dashboard/vehicles/$id/categories/$categoryId"
| "/dashboard/catalog/$brandName/$modelId/"
| "/dashboard/catalog/emex/$catalogCode/"
| "/dashboard/catalog/$brandName/$modelId/categories/$categoryId"
| "/dashboard/catalog/emex/$catalogCode/$vehicleId/"
| "/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId"
fileRoutesByTo: FileRoutesByTo
to:
| "/"
@@ -407,7 +440,10 @@ export interface FileRouteTypes {
| "/dashboard/vehicles/$id"
| "/dashboard/vehicles/$id/categories/$categoryId"
| "/dashboard/catalog/$brandName/$modelId"
| "/dashboard/catalog/emex/$catalogCode"
| "/dashboard/catalog/$brandName/$modelId/categories/$categoryId"
| "/dashboard/catalog/emex/$catalogCode/$vehicleId"
| "/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId"
id:
| "__root__"
| "/"
@@ -444,7 +480,10 @@ export interface FileRouteTypes {
| "/dashboard/vehicles_/$id/"
| "/dashboard/vehicles_/$id/categories_/$categoryId"
| "/dashboard/catalog_/$brandName_/$modelId/"
| "/dashboard/catalog_/emex/$catalogCode/"
| "/dashboard/catalog_/$brandName_/$modelId/categories_/$categoryId"
| "/dashboard/catalog_/emex/$catalogCode_/$vehicleId/"
| "/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId"
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
@@ -688,6 +727,13 @@ declare module "@tanstack/react-router" {
preLoaderRoute: typeof DashboardCatalogBrandNameIndexRouteImport
parentRoute: typeof DashboardRoute
}
"/dashboard/catalog_/emex/$catalogCode/": {
id: "/dashboard/catalog_/emex/$catalogCode/"
path: "/catalog/emex/$catalogCode"
fullPath: "/dashboard/catalog/emex/$catalogCode/"
preLoaderRoute: typeof DashboardCatalogEmexCatalogCodeIndexRouteImport
parentRoute: typeof DashboardRoute
}
"/dashboard/catalog_/$brandName_/$modelId/": {
id: "/dashboard/catalog_/$brandName_/$modelId/"
path: "/catalog/$brandName/$modelId"
@@ -702,6 +748,13 @@ declare module "@tanstack/react-router" {
preLoaderRoute: typeof DashboardVehiclesIdCategoriesCategoryIdRouteImport
parentRoute: typeof DashboardRoute
}
"/dashboard/catalog_/emex/$catalogCode_/$vehicleId/": {
id: "/dashboard/catalog_/emex/$catalogCode_/$vehicleId/"
path: "/catalog/emex/$catalogCode/$vehicleId"
fullPath: "/dashboard/catalog/emex/$catalogCode/$vehicleId/"
preLoaderRoute: typeof DashboardCatalogEmexCatalogCodeVehicleIdIndexRouteImport
parentRoute: typeof DashboardRoute
}
"/dashboard/catalog_/$brandName_/$modelId/categories_/$categoryId": {
id: "/dashboard/catalog_/$brandName_/$modelId/categories_/$categoryId"
path: "/catalog/$brandName/$modelId/categories/$categoryId"
@@ -709,6 +762,13 @@ declare module "@tanstack/react-router" {
preLoaderRoute: typeof DashboardCatalogBrandNameModelIdCategoriesCategoryIdRouteImport
parentRoute: typeof DashboardRoute
}
"/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId": {
id: "/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId"
path: "/catalog/emex/$catalogCode/$vehicleId/groups/$groupId"
fullPath: "/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId"
preLoaderRoute: typeof DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRouteImport
parentRoute: typeof DashboardRoute
}
}
}
@@ -747,7 +807,10 @@ interface DashboardRouteChildren {
DashboardVehiclesIdIndexRoute: typeof DashboardVehiclesIdIndexRoute
DashboardVehiclesIdCategoriesCategoryIdRoute: typeof DashboardVehiclesIdCategoriesCategoryIdRoute
DashboardCatalogBrandNameModelIdIndexRoute: typeof DashboardCatalogBrandNameModelIdIndexRoute
DashboardCatalogEmexCatalogCodeIndexRoute: typeof DashboardCatalogEmexCatalogCodeIndexRoute
DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute: typeof DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute
DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute: typeof DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute
DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute: typeof DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute
}
const DashboardRouteChildren: DashboardRouteChildren = {
@@ -771,8 +834,14 @@ const DashboardRouteChildren: DashboardRouteChildren = {
DashboardVehiclesIdCategoriesCategoryIdRoute,
DashboardCatalogBrandNameModelIdIndexRoute:
DashboardCatalogBrandNameModelIdIndexRoute,
DashboardCatalogEmexCatalogCodeIndexRoute:
DashboardCatalogEmexCatalogCodeIndexRoute,
DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute:
DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute,
DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute:
DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute,
DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute:
DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute,
}
const DashboardRouteWithChildren = DashboardRoute._addFileChildren(