Files
service-finder/plans/logic_spec_vehicle_registration_documents.md
2026-06-23 21:11:21 +00:00

265 lines
10 KiB
Markdown

# 📐 Logic Spec — Vehicle Registration Documents
## Modul célja és Masterbook 2 illeszkedés
**Cél:** A forgalmi engedély száma, érvényességi ideje és a törzskönyv száma mezők hiányának pótlása a teljes adatfolyamban (adatbázis → API szint → Frontend UI).
**Masterbook 2 illeszkedés:** A Thick Asset Digital Twin filozófiába illeszkedik — minden adminisztratív adatot közvetlenül az Asset modellben tárolunk, nem JSONB-ben.
---
## Adatmodell
### Új mezők az Asset modellben
| Mező | Típus | SQL típus | Kötelező | Alapértelmezett |
|------|-------|-----------|----------|-----------------|
| `registration_certificate_number` | `Optional[str]` | `VARCHAR(50)` | Nem | `None` |
| `registration_certificate_validity` | `Optional[datetime]` | `DateTime(timezone=True)` | Nem | `None` |
| `vehicle_registration_document_number` | `Optional[str]` | `VARCHAR(50)` | Nem | `None` |
### Miért nem JSONB?
Ezek strukturált, kereshető admin adatok, amelyek:
- Külön lekérdezhetők (WHERE registration_certificate_number = '...')
- Indexelhetők
- Érvényesíthetők (pl. string hossz, dátum formátum)
- Nincsenek elrejtve a szabad formátumú JSONB-ben
---
## 1. Lépés: Adatbázis modell bővítése
**Fájl:** `backend/app/models/vehicle/asset.py`
### Módosítás
Az `Asset` osztályhoz (a warranty mezők után, a `notes` előtt) hozzáadandó:
```python
# === REGISTRATION DOCUMENTS ===
registration_certificate_number: Mapped[Optional[str]] = mapped_column(
String(50), nullable=True, default=None,
comment="Forgalmi engedély száma"
)
registration_certificate_validity: Mapped[Optional[datetime]] = mapped_column(
DateTime(timezone=True), nullable=True, default=None,
comment="Forgalmi engedély érvényességi ideje"
)
vehicle_registration_document_number: Mapped[Optional[str]] = mapped_column(
String(50), nullable=True, default=None,
comment="Törzskönyv száma"
)
```
### Sync
```bash
docker exec -it sf_api python -m app.scripts.sync_engine
```
---
## 2. Lépés: Pydantic sémák bővítése
**Fájl:** `backend/app/schemas/asset.py`
### AssetResponse (32. sor után)
```python
# === REGISTRATION DOCUMENTS ===
registration_certificate_number: Optional[str] = Field(None, max_length=50, description="Forgalmi engedély száma")
registration_certificate_validity: Optional[datetime] = Field(None, description="Forgalmi engedély érvényességi ideje")
vehicle_registration_document_number: Optional[str] = Field(None, max_length=50, description="Törzskönyv száma")
```
### AssetCreate (a warranty után, 233. sor környékén)
```python
# === REGISTRATION DOCUMENTS ===
registration_certificate_number: Optional[str] = Field(None, max_length=50, description="Forgalmi engedély száma")
registration_certificate_validity: Optional[datetime] = Field(None, description="Forgalmi engedély érvényességi ideje")
vehicle_registration_document_number: Optional[str] = Field(None, max_length=50, description="Törzskönyv száma")
```
### AssetUpdate (a warranty után, 375. sor környékén)
```python
# === REGISTRATION DOCUMENTS ===
registration_certificate_number: Optional[str] = Field(None, max_length=50, description="Forgalmi engedély száma")
registration_certificate_validity: Optional[datetime] = Field(None, description="Forgalmi engedély érvényességi ideje")
vehicle_registration_document_number: Optional[str] = Field(None, max_length=50, description="Törzskönyv száma")
```
---
## 3. Lépés: Asset Service bővítése
**Fájl:** `backend/app/services/asset_service.py`
### Módosítás a create_or_claim_vehicle() metódusban
A 219-es sor előtt (a `first_registration_date` után) az `asset_fields` dict-be:
```python
# Registration Documents
'registration_certificate_number': asset_data.registration_certificate_number,
'registration_certificate_validity': asset_data.registration_certificate_validity,
'vehicle_registration_document_number': asset_data.vehicle_registration_document_number,
```
---
## 4. Lépés: Frontend — Vehicle Store bővítése
**Fájl:** `frontend/src/stores/vehicle.ts`
### Módosítás a Vehicle interfészben (a 88-89. sor környékén)
```typescript
// Registration Documents
registration_certificate_number?: string | null
registration_certificate_validity?: string | null
vehicle_registration_document_number?: string | null
```
---
## 5. Lépés: Frontend — VehicleFormModal bővítése
**Fájl:** `frontend/src/components/dashboard/VehicleFormModal.vue`
### 5a. Form state bővítése (a 1779-es sor után)
```typescript
// Registration Documents
registration_certificate_number: '',
registration_certificate_validity: '',
vehicle_registration_document_number: '',
```
### 5b. Admin Tab UI bővítése (a 1006-os sor előtt, a warranty szekció után)
```html
<!-- ════════════════════════════════════════════════════════════ -->
<!-- REGISTRATION DOCUMENTS SECTION -->
<!-- ════════════════════════════════════════════════════════════ -->
<div class="border-t border-slate-200 pt-4">
<h4 class="text-sm font-semibold text-slate-700 mb-3">{{ t('vehicle.registration_documents_title') || 'Forgalmi engedély és Törzskönyv' }}</h4>
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div>
<label class="mb-1.5 block text-sm font-medium text-slate-700">{{ t('vehicle.label_registration_certificate_number') || 'Forgalmi engedély száma' }}</label>
<input
v-model="form.registration_certificate_number"
type="text"
class="w-full rounded-xl border border-slate-300 bg-white px-4 py-2.5 text-sm text-slate-800 placeholder-slate-400 focus:border-sf-accent focus:outline-none focus:ring-2 focus:ring-sf-accent/20"
:placeholder="t('vehicle.placeholder_registration_certificate_number') || 'Pl. AB-123456'"
/>
</div>
<div>
<label class="mb-1.5 block text-sm font-medium text-slate-700">{{ t('vehicle.label_registration_certificate_validity') || 'Forgalmi engedély érvényessége' }}</label>
<input
v-model="form.registration_certificate_validity"
type="date"
class="w-full rounded-xl border border-slate-300 bg-white px-4 py-2.5 text-sm text-slate-800 focus:border-sf-accent focus:outline-none focus:ring-2 focus:ring-sf-accent/20"
/>
</div>
</div>
<div class="mt-3">
<label class="mb-1.5 block text-sm font-medium text-slate-700">{{ t('vehicle.label_vehicle_registration_document_number') || 'Törzskönyv száma' }}</label>
<input
v-model="form.vehicle_registration_document_number"
type="text"
class="w-full rounded-xl border border-slate-300 bg-white px-4 py-2.5 text-sm text-slate-800 placeholder-slate-400 focus:border-sf-accent focus:outline-none focus:ring-2 focus:ring-sf-accent/20"
:placeholder="t('vehicle.placeholder_vehicle_registration_document_number') || 'Pl. 1234567890'"
/>
</div>
</div>
```
### 5c. handleSave payload bővítése (a 2159-es sor után)
```typescript
// Registration Documents
registration_certificate_number: form.registration_certificate_number || null,
registration_certificate_validity: form.registration_certificate_validity || null,
vehicle_registration_document_number: form.vehicle_registration_document_number || null,
```
### 5d. populateForm bővítése (a 2065-ös sor után)
```typescript
// Registration Documents
form.registration_certificate_number = vehicle.registration_certificate_number || ''
form.registration_certificate_validity = vehicle.registration_certificate_validity || ''
form.vehicle_registration_document_number = vehicle.vehicle_registration_document_number || ''
```
### 5e. resetForm bővítése (kb. 1987-2026 sorok között)
```typescript
form.registration_certificate_number = ''
form.registration_certificate_validity = ''
form.vehicle_registration_document_number = ''
```
---
## 6. Lépés: Frontend i18n fordítások
**Fájl:** `frontend/src/i18n/hu.ts`
```typescript
label_registration_certificate_number: 'Forgalmi engedély száma',
label_registration_certificate_validity: 'Forgalmi engedély érvényessége',
label_vehicle_registration_document_number: 'Törzskönyv száma',
placeholder_registration_certificate_number: 'Pl. AB-123456',
placeholder_vehicle_registration_document_number: 'Pl. 1234567890',
registration_documents_title: 'Forgalmi engedély és Törzskönyv',
```
**Fájl:** `frontend/src/i18n/en.ts`
```typescript
label_registration_certificate_number: 'Registration Certificate Number',
label_registration_certificate_validity: 'Registration Certificate Validity',
label_vehicle_registration_document_number: 'Vehicle Registration Document Number',
placeholder_registration_certificate_number: 'e.g. AB-123456',
placeholder_vehicle_registration_document_number: 'e.g. 1234567890',
registration_documents_title: 'Registration Certificate & Vehicle Document',
```
---
## 7. Lépés: Backend i18n (opcionális)
**Fájl:** `backend/static/locales/hu.json`
```json
"REGISTRATION_DOCUMENTS": {
"CERTIFICATE_NUMBER": "Forgalmi engedély száma",
"CERTIFICATE_VALIDITY": "Forgalmi engedély érvényessége",
"DOCUMENT_NUMBER": "Törzskönyv száma"
}
```
**Fájl:** `backend/static/locales/en.json`
```json
"REGISTRATION_DOCUMENTS": {
"CERTIFICATE_NUMBER": "Registration Certificate Number",
"CERTIFICATE_VALIDITY": "Registration Certificate Validity",
"DOCUMENT_NUMBER": "Vehicle Registration Document Number"
}
```
---
## Tesztelési terv
1. **Adatbázis:** `docker exec -it sf_api python -m app.scripts.sync_engine` futtatása után ellenőrizni, hogy a 3 új oszlop létrejött a `vehicle.assets` táblában
2. **API:** POST /vehicles hívás új mezőkkel → 201 Created + az új mezők visszaküldése
3. **API:** PUT /vehicles/{id} hívás új mezőkkel → 200 OK + az új mezők frissítése
4. **API:** GET /vehicles/{id} → az új mezők megjelennek a válaszban
5. **Frontend:** VehicleFormModal → Admin tabon megjelennek az új mezők, mentéskor elküldődnek, szerkesztéskor visszatöltődnek