Initial commit - Migrated to Dev environment

This commit is contained in:
2026-02-03 19:55:45 +00:00
commit a34e5b7976
3518 changed files with 481663 additions and 0 deletions

24
backend/app/models/__init__.py Executable file
View File

@@ -0,0 +1,24 @@
from app.db.base import Base
from .user import User, UserRole
from .company import Company, CompanyMember, VehicleAssignment
from .vehicle import (
Vehicle,
VehicleOwnership,
VehicleBrand,
EngineSpec,
ServiceProvider,
ServiceRecord,
VehicleCategory,
VehicleModel,
VehicleVariant
)
# Alias a kompatibilitás kedvéért
UserVehicle = Vehicle
__all__ = [
"Base", "User", "UserRole", "Vehicle", "VehicleOwnership", "VehicleBrand",
"EngineSpec", "ServiceProvider", "ServiceRecord", "Company",
"CompanyMember", "VehicleAssignment", "UserVehicle", "VehicleCategory",
"VehicleModel", "VehicleVariant"
]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

63
backend/app/models/company.py Executable file
View File

@@ -0,0 +1,63 @@
from sqlalchemy import Column, Integer, String, Boolean, ForeignKey, DateTime
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from sqlalchemy.dialects.postgresql import ENUM as PG_ENUM, UUID
from app.db.base import Base
import enum
# A Python enum marad, de a Column definíciónál pontosítunk
class CompanyRole(str, enum.Enum):
OWNER = "owner"
MANAGER = "manager"
DRIVER = "driver"
class Company(Base):
__tablename__ = "companies"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
tax_number = Column(String, nullable=True)
subscription_tier = Column(String, default="free")
owner_id = Column(Integer, ForeignKey("data.users.id"), nullable=False)
members = relationship("CompanyMember", back_populates="company", cascade="all, delete-orphan")
assignments = relationship("VehicleAssignment", back_populates="company")
class CompanyMember(Base):
__tablename__ = "company_members"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
company_id = Column(Integer, ForeignKey("data.companies.id"), nullable=False)
user_id = Column(Integer, ForeignKey("data.users.id"), nullable=False)
# JAVÍTÁS: Kifejezetten megadjuk a natív Postgres típust
role = Column(
PG_ENUM('owner', 'manager', 'driver', name='companyrole', schema='data', create_type=False),
nullable=False
)
can_edit_service = Column(Boolean, default=False)
can_see_costs = Column(Boolean, default=False)
is_active = Column(Boolean, default=True)
company = relationship("Company", back_populates="members")
user = relationship("User")
class VehicleAssignment(Base):
__tablename__ = "vehicle_assignments"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
company_id = Column(Integer, ForeignKey("data.companies.id"), nullable=False)
vehicle_id = Column(UUID(as_uuid=True), ForeignKey("data.vehicles.id"), nullable=False)
driver_id = Column(Integer, ForeignKey("data.users.id"), nullable=False)
start_date = Column(DateTime(timezone=True), server_default=func.now())
end_date = Column(DateTime(timezone=True), nullable=True)
notes = Column(String, nullable=True)
company = relationship("Company", back_populates="assignments")
vehicle = relationship("Vehicle") # Itt már a Vehicle-re hivatkozunk
driver = relationship("User", foreign_keys=[driver_id])

View File

