From 32325b261b369719bfdcb60341dd6d2dae770f56 Mon Sep 17 00:00:00 2001 From: Kincses Date: Fri, 6 Feb 2026 20:54:28 +0000 Subject: [PATCH] feat: Unified Auth system and SendGrid integration - STABLE v1.0.1 --- backend/app/__pycache__/main.cpython-312.pyc | Bin 992 -> 1084 bytes .../__pycache__/auth.cpython-312.pyc | Bin 1768 -> 3243 bytes backend/app/api/v1/endpoints/auth.py | 52 +- .../core/__pycache__/security.cpython-312.pyc | Bin 2009 -> 1913 bytes backend/app/main.py | 13 +- .../__pycache__/identity.cpython-312.pyc | Bin 3647 -> 3822 bytes backend/app/models/identity.py | 40 +- .../schemas/__pycache__/auth.cpython-312.pyc | Bin 2537 -> 1360 bytes backend/app/schemas/auth.py | 45 +- .../__pycache__/auth_service.cpython-312.pyc | Bin 7554 -> 4476 bytes backend/app/services/auth_service.py | 157 +-- docs/V01_gemini/15_Changelog.md | 19 +- docs/V01_gemini/_00_gemini_gem_kód | 99 ++ schema_dump.sql | 1196 +++++++++++++++++ 14 files changed, 1432 insertions(+), 189 deletions(-) create mode 100644 docs/V01_gemini/_00_gemini_gem_kód create mode 100644 schema_dump.sql diff --git a/backend/app/__pycache__/main.cpython-312.pyc b/backend/app/__pycache__/main.cpython-312.pyc index fead05bec161c09bc6032978d756e24f55462b24..577fa69e18edd4e04bcb5ae24bca95cdcaaa4989 100644 GIT binary patch delta 333 zcmaFBzK4VFG%qg~0}%Z9-#DcmVM>5L$}hIir|WqZCg z{HvKjsu>s<8B#g2#35{CGDToDBZQwK*utV(P=49j-mq3KYLBhpAJt?VWdId%KX_-m+C3+d9 zA-5Q{CeLS_q@Wm_T2z*qoT}iKnU|7Uq~M!aTmqzmD}hw5LYd)YcP2Y28K7&5g@D8h zh93ikBv1#%KW(&C+!eSFt uZ-_}jXb|TEHv^;a7X~&)rVm1sIarj0+!#MIGcfUeWMX7=V=NK}8VCSxKsed} 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 e7d48ea4a9cbbb8a7bba7882486db93ef8f0fa0a..fbd38e7bd54538bd2a4bdda0a8e2f6def4fcffc5 100644 GIT binary patch literal 3243 zcmbtWOHdrg8Sb9PzIRz3D~v$WAf!|+7Q2O`l2Q_q1rjRaSRnHd%G$}+u+zZcncY>- z0D^!DNeDF|Eg)}9~dH4|DR*!?Dq1Jvte?|F-IMY-nAg0zFXeNvp!xMcD&SyI3+ka%$iW^htVdE22Ya;&J(`L-*r!$M zRjDeyI#sRLq-rqY5W$P3Wu#&xHrC=Uu3RgAQmq7*f{T2y4|F&ZT7)&TZx|~fQl*56 zZ&*+wzZAEv)qan)3R1lkUF3?|%$BS1l3h-zB%YGpsvUM;`5wE~?uuTrgOwUmQ?e7= zVW)0tSG@Kcwv4!7``gd|xHmU$5^8(TkUYsMh8^ze??2ypIYaWMn#{4qdEvf?Z#9#(?<*gl%Oq`8Ey=M zwgMtaR}VKUU@9 za_#O<#Y++RG!#=)c{hP>I6}r!<5sJzG)ymq0*>2 zBp;LFA=^tXlMD+w=3ZNLmTCKjiJ2MAWeF9bmoo3#VVB%#MsCXd4C^te&8Z5NSj)d1 zsBsUih91gXVvCtkl6lt_*lF0JvpCB9V6faPIp2%Mq@2%}{%UffH3`w5L{NXihY ziTo5jzznj2&1|ed@lW*a94dHFb?jR6$IYMgTl>4$_w-o31J>ZrHwTrqLB)EDtXB!~$JDx*j{eS#kWT z@HpDEaPUvn%l&r-Zw=mVu;M2-qOV^SA4&(8FWx`%W%q;bwTibb-`j->6du9f76K^R z_OIt26pB4Xm>FdgEocAIcfWG=!b+EQ_}oUM+wyh)yTCK?e~eDp#QdwL!}uod*eCp< z5zyUeT}KnT8^;}u!rkV>fbZ?)p#NSYX1K|JI>6sMRCikBS49!>jc?5dhi_=wy+P$2%V|+($ zF?Qw;tZ+-bn-S)5IeRFA8FmdqK8m=wT)S}z8DKj`XZaak@xb_Kd7O(BZz%(uaU#{% zt$xfxuO8%G>d@+SLn19sWKPHjGjOo?e30ezsTE~jrtY~1x9w_4eVladlD@oQ= zGjMI#K1S`VtOLrIE~H}MFsjmntoQ*dBq-tnJ;X2z4H{=fGZY3()+`k0s{m}#@g{8r z%;q;np>Wv#b!Ee5WqhqNzOa8m-AtTXOPpGXZ+7&rb@Z=S4r~So=FU6{R+Je2)<&e) z^7Vcl+V>e*>RYb4Q+um+@g3{nv5nAi2#AKp>38}|FFwt#>+f{=MykT#ZE@| zIsW9kZLbbjwmd?{*%5aUZHkiB>zcND(**CTkV>^FS(i9VK9=+A85s&)Rjyig5YPqOJSr}6m zzm#3?wucrUc0xV}R|d=C4!ND9yMdlT8x@)FYlBD9xJFLW)6mC~lks;bAY)?u6*{qw zPHdqgTPV4O>bFqi7HWmxSLls3^v2)(RUg&QdH#yMAJ)HDZ-w_Pkd^AW`gPp-=hR`D2RKo)!15a!1Byfr+&sG?kp~FOjy{BI3H8Ldhs*DbPqi`dh+(v+Q2*3&ob)+ z$`jl?Wt2U6D*cEC3O3mF0q?f?J) literal 1768 zcmZuxU2GIp6ux)<_J7;$7All#>rY`#y0s`l10mT;Owkl=h)iT+8#!3Tj-U#TsEUrHN{+0`j-o1< zp9^-#39DgW7VU@=RinNv*)b=s#+`(kaFS}$-;?b&r(JFLWyMZ89cl+g0wQ>+6;@4? zbTJbo^YCkiNP@`4=O69_(sFo7Y|7wAF(XU(fhLe>piK*Alt^Zb#LYMfPb+5PZTUgW z&9!8v?JsVYQCK8*aBQ+%^$2C5{iH%lrppqeQ&R^=jvJ)nS>+N7O_HNk;(APRJ>9Fi zOd2kmwG3wQoLegydE&YN16`RRo@N#@B8wk#37sS}mdhQ>Q{^M1#3FoiqC8`9Y%Evx zX7hy3Sq1?$ZBU|nMAHoe+-V*+I1w47Ef*PqB`I+$<&sM@r)(0N#hS@z254CpqOBZ5 zRS2S4B_@~!qg5%tLNcsp;9VbwioK37blYpy4xyspV;))Ng?U^AzC8XcwXkP^4JRSO zC&Hrmt}G)r;e`UMiA`Zy43MYshDZV90w{cWq* z0e)UAwg>XVZ@>>Y{hxnk$`^!Fl9vwf^U|^sSe%mQWiw=kF9>2um}1x#DS1qqEd$j>*P~3ZOv($IQD_G@<+=J< zGs!n;1?LG;{`Xx4mR|q4-#4gNDy`QVoEsX1n^h@WCC?qyf%(}=jfI0G=ytG+aR+B% z`4in+KzEatDf3*xo~Cs4+Gy1Tu+Uz#zt3Sqc@Y?7sZvACT}G3E8+ZI#YblA zsq9)TvDV(TmfpI!@8f-|>Hd1U|87X?Q2s?yTv^x;KDYLqoBHhVr-#pPyDWVd{U%yZ z?O7PVneM+hej~kmVdD0-9aqBjSZ+niHF{8d4Bu;n!SufSG~{*q+2LpKmw5Oo>8l(9 z@#=Ow+$UY#@iNFi_F-5LWV%>rT8E2Su_(WLl#|S_IOV0G{C-e=0oZ2uD6j%L<Jj4f@LG zOOqEVer}X00l!9-azgOtGKDtBpH$(EZ|Ad5+xfzf_UhzFZfaz|-<+?}IzSQa=LX@u zFoCKz*+*XlmCq3OBrFXPWBdo2SVa@J(BLi9_Y2xnM|*CeA^80o>G+^~LAi}X?{&Y` z{r(#lH(hycb#K1DH^0z*9Z%g+P*30I>GNYhcRhJ-?(Ca)LY;URuO&JgA{TBawlrie YG!zus^pAhIE+XL&z9aB$x)b962LQUb*#H0l 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 f920070f0065c8da457051343acd3f62c8e54894..ba97cab458d38d91f8fd8c7284ae3ef52cc0ad92 100644 GIT binary patch delta 240 zcmcb~|C5jJG%qg~0}zC0w`Q(k-pHrU#H|nHHZa`emRexC*^$YSk&$O|Gjleh$>jIU zs!S!!llL*nOg3ZDV69**mSWtzl4Ta7tpHF5Q49 zF<)n<&ShTp6}FeOi}!e*$++%UbkVQqicRrF-jW8l$y3=LCNnWcGcIuczyP9mC`0H2 zDxbmp4;)O4o{S5aL86|FE0{r|o{S$kSQtYXXQV7JUctP;VrJe41`vNo#DUCvNt#v=6+=E-}RWF{N3XmC{l71uK7*};X>HpjEfWDF7niWh?<8yIc~h)n04$T^w2 z!Sg1&$Q?n+=`s^#=48yznVEB0Pyl5K$;arG`{{j{*5(PRK08{T$Y5)KL 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 59412fffa1e303898b33ba71e76cbb717691bf5a..d9cdbf9b81de50ef4a00ee2ef30e3f8144e9b99d 100644 GIT binary patch delta 1829 zcmb7EU1%It6rS1t-I>|l+5c>^O`2}&PMU5^8Z{{;mNqe_(Nt(k%UTJO%q7_{yBqIp zjLCzESR^k(!$qk0VjqMJS+TxFd}#aurM^U5luQxHi{OhW#0mw)b7sww1|M{o`R3g3 zo_p@S=Y03xZTThT|5}oK96YU;-pt#DHGhKtY3;EK=L=F!;yI1e?7F`Y$OSChp$7|c zPPS~P9x8-$Vas;ukwP>VLIQwYvmJMZ zu@z=-*fOqE-TcVbWc!Y1exZl`W&3m4NfMe{b63U2`d}r*37@Pvs?r7zqu_yda`wr( zeGoVPX;g&`TiwjH{GaiijR5{efD{Bcq6M^IRc>&tiy$Kp1U8Et|f2NVKURJ)H9fp$2UMn_8JYf>zr;U=-sI_Li9N z_$rP&gEenIyYIYa-;E?$pR4=IZ!S)b-(09TH=VWMz{<$39Dm1CN!JoxTb?b)m!3~O zpZjX^=*q>NM#pAmGkrJnapsebnmn{}aaT;-irw+l#QxWZ>MLktSX&)ydz#&IoeV)9 z1tRX3kchKM*5yt`{a7Fp&|Fn-BfmkWy2H!zzw}@fCkX>aG+{p$NW;?*OceTJnyB$0 zmwgd{^nvq36AI@wIw@O63}n~K);&j;O_xD*GF3(bogBKlv`Di!s1smJIdV{UNI!vqCy3%jKphBA zAvgg{Cn>0T-3-jA#tbNKPBn~$64j`P9@Zho6K*bQ(jNA{_h^qBO;jlzL>NLiBxWn22$($M9((8=cz#!q z*U~p%W!XyR!&B?0YC_-2;7%}xO0EU7Dr(j}I+K=P delta 1620 zcmaJ>O-vg{6yEi}*WUFHHpT`AgJ|$J#Uz1-kWy3>%wK{d5g?U&unfCR9IY{(b)ayl z9VwMK#+pNsdMTA!Il@vS_0U^e^$=C6R7I+#md&A}H!l5==%rGXzBdMkaOi0Fn>XM4 znYZ)a&hOE0I;0;&QQ%;#L_f?`go@P0|5oX}I?8hjrK% zw4cc~ttB5w2YAlJO>&C;0jD_BV5Qc1qm>a(AOtnAYsNh|E*)a53t0CFwvDkOu+j-O zyur(!19VHt0*&xD=?4E@pJ5#vpPfz_mW7+iIl~UHIDIu~h!fY7$@$FeSZZt%c-#2g z^kQ<3&YNDb`5^-F(~>DJbTJWNx#A1*Z_%&q1N0x$zri-et%x;g*90mU>F|a}_R>!+ zOMHS_t=;sRwOfpkHc*i;LWFKw2^9g3yq zXlCj%ajNwc=SB`*QI&Ri@P?sEchAs%N0gS#5&Et}Dzz{_pJJ;yo3R3n3%(Q|$_Vjo zfFZ?o9F18VmlTSphT;79n%ImKVVtCRAilR*{C39r6n{-DHBCE!#AI>Xmg5az9lbl! zNc|-49xZBtrhn%~P;Mm`K|#h5&LZ>z%#%3aglr~#NWF@XK30U^Yxs3!5G# zTg)a_p>Bm0JpuJ(|}EQ zLoOicU?3&Lgk+!-4)JbGa{m(?<>q_CD#RAM-f2-w+;cC2ALKr$?(psB=$qBEyw zvdhKXno387NUt3^K~W(&Rmo(F#KDXjACZAb*o|a>>O$9`2UX^k!nz?W6E%C}5JQ6( zEy_+10Y6^POVE~~==Ne&skaW4Z|r$nAFfp`b#GsJdf(-%^gMi@CaUo-`X2Sw zU6;$_s9!(Q@A;vPtAV;dQN9LIU}dic>%RW-%$_f_?Whjcedo(F`{=PFJUut^Q|!&} zA@Xc_dQS{*#~%;X#W%|I9hXPki=6%BgKuxwBdMpB5Y5;_;{BOM+L$c<81zfmPH74j zhJBq?OF!KNnK01a2r1d~zZG^gOZ?1z zp_83Gw#?~!0J9`h^qiOz*~#Ntj*wxxBTo7aNqIVMb3z=#P)3+n{gp2`b7#`JtCpCLqeO=L$kY&?`XCF zZ1EiHYSsbPJ;#o6@;dW?*=4a~=jKRk*@FHYw z%<8D{H!5NjI=-WM7iX=KS5~8|l8dKN&R6(aBy$b|IZB;BbzlidD&j^c zQohSXs7kLRA#;`n30H0$^h0BDRh0$ol%=cz2d{gsa+qGmm?|-rWZ`DaA+9jCu^Gg; z0b>GBt40_L(lpBhv_%4oAGhd%?wuB35 z4fwU319(r`<%#X(Z`GNDTOV&6SLe1CcN<66TzeGQ_Q?2ly*)L%^<;12*qRm7{m(B{ zqt_th>?WiKSA*N&yrF$HJxjUT*K93H1@^B#M%^ojahyybR1xstViMsB!W4p*FoV%- zA1V+?gx*=&!(%&3-G#VjuvXk>u-29V-C2FsE9MH9JYV4(n;cw5v31Y>zs^e%ufckO zFbc0M0%(al%UyMt8LSQ~GgzJOaP6e_)YP6@o~`T`*&Cj!O3-L+6sa2v{76WrBl@Paav5y*`=fp9vS$y$alhRv4st z)DYMn-BM!HsRD?J(lt@QiGx==j}k7>oNjySx@zb2UoTp!oQ3W!xhrnN7ZhH358$Us zDg91rUrFtR%$|^$j%CxUd#w(Ep)+jI@jbUgVCXoMRuArU2n?NqNvpe$e-RjTMg9O7 CJ|W8h literal 2537 zcmb7FO=ufO6yB9)W&QczvgLm#ic`yuf0DE$rAeALKh2+IQYTOZVOj5v?QQl)nO!-N zNkPyA9D1mHs(kY?#V!;IJr_bxy%^R9d7+fjL&+_v-Ahk>Z+Gn|h8{YgZ{~gP>CKy& z_ul@}*cj(vRED3bw*`*-1BLwovNv{@VfuzsIEB|ZozL@nC?C?p`LIs%ghxK433?{+k6Gfz zK9(#xZ7NiAqgQlE)n;wx3RhLCDQ@#TPU4cJsfuKqEE{s8GX+~U4M}s!E!DEKyh}hu zWj_obBZ08H$Kx3(m**8OAG!;X)3CxTq0R6{$hXN8D$s~R&VlG@1tqfCaG-6VQ5x$8 z9oR$9@25%P_7yEO+~6L8Hz1T6vAQfJp1 zaIJNAZ2{L-XV)HZ?R9n?$lbNh3Cuq0%U zy2-m1WuMXo$PvmWmRk#|X4)4E%$!%}OnYLn2$|DBA4z&aqpm#p-@X^s+YZPQa9~I$}HbgVoqiDqFB%*8Ql5;Cbiq7DxxegMKp@~9A$50 z`lz6?lABVPxrHB^k=8!<rqzgRdVxd-zppEBem*y8yeO;<7_-RP-KP6y3Ne>ZVfED6EsB_@F3hm{g+3 zutBp%1OnhTi=t#0rY&LDvq0a1ss>brEt|166x$I}2%QKR35y}55wLqO43YH$xI}}R zVErg#zOw;@L4>0S8H8g9!wA?*-GmHjZ|T%tG!=FNm~S~Yj@mJV#6F;{brYWEDYw(v zTfMZEJ-6L?zI;7s}2%3{TOraR=!PO7JR`uWN2)Oh*&isg`T z?|;uf+U}ev->8HgGO?5HugY7K)7$A>`Bo+4kX-G^aQS8>UCpfaJ7gH88sT zVt`K&6h-ovd2GjP5~)$p?~9FqB6=&0OtgiK9nc@^S?k@fH^4yNbf zzi`?ObCFhrW3LH_{ypOrzx9d3iomgpZ&v?_gJw0RjBknh z{~fac(Z7i~hDCSFTu=?aA~5%J*~sBIu~7Uty@(G5`vGbZFte>B00f(8|8l0*)cR!F zj}_IqY$J60k|G(lDl@!buLAvo^vWOt_oNyNUiEpk<3_Pf+p13ea`P&|yBu%Rw*zsb z=lqhtz&-@$*ugBccopV({!i|r!(IH1JMt^ny+^wEk;?mf987zsLVU-{^*s)zy=aJU MtHl0>b( 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 a4739517ad9f9e047186ac7a997ab5bbc7345832..8215d4c38881a902a36750cdbb6bffb4a6946f2e 100644 GIT binary patch literal 4476 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 CKk!Nb 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 +