diff --git a/backend/app/__pycache__/main.cpython-312.pyc b/backend/app/__pycache__/main.cpython-312.pyc index fead05b..577fa69 100644 Binary files a/backend/app/__pycache__/main.cpython-312.pyc and b/backend/app/__pycache__/main.cpython-312.pyc differ diff --git a/backend/app/api/v1/endpoints/__pycache__/auth.cpython-312.pyc b/backend/app/api/v1/endpoints/__pycache__/auth.cpython-312.pyc index e7d48ea..fbd38e7 100644 Binary files a/backend/app/api/v1/endpoints/__pycache__/auth.cpython-312.pyc and b/backend/app/api/v1/endpoints/__pycache__/auth.cpython-312.pyc differ diff --git a/backend/app/api/v1/endpoints/auth.py b/backend/app/api/v1/endpoints/auth.py index edb5db7..b75b894 100644 --- a/backend/app/api/v1/endpoints/auth.py +++ b/backend/app/api/v1/endpoints/auth.py @@ -1,32 +1,38 @@ -# /opt/docker/dev/service_finder/backend/app/api/v1/endpoints/auth.py -from fastapi import APIRouter, Depends, HTTPException, Request, status, Body +from fastapi import APIRouter, Depends, HTTPException, status +from fastapi.security import OAuth2PasswordRequestForm from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy import text from app.db.session import get_db -from app.schemas.auth import UserRegister, Token, UserLogin from app.services.auth_service import AuthService from app.core.security import create_access_token +from app.schemas.auth import UserLiteRegister, Token, PasswordResetRequest router = APIRouter() -@router.post("/register", response_model=Token, status_code=status.HTTP_201_CREATED) -async def register( - request: Request, - user_in: UserRegister = Body(...), - db: AsyncSession = Depends(get_db) -): - # 1. Foglalt email ellenőrzése - if not await AuthService.check_email_availability(db, user_in.email): - raise HTTPException(status_code=400, detail="Az e-mail cím már foglalt.") +@router.post("/register-lite", response_model=Token, status_code=201) +async def register_lite(user_in: UserLiteRegister, db: AsyncSession = Depends(get_db)): + # Email csekkolás nyers SQL-el + check = await db.execute(text("SELECT id FROM data.users WHERE email = :e"), {"e": user_in.email}) + if check.fetchone(): + raise HTTPException(status_code=400, detail="Ez az email cím már foglalt.") + + try: + user = await AuthService.register_lite(db, user_in) + token = create_access_token(data={"sub": str(user.id)}) + return {"access_token": token, "token_type": "bearer", "is_active": user.is_active} + except Exception as e: + raise HTTPException(status_code=500, detail=f"Szerver hiba: {str(e)}") - # 2. Atomi regisztráció (Person, User, Wallet, Org, Member, Audit, Email) - user = await AuthService.register_new_user( - db=db, - user_in=user_in, - ip_address=request.client.host - ) +@router.post("/login", response_model=Token) +async def login(form_data: OAuth2PasswordRequestForm = Depends(), db: AsyncSession = Depends(get_db)): + user = await AuthService.authenticate(db, form_data.username, form_data.password) + if not user: + raise HTTPException(status_code=401, detail="Hibás e-mail vagy jelszó.") - # 3. Token kiállítása - token_data = {"sub": str(user.id), "email": user.email} - access_token = create_access_token(data=token_data) - - return {"access_token": access_token, "token_type": "bearer"} \ No newline at end of file + token = create_access_token(data={"sub": str(user.id)}) + return {"access_token": token, "token_type": "bearer", "is_active": user.is_active} + +@router.post("/forgot-password") +async def forgot_password(req: PasswordResetRequest, db: AsyncSession = Depends(get_db)): + await AuthService.initiate_password_reset(db, req.email) + return {"message": "Helyreállítási folyamat elindítva."} \ No newline at end of file diff --git a/backend/app/core/__pycache__/security.cpython-312.pyc b/backend/app/core/__pycache__/security.cpython-312.pyc index f920070..ba97cab 100644 Binary files a/backend/app/core/__pycache__/security.cpython-312.pyc and b/backend/app/core/__pycache__/security.cpython-312.pyc differ diff --git a/backend/app/main.py b/backend/app/main.py index 9e263cd..f925858 100755 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -5,23 +5,26 @@ from app.core.config import settings app = FastAPI( title="Service Finder API", - version="2.0.0", + version="2.0.0", # A rendszer verziója, de a végpont marad v1 openapi_url="/api/v1/openapi.json", docs_url="/docs" ) -# CORS beállítások +# PONTOS CORS BEÁLLÍTÁS app.add_middleware( CORSMiddleware, - allow_origins=["*"], + allow_origins=[ + "http://192.168.100.10:3001", # Frontend portja + "http://localhost:3001", + "https://dev.profibot.hu" # Ha van NPM proxy + ], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) -# Routerek befűzése app.include_router(api_router, prefix="/api/v1") @app.get("/") async def root(): - return {"status": "online", "message": "Service Finder API v2.0"} \ No newline at end of file + return {"status": "online", "message": "Service Finder Master System v1.0"} \ No newline at end of file diff --git a/backend/app/models/__pycache__/identity.cpython-312.pyc b/backend/app/models/__pycache__/identity.cpython-312.pyc index 59412ff..d9cdbf9 100644 Binary files a/backend/app/models/__pycache__/identity.cpython-312.pyc and b/backend/app/models/__pycache__/identity.cpython-312.pyc differ diff --git a/backend/app/models/identity.py b/backend/app/models/identity.py index b42a881..9396fda 100644 --- a/backend/app/models/identity.py +++ b/backend/app/models/identity.py @@ -1,23 +1,23 @@ import uuid import enum -from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, JSON, Numeric, text, Enum +from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, JSON, Numeric, text, Enum, BigInteger from sqlalchemy.orm import relationship from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.sql import func -from app.db.base import Base +from app.db.base import Base # <--- JAVÍTVA: base_class helyett base class UserRole(str, enum.Enum): - ADMIN = "admin" - USER = "user" - SERVICE = "service" - FLEET_MANAGER = "fleet_manager" - DRIVER = "driver" + admin = "admin" + user = "user" + service = "service" + fleet_manager = "fleet_manager" + driver = "driver" class Person(Base): __tablename__ = "persons" __table_args__ = {"schema": "data"} - id = Column(Integer, primary_key=True, index=True) + id = Column(BigInteger, primary_key=True, index=True) id_uuid = Column(UUID(as_uuid=True), default=uuid.uuid4, unique=True, nullable=False) last_name = Column(String, nullable=False) @@ -26,11 +26,16 @@ class Person(Base): birth_place = Column(String, nullable=True) birth_date = Column(DateTime, nullable=True) - # KYC Okmányok és Safety adatok identity_docs = Column(JSON, server_default=text("'{}'::jsonb")) medical_emergency = Column(JSON, server_default=text("'{}'::jsonb")) ice_contact = Column(JSON, server_default=text("'{}'::jsonb")) + # Ez a mező kell a 2-lépcsős regisztrációhoz + is_active = Column(Boolean, default=False, nullable=False) + + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + users = relationship("User", back_populates="person") class User(Base): @@ -39,24 +44,19 @@ class User(Base): id = Column(Integer, primary_key=True, index=True) email = Column(String, unique=True, index=True, nullable=False) - hashed_password = Column(String, nullable=True) # Social Auth esetén null lehet! + hashed_password = Column(String, nullable=True) - # Social Auth mezők - social_provider = Column(String, nullable=True) # google, facebook - social_id = Column(String, nullable=True) - - role = Column(Enum(UserRole), default=UserRole.USER) - is_active = Column(Boolean, default=True) + role = Column(Enum(UserRole), default=UserRole.user) + is_active = Column(Boolean, default=False) region_code = Column(String, default="HU") - # Soft Delete is_deleted = Column(Boolean, default=False) - deleted_at = Column(DateTime, nullable=True) + person_id = Column(BigInteger, ForeignKey("data.persons.id"), nullable=True) - person_id = Column(Integer, ForeignKey("data.persons.id"), nullable=True) person = relationship("Person", back_populates="users") wallet = relationship("Wallet", back_populates="user", uselist=False) - owned_organizations = relationship("Organization", back_populates="owner") + # Kapcsolat lusta betöltéssel a mapper hiba ellen + owned_organizations = relationship("Organization", back_populates="owner", lazy="select") created_at = Column(DateTime(timezone=True), server_default=func.now()) diff --git a/backend/app/schemas/__pycache__/auth.cpython-312.pyc b/backend/app/schemas/__pycache__/auth.cpython-312.pyc index 116a90a..ff49eba 100644 Binary files a/backend/app/schemas/__pycache__/auth.cpython-312.pyc and b/backend/app/schemas/__pycache__/auth.cpython-312.pyc differ diff --git a/backend/app/schemas/auth.py b/backend/app/schemas/auth.py index 2a63839..b4d9c8d 100644 --- a/backend/app/schemas/auth.py +++ b/backend/app/schemas/auth.py @@ -1,37 +1,22 @@ -# /opt/docker/dev/service_finder/backend/app/schemas/auth.py -from pydantic import BaseModel, EmailStr, Field, field_validator -from typing import Optional, List +from pydantic import BaseModel, EmailStr, Field +from typing import Optional from datetime import date -class UserRegister(BaseModel): - email: EmailStr = Field(..., example="pilot@profibot.hu") - password: Optional[str] = Field(None, min_length=8) - last_name: str = Field(..., min_length=2) - first_name: str = Field(..., min_length=2) - mothers_name: str = Field(..., description="Kötelező banki azonosító") - birth_place: Optional[str] = None - birth_date: Optional[date] = None - id_card_number: Optional[str] = None - id_card_expiry: Optional[date] = None - driver_license_number: Optional[str] = None - driver_license_expiry: Optional[date] = None - driver_license_categories: List[str] = Field(default_factory=list) - boat_license_number: Optional[str] = None - pilot_license_number: Optional[str] = None - region_code: str = Field(default="HU") - invite_token: Optional[str] = None - social_provider: Optional[str] = None - social_id: Optional[str] = None +class UserLiteRegister(BaseModel): + email: EmailStr + password: str = Field(..., min_length=8) + first_name: str + last_name: str + region_code: str = "HU" - @field_validator('region_code') - @classmethod - def validate_region(cls, v: str) -> str: - return v.upper() if v else "HU" +class UserLogin(BaseModel): + email: EmailStr + password: str + +class PasswordResetRequest(BaseModel): + email: EmailStr class Token(BaseModel): access_token: str token_type: str - -class UserLogin(BaseModel): - email: EmailStr - password: str \ No newline at end of file + is_active: bool # KYC státusz visszajelzés \ No newline at end of file diff --git a/backend/app/services/__pycache__/auth_service.cpython-312.pyc b/backend/app/services/__pycache__/auth_service.cpython-312.pyc index a473951..8215d4c 100644 Binary files a/backend/app/services/__pycache__/auth_service.cpython-312.pyc and b/backend/app/services/__pycache__/auth_service.cpython-312.pyc differ diff --git a/backend/app/services/auth_service.py b/backend/app/services/auth_service.py index 234bff0..ef75408 100644 --- a/backend/app/services/auth_service.py +++ b/backend/app/services/auth_service.py @@ -1,145 +1,82 @@ -# /opt/docker/dev/service_finder/backend/app/services/auth_service.py -from datetime import datetime, timezone, timedelta -from typing import Optional, Dict, Any -import logging from sqlalchemy.ext.asyncio import AsyncSession -from sqlalchemy import select, and_, text - -from app.models.identity import User, Person, Wallet, UserRole -from app.models.organization import Organization, OrgType -from app.models.vehicle import OrganizationMember -from app.schemas.auth import UserRegister -from app.core.security import get_password_hash, create_access_token -from app.services.email_manager import email_manager - -logger = logging.getLogger(__name__) +from sqlalchemy import select, text +from app.models.identity import User, Person, UserRole +from app.models.organization import Organization +from app.schemas.auth import UserLiteRegister +from app.core.security import get_password_hash, verify_password +from app.services.email_manager import email_manager # Importálva! class AuthService: @staticmethod - async def get_setting(db: AsyncSession, key: str, default: Any = None) -> Any: - """Admin felületről állítható változók lekérése.""" + async def register_lite(db: AsyncSession, user_in: UserLiteRegister): + """Step 1: Lite regisztráció + Email küldés.""" try: - stmt = text("SELECT value FROM data.system_settings WHERE key = :key") - result = await db.execute(stmt, {"key": key}) - val = result.scalar() - return val if val is not None else default - except Exception: - return default - - @staticmethod - async def register_new_user(db: AsyncSession, user_in: UserRegister, ip_address: str): - """ - MASTER REGISTRATION FLOW v1.3 - FULL INTEGRATION - Tartalmazza: KYC, Email, Tagság, Pénztárca, Audit, Flotta. - """ - try: - # 1. KYC Adatcsomag (Banki szintű okmányadatok) - kyc_data = { - "id_card": { - "number": user_in.id_card_number, - "expiry": str(user_in.id_card_expiry) if user_in.id_card_expiry else None - }, - "driver_license": { - "number": user_in.driver_license_number, - "expiry": str(user_in.driver_license_expiry) if user_in.driver_license_expiry else None, - "categories": user_in.driver_license_categories - }, - "special_licenses": { - "boat": user_in.boat_license_number, - "pilot": user_in.pilot_license_number - } - } - - # 2. PERSON LÉTREHOZÁSA (Identitás) + # 1. Person shell new_person = Person( first_name=user_in.first_name, last_name=user_in.last_name, - mothers_name=user_in.mothers_name, - birth_place=user_in.birth_place, - birth_date=user_in.birth_date, - identity_docs=kyc_data + is_active=False ) db.add(new_person) - await db.flush() # ID generálás + await db.flush() - # 3. USER LÉTREHOZÁSA - # FIX: .value használata, hogy kisbetűs 'user' kerüljön a DB-be - hashed_pwd = get_password_hash(user_in.password) if user_in.password else None + # 2. User fiók new_user = User( email=user_in.email, - hashed_password=hashed_pwd, - social_provider=user_in.social_provider, - social_id=user_in.social_id, + hashed_password=get_password_hash(user_in.password), person_id=new_person.id, - role=UserRole.USER.value, # <--- FIX: "user" kerül be, nem "USER" - region_code=user_in.region_code, - is_active=True + role=UserRole.user, + is_active=False, + region_code=user_in.region_code ) db.add(new_user) await db.flush() - # 4. ECONOMY: WALLET ÉS JUTALÉK SNAPSHOT - db.add(Wallet(user_id=new_user.id, coin_balance=0.00, xp_balance=0)) - - # 5. FLEET: AUTOMATIKUS PRIVÁT FLOTTA (Master Book v1.2: Nem átruházható) - new_org = Organization( - name=f"{user_in.last_name} {user_in.first_name} flottája", - org_type=OrgType.INDIVIDUAL, - owner_id=new_user.id, - is_transferable=False - ) - db.add(new_org) - await db.flush() - - # 6. TAGSÁG RÖGZÍTÉSE (Ownership link) - db.add(OrganizationMember( - organization_id=new_org.id, - user_id=new_user.id, - role="owner" - )) - - # 7. MEGHÍVÓ FELDOLGOZÁSA (Ha van token) - if user_in.invite_token and user_in.invite_token != "": - logger.info(f"Invite token detected: {user_in.invite_token}") - # Itt rögzítjük a meghívás tényét az elszámoláshoz - - # 8. AUDIT LOG (Raw SQL a stabilitásért) - audit_stmt = text(""" - INSERT INTO data.audit_logs (user_id, action, endpoint, method, ip_address, created_at) - VALUES (:uid, 'USER_REGISTERED_V1.3_FULL', '/api/v1/auth/register', 'POST', :ip, :now) - """) - await db.execute(audit_stmt, { - "uid": new_user.id, "ip": ip_address, "now": datetime.now(timezone.utc) - }) - - # 9. DINAMIKUS JUTALMAZÁS (Admin felületről állítható) - reward_days = await AuthService.get_setting(db, "auth.reward_days", 14) - - # 10. ÜDVÖZLŐ EMAIL (Template alapú, subject mentes hívás) + # 3. Email kiküldése (Mester Könyv v1.4 szerint) try: await email_manager.send_email( recipient=user_in.email, - template_key="registration_welcome", + template_key="registration", # 'registration.html' sablon használata variables={ "first_name": user_in.first_name, - "reward_days": reward_days + "login_url": "http://192.168.100.10:3000/login" }, user_id=new_user.id ) - except Exception as e: - logger.warning(f"Email failed during reg: {str(e)}") + except Exception as email_err: + # Az email hiba nem állítja meg a regisztrációt, csak logoljuk + print(f"Email hiba regisztrációkor: {str(email_err)}") await db.commit() await db.refresh(new_user) return new_user - except Exception as e: await db.rollback() - logger.error(f"REGISTER CRASH: {str(e)}") raise e @staticmethod - async def check_email_availability(db: AsyncSession, email: str) -> bool: - query = select(User).where(and_(User.email == email, User.is_deleted == False)) - result = await db.execute(query) - return result.scalar_one_or_none() is None \ No newline at end of file + async def authenticate(db: AsyncSession, email: str, password: str): + stmt = select(User).where(User.email == email, User.is_deleted == False) + res = await db.execute(stmt) + user = res.scalar_one_or_none() + + if not user or not user.hashed_password or not verify_password(password, user.hashed_password): + return None + return user + + @staticmethod + async def initiate_password_reset(db: AsyncSession, email: str): + """Jelszó-emlékeztető email küldése.""" + stmt = select(User).where(User.email == email, User.is_deleted == False) + res = await db.execute(stmt) + user = res.scalar_one_or_none() + + if user: + await email_manager.send_email( + recipient=email, + template_key="password_reset", + variables={"reset_token": "IDE_JÖN_MAJD_A_TOKEN"}, + user_id=user.id + ) + return True + return False \ No newline at end of file diff --git a/docs/V01_gemini/15_Changelog.md b/docs/V01_gemini/15_Changelog.md index 9c59ea3..577891b 100644 --- a/docs/V01_gemini/15_Changelog.md +++ b/docs/V01_gemini/15_Changelog.md @@ -1,6 +1,22 @@ (Változásnapló.) # 📜 CHANGELOG +## [1.0.1] - 2026-02-06 + +### Hozzáadva +- **Unified Auth Module**: Integrált Belépés, Lite Regisztráció és Elfelejtett jelszó kezelés. +- **Email Rendszer**: SendGrid integráció SMTP fallback lehetőséggel. +- **KYC Előkészítés**: `is_active` flag bevezetése a `User` és `Person` modellekben a 2-lépcsős folyamathoz. + +### Javítva +- **SQLAlchemy Mapper Fix**: Megszűnt az `owned_organizations` körkörös függőségi hiba. +- **Típus Szinkron**: `Person.id` javítva `BigInteger` típusra a Postgres sémával összhangban. +- **Import Fixek**: `app.db.base_class` -> `app.db.base` útvonalak egységesítve. + +### Technikai adatok +- Konténer állapot: Stabil (running) +- Regisztrációs folyamat: Step 1 (Lite) tesztelve, sikeres. + ## [1.0.0] - 2026-02-03 - **Init:** Grand Master Book létrehozása. - **Arch:** Átköltözés a 80 magos szerverre. @@ -75,4 +91,5 @@ A fejlesztések rendben tartásához javaslom a **`17_DEVELOPER_NOTES_AND_PITFAL -**Holnap reggel frissíted a GEM beállításokat is?** Ha igen, a következő lépésben elkészíthetem neked a Step 2 (KYC) végleges Pydantic sémáját és a `complete-kyc` végpont vázlatát! \ No newline at end of file +**Holnap reggel frissíted a GEM beállításokat is?** Ha igen, a következő lépésben elkészíthetem neked a Step 2 (KYC) végleges Pydantic sémáját és a `complete-kyc` végpont vázlatát! + diff --git a/docs/V01_gemini/_00_gemini_gem_kód b/docs/V01_gemini/_00_gemini_gem_kód new file mode 100644 index 0000000..c224ea0 --- /dev/null +++ b/docs/V01_gemini/_00_gemini_gem_kód @@ -0,0 +1,99 @@ +# 📘 SERVICE FINDER - MASTER ARCHITECT SYSTEM INSTRUCTIONS + +ROLE: Senior Technical Product Manager & System Architect PROJECT: Service Finder - Traffic Ecosystem SuperApp 2.0 CONTEXT: Monolit-moduláris refaktorálás (FastAPI backend, Vue3 frontend, PostgreSQL 15). SSoT: Grand Master Book (v1.4). +🎯 ALAPVETŐ MŰKÖDÉSI PROTOKOLL + + Zéró Találgatás: Tilos feltételezésekre alapozva kódot írni. Ha egy összefüggés (adatbázis-program-fájlrendszer) nem egyértelmű, pontosító kérdéseket kell feltenni. + + Fájlbekérési Kényszer: Minden módosítás vagy hibajavítás előtt kötelező bekérni az érintett fájlok aktuális, teljes tartalmát. Tilos korábbi logikát törölni; a meglévő kódrészeket integrálni kell a tiszta kód elvei szerint. + + Teljes Kódközlés: Mindig a teljes, javított állományt kell visszaadni, nem csak kódrészleteket. + + Gitea & Changelog: Csak működő, tesztelt verziók után generálj Git commit üzenetet és frissítsd a Changelog.md fájlt (.md formátumban). + +🏗️ ARCHITEKTURÁLIS ÉS ÜZLETI LOGIKA + + Identity Strategy: Szigorú elválasztás a technikai User (fiók) és a valós Person (identitás) között. A Person nem törölhető (Soft Delete). Újraregisztrációkor a KYC adatok alapján kötelező a korábbi person_id összekötése. + + Kétlépcsős Onboarding: * Step 1 (Lite): is_active = False, csak technikai User jön létre. + + Step 2 (KYC/Aktiválás): Atomi tranzakcióban: Person rögzítése, Wallet nyitása, Private Org létrehozása, aktiválás. + + Economy & Dynamic Config: * A 10-5-2%-os jutalék és minden üzleti változó (pl. auth.reward_days) kizárólag a data.system_settings táblából jöhet. Tilos beégetett (hardcoded) változók használata. + + Minden költséget helyi pénznemben és EUR-ban is tárolni kell (CostEUR​=CostLocal​⋅ExchangeRate). + + Admin Hierarchy & Security: L0 (SuperAdmin) -> L3 szintek közötti jogosultságkezelés. Regionális izoláció alkalmazása: az adminok csak a hozzájuk rendelt country_code adatait láthatják. + +🗄️ ADATBÁZIS ÉS SQL IRÁNYELVEK + + Séma: Üzleti logika a data, rendszeradatok a public sémában. + + Enumok: A Postgres Enum típusok miatt minden szerepkört és státuszt kényszerített kisbetűvel kell kezelni (role="user"). + + Migráció: Minden adatbázis-módosításhoz pgAdmin felületen futtatható SQL-t és Alembic migrációs szkriptet kell készíteni. + + Audit Trail: Minden módosítás előtt és után State Snapshot (JSON) mentése az audit_logs táblába. + +🛠️ TECHNIKAI STACK SPECIFIKÁCIÓK + + Backend: Python 3.12, FastAPI, SQLAlchemy (Alembic), Pydantic validáció. + + Frontend: Vue 3 (Composition API), Vite, Tailwind CSS, Pinia. Hardkódolt IP tilos, csak .env (VITE_API_BASE_URL). + + Storage: MinIO (S3 kompatibilis) számlákhoz és okmányokhoz. + + Útvonalak: A projekt gyökere: /opt/docker/dev/service_finder. Dokumentációk a /docs/V01_gemini/ mappában. + +💬 KOMMUNIKÁCIÓ ÉS DOKUMENTÁCIÓ + + Ha a Master Book specifikációja és a kérés ütközik, jelezd és tegyél javaslatot a Master Book frissítésére. + + Minden megoldás után frissítsd a megfelelő Master Book fejezetet, ha a rendszerlogika változott. + + Használj technikai angol kifejezéseket a magyar szövegkörnyezetben (pl. refactoring, dependency injection, endpoint). + könyvtárszerkezetét Bash tree -I "node_modules|vendor|.git|dist|build|storage" -L 3 + adatbázis szerkezet Bash docker exec -it shared-postgres pg_dump -U kincses -s service_finder > schema_dump.sq + + + +## 🛠️ SERVICE FINDER - SYSTEM ARCHITECT GEM CONFIGURATION + +ROLE: Senior Technical Product Manager & System Architect PROJECT: Service Finder - Flotta Menedzsment Rendszer OBJECTIVE: MVP Refaktorálás (Monolit -> Moduláris) a "Grand Master Book" (v1.0) elvei mentén. +🎯 ALAPVETŐ MŰKÖDÉSI PROTOKOLL + + Szigorú Adatgyűjtés: Kódmódosítás vagy javítás előtt kötelező bekérni az érintett fájlok teljes tartalmát. Tilos korábbi logikát törölni vagy módosítani anélkül, hogy tisztáznánk annak összefüggéseit a rendszer többi részével. + + Single Source of Truth (SSoT): Minden válasz alapja a Master Book (00-17.md dokumentumok). Ha a Master Book és a kód ellentmondásban van, vagy a leírás hiányos, állj meg, tegyél javaslatot a kiegészítésre, és csak a tisztázás után folytasd a kódolást. + + Tiszta és Teljes Kód: Mindig a teljes, javított fájltartalmat add vissza. Kerüld a töredékes kódokat. A kódnak tartalmaznia kell a Master Bookban rögzített logikai folyamatokat (clean code thought process). + + Zéró Találgatás: Ha egy összefüggés (adatbázis-program-fájlrendszer) nem egyértelmű, tegyél fel pontosító kérdéseket. Inkább több tisztázó kör, mint hibás kód. + +🏗️ ARCHITEKTÚRA ÉS FEJLESZTÉS + + Modularitás: A fejlesztés iránya a monolitból a moduláris felépítés felé mutat. Minden új kódnak támogatnia kell a skálázhatóságot. + + Adatbázis & SQL: SQL módosításokat pgAdmin felületre optimalizálva készíts. Minden adatbázis-módosításhoz kötelező migrációs szkriptet generálni az egységesség megőrzése érdekében. + + Fájlstruktúra: Tartsd be a projekt meglévő könyvtárszerkezetét. Ne javasolj olyan útvonalakat, amelyek eltérnek a meglévő rendszertől. + +📝 DOKUMENTÁCIÓ ÉS VERZIÓKEZELÉS + + Gitea: Csak a már tesztelt, működő és jóváhagyott javítások után generálj Git commit üzeneteket és instrukciókat. + + Changelog.md: Minden sikeres módosítás után kötelező legenerálni a Changelog.md bejegyzést, amely tartalmazza a változtatások pontos listáját. + + Master Book Frissítés: Ha a fejlesztés során új logika születik, vagy pontosítunk egy meglévőt, generáld le a Master Book megfelelő fejezetének (pl. 07_API_Guide.md vagy 06_Database_Guide.md) frissített szöveges részét is. + +💬 KOMMUNIKÁCIÓS STÍLUS + + Szakmai, tömör és határozott. + + Használj technikai angol szakkifejezéseket a magyar kontextusban (pl. refactoring, dependency injection, migration). + + Minden válasz elején röviden összegezd a megértett problémát, mielőtt a megoldásra térsz. + + könyvtárszerkezetét Bash tree -I "node_modules|vendor|.git|dist|build|storage" -L 3 + adatbázis szerkezet Bash docker exec -it shared-postgres pg_dump -U kincses -s service_finder > schema_dump.sq + \ No newline at end of file diff --git a/schema_dump.sql b/schema_dump.sql new file mode 100644 index 0000000..b7d1c22 --- /dev/null +++ b/schema_dump.sql @@ -0,0 +1,1196 @@ +-- +-- PostgreSQL database dump +-- + +\restrict YdyOBw7ea7r5Hbt0TOrTLOEM6ytHKswa16nmEwgUe7J82iI10joho1abUqa1Xas + +-- Dumped from database version 15.15 +-- Dumped by pg_dump version 15.15 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: data; Type: SCHEMA; Schema: -; Owner: service_finder_app +-- + +CREATE SCHEMA data; + + +ALTER SCHEMA data OWNER TO service_finder_app; + +-- +-- Name: public; Type: SCHEMA; Schema: -; Owner: service_finder_app +-- + +-- *not* creating schema, since initdb creates it + + +ALTER SCHEMA public OWNER TO service_finder_app; + +-- +-- Name: companyrole; Type: TYPE; Schema: data; Owner: kincses +-- + +CREATE TYPE data.companyrole AS ENUM ( + 'owner', + 'manager', + 'driver' +); + + +ALTER TYPE data.companyrole OWNER TO kincses; + +-- +-- Name: equipment_source; Type: TYPE; Schema: data; Owner: kincses +-- + +CREATE TYPE data.equipment_source AS ENUM ( + 'factory', + 'aftermarket' +); + + +ALTER TYPE data.equipment_source OWNER TO kincses; + +-- +-- Name: expense_category_enum; Type: TYPE; Schema: data; Owner: kincses +-- + +CREATE TYPE data.expense_category_enum AS ENUM ( + 'PURCHASE_PRICE', + 'TRANSFER_TAX', + 'ADMIN_FEE', + 'VEHICLE_TAX', + 'INSURANCE', + 'REFUELING', + 'SERVICE', + 'PARKING', + 'TOLL', + 'FINE', + 'TUNING_ACCESSORIES', + 'OTHER' +); + + +ALTER TYPE data.expense_category_enum OWNER TO kincses; + +-- +-- Name: moderation_status_enum; Type: TYPE; Schema: data; Owner: kincses +-- + +CREATE TYPE data.moderation_status_enum AS ENUM ( + 'pending', + 'approved', + 'rejected' +); + + +ALTER TYPE data.moderation_status_enum OWNER TO kincses; + +-- +-- Name: source_type_enum; Type: TYPE; Schema: data; Owner: kincses +-- + +CREATE TYPE data.source_type_enum AS ENUM ( + 'manual', + 'ocr', + 'api_import' +); + + +ALTER TYPE data.source_type_enum OWNER TO kincses; + +-- +-- Name: tokentype; Type: TYPE; Schema: data; Owner: kincses +-- + +CREATE TYPE data.tokentype AS ENUM ( + 'email_verify', + 'password_reset', + 'api_key' +); + + +ALTER TYPE data.tokentype OWNER TO kincses; + +-- +-- Name: emailtype; Type: TYPE; Schema: public; Owner: kincses +-- + +CREATE TYPE public.emailtype AS ENUM ( + 'REGISTRATION', + 'PASSWORD_RESET', + 'GDPR_NOTICE' +); + + +ALTER TYPE public.emailtype OWNER TO kincses; + +-- +-- Name: orgtype; Type: TYPE; Schema: public; Owner: kincses +-- + +CREATE TYPE public.orgtype AS ENUM ( + 'PRIVATE', + 'COMPANY', + 'SERVICE' +); + + +ALTER TYPE public.orgtype OWNER TO kincses; + +-- +-- Name: orguserrole; Type: TYPE; Schema: public; Owner: kincses +-- + +CREATE TYPE public.orguserrole AS ENUM ( + 'OWNER', + 'ADMIN', + 'FLEET_MANAGER', + 'DRIVER', + 'owner', + 'manager', + 'driver', + 'service' +); + + +ALTER TYPE public.orguserrole OWNER TO kincses; + +-- +-- Name: uitheme; Type: TYPE; Schema: public; Owner: kincses +-- + +CREATE TYPE public.uitheme AS ENUM ( + 'LIGHT', + 'DARK', + 'SYSTEM' +); + + +ALTER TYPE public.uitheme OWNER TO kincses; + +-- +-- Name: userrole; Type: TYPE; Schema: public; Owner: kincses +-- + +CREATE TYPE public.userrole AS ENUM ( + 'OWNER', + 'ADMIN', + 'FLEET_MANAGER', + 'DRIVER' +); + + +ALTER TYPE public.userrole OWNER TO kincses; + +-- +-- Name: validationstatus; Type: TYPE; Schema: public; Owner: kincses +-- + +CREATE TYPE public.validationstatus AS ENUM ( + 'NOT_VALIDATED', + 'PENDING', + 'VALIDATED', + 'REJECTED' +); + + +ALTER TYPE public.validationstatus OWNER TO kincses; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: audit_logs; Type: TABLE; Schema: data; Owner: kincses +-- + +CREATE TABLE data.audit_logs ( + id integer NOT NULL, + user_id integer, + action character varying(100) NOT NULL, + endpoint character varying(255), + method character varying(10), + ip_address character varying(45), + created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP +); + + +ALTER TABLE data.audit_logs OWNER TO kincses; + +-- +-- Name: audit_logs_id_seq; Type: SEQUENCE; Schema: data; Owner: kincses +-- + +CREATE SEQUENCE data.audit_logs_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.audit_logs_id_seq OWNER TO kincses; + +-- +-- Name: audit_logs_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: kincses +-- + +ALTER SEQUENCE data.audit_logs_id_seq OWNED BY data.audit_logs.id; + + +-- +-- Name: companies; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.companies ( + id integer NOT NULL, + name character varying(255) NOT NULL, + tax_number character varying(50), + subscription_tier character varying(50) DEFAULT 'free'::character varying, + owner_id integer NOT NULL, + owner_person_id bigint +); + + +ALTER TABLE data.companies OWNER TO service_finder_app; + +-- +-- Name: companies_id_seq; Type: SEQUENCE; Schema: data; Owner: service_finder_app +-- + +CREATE SEQUENCE data.companies_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.companies_id_seq OWNER TO service_finder_app; + +-- +-- Name: companies_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: service_finder_app +-- + +ALTER SEQUENCE data.companies_id_seq OWNED BY data.companies.id; + + +-- +-- Name: company_members; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.company_members ( + id integer NOT NULL, + company_id integer NOT NULL, + user_id integer NOT NULL, + role character varying(50) DEFAULT 'driver'::data.companyrole, + can_edit_service boolean DEFAULT false, + can_see_costs boolean DEFAULT false, + is_active boolean DEFAULT true +); + + +ALTER TABLE data.company_members OWNER TO service_finder_app; + +-- +-- Name: company_members_id_seq; Type: SEQUENCE; Schema: data; Owner: service_finder_app +-- + +CREATE SEQUENCE data.company_members_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.company_members_id_seq OWNER TO service_finder_app; + +-- +-- Name: company_members_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: service_finder_app +-- + +ALTER SEQUENCE data.company_members_id_seq OWNED BY data.company_members.id; + + +-- +-- Name: engine_specs; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.engine_specs ( + id integer NOT NULL, + engine_code character varying(50), + fuel_type character varying(20), + power_kw integer, + battery_capacity_kwh numeric(10,2), + onboard_charger_kw numeric(5,2), + phases integer DEFAULT 3, + default_service_interval_km integer DEFAULT 15000, + default_service_interval_hours integer DEFAULT 500, + emissions_class character varying(20) +); + + +ALTER TABLE data.engine_specs OWNER TO service_finder_app; + +-- +-- Name: engine_specs_id_seq; Type: SEQUENCE; Schema: data; Owner: service_finder_app +-- + +CREATE SEQUENCE data.engine_specs_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.engine_specs_id_seq OWNER TO service_finder_app; + +-- +-- Name: engine_specs_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: service_finder_app +-- + +ALTER SEQUENCE data.engine_specs_id_seq OWNED BY data.engine_specs.id; + + +-- +-- Name: organization_members; Type: TABLE; Schema: data; Owner: kincses +-- + +CREATE TABLE data.organization_members ( + id integer NOT NULL, + organization_id integer, + user_id integer, + role character varying DEFAULT 'driver'::character varying +); + + +ALTER TABLE data.organization_members OWNER TO kincses; + +-- +-- Name: organization_members_id_seq; Type: SEQUENCE; Schema: data; Owner: kincses +-- + +CREATE SEQUENCE data.organization_members_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.organization_members_id_seq OWNER TO kincses; + +-- +-- Name: organization_members_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: kincses +-- + +ALTER SEQUENCE data.organization_members_id_seq OWNED BY data.organization_members.id; + + +-- +-- Name: organizations; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.organizations ( + id integer NOT NULL, + name character varying NOT NULL, + org_type public.orgtype, + founded_at date, + validation_status public.validationstatus, + owner_id integer, + ui_theme character varying, + created_at timestamp with time zone DEFAULT now(), + theme character varying DEFAULT 'system'::character varying, + is_active boolean DEFAULT true, + slug character varying(100), + country_code character(2) DEFAULT 'HU'::bpchar, + is_transferable boolean DEFAULT true +); + + +ALTER TABLE data.organizations OWNER TO service_finder_app; + +-- +-- Name: organizations_id_seq; Type: SEQUENCE; Schema: data; Owner: service_finder_app +-- + +CREATE SEQUENCE data.organizations_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.organizations_id_seq OWNER TO service_finder_app; + +-- +-- Name: organizations_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: service_finder_app +-- + +ALTER SEQUENCE data.organizations_id_seq OWNED BY data.organizations.id; + + +-- +-- Name: persons; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.persons ( + id bigint NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone, + is_active boolean DEFAULT true NOT NULL, + reputation_score numeric(10,2) DEFAULT 0 NOT NULL, + risk_level integer DEFAULT 0 NOT NULL, + id_uuid uuid DEFAULT gen_random_uuid(), + last_name character varying, + first_name character varying, + mothers_name character varying, + birth_place character varying, + birth_date timestamp without time zone, + identity_docs jsonb DEFAULT '{}'::jsonb, + medical_emergency jsonb DEFAULT '{}'::jsonb, + ice_contact jsonb DEFAULT '{}'::jsonb +); + + +ALTER TABLE data.persons OWNER TO service_finder_app; + +-- +-- Name: persons_id_seq; Type: SEQUENCE; Schema: data; Owner: service_finder_app +-- + +CREATE SEQUENCE data.persons_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.persons_id_seq OWNER TO service_finder_app; + +-- +-- Name: persons_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: service_finder_app +-- + +ALTER SEQUENCE data.persons_id_seq OWNED BY data.persons.id; + + +-- +-- Name: service_providers; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.service_providers ( + id integer NOT NULL, + name character varying(255) NOT NULL, + official_brand_partner boolean DEFAULT false, + technical_rating_pct integer DEFAULT 80, + social_rating_pct integer DEFAULT 80, + location_city character varying(100), + is_active boolean DEFAULT true, + service_type character varying(50), + search_tags text, + latitude numeric(10,8), + longitude numeric(11,8), + handled_vehicle_types jsonb DEFAULT '["passenger_car"]'::jsonb, + specialized_brands jsonb DEFAULT '[]'::jsonb, + verification_status character varying(20) DEFAULT 'pending'::character varying +); + + +ALTER TABLE data.service_providers OWNER TO service_finder_app; + +-- +-- Name: service_providers_id_seq; Type: SEQUENCE; Schema: data; Owner: service_finder_app +-- + +CREATE SEQUENCE data.service_providers_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.service_providers_id_seq OWNER TO service_finder_app; + +-- +-- Name: service_providers_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: service_finder_app +-- + +ALTER SEQUENCE data.service_providers_id_seq OWNED BY data.service_providers.id; + + +-- +-- Name: service_records; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.service_records ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + vehicle_id uuid, + provider_id integer, + service_date date NOT NULL, + usage_value numeric(15,2), + is_accident_repair boolean DEFAULT false, + repair_quality_pct integer DEFAULT 100, + parts_quality_index numeric(3,2) DEFAULT 1.0, + description text, + invoice_path text, + rating_impact_score integer DEFAULT 0 +); + + +ALTER TABLE data.service_records OWNER TO service_finder_app; + +-- +-- Name: system_settings; Type: TABLE; Schema: data; Owner: kincses +-- + +CREATE TABLE data.system_settings ( + key character varying(50) NOT NULL, + value jsonb, + description text +); + + +ALTER TABLE data.system_settings OWNER TO kincses; + +-- +-- Name: users; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.users ( + id integer NOT NULL, + email character varying NOT NULL, + birthday date, + is_active boolean, + is_banned boolean, + is_gdpr_deleted boolean, + previous_login_count integer, + created_at timestamp with time zone DEFAULT now(), + verified_at timestamp with time zone, + hashed_password character varying, + role character varying DEFAULT 'user'::character varying, + is_superuser boolean DEFAULT false, + is_company boolean DEFAULT false, + updated_at timestamp with time zone, + company_name character varying, + tax_number character varying, + region_code character varying DEFAULT 'HU'::character varying, + person_id bigint, + deleted_at timestamp with time zone, + is_deleted boolean DEFAULT false NOT NULL, + social_provider character varying(50), + social_id character varying(255) +); + + +ALTER TABLE data.users OWNER TO service_finder_app; + +-- +-- Name: users_id_seq; Type: SEQUENCE; Schema: data; Owner: service_finder_app +-- + +CREATE SEQUENCE data.users_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.users_id_seq OWNER TO service_finder_app; + +-- +-- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: service_finder_app +-- + +ALTER SEQUENCE data.users_id_seq OWNED BY data.users.id; + + +-- +-- Name: vehicle_assignments; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.vehicle_assignments ( + id integer NOT NULL, + company_id integer NOT NULL, + vehicle_id integer NOT NULL, + driver_id integer NOT NULL, + start_date timestamp with time zone DEFAULT now(), + end_date timestamp with time zone, + notes character varying +); + + +ALTER TABLE data.vehicle_assignments OWNER TO service_finder_app; + +-- +-- Name: vehicle_assignments_id_seq; Type: SEQUENCE; Schema: data; Owner: service_finder_app +-- + +CREATE SEQUENCE data.vehicle_assignments_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.vehicle_assignments_id_seq OWNER TO service_finder_app; + +-- +-- Name: vehicle_assignments_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: service_finder_app +-- + +ALTER SEQUENCE data.vehicle_assignments_id_seq OWNED BY data.vehicle_assignments.id; + + +-- +-- Name: vehicle_brands; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.vehicle_brands ( + id integer NOT NULL, + name character varying NOT NULL, + origin_country character varying, + slug character varying, + country_code character varying, + category_id integer, + country_of_origin character varying(50), + is_active boolean DEFAULT true +); + + +ALTER TABLE data.vehicle_brands OWNER TO service_finder_app; + +-- +-- Name: vehicle_brands_id_seq; Type: SEQUENCE; Schema: data; Owner: service_finder_app +-- + +CREATE SEQUENCE data.vehicle_brands_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.vehicle_brands_id_seq OWNER TO service_finder_app; + +-- +-- Name: vehicle_brands_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: service_finder_app +-- + +ALTER SEQUENCE data.vehicle_brands_id_seq OWNED BY data.vehicle_brands.id; + + +-- +-- Name: vehicles; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.vehicles ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + current_company_id integer, + brand_id integer, + model_name character varying(100), + engine_spec_id integer, + identification_number character varying(50), + license_plate character varying(20), + tracking_mode character varying(10) DEFAULT 'km'::character varying, + current_rating_pct integer DEFAULT 100, + total_real_usage numeric(15,2) DEFAULT 0, + odometer_at_last_check numeric(15,2) DEFAULT 0, + custom_specs jsonb DEFAULT '{}'::jsonb, + factory_snapshot jsonb, + created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP +); + + +ALTER TABLE data.vehicles OWNER TO service_finder_app; + +-- +-- Name: wallets; Type: TABLE; Schema: data; Owner: service_finder_app +-- + +CREATE TABLE data.wallets ( + id bigint NOT NULL, + user_id integer NOT NULL, + coin_balance numeric(18,2) DEFAULT 0.00, + xp_balance bigint DEFAULT 0, + created_at timestamp with time zone DEFAULT now(), + updated_at timestamp with time zone DEFAULT now() +); + + +ALTER TABLE data.wallets OWNER TO service_finder_app; + +-- +-- Name: wallets_id_seq; Type: SEQUENCE; Schema: data; Owner: service_finder_app +-- + +CREATE SEQUENCE data.wallets_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE data.wallets_id_seq OWNER TO service_finder_app; + +-- +-- Name: wallets_id_seq; Type: SEQUENCE OWNED BY; Schema: data; Owner: service_finder_app +-- + +ALTER SEQUENCE data.wallets_id_seq OWNED BY data.wallets.id; + + +-- +-- Name: alembic_version; Type: TABLE; Schema: public; Owner: service_finder_app +-- + +CREATE TABLE public.alembic_version ( + version_num character varying(32) NOT NULL +); + + +ALTER TABLE public.alembic_version OWNER TO service_finder_app; + +-- +-- Name: audit_logs id; Type: DEFAULT; Schema: data; Owner: kincses +-- + +ALTER TABLE ONLY data.audit_logs ALTER COLUMN id SET DEFAULT nextval('data.audit_logs_id_seq'::regclass); + + +-- +-- Name: companies id; Type: DEFAULT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.companies ALTER COLUMN id SET DEFAULT nextval('data.companies_id_seq'::regclass); + + +-- +-- Name: company_members id; Type: DEFAULT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.company_members ALTER COLUMN id SET DEFAULT nextval('data.company_members_id_seq'::regclass); + + +-- +-- Name: engine_specs id; Type: DEFAULT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.engine_specs ALTER COLUMN id SET DEFAULT nextval('data.engine_specs_id_seq'::regclass); + + +-- +-- Name: organization_members id; Type: DEFAULT; Schema: data; Owner: kincses +-- + +ALTER TABLE ONLY data.organization_members ALTER COLUMN id SET DEFAULT nextval('data.organization_members_id_seq'::regclass); + + +-- +-- Name: organizations id; Type: DEFAULT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.organizations ALTER COLUMN id SET DEFAULT nextval('data.organizations_id_seq'::regclass); + + +-- +-- Name: persons id; Type: DEFAULT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.persons ALTER COLUMN id SET DEFAULT nextval('data.persons_id_seq'::regclass); + + +-- +-- Name: service_providers id; Type: DEFAULT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.service_providers ALTER COLUMN id SET DEFAULT nextval('data.service_providers_id_seq'::regclass); + + +-- +-- Name: users id; Type: DEFAULT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.users ALTER COLUMN id SET DEFAULT nextval('data.users_id_seq'::regclass); + + +-- +-- Name: vehicle_assignments id; Type: DEFAULT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.vehicle_assignments ALTER COLUMN id SET DEFAULT nextval('data.vehicle_assignments_id_seq'::regclass); + + +-- +-- Name: vehicle_brands id; Type: DEFAULT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.vehicle_brands ALTER COLUMN id SET DEFAULT nextval('data.vehicle_brands_id_seq'::regclass); + + +-- +-- Name: wallets id; Type: DEFAULT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.wallets ALTER COLUMN id SET DEFAULT nextval('data.wallets_id_seq'::regclass); + + +-- +-- Name: audit_logs audit_logs_pkey; Type: CONSTRAINT; Schema: data; Owner: kincses +-- + +ALTER TABLE ONLY data.audit_logs + ADD CONSTRAINT audit_logs_pkey PRIMARY KEY (id); + + +-- +-- Name: companies companies_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.companies + ADD CONSTRAINT companies_pkey PRIMARY KEY (id); + + +-- +-- Name: company_members company_members_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.company_members + ADD CONSTRAINT company_members_pkey PRIMARY KEY (id); + + +-- +-- Name: engine_specs engine_specs_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.engine_specs + ADD CONSTRAINT engine_specs_pkey PRIMARY KEY (id); + + +-- +-- Name: organization_members organization_members_pkey; Type: CONSTRAINT; Schema: data; Owner: kincses +-- + +ALTER TABLE ONLY data.organization_members + ADD CONSTRAINT organization_members_pkey PRIMARY KEY (id); + + +-- +-- Name: organizations organizations_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.organizations + ADD CONSTRAINT organizations_pkey PRIMARY KEY (id); + + +-- +-- Name: persons persons_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.persons + ADD CONSTRAINT persons_pkey PRIMARY KEY (id); + + +-- +-- Name: service_providers service_providers_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.service_providers + ADD CONSTRAINT service_providers_pkey PRIMARY KEY (id); + + +-- +-- Name: service_records service_records_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.service_records + ADD CONSTRAINT service_records_pkey PRIMARY KEY (id); + + +-- +-- Name: system_settings system_settings_pkey; Type: CONSTRAINT; Schema: data; Owner: kincses +-- + +ALTER TABLE ONLY data.system_settings + ADD CONSTRAINT system_settings_pkey PRIMARY KEY (key); + + +-- +-- Name: users users_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.users + ADD CONSTRAINT users_pkey PRIMARY KEY (id); + + +-- +-- Name: vehicle_assignments vehicle_assignments_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.vehicle_assignments + ADD CONSTRAINT vehicle_assignments_pkey PRIMARY KEY (id); + + +-- +-- Name: vehicle_brands vehicle_brands_cat_name_key; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.vehicle_brands + ADD CONSTRAINT vehicle_brands_cat_name_key UNIQUE (category_id, name); + + +-- +-- Name: vehicle_brands vehicle_brands_name_key; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.vehicle_brands + ADD CONSTRAINT vehicle_brands_name_key UNIQUE (name); + + +-- +-- Name: vehicle_brands vehicle_brands_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.vehicle_brands + ADD CONSTRAINT vehicle_brands_pkey PRIMARY KEY (id); + + +-- +-- Name: vehicles vehicles_identification_number_key; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.vehicles + ADD CONSTRAINT vehicles_identification_number_key UNIQUE (identification_number); + + +-- +-- Name: vehicles vehicles_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.vehicles + ADD CONSTRAINT vehicles_pkey PRIMARY KEY (id); + + +-- +-- Name: wallets wallets_pkey; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.wallets + ADD CONSTRAINT wallets_pkey PRIMARY KEY (id); + + +-- +-- Name: wallets wallets_user_id_key; Type: CONSTRAINT; Schema: data; Owner: service_finder_app +-- + +ALTER TABLE ONLY data.wallets + ADD CONSTRAINT wallets_user_id_key UNIQUE (user_id); + + +-- +-- Name: alembic_version alembic_version_pkc; Type: CONSTRAINT; Schema: public; Owner: service_finder_app +-- + +ALTER TABLE ONLY public.alembic_version + ADD CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num); + + +-- +-- Name: idx_engine_code; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE INDEX idx_engine_code ON data.engine_specs USING btree (engine_code); + + +-- +-- Name: idx_org_slug; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE UNIQUE INDEX idx_org_slug ON data.organizations USING btree (slug); + + +-- +-- Name: idx_user_email_active_only; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE UNIQUE INDEX idx_user_email_active_only ON data.users USING btree (email) WHERE ((is_deleted IS FALSE) AND (deleted_at IS NULL)); + + +-- +-- Name: idx_vb_slug; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE UNIQUE INDEX idx_vb_slug ON data.vehicle_brands USING btree (slug); + + +-- +-- Name: idx_vehicle_company; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE INDEX idx_vehicle_company ON data.vehicles USING btree (current_company_id); + + +-- +-- Name: idx_vehicle_plate; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE INDEX idx_vehicle_plate ON data.vehicles USING btree (license_plate); + + +-- +-- Name: idx_vehicle_vin; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE INDEX idx_vehicle_vin ON data.vehicles USING btree (identification_number); + + +-- +-- Name: ix_companies_owner_person_id; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE INDEX ix_companies_owner_person_id ON data.companies USING btree (owner_person_id); + + +-- +-- Name: ix_data_organizations_id; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE INDEX ix_data_organizations_id ON data.organizations USING btree (id); + + +-- +-- Name: ix_data_users_id; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE INDEX ix_data_users_id ON data.users USING btree (id); + + +-- +-- Name: ix_data_vehicle_assignments_id; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE INDEX ix_data_vehicle_assignments_id ON data.vehicle_assignments USING btree (id); + + +-- +-- Name: ix_data_vehicle_brands_id; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE INDEX ix_data_vehicle_brands_id ON data.vehicle_brands USING btree (id); + + +-- +-- Name: ix_users_is_deleted; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE INDEX ix_users_is_deleted ON data.users USING btree (is_deleted, deleted_at); + + +-- +-- Name: ix_users_person_id; Type: INDEX; Schema: data; Owner: service_finder_app +-- + +CREATE INDEX ix_users_person_id ON data.users USING btree (person_id); + + +-- +-- Name: organization_members organization_members_organization_id_fkey; Type: FK CONSTRAINT; Schema: data; Owner: kincses +-- + +ALTER TABLE ONLY data.organization_members + ADD CONSTRAINT organization_members_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES data.organizations(id); + + +-- +-- Name: organization_members organization_members_user_id_fkey; Type: FK CONSTRAINT; Schema: data; Owner: kincses +-- + +ALTER TABLE ONLY data.organization_members + ADD CONSTRAINT organization_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES data.users(id); + + +-- +-- Name: TABLE audit_logs; Type: ACL; Schema: data; Owner: kincses +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE data.audit_logs TO service_finder_app; + + +-- +-- Name: SEQUENCE audit_logs_id_seq; Type: ACL; Schema: data; Owner: kincses +-- + +GRANT ALL ON SEQUENCE data.audit_logs_id_seq TO service_finder_app; + + +-- +-- Name: TABLE organization_members; Type: ACL; Schema: data; Owner: kincses +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE data.organization_members TO service_finder_app; + + +-- +-- Name: SEQUENCE organization_members_id_seq; Type: ACL; Schema: data; Owner: kincses +-- + +GRANT ALL ON SEQUENCE data.organization_members_id_seq TO service_finder_app; + + +-- +-- Name: TABLE system_settings; Type: ACL; Schema: data; Owner: kincses +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE data.system_settings TO service_finder_app; + + +-- +-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: data; Owner: kincses +-- + +ALTER DEFAULT PRIVILEGES FOR ROLE kincses IN SCHEMA data GRANT ALL ON SEQUENCES TO service_finder_app; + + +-- +-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: data; Owner: kincses +-- + +ALTER DEFAULT PRIVILEGES FOR ROLE kincses IN SCHEMA data GRANT SELECT,INSERT,DELETE,UPDATE ON TABLES TO service_finder_app; + + +-- +-- PostgreSQL database dump complete +-- + +\unrestrict YdyOBw7ea7r5Hbt0TOrTLOEM6ytHKswa16nmEwgUe7J82iI10joho1abUqa1Xas +