@@ -0,0 +1,42 @@
from sqlalchemy import Column, Integer, String, ForeignKey, Boolean, DateTime, JSON, Numeric
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from app.db.base import Base
class SubscriptionTier(Base):
__tablename__ = "subscription_tiers"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True)
name = Column(String, unique=True) # Free, Premium, VIP, Custom
rules = Column(JSON) # {"max_vehicles": 5, "allow_api": true}
is_custom = Column(Boolean, default=False)
class OrganizationSubscription(Base):
__tablename__ = "org_subscriptions"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True)
org_id = Column(Integer, ForeignKey("data.organizations.id"))
tier_id = Column(Integer, ForeignKey("data.subscription_tiers.id"))
valid_from = Column(DateTime, server_default=func.now())
valid_until = Column(DateTime)
is_active = Column(Boolean, default=True)
class CreditTransaction(Base):
__tablename__ = "credit_logs"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True)
org_id = Column(Integer, ForeignKey("data.organizations.id"))
amount = Column(Numeric(10, 2))
description = Column(String)
created_at = Column(DateTime, server_default=func.now())
class ServiceSpecialty(Base):
"""Fa struktúra a szerviz szolgáltatásokhoz"""
__tablename__ = "service_specialties"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("data.service_specialties.id"), nullable=True)
name = Column(String, nullable=False)
slug = Column(String, unique=True)
parent = relationship("ServiceSpecialty", remote_side=[id], backref="children")

17
backend/app/models/email_log.py Executable file
View File

@@ -0,0 +1,17 @@
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey
from sqlalchemy.sql import func
from app.db.base import Base
class EmailLog(Base):
__tablename__ = "email_logs"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, nullable=True) # Hozzáadva
recipient = Column(String, index=True) # Hozzáadva
email = Column(String, index=True)
email_type = Column(String) # Frissítve a kódhoz
type = Column(String) # Megtartva a kompatibilitás miatt
provider_id = Column(Integer) # Hozzáadva
status = Column(String) # Hozzáadva
sent_at = Column(DateTime(timezone=True), server_default=func.now())

View File

@@ -0,0 +1,21 @@
from sqlalchemy import Column, Integer, String, Boolean, JSON, Float
from app.db.base import Base
class EmailProviderConfig(Base):
__tablename__ = "email_provider_configs"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
name = Column(String(50), unique=True) # Pl: SendGrid_Main, Office365_Backup
provider_type = Column(String(20)) # SENDGRID, SMTP, MAILGUN
priority = Column(Integer, default=1) # 1 = legfontosabb
# JSON-ban tároljuk a paramétereket (host, port, api_key, user, stb.)
settings = Column(JSON, nullable=False)
is_active = Column(Boolean, default=True)
# Failover figyelés
fail_count = Column(Integer, default=0)
max_fail_threshold = Column(Integer, default=3) # Hány hiba után kapcsoljon le?
success_rate = Column(Float, default=100.0) # Statisztika az adminnak

View File

@@ -0,0 +1,30 @@
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, Text, Numeric
from sqlalchemy.sql import func
from app.db.base import Base
class EmailProvider(Base):
__tablename__ = 'email_providers'
__table_args__ = {'schema': 'data'}
id = Column(Integer, PRIMARY KEY=True)
name = Column(String(50), nullable=False)
priority = Column(Integer, default=1)
provider_type = Column(String(10), default='SMTP')
host = Column(String(255))
port = Column(Integer)
username = Column(String(255))
password_hash = Column(String(255))
is_active = Column(Boolean, default=True)
daily_limit = Column(Integer, default=300)
current_daily_usage = Column(Integer, default=0)
class EmailLog(Base):
__tablename__ = 'email_logs'
__table_args__ = {'schema': 'data'}
id = Column(Integer, PRIMARY KEY=True)
user_id = Column(Integer, ForeignKey('data.users.id'), nullable=True)
email_type = Column(String(50))
recipient = Column(String(255))
provider_id = Column(Integer, ForeignKey('data.email_providers.id'))
status = Column(String(20))
sent_at = Column(DateTime(timezone=True), server_default=func.now())
error_message = Column(Text)

View File

@@ -0,0 +1,17 @@
from sqlalchemy import Column, Integer, String, Text, Enum
import enum
from app.db.base import Base
class EmailType(str, enum.Enum):
REGISTRATION = "REGISTRATION"
PASSWORD_RESET = "PASSWORD_RESET"
GDPR_NOTICE = "GDPR_NOTICE"
class EmailTemplate(Base):
__tablename__ = "email_templates"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
type = Column(Enum(EmailType), unique=True, index=True)
subject = Column(String(255), nullable=False)
body_html = Column(Text, nullable=False) # Adminról szerkeszthető HTML tartalom

