admin felület fejlesztése garázs, előfizeztési csomagok

This commit is contained in:
Roo
2026-06-25 01:58:04 +00:00
parent 80a5d67f79
commit 52011606ff
334 changed files with 46636 additions and 1606 deletions

View File

@@ -0,0 +1,189 @@
# P0 Architecture Refactor: Option C (Hybrid) — Vendor/Expense Domain Separation
**Date:** 2026-06-25
**Author:** Rendszer-Architect
**Status:** DRAFT — Awaiting approval
**Masterbook 2.0 Alignment:** Domain-Driven Design, Schema Separation
---
## 1. Modul Célja és MasterBook 2.0 illeszkedés
### Cél
A `quick_add_provider()` jelenleg teljes `Organization` rekordokat hoz létre a `fleet.organizations` táblában minden egyes crowdsource-olt szolgáltató (vendor) számára. Ez **domain-szennyezés**: a könnyűsúlyú beszállítók (szerelők, gumiszervizek) nem érdemelnek teljes szervezeti entitást garázsadminnal, előfizetéssel és tagokkal.
### MasterBook 2.0 illeszkedés
- **DDD Szeparáció:** A `marketplace.service_providers` tábla a könnyűsúlyú, közösség által beküldött szolgáltatók otthona. A `fleet.organizations` csak a valódi garázsokat (flottakezelő cégeket) tartalmazza.
- **"Dual Entity":** A két entitás (Organization vs ServiceProvider) külön sémában él, eltérő életciklussal és adatigénnyel.
- **Twin-technika:** A ServiceProvider egyszerű, mindössze név + cím adatokkal. A teljes garázs-entitásnak (Organization) viszont subscription, lifecycle, member management kell.
---
## 2. Jelenlegi Architektúra (As-Is)
### 2.1. `quick_add_provider()` flow
```
User -> POST /providers/quick-add
-> 1. Organization létre (fleet.organizations, org_type=service_provider)
-> 2. ServiceProfile létre (marketplace.service_profiles, FK -> organization)
-> 3. ServiceExpertise létre (marketplace.service_expertises)
-> 4. Branch létre (fleet.branches, FK -> organization)
-> 5. OrganizationMember létre (fleet.organization_members) - mar kikommentezve!
```
### 2.2. AssetCost vendor link
```python
# fleet_finance.asset_costs
vendor_organization_id -> fleet.organizations.id (a beszallito Organization-re mutat)
```
### 2.3. Probléma
- Minden crowdsource vendor beszennyezi a `fleet.organizations` táblát
- Az admin `/admin/organizations` API a valódi garázsok mellett a fake orgokat is visszaadja
- A valódi garázsok safe listája: `(15, 21, 43, 45, 47, 48, 49, 50, 66, 67, 69, 70, 71)` — a többi org a quick_add által létrehozott beszállító!
---
## 3. Célarchitektúra (To-Be) — Option C (Hybrid)
### 3.1. Adatmodell változások
#### A) `fleet_finance.asset_costs` — ÚJ oszlop
```python
# MEGTARTVA (kompatibilitás):
vendor_organization_id: Optional[int] -> fleet.organizations.id
# HOZZÁADVA (új elsődleges hivatkozás):
service_provider_id: Optional[int] -> marketplace.service_providers.id
```
#### B) `marketplace.service_profiles` — ÚJ oszlop
```python
# MEGTARTVA (meglévő kapcsolatok miatt, nullable):
organization_id: Optional[int] -> fleet.organizations.id
# HOZZÁADVA (új elsődleges hivatkozás):
service_provider_id: Optional[int] -> marketplace.service_providers.id
```
#### C) `marketplace.service_providers` — Bővítés
```python
# MEGLÉVŐ:
id, name, address, category, status, source, validation_score, ...
# HOZZÁADVA (a quick_add által igényelt mezők):
city: Optional[str]
address_zip: Optional[str]
address_street_name: Optional[str]
address_street_type: Optional[str]
address_house_number: Optional[str]
plus_code: Optional[str]
contact_phone: Optional[str]
contact_email: Optional[str]
website: Optional[str]
```
### 3.2. Új `quick_add_provider()` flow
```
User -> POST /providers/quick-add
-> 1. ServiceProvider létre (marketplace.service_providers) <- ÚJ!
-> 2. ServiceProfile létre (marketplace.service_profiles, FK -> service_provider)
-> 3. ServiceExpertise létre (marketplace.service_expertises)
-> x NINCS Organization létrehozva!
-> x NINCS Branch létrehozva!
-> x NINCS OrganizationMember létrehozva!
```
### 3.3. AssetCost vendor választás logika
```
When creating an expense:
1. IF service_provider_id is provided -> save to service_provider_id column
2. IF vendor_organization_id is provided (legacy) -> save to vendor_organization_id column
3. Both can coexist
```
### 3.4. API response changes
- `GET /expenses/{asset_id}` -> add `service_provider_id` and resolved `vendor_name`
- `AssetCostResponse` schema -> add `service_provider_id`
---
## 4. Data Migration: Fake Org -> ServiceProvider
### 4.1. Safe list (valódi garázsok)
```sql
(15, 21, 43, 45, 47, 48, 49, 50, 66, 67, 69, 70, 71)
```
### 4.2. Migrációs lépések
1. SELECT all orgs where id NOT IN safe list
2. For each fake org:
- INSERT into marketplace.service_providers (name, address, city, etc.)
- UPDATE marketplace.service_profiles SET service_provider_id = new_id WHERE organization_id = fake_org_id
- UPDATE fleet_finance.asset_costs SET service_provider_id = new_id WHERE vendor_organization_id = fake_org_id
3. DELETE cascade:
- DELETE from fleet.branches WHERE organization_id IN (fake org IDs)
- DELETE from fleet.organization_members WHERE organization_id IN (fake org IDs)
- DELETE from fleet.organizations WHERE id IN (fake org IDs)
---
## 5. Érintett fájlok
### Módosítandó fájlok:
| Fájl | Változtatás |
|------|-------------|
| `backend/app/models/fleet_finance/models.py` | Add `service_provider_id` column + relationship to `AssetCost` |
| `backend/app/models/marketplace/service.py` | Add `service_provider_id` column to `ServiceProfile` |
| `backend/app/models/identity/social.py` | Add address/contact fields to `ServiceProvider` |
| `backend/app/models/__init__.py` | Update imports if needed |
| `backend/app/services/provider_service.py` | Rewrite `quick_add_provider` — create ServiceProvider, not Organization |
| `backend/app/api/v1/endpoints/expenses.py` | Update `create_expense` to handle `service_provider_id` |
| `backend/app/schemas/asset_cost.py` | Add `service_provider_id` field to schemas |
| `backend/scripts/migrate_providers.py` | **NEW** — data migration script |
---
## 6. Végrehajtási Sorrend
### Fázis 1: Schema változások
1. Add `service_provider_id` to `AssetCost` model
2. Add `service_provider_id` to `ServiceProfile` model
3. Extend `ServiceProvider` model with address/contact fields
4. Run sync_engine to apply schema changes
### Fázis 2: Refactor `quick_add_provider()`
5. Rewrite `quick_add_provider()` to create ServiceProvider + ServiceProfile only
6. Update schemas (add `service_provider_id`)
7. Update expense creation endpoint
### Fázis 3: Data Migration
8. Create `backend/scripts/migrate_providers.py`
9. Run migration
### Fázis 4: Verification
10. Verify GET /admin/organizations returns only 13 garages
11. Verify quick-add flow no longer pollutes garages list
---
## 7. Kockázatok és Függőségek
| Kockázat | Hatás | Mitigáció |
|----------|-------|-----------|
| Meglévő FK constraint a `vendor_organization_id`-ra | Adatintegritás sérülhet | Továbbra is nullable; a migration átírja a kapcsolatokat |
| ServiceProfile.organization_id meglévő NOT NULL constraint | Migration elakadhat | Már nullable (`Optional[int]`), meglévő rekordok megmaradnak |
| Frontend küld `vendor_organization_id`-t | Új mező nem töltődik | Backward compat: mindkét mezőt kezeljük |
| Branch törlés cascade | Adatvesztés | Csak a fake org-ok Branch-eit töröljük |
---
## 8. Összefoglaló
Az Option C (Hybrid) megoldás:
- **Megtartja** a `vendor_organization_id`-t a backward compatibility érdekében
- **Hozzáad** egy új `service_provider_id`-t, ami a `marketplace.service_providers` táblára hivatkozik
- **Átírja** a `quick_add_provider()`-t, hogy ne hozzon létre Organization-t
- **Adatmigrációt** végez: a meglévő fake org-okat áthelyezi a ServiceProvider táblába
- **Ellenőrzi** a végeredményt: az admin garázslista pontosan a 13 valódi garázst tartalmazza