2026.03.29 20:00 Gitea_manager javítás előtt
This commit is contained in:
59
docs/v201/05_Architectural_Audit.md
Normal file
59
docs/v201/05_Architectural_Audit.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# 🚨 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.
|
||||
Reference in New Issue
Block a user