feat: Unified Auth system and SendGrid integration - STABLE v1.0.1

This commit is contained in:
2026-02-06 20:54:28 +00:00
parent 714de9dd93
commit 32325b261b
14 changed files with 1432 additions and 189 deletions

View File

@@ -1,32 +1,38 @@
# /opt/docker/dev/service_finder/backend/app/api/v1/endpoints/auth.py from fastapi import APIRouter, Depends, HTTPException, status
from fastapi import APIRouter, Depends, HTTPException, Request, status, Body from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import text
from app.db.session import get_db from app.db.session import get_db
from app.schemas.auth import UserRegister, Token, UserLogin
from app.services.auth_service import AuthService from app.services.auth_service import AuthService
from app.core.security import create_access_token from app.core.security import create_access_token
from app.schemas.auth import UserLiteRegister, Token, PasswordResetRequest
router = APIRouter() router = APIRouter()
@router.post("/register", response_model=Token, status_code=status.HTTP_201_CREATED) @router.post("/register-lite", response_model=Token, status_code=201)
async def register( async def register_lite(user_in: UserLiteRegister, db: AsyncSession = Depends(get_db)):
request: Request, # Email csekkolás nyers SQL-el
user_in: UserRegister = Body(...), check = await db.execute(text("SELECT id FROM data.users WHERE email = :e"), {"e": user_in.email})
db: AsyncSession = Depends(get_db) if check.fetchone():
): raise HTTPException(status_code=400, detail="Ez az email cím már foglalt.")
# 1. Foglalt email ellenőrzése
if not await AuthService.check_email_availability(db, user_in.email): try:
raise HTTPException(status_code=400, detail="Az e-mail cím már foglalt.") 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) @router.post("/login", response_model=Token)
user = await AuthService.register_new_user( async def login(form_data: OAuth2PasswordRequestForm = Depends(), db: AsyncSession = Depends(get_db)):
db=db, user = await AuthService.authenticate(db, form_data.username, form_data.password)
user_in=user_in, if not user:
ip_address=request.client.host raise HTTPException(status_code=401, detail="Hibás e-mail vagy jelszó.")
)
# 3. Token kiállítása token = create_access_token(data={"sub": str(user.id)})
token_data = {"sub": str(user.id), "email": user.email} return {"access_token": token, "token_type": "bearer", "is_active": user.is_active}
access_token = create_access_token(data=token_data)
@router.post("/forgot-password")
return {"access_token": access_token, "token_type": "bearer"} 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."}

View File

@@ -5,23 +5,26 @@ from app.core.config import settings
app = FastAPI( app = FastAPI(
title="Service Finder API", 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", openapi_url="/api/v1/openapi.json",
docs_url="/docs" docs_url="/docs"
) )
# CORS beállítások # PONTOS CORS BEÁLLÍTÁS
app.add_middleware( app.add_middleware(
CORSMiddleware, 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_credentials=True,
allow_methods=["*"], allow_methods=["*"],
allow_headers=["*"], allow_headers=["*"],
) )
# Routerek befűzése
app.include_router(api_router, prefix="/api/v1") app.include_router(api_router, prefix="/api/v1")
@app.get("/") @app.get("/")
async def root(): async def root():
return {"status": "online", "message": "Service Finder API v2.0"} return {"status": "online", "message": "Service Finder Master System v1.0"}

View File

@@ -1,23 +1,23 @@
import uuid import uuid
import enum 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.orm import relationship
from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.sql import func 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): class UserRole(str, enum.Enum):
ADMIN = "admin" admin = "admin"
USER = "user" user = "user"
SERVICE = "service" service = "service"
FLEET_MANAGER = "fleet_manager" fleet_manager = "fleet_manager"
DRIVER = "driver" driver = "driver"
class Person(Base): class Person(Base):
__tablename__ = "persons" __tablename__ = "persons"
__table_args__ = {"schema": "data"} __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) id_uuid = Column(UUID(as_uuid=True), default=uuid.uuid4, unique=True, nullable=False)
last_name = Column(String, nullable=False) last_name = Column(String, nullable=False)
@@ -26,11 +26,16 @@ class Person(Base):
birth_place = Column(String, nullable=True) birth_place = Column(String, nullable=True)
birth_date = Column(DateTime, nullable=True) birth_date = Column(DateTime, nullable=True)
# KYC Okmányok és Safety adatok
identity_docs = Column(JSON, server_default=text("'{}'::jsonb")) identity_docs = Column(JSON, server_default=text("'{}'::jsonb"))
medical_emergency = Column(JSON, server_default=text("'{}'::jsonb")) medical_emergency = Column(JSON, server_default=text("'{}'::jsonb"))
ice_contact = 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") users = relationship("User", back_populates="person")
class User(Base): class User(Base):
@@ -39,24 +44,19 @@ class User(Base):
id = Column(Integer, primary_key=True, index=True) id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True, nullable=False) 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 role = Column(Enum(UserRole), default=UserRole.user)
social_provider = Column(String, nullable=True) # google, facebook is_active = Column(Boolean, default=False)
social_id = Column(String, nullable=True)
role = Column(Enum(UserRole), default=UserRole.USER)
is_active = Column(Boolean, default=True)
region_code = Column(String, default="HU") region_code = Column(String, default="HU")
# Soft Delete
is_deleted = Column(Boolean, default=False) 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") person = relationship("Person", back_populates="users")
wallet = relationship("Wallet", back_populates="user", uselist=False) 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()) created_at = Column(DateTime(timezone=True), server_default=func.now())