50
backend/app/models/expense.py Executable file
View File

@@ -0,0 +1,50 @@
import enum
from sqlalchemy import Column, Integer, String, ForeignKey, Enum, DateTime, Boolean, Date, JSON
from sqlalchemy.sql import func
from app.db.base import Base
# Költség Kategóriák
class ExpenseCategory(str, enum.Enum):
PURCHASE_PRICE = "PURCHASE_PRICE" # Vételár
TRANSFER_TAX = "TRANSFER_TAX" # Vagyonszerzési illeték
ADMIN_FEE = "ADMIN_FEE" # Eredetiség, forgalmi, törzskönyv
VEHICLE_TAX = "VEHICLE_TAX" # Gépjárműadó
INSURANCE = "INSURANCE" # Biztosítás
REFUELING = "REFUELING" # Tankolás
SERVICE = "SERVICE" # Szerviz / Javítás
PARKING = "PARKING" # Parkolás
TOLL = "TOLL" # Autópálya matrica
FINE = "FINE" # Bírság
TUNING_ACCESSORIES = "TUNING_ACCESSORIES" # Extrák
OTHER = "OTHER" # Egyéb
class VehicleEvent(Base):
__tablename__ = "vehicle_events"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
vehicle_id = Column(Integer, ForeignKey("data.user_vehicles.id"), nullable=False)
# Esemény típusa
event_type = Column(Enum(ExpenseCategory, schema="data", name="expense_category_enum"), nullable=False)
date = Column(Date, nullable=False)
# Kilométeróra (KÖTELEZŐ!)
odometer_value = Column(Integer, nullable=False)
odometer_anomaly = Column(Boolean, default=False) # Ha csökkenést észlelünk, True lesz
# Pénzügyek
cost_amount = Column(Integer, nullable=False, default=0) # HUF
# Leírás és Képek
description = Column(String, nullable=True)
image_paths = Column(JSON, nullable=True) # Lista a feltöltött képek (számla, fotó) útvonalairól
# Kapcsolat a szolgáltatóval
# Ha is_diy=True, akkor a user maga csinálta.
# Ha is_diy=False és service_provider_id=None, akkor ismeretlen helyen készült.
is_diy = Column(Boolean, default=False)
service_provider_id = Column(Integer, ForeignKey("data.service_providers.id"), nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())

View File

