# 🚨 ROO: MANDATORY ARCHITECTURAL AUDIT & DOCUMENTATION (v201) ## Context This document aligns the system with the "Personal Workspace" vision (Every user has a private organization/garage). It documents the current reality of the system to identify where the logic is broken. --- ## 🔍 Task 1: Forensic Logic Analysis ### 1. User-Org Link - **Database Schema:** In the `users` table (`identity.users`), there is **NO** `default_organization_id`. - **Current Linkage:** A user is linked to their "Private Garage" (or multiple garages) via two relationships: 1. Ownership: `organizations.owner_id` -> `users.id` 2. Membership: `organization_members.user_id` -> `users.id` - **Scope Field:** The `users` table has a `scope_id` field (and `scope_level`), but it is often `None` because the registration/KYC flow does not explicitly set it to the newly created Organization ID. ### 2. Auth Payload - **Login Response:** Looked at `backend/app/api/v1/endpoints/auth.py`. The `/login` endpoint creates a JWT token with `scope_id: str(user.scope_id) if user.scope_id else str(user.id)`. Since `user.scope_id` is often null, the token just duplicates the `user.id`. - **`/users/me` Endpoint:** It returns the `UserResponse` schema (from `app.schemas.user`), which includes `scope_id: Optional[str] = None`. It **does not** return a specific `organization_id` array or the user's active/default organization ID to the frontend. ### 3. Frontend Storage - **Auth Store (`frontend/src/stores/authStore.js`):** Fetches `/users/me` and stores the raw response in `userProfile.value`. It decodes the JWT to get the user's role, but it does **not** store or manage an active `organization_id` state. - **Garage Store (`frontend/src/stores/garageStore.js`):** Contains logic to add a vehicle, but the active organization is not retrieved from the user's profile. Instead, it relies on the payload passed from components and falls back to a hardcoded `1`. ### 4. The "Hardcode" Hunt Every file where `organization_id: 1` or any hardcoded ID is used instead of a dynamic value from the store: 1. `frontend/src/components/actions/AddVehicleModal.vue`: Explicitly hardcodes `organizationId: 1` in its payload. 2. `frontend/src/views/AddVehicle.vue`: Contains `organization_id: 1 // default organization`. 3. `frontend/src/stores/garageStore.js`: Inside the `addVehicle` action, it explicitly defaults to `organization_id: vehicle.organizationId || 1 // Default org ID`. 4. `backend/app/api/v1/endpoints/assets.py`: When creating expenses/maintenance costs, it falls back to `organization_id=asset.current_organization_id or asset.owner_org_id or 1`. --- ## 📝 Task 2: Real State of the System (The Gap) ### Database Level When a new user completes KYC (`complete_kyc` in `AuthService`), a new "Personal" Organization is dynamically created (e.g., `{last_name} Széfe`). The user is assigned as the `OWNER` in the `OrganizationMember` table, and the `organizations.owner_id` is set. **However, `user.scope_id` is never updated to point to this new organization.** ### API Level The frontend calls `/login` and `/users/me`, but neither endpoint returns the actual ID of the user's newly created Organization. The frontend receives only the generic `UserResponse` with `scope_id: null`. The frontend has no knowledge of which `organization_id` belongs to the logged-in user. ### Frontend Level Because the frontend (`AddVehicleModal`, `AddVehicle` view, and `garageStore`) does not receive the user's organization ID, it just gives up and blindly sends `organization_id: 1` on every POST request to create a vehicle. ### The Gap (Contradictions) 1. **The Vision:** Every user has their own Organization/Garage. 2. **The Code:** The Backend creates the Organization but doesn't tell the Frontend what its ID is. 3. **The Result:** The Frontend ignores the Backend's logic and assigns every new vehicle to Organization `1` (usually the Superadmin or System's default organization), completely breaking data isolation and the "Private Garage" architecture. --- ## 🔬 Task 3: Verification of the "Tester_Pro" account - **User:** ID 28 (`tester_pro@profibot.hu`) - **Database Status:** Querying the database shows that User 28 has `scope_id: None`. - **True Organization:** In the `organization_members` table, User 28 belongs to **Org ID: 15** (Name: "Profibot Test Fleet") with the role `ADMIN`. - **Why the frontend does NOT use this ID:** 1. The API never provides `Org ID: 15` to the frontend during login or profile fetch. 2. `AddVehicleModal.vue` and `garageStore.js` are hardcoded to send `1` if they don't explicitly receive an ID. Since `authStore` doesn't know about `15`, it sends `1`. Consequently, Tester_Pro's vehicles are saved into the wrong organization.