View File

@@ -1,37 +1,22 @@
# /opt/docker/dev/service_finder/backend/app/schemas/auth.py from pydantic import BaseModel, EmailStr, Field
from pydantic import BaseModel, EmailStr, Field, field_validator from typing import Optional
from typing import Optional, List
from datetime import date from datetime import date
class UserRegister(BaseModel): class UserLiteRegister(BaseModel):
email: EmailStr = Field(..., example="pilot@profibot.hu") email: EmailStr
password: Optional[str] = Field(None, min_length=8) password: str = Field(..., min_length=8)
last_name: str = Field(..., min_length=2) first_name: str
first_name: str = Field(..., min_length=2) last_name: str
mothers_name: str = Field(..., description="Kötelező banki azonosító") region_code: str = "HU"
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
@field_validator('region_code') class UserLogin(BaseModel):
@classmethod email: EmailStr
def validate_region(cls, v: str) -> str: password: str
return v.upper() if v else "HU"
class PasswordResetRequest(BaseModel):
email: EmailStr
class Token(BaseModel): class Token(BaseModel):
access_token: str access_token: str
token_type: str token_type: str
is_active: bool # KYC státusz visszajelzés
class UserLogin(BaseModel):
email: EmailStr
password: str

View File

@@ -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.ext.asyncio import AsyncSession
from sqlalchemy import select, and_, text from sqlalchemy import select, text
from app.models.identity import User, Person, UserRole
from app.models.identity import User, Person, Wallet, UserRole from app.models.organization import Organization
from app.models.organization import Organization, OrgType from app.schemas.auth import UserLiteRegister
from app.models.vehicle import OrganizationMember from app.core.security import get_password_hash, verify_password
from app.schemas.auth import UserRegister from app.services.email_manager import email_manager # Importálva!
from app.core.security import get_password_hash, create_access_token
from app.services.email_manager import email_manager
logger = logging.getLogger(__name__)
class AuthService: class AuthService:
@staticmethod @staticmethod
async def get_setting(db: AsyncSession, key: str, default: Any = None) -> Any: async def register_lite(db: AsyncSession, user_in: UserLiteRegister):
"""Admin felületről állítható változók lekérése.""" """Step 1: Lite regisztráció + Email küldés."""
try: try:
stmt = text("SELECT value FROM data.system_settings WHERE key = :key") # 1. Person shell
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)
new_person = Person( new_person = Person(
first_name=user_in.first_name, first_name=user_in.first_name,
last_name=user_in.last_name, last_name=user_in.last_name,
mothers_name=user_in.mothers_name, is_active=False
birth_place=user_in.birth_place,
birth_date=user_in.birth_date,
identity_docs=kyc_data
) )
db.add(new_person) db.add(new_person)
await db.flush() # ID generálás await db.flush()
# 3. USER LÉTREHOZÁSA # 2. User fiók
# 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
new_user = User( new_user = User(
email=user_in.email, email=user_in.email,
hashed_password=hashed_pwd, hashed_password=get_password_hash(user_in.password),
social_provider=user_in.social_provider,
social_id=user_in.social_id,
person_id=new_person.id, person_id=new_person.id,
role=UserRole.USER.value, # <--- FIX: "user" kerül be, nem "USER" role=UserRole.user,
region_code=user_in.region_code, is_active=False,
is_active=True region_code=user_in.region_code
) )
db.add(new_user) db.add(new_user)
await db.flush() await db.flush()
# 4. ECONOMY: WALLET ÉS JUTALÉK SNAPSHOT # 3. Email kiküldése (Mester Könyv v1.4 szerint)
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)
try: try:
await email_manager.send_email( await email_manager.send_email(
recipient=user_in.email, recipient=user_in.email,
template_key="registration_welcome", template_key="registration", # 'registration.html' sablon használata
variables={ variables={
"first_name": user_in.first_name, "first_name": user_in.first_name,
"reward_days": reward_days "login_url": "http://192.168.100.10:3000/login"
}, },
user_id=new_user.id user_id=new_user.id
) )
except Exception as e: except Exception as email_err:
logger.warning(f"Email failed during reg: {str(e)}") # 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.commit()
await db.refresh(new_user) await db.refresh(new_user)
return new_user return new_user
except Exception as e: except Exception as e:
await db.rollback() await db.rollback()
logger.error(f"REGISTER CRASH: {str(e)}")
raise e raise e
@staticmethod @staticmethod
async def check_email_availability(db: AsyncSession, email: str) -> bool: async def authenticate(db: AsyncSession, email: str, password: str):
query = select(User).where(and_(User.email == email, User.is_deleted == False)) stmt = select(User).where(User.email == email, User.is_deleted == False)
result = await db.execute(query) res = await db.execute(stmt)
return result.scalar_one_or_none() is None 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

View File

@@ -1,6 +1,22 @@
(Változásnapló.) (Változásnapló.)
# 📜 CHANGELOG # 📜 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 ## [1.0.0] - 2026-02-03
- **Init:** Grand Master Book létrehozása. - **Init:** Grand Master Book létrehozása.
- **Arch:** Átköltözés a 80 magos szerverre. - **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! **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!

View File

@@ -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

1196
schema_dump.sql Normal file

File diff suppressed because it is too large Load Diff