@@ -0,0 +1,70 @@
from datetime import datetime
from typing import Optional
from sqlalchemy import ForeignKey, String, Integer, DateTime, func, Boolean
from sqlalchemy.orm import Mapped, mapped_column
from app.db.base import Base
# Közös beállítás az összes táblához ebben a fájlban
SCHEMA_ARGS = {"schema": "data"}
class PointRule(Base):
__tablename__ = "point_rules"
__table_args__ = SCHEMA_ARGS
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
action_key: Mapped[str] = mapped_column(String, unique=True, index=True)
points: Mapped[int] = mapped_column(Integer, default=0)
description: Mapped[Optional[str]] = mapped_column(String)
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
class LevelConfig(Base):
__tablename__ = "level_configs"
__table_args__ = SCHEMA_ARGS
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
level_number: Mapped[int] = mapped_column(Integer, unique=True)
min_points: Mapped[int] = mapped_column(Integer)
rank_name: Mapped[str] = mapped_column(String)
class RegionalSetting(Base):
__tablename__ = "regional_settings"
__table_args__ = SCHEMA_ARGS
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
country_code: Mapped[str] = mapped_column(String, unique=True)
currency: Mapped[str] = mapped_column(String, default="HUF")
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
class PointsLedger(Base):
__tablename__ = "points_ledger"
__table_args__ = SCHEMA_ARGS
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
# JAVÍTVA: data.users.id hivatkozás
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("data.users.id"))
points: Mapped[int] = mapped_column(Integer)
reason: Mapped[str] = mapped_column(String)
created_at: Mapped[datetime] = mapped_column(DateTime, default=func.now())
class UserStats(Base):
__tablename__ = "user_stats"
__table_args__ = SCHEMA_ARGS
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
# JAVÍTVA: data.users.id hivatkozás
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("data.users.id"), unique=True)
total_points: Mapped[int] = mapped_column(Integer, default=0)
current_level: Mapped[int] = mapped_column(Integer, default=1)
last_activity: Mapped[datetime] = mapped_column(DateTime, default=func.now())
class Badge(Base):
__tablename__ = "badges"
__table_args__ = SCHEMA_ARGS
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
name: Mapped[str] = mapped_column(String, unique=True)
description: Mapped[str] = mapped_column(String)
icon_url: Mapped[Optional[str]] = mapped_column(String)
class UserBadge(Base):
__tablename__ = "user_badges"
__table_args__ = SCHEMA_ARGS
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
# JAVÍTVA: data.users.id hivatkozás
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("data.users.id"))
badge_id: Mapped[int] = mapped_column(Integer, ForeignKey("data.badges.id"))
earned_at: Mapped[datetime] = mapped_column(DateTime, default=func.now())

63
backend/app/models/history.py Executable file
View File

@@ -0,0 +1,63 @@
# /opt/service_finder/backend/app/models/history.py
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, JSON, Date, Text
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from app.db.base import Base
# --- 1. Jármű Birtoklási Előzmények (Ownership History) ---
# Ez a tábla mondja meg, kié volt az autó egy adott időpillanatban.
# Így biztosítjuk, hogy a régi tulajdonos adatai védve legyenek az újtól.
class VehicleOwnership(Base):
__tablename__ = "vehicle_ownerships"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
# Kapcsolatok
vehicle_id = Column(Integer, ForeignKey("data.user_vehicles.id"), nullable=False)
user_id = Column(Integer, ForeignKey("data.users.id"), nullable=False)
# Időszak
start_date = Column(Date, nullable=False, default=func.current_date()) # Mikor került hozzá
end_date = Column(Date, nullable=True) # Ha NULL, akkor ő a jelenlegi tulajdonos!
# Jegyzet (pl. adásvételi szerződés száma)
notes = Column(Text, nullable=True)
# SQLAlchemy kapcsolatok (visszahivatkozások a fő modellekben kellenek majd)
vehicle = relationship("UserVehicle", back_populates="ownership_history")
user = relationship("User", back_populates="owned_vehicles")
# --- 2. Audit Log (A "Fekete Doboz") ---
# Minden kritikus módosítást itt tárolunk. Ez a rendszer "igazságügyi naplója".
class AuditLog(Base):
__tablename__ = "audit_logs"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
# KI? (A felhasználó, aki a műveletet végezte)
user_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
# MIT? (Milyen objektumot érintett?)
target_type = Column(String, index=True) # pl. "vehicle", "cost", "user_profile"
target_id = Column(Integer, index=True) # pl. az autó ID-ja
# HOGYAN?
action = Column(String, nullable=False) # CREATE, UPDATE, DELETE, LOGIN_FAILED, EXPORT_DATA
# RÉSZLETEK (Mi változott?)
# Pl: {"field": "odometer", "old_value": 150000, "new_value": 120000} <- Visszatekerés gyanú!
changes = Column(JSON, nullable=True)
# BIZTONSÁG
ip_address = Column(String, nullable=True) # Honnan jött a kérés?
user_agent = Column(String, nullable=True) # Milyen böngészőből?
# MIKOR?
timestamp = Column(DateTime(timezone=True), server_default=func.now())
# Kapcsolat (Opcionális, csak ha le akarjuk kérdezni a user adatait a logból)
user = relationship("User")

29
backend/app/models/legal.py Executable file
View File

@@ -0,0 +1,29 @@
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Boolean
from sqlalchemy.sql import func
from app.db.base import Base
class LegalDocument(Base):
__tablename__ = "legal_documents"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
title = Column(String(255))
content = Column(Text, nullable=False)
version = Column(String(20), nullable=False)
region_code = Column(String(5), default="HU")
language = Column(String(5), default="hu")
is_active = Column(Boolean, default=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
class LegalAcceptance(Base):
__tablename__ = "legal_acceptances"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("data.users.id"))
document_id = Column(Integer, ForeignKey("data.legal_documents.id"))
accepted_at = Column(DateTime(timezone=True), server_default=func.now())
ip_address = Column(String(45))
user_agent = Column(Text)

25
backend/app/models/logistics.py Executable file
View File

@@ -0,0 +1,25 @@
from sqlalchemy import Column, Integer, String, Enum
from app.db.base import Base
import enum
# Enum definiálása
class LocationType(str, enum.Enum):
stop = "stop" # Megálló / Parkoló
warehouse = "warehouse" # Raktár
client = "client" # Ügyfél címe
class Location(Base):
__tablename__ = "locations"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
# FONTOS: Itt is megadjuk a schema="data"-t, hogy ne a public sémába akarja írni!
type = Column(Enum(LocationType, schema="data", name="location_type_enum"), nullable=False)
# Koordináták (egyelőre String, később PostGIS)
coordinates = Column(String, nullable=True)
address_full = Column(String, nullable=True)
capacity = Column(Integer, nullable=True)

View File

@@ -0,0 +1,36 @@
import enum
from sqlalchemy import Column, Integer, String, Boolean, Enum, DateTime
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from app.db.base import Base
class OrgType(str, enum.Enum):
INDIVIDUAL = "individual"
SERVICE = "service"
FLEET_OWNER = "fleet_owner"
CLUB = "club"
class UITheme(str, enum.Enum):
LIGHT = "light"
DARK = "dark"
SYSTEM = "system"
class Organization(Base):
__tablename__ = "organizations"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
org_type = Column(Enum(OrgType), default=OrgType.INDIVIDUAL)
# Új UI beállítások a V2-höz
theme = Column(Enum(UITheme), default=UITheme.SYSTEM)
logo_url = Column(String, nullable=True)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
# Kapcsolatok
# members = relationship("OrganizationMember", back_populates="organization")
vehicles = relationship("UserVehicle", back_populates="current_org")

View File

@@ -0,0 +1,26 @@
import enum
from sqlalchemy import Column, Integer, String, Boolean, Enum, ForeignKey
from sqlalchemy.orm import relationship
from app.db.base import Base
# Átnevezve OrgUserRole-ra, hogy ne ütközzön a globális UserRole-al
class OrgUserRole(str, enum.Enum):
OWNER = "OWNER"
ADMIN = "ADMIN"
FLEET_MANAGER = "FLEET_MANAGER"
DRIVER = "DRIVER"
class OrganizationMember(Base):
__tablename__ = "organization_members"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
org_id = Column(Integer, ForeignKey("data.organizations.id", ondelete="CASCADE"))
user_id = Column(Integer, ForeignKey("data.users.id", ondelete="CASCADE"))
# Itt is frissítjük a hivatkozást
role = Column(Enum(OrgUserRole), default=OrgUserRole.DRIVER)
is_permanent = Column(Boolean, default=False)
organization = relationship("Organization", back_populates="members")
# # # user = relationship("User", back_populates="memberships")

71
backend/app/models/social.py Executable file
View File

@@ -0,0 +1,71 @@
import enum
from sqlalchemy import Column, Integer, String, ForeignKey, Enum, DateTime, Boolean, Text, UniqueConstraint
from app.db.base import Base
from datetime import datetime
# Enums (már schema="data" beállítással a biztonságért)
class ModerationStatus(str, enum.Enum):
pending = "pending"
approved = "approved"
rejected = "rejected"
class SourceType(str, enum.Enum):
manual = "manual"
ocr = "ocr"
api_import = "import"
class ServiceProvider(Base):
__tablename__ = "service_providers"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
address = Column(String, nullable=False)
category = Column(String)
status = Column(Enum(ModerationStatus, schema="data", name="moderation_status_enum"), default=ModerationStatus.pending, nullable=False)
source = Column(Enum(SourceType, schema="data", name="source_type_enum"), default=SourceType.manual, nullable=False)
# --- ÚJ MEZŐ ---
validation_score = Column(Integer, default=0) # A közösségi szavazatok összege
# ---------------
evidence_image_path = Column(String, nullable=True)
added_by_user_id = Column(Integer, ForeignKey("data.users.id"))
created_at = Column(DateTime, default=datetime.utcnow)
class Vote(Base):
__tablename__ = "votes"
__table_args__ = (
UniqueConstraint('user_id', 'provider_id', name='uq_user_provider_vote'),
{"schema": "data"}
)
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey("data.users.id"), nullable=False)
provider_id = Column(Integer, ForeignKey("data.service_providers.id"), nullable=False)
vote_value = Column(Integer, nullable=False) # +1 vagy -1
class Competition(Base):
__tablename__ = "competitions"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False) # Pl: "Januári Feltöltő Verseny"
description = Column(Text)
start_date = Column(DateTime, nullable=False)
end_date = Column(DateTime, nullable=False)
is_active = Column(Boolean, default=True)
class UserScore(Base):
__tablename__ = "user_scores"
__table_args__ = (
UniqueConstraint('user_id', 'competition_id', name='uq_user_competition_score'),
{"schema": "data"}
)
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey("data.users.id"))
competition_id = Column(Integer, ForeignKey("data.competitions.id"))
points = Column(Integer, default=0)
last_updated = Column(DateTime, default=datetime.utcnow)

View File

@@ -0,0 +1,17 @@
from sqlalchemy import Column, Integer, String, JSON, DateTime, func
from app.db.base import Base
class StagedVehicleData(Base):
"""Ide érkeznek a nyers, validálatlan adatok a külső forrásokból"""
__tablename__ = "staged_vehicle_data"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True)
source_url = Column(String) # Honnan jött az adat?
raw_data = Column(JSON) # A teljes leszedett JSON struktúra
# Feldolgozási állapot
status = Column(String, default="PENDING") # PENDING, PROCESSED, ERROR
error_log = Column(String, nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())

View File

@@ -0,0 +1,15 @@
from sqlalchemy import Column, String, JSON
from app.db.base import Base
class SystemSetting(Base):
"""
Globális rendszerbeállítások tárolása.
Kulcs-Érték párok (JSON támogatással a komplex szabályokhoz).
Példa: key='FREE_VEHICLE_LIMIT', value='2'
"""
__tablename__ = "system_settings"
__table_args__ = {"schema": "data"}
key = Column(String, primary_key=True, index=True)
value = Column(JSON, nullable=False)
description = Column(String, nullable=True)

View File

@@ -0,0 +1,15 @@
from sqlalchemy import Column, Integer, String, Text, Boolean, UniqueConstraint
from app.db.base import Base
class Translation(Base):
__tablename__ = "translations"
__table_args__ = (
UniqueConstraint("key", "lang_code", name="uq_translation_key_lang"),
{"schema": "data"}
)
id = Column(Integer, primary_key=True, index=True)
key = Column(String(100), nullable=False, index=True)
lang_code = Column(String(5), nullable=False, index=True)
value = Column(Text, nullable=False)
is_published = Column(Boolean, default=False) # Publikálási állapot

35
backend/app/models/user.py Executable file
View File

@@ -0,0 +1,35 @@
import enum
from sqlalchemy import Column, Integer, String, Boolean, Date, DateTime
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from app.db.base import Base
class UserRole(str, enum.Enum):
ADMIN = "admin"
USER = "user"
SERVICE = "service"
FLEET_MANAGER = "fleet_manager"
class User(Base):
__tablename__ = "users"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True, nullable=False)
hashed_password = Column(String, nullable=False)
first_name = Column(String)
last_name = Column(String)
birthday = Column(Date, nullable=True)
role = Column(String, default=UserRole.USER)
is_active = Column(Boolean, default=True)
is_superuser = Column(Boolean, default=False)
is_company = Column(Boolean, default=False)
company_name = Column(String, nullable=True)
tax_number = Column(String, nullable=True)
region_code = Column(String, default="HU")
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
# Kapcsolatok
# memberships = relationship("OrganizationMember", back_populates="user", cascade="all, delete-orphan")
# vehicles = relationship("VehicleOwnership", back_populates="user", cascade="all, delete-orphan")

77
backend/app/models/vehicle.py Executable file
View File

@@ -0,0 +1,77 @@
from sqlalchemy import Column, Integer, String, Boolean, ForeignKey, Numeric, DateTime, JSON, Date
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
import uuid
from app.db.base import Base
class VehicleBrand(Base):
__tablename__ = "vehicle_brands"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
name = Column(String(100), nullable=False, unique=True)
slug = Column(String(100), unique=True)
country_of_origin = Column(String(50))
is_active = Column(Boolean, default=True)
class ServiceProvider(Base):
__tablename__ = "service_providers"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
name = Column(String(255), nullable=False)
official_brand_partner = Column(Boolean, default=False)
technical_rating_pct = Column(Integer, default=80)
social_rating_pct = Column(Integer, default=80)
location_city = Column(String(100))
service_type = Column(String(50))
search_tags = Column(String)
latitude = Column(Numeric(10, 8))
longitude = Column(Numeric(11, 8))
is_active = Column(Boolean, default=True)
records = relationship("ServiceRecord", back_populates="provider")
class EngineSpec(Base):
__tablename__ = "engine_specs"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
engine_code = Column(String(50), unique=True)
fuel_type = Column(String(20))
power_kw = Column(Integer)
default_service_interval_km = Column(Integer, default=15000)
vehicles = relationship("Vehicle", back_populates="engine_spec")
class Vehicle(Base):
__tablename__ = "vehicles"
__table_args__ = {"schema": "data"}
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
current_company_id = Column(Integer, ForeignKey("data.companies.id"))
brand_id = Column(Integer, ForeignKey("data.vehicle_brands.id"))
model_name = Column(String(100))
engine_spec_id = Column(Integer, ForeignKey("data.engine_specs.id"))
identification_number = Column(String(50), unique=True)
license_plate = Column(String(20))
tracking_mode = Column(String(10), default="km")
current_rating_pct = Column(Integer, default=100)
total_real_usage = Column(Numeric(15, 2), default=0)
created_at = Column(DateTime(timezone=True), server_default=func.now())
engine_spec = relationship("EngineSpec", back_populates="vehicles")
service_records = relationship("ServiceRecord", back_populates="vehicle", cascade="all, delete-orphan")
# --- KOMPATIBILITÁSI RÉTEG A RÉGI KÓDOKHOZ ---
VehicleOwnership = Vehicle
VehicleModel = Vehicle
VehicleVariant = Vehicle
VehicleCategory = VehicleBrand # JAVÍTVA: Nagy "B" betűvel
class ServiceRecord(Base):
__tablename__ = "service_records"
__table_args__ = {"schema": "data"}
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
vehicle_id = Column(UUID(as_uuid=True), ForeignKey("data.vehicles.id"))
provider_id = Column(Integer, ForeignKey("data.service_providers.id"))
service_date = Column(Date, nullable=False)
usage_value = Column(Numeric(15, 2))
repair_quality_pct = Column(Integer, default=100)
vehicle = relationship("Vehicle", back_populates="service_records")
provider = relationship("ServiceProvider", back_populates="records") # JAVÍTVA

View File

@@ -0,0 +1,54 @@
from sqlalchemy import Column, Integer, String, ForeignKey, Boolean, Float, JSON, Date
from sqlalchemy.orm import relationship
from app.db.base import Base
# 1. Kategória (Autó, Motor, Kisteher...)
class VehicleCategory(Base):
__tablename__ = "vehicle_categories"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True)
name_key = Column(String, nullable=False) # i18n kulcs: 'CAR', 'MOTORCYCLE'
# 2. Márka (Audi, Honda, BMW...)
class VehicleMake(Base):
__tablename__ = "vehicle_makes"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True)
name = Column(String, unique=True, nullable=False)
logo_url = Column(String, nullable=True)
# 3. Modell és Generáció (pl. Audi A3 -> A3 8V)
class VehicleModel(Base):
__tablename__ = "vehicle_models"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True)
make_id = Column(Integer, ForeignKey("data.vehicle_makes.id"))
category_id = Column(Integer, ForeignKey("data.vehicle_categories.id"))
name = Column(String, nullable=False)
generation_name = Column(String, nullable=True) # pl: "8V Facelift"
production_start_year = Column(Integer, nullable=True)
production_end_year = Column(Integer, nullable=True)
# 4. Motor és Hajtáslánc (Technikai specifikációk)
class VehicleEngine(Base):
__tablename__ = "vehicle_engines"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True)
model_id = Column(Integer, ForeignKey("data.vehicle_models.id"))
engine_code = Column(String, nullable=True)
fuel_type = Column(String, nullable=False) # 'Petrol', 'Diesel', 'Hybrid', 'EV'
displacement_ccm = Column(Integer, nullable=True)
power_kw = Column(Integer, nullable=True)
torque_nm = Column(Integer, nullable=True)
transmission_type = Column(String, nullable=True) # 'Manual', 'Automatic'
gears_count = Column(Integer, nullable=True)
drive_type = Column(String, nullable=True) # 'FWD', 'RWD', 'AWD'
# 5. Opciók Katalógusa (Gyári extrák listája)
class VehicleOptionCatalog(Base):
__tablename__ = "vehicle_options_catalog"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True)
category = Column(String) # 'Security', 'Comfort', 'Multimedia'
name_key = Column(String) # 'MATRIX_LED'

View File

@@ -0,0 +1,19 @@
from sqlalchemy import Column, Integer, ForeignKey, DateTime, Boolean
from sqlalchemy.sql import func
from app.db.base import Base
class VehicleOwnership(Base):
__tablename__ = "vehicle_ownerships"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
vehicle_id = Column(Integer, ForeignKey("data.vehicles.id"))
org_id = Column(Integer, ForeignKey("data.organizations.id"))
# Érvényességi időablak
start_date = Column(DateTime(timezone=True), server_default=func.now())
end_date = Column(DateTime(timezone=True), nullable=True) # Ha eladja, ide kerül a dátum
is_active = Column(Boolean, default=True)
# Csak ezen az ablakon belüli szervizeket láthatja az aktuális tulajdonos

View File

@@ -0,0 +1,21 @@
import enum
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Enum
from sqlalchemy.sql import func
from app.db.base import Base
class TokenType(str, enum.Enum):
email_verify = "email_verify"
password_reset = "password_reset"
class VerificationToken(Base):
__tablename__ = "verification_tokens"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("data.users.id", ondelete="CASCADE"), nullable=False)
token_hash = Column(String(64), unique=True, index=True, nullable=False)
token_type = Column(Enum(TokenType, name="tokentype", schema="data"), nullable=False)
expires_at = Column(DateTime(timezone=True), nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)