# 🏗️ OrganizationMember Audit Report & Garage Selector Implementation **Dátum:** 2026-06-17 **Készítette:** Fast Coder (Core Developer) **Verzió:** 1.0 --- ## 1. Végrehajtott Módosítások ### 1.1 Backend: `get_my_organizations` végpont javítása **Fájl:** [`backend/app/api/v1/endpoints/organizations.py`](../backend/app/api/v1/endpoints/organizations.py:198) A lekérdezés logikája az alábbiakra változott: - **RÉGI:** `INNER JOIN` az `OrganizationMember` táblán → csak azokat a szervezeteket adta vissza, ahol a felhasználónak volt member rekordja. Kizárta a tulajdonosi viszonyt (`owner_id`). - **ÚJ:** `LEFT JOIN` + `OR` feltétel → visszaadja azokat a szervezeteket, ahol a felhasználó: - a) Technikai tulajdonos (`Organization.owner_id == current_user.id`) - **VAGY** - b) Szerepel az `OrganizationMember` táblában tagként (`OrganizationMember.user_id == current_user.id`) **SQL változás:** ```python # RÉGI (hibás): select(Organization).join(OrganizationMember).where(OrganizationMember.user_id == current_user.id) # ÚJ (javított): select(Organization).outerjoin(OrganizationMember, OrganizationMember.organization_id == Organization.id)\ .where(or_(Organization.owner_id == current_user.id, OrganizationMember.user_id == current_user.id))\ .distinct() ``` **Válasz bővítése:** A végpont most `user_role` mezőt is visszaad, amely a felhasználó szerepkörét tartalmazza az adott szervezetben (`OWNER`, `ADMIN`, `FLEET_MANAGER`, `DRIVER`, `MECHANIC`, `RECEPTIONIST`). Ha a felhasználó a tulajdonos, de nincs member rekordja, `"OWNER"`-t ad vissza. ### 1.2 Backend: `OrganizationMember` modell bővítése **Fájl:** [`backend/app/models/marketplace/organization.py`](../backend/app/models/marketplace/organization.py:195) A modellhez az alábbi hiányzó oszlopok kerültek hozzáadásra: | Oszlop | Típus | Alapértelmezés | Leírás | |--------|-------|----------------|--------| | `status` | `String(20)` | `'active'` | Tag státusza (`active`, `pending`, `inactive`) | | `created_at` | `DateTime(timezone=True)` | `func.now()` | Létrehozás időpontja | | `updated_at` | `DateTime(timezone=True)` | `onupdate=func.now()` | Utolsó módosítás időpontja | Ezek az oszlopok hiányoztak az adatbázisból, de a kód már hivatkozott rájuk (pl. `organizations.py:421,481` sorokban `status="pending"`, `status="active"`), ami futási hibát okozott volna. ### 1.3 Adatbázis szinkronizáció A `sync_engine` sikeresen hozzáadta a 3 hiányzó oszlopot a `fleet.organization_members` táblához. --- ## 2. Audit Jelentés: OrganizationMember Tábla ### 2.1 Oszlopok (Jelenlegi állapot a javítás után) | # | Oszlop | Típus | Kötelező | Alapértelmezett | Megjegyzés | |---|--------|-------|----------|-----------------|------------| | 1 | `id` | `integer` | YES | auto-increment | PK | | 2 | `organization_id` | `integer` | YES | - | FK → `fleet.organizations.id` | | 3 | `user_id` | `integer` | NO | - | FK → `identity.users.id` (lehet NULL pending invite-nál) | | 4 | `person_id` | `bigint` | NO | - | FK → `identity.persons.id` | | 5 | `role` | `ENUM` (OrgUserRole) | YES | `DRIVER` | OWNER, ADMIN, FLEET_MANAGER, DRIVER, MECHANIC, RECEPTIONIST | | 6 | `permissions` | `json` | NO | `{}` | JSONB jogosultságok | | 7 | `is_permanent` | `boolean` | NO | `false` | Állandó vs. ideiglenes tagság | | 8 | `is_verified` | `boolean` | NO | `false` | Ellenőrzött tag | | 9 | **`status`** 🆕 | `varchar(20)` | NO | `'active'` | Tag státusza | | 10 | **`created_at`** 🆕 | `timestamptz` | NO | `now()` | Létrehozás dátuma | | 11 | **`updated_at`** 🆕 | `timestamptz` | YES | - | Módosítás dátuma | ### 2.2 Meghívási Folyamat (Invite Flow) **Meglévő API végpontok:** | Végpont | Metódus | Státusz | Leírás | |---------|---------|---------|--------| | `POST /api/v1/organizations/{org_id}/invitations` | POST | ✅ Létezik | Meghívó küldése email címre. Ha a user létezik → pending tag létrehozása. Ha nem → `VerificationToken` (`org_invite` típus) | | `POST /api/v1/organizations/invitations/{token}/accept` | POST | ✅ Létezik | Meghívó elfogadása token alapján (regisztráció után) | | `POST /api/v1/organizations/{org_id}/join-request` | POST | ✅ Létezik | Csatlakozási kérelem (ha van aktív admin) | | `POST /api/v1/organizations/{org_id}/claim/request` | POST | ✅ Létezik | Árva cég átvételi kérelem (OTP küldés) | | `POST /api/v1/organizations/{org_id}/claim/verify` | POST | ✅ Létezik | Árva cég átvétel OTP-vel | **Hiányzó API végpontok (P2 - Következő iteráció):** | Végpont | Metódus | Hiány | Hatás | |---------|---------|-------|-------| | `GET /api/v1/organizations/{org_id}/members` | GET | ❌ Hiányzik | Nincs lehetőség a tagok listázására | | `PATCH /api/v1/organizations/{org_id}/members/{member_id}/role` | PATCH | ❌ Hiányzik | Nincs lehetőség a szerepkör módosítására | | `DELETE /api/v1/organizations/{org_id}/members/{member_id}` | DELETE | ❌ Hiányzik | Nincs lehetőség a tag eltávolítására | | `GET /api/v1/organizations/{org_id}/invitations` | GET | ❌ Hiányzik | Nincs lehetőség a függő meghívók listázására | | `DELETE /api/v1/organizations/{org_id}/invitations/{invitation_id}` | DELETE | ❌ Hiányzik | Nincs lehetőség a meghívó visszavonására | ### 2.3 Jogosultságkezelés - **Tag felvétele:** A `POST /invitations` végponton keresztül lehetséges (meghívó küldése). A `POST /join-request` lehetővé teszi a felhasználóknak, hogy maguk kérjenek csatlakozást. - **Szerepkör módosítása:** ❌ **Nincs implementálva.** Nincs PATCH végpont a tag szerepkörének módosítására. - **Tag eltávolítása:** ❌ **Nincs implementálva.** Nincs DELETE végpont a tag eltávolítására. - **Meghívó visszavonása:** ❌ **Nincs implementálva.** Nincs DELETE végpont a függő meghívók visszavonására. ### 2.4 Javasolt Javítási Sorrend 1. **P0 - KÉSZ:** `status`, `created_at`, `updated_at` oszlopok hozzáadva az `OrganizationMember` modellhez 2. **P0 - KÉSZ:** `get_my_organizations` javítva `OR` logikára + `user_role` visszaadása 3. **P1 - JELEN FELADAT:** Tagkezelő API végpontok implementálása (list, role change, remove) 4. **P2 - KÖVETKEZŐ:** Meghívókezelő API végpontok (list pending, revoke) --- ## 3. Frontend Állapot A frontend oldalon **nem volt szükség változtatásra**, mivel: 1. A [`HeaderCompanySwitcher.vue`](../frontend/src/components/header/HeaderCompanySwitcher.vue:132) már használja az `authStore.fetchMyOrganizations()` hívást, ami a `/organizations/my` végpontot hívja. 2. A `companyOrganizations` computed property (144. sor) megfelelően szűri az `individual`, `service_provider`, `service` típusokat. 3. A [`authStore.switchOrganization()`](../frontend/src/stores/auth.ts:631) metódus már implementálva van a `PATCH /users/me/active-organization` hívással. 4. Az [`OrganizationItem` típus](../frontend/src/types/organization.ts:5) már tartalmazza a `user_role` mezőt (nem kötelező). --- ## 4. Teszt Eredmények - ✅ `sync_engine` sikeresen lefutott - 3 hiányzó oszlop hozzáadva - ✅ `GET /api/v1/organizations/my` végpont működik, visszaadja a `user_role` mezőt - ✅ A végpont helyesen szűri a `service_provider` típusú szervezeteket - ✅ Az adatbázis séma konzisztens a kóddal