Appearance
Design: Car Modification — 4th Level of Car Hierarchy
Date: 2026-02-14 Status: Approved
Problem
Backend added a 4th level to the car reference hierarchy — Modifications (30,066 records with engine/transmission specs). The frontend currently supports only 3 levels: Make → Model → Generation. All cascade selectors, schemas, admin CRUD, and catalog filters need to be extended to support the new level.
Decisions
modification_idis optional (nullable) everywhere — users are never required to select a modification- Modification dropdown label uses
namefield as-is from backend (already formatted: "1.8L 5MT FWD (90 HP)") - Homepage hero: 4 dropdowns in a row (ужать), expand max-width
- Admin references: 4-column grid
- Admin CRUD: full create/update/delete for modifications
Data Model
New Entity: CarModification
entities/car/model/car.schema.ts
CarModification {
id: number
generation_id: number
name: string // "1.8L 5MT FWD (90 HP)"
engine_volume: string | null // "1.8", "2.0"
fuel_type: FuelType | null // petrol|diesel|hybrid|electric|gas
power: number | null // HP
transmission: Transmission | null // mt|at|cvt|amt|robot
drivetrain: Drivetrain | null // fwd|rwd|awd|4wd
}New enum schemas: fuelTypeSchema, transmissionSchema, drivetrainSchema. Update carSteeringSchema to add 'universal' value.
Compatibility Extension
entities/product/model/product.schema.ts
compatibilitySchema += modification_id: z.number().nullable()API Endpoint
GET /store/cars/generations/{generationId}/modifications → { data: CarModification[] }Admin CRUD:
POST /admin/cars/modifications
PUT /admin/cars/modifications/{id}
DELETE /admin/cars/modifications/{id}Cascade Logic
useYmmCascade.ts (public cascade)
- New refs:
modifications,selectedModificationId,loadingModifications fetchModifications(generationId)→ GET endpointYmmSelectioninterface +=modification_id- Watcher:
watch(selectedGenerationId)→ fetch modifications or clear - All upstream watchers clear modifications downstream
hydrate()handles modification_idreset()clears modifications
useAdminCars.ts (admin CRUD)
- New refs:
modifications,selectedGenerationId fetchModifications(generationId)- Watcher:
watch(selectedGenerationId)→ fetch/clear selectedModelIdwatcher also clears modifications + selectedGenerationId- CRUD:
createModification,updateModification,deleteModification
useProductForm.ts
No changes needed. Code is generic — compatibility array passes through, buildRequestBody() filters by make_id > 0. New modification_id flows automatically via updated Zod type.
UI Changes
YmmSelect.vue (single cascade row)
4th USelectMenu for modification:
- Props:
modifications[],loadingModifications - Model:
modificationId - Disabled until
generationIdselected - Label:
modification.name(as-is)
YmmMultiSelect.vue (multi-row in product form)
addRow()creates entry withmodification_id: nullupdateRow()accepts'modification_id'field- Passes modifications data + events to YmmSelect
Homepage Hero (pages/index.vue)
- 4 dropdowns + "Подобрать" button in single row
max-w-3xl→max-w-4xl- Add modification USelectMenu (disabled without generationId)
submitYmm()includesmodification_idin query
Catalog Sidebar (pages/catalog/index.vue)
- Add missing Generation filter (v-if selectedModelId)
- Add Modification filter (v-if selectedGenerationId)
filters.modification_idin reactive state- Cascade reset downstream on upper-level change
- Hydration from URL query params
Admin References (pages/admin/references.vue)
- Grid:
md:grid-cols-3→md:grid-cols-4 - Generations ReferenceList becomes selectable (selectedGenerationId)
- 4th ReferenceList for modifications
modificationFieldswith select options for fuel_type, transmission, drivetrain
Product Detail Pages
No changes. Compatibility displays via compat.note (backend formats text). Fallback is dev-only.
i18n (ru.json)
json
ymm: {
+ "modification": "Модификация",
+ "selectModification": "Выберите модификацию"
}
car: {
"fuelType": "Тип топлива",
"fuelPetrol": "Бензин", "fuelDiesel": "Дизель", "fuelHybrid": "Гибрид",
"fuelElectric": "Электро", "fuelGas": "Газ",
"transmission": "КПП",
"transmissionMt": "МКПП", "transmissionAt": "АКПП", "transmissionCvt": "Вариатор",
"transmissionAmt": "АМТ", "transmissionRobot": "Робот",
"drivetrain": "Привод",
"drivetrainFwd": "Передний", "drivetrainRwd": "Задний",
"drivetrainAwd": "Полный (AWD)", "drivetrain4wd": "Полный (4WD)",
"engineVolume": "Объём двигателя", "power": "Мощность"
}
admin: {
+ "modifications": "Модификации"
}Files to Modify
| # | File | Change |
|---|---|---|
| 1 | app/entities/car/model/car.schema.ts | Add CarModification + enums |
| 2 | app/entities/product/model/product.schema.ts | Add modification_id to compatibility |
| 3 | i18n/locales/ru.json | New i18n keys |
| 4 | app/features/ymm-select/composables/useYmmCascade.ts | 4th cascade level |
| 5 | app/features/admin-references/composables/useAdminCars.ts | Admin CRUD + cascade |
| 6 | app/features/ymm-select/ui/YmmSelect.vue | 4th dropdown |
| 7 | app/features/ymm-select/ui/YmmMultiSelect.vue | Pass modification data |
| 8 | app/pages/index.vue | Hero 4-dropdown layout |
| 9 | app/pages/catalog/index.vue | Generation + modification filters |
| 10 | app/pages/admin/references.vue | 4-column grid + modification CRUD |
| 11 | tests/entities/product/model/product.schema.test.ts | Update compatibility tests |
| 12 | app/features/admin-references/composables/useAdminCars.test.ts | Add modification CRUD tests |
| 13 | CLAUDE.md | Documentation update |
Testing
npm run typecheck— no TypeScript errorsnpm run test:run— all tests passnpm run lint— no ESLint/FSD violations- Manual verification on dev server: hero, catalog, product form, admin references