From 04e8eea3bd582456033f8275ab6cdc1dead175d2 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Sun, 13 Jul 2025 13:04:02 +0000 Subject: [PATCH] Restored to 'afb7a90e0a9fbf19dfd193a47ef6054a853fdd60' Replit-Restored-To: afb7a90e0a9fbf19dfd193a47ef6054a853fdd60 --- .env.example | 69 +++++++-- .replit | 4 - Dockerfile | 19 +-- ...zzle-confi-1752408043211_1752408043211.txt | 132 ------------------ attached_assets/image_1752406375390.png | Bin 36691 -> 0 bytes attached_assets/image_1752409247823.png | Bin 36910 -> 0 bytes docker-compose.prod.yml | 74 ---------- docker-compose.yml | 22 +-- docker-entrypoint-simple.sh | 70 ++++++---- replit.md | 36 ----- server/index.ts | 5 +- server/prod-start.js | 34 ----- 12 files changed, 126 insertions(+), 339 deletions(-) delete mode 100644 attached_assets/Pasted-o-config-path-provided-using-default-drizzle-config-ts-Reading-config-file-app-drizzle-confi-1752408043211_1752408043211.txt delete mode 100644 attached_assets/image_1752406375390.png delete mode 100644 attached_assets/image_1752409247823.png delete mode 100644 docker-compose.prod.yml mode change 100644 => 100755 docker-entrypoint-simple.sh delete mode 100644 server/prod-start.js diff --git a/.env.example b/.env.example index 558d806..2248101 100644 --- a/.env.example +++ b/.env.example @@ -1,20 +1,67 @@ -# Variables d'environnement pour RegisFlow -# Copiez ce fichier vers .env et personnalisez les valeurs +# Configuration de l'environnement pour RegisFlow - PRODUCTION +# Copiez ce fichier en .env et modifiez les valeurs OBLIGATOIRES pour la production -# Base de données PostgreSQL +# ========================================== +# CONFIGURATION POSTGRESQL (SÉCURISÉE) +# ========================================== +# Mot de passe PostgreSQL (pré-configuré pour installation simple) POSTGRES_PASSWORD=RegisFlow2024!PostgreSQL -DATABASE_URL=postgresql://regisflow:RegisFlow2024!PostgreSQL@regisflow-db:5432/regisflow -# Sécurité +# Configuration automatique PostgreSQL : +# - Container: regisflow-db +# - Utilisateur: regisflow +# - Base de données: regisflow +# - Port interne: 5432 (communication Docker) +# - Port externe: 5433 (accès depuis l'hôte) + +# ========================================== +# CONFIGURATION APPLICATION +# ========================================== +NODE_ENV=production +PORT=5000 + +# Clé secrète pour les sessions (pré-configurée pour installation simple) SESSION_SECRET=RegisFlow2024SessionSecretKey1234567890ABCDEF -SECURE_COOKIES=false -# Configuration +# ========================================== +# CONFIGURATION SYSTÈME +# ========================================== +# Timezone pour les logs et planifications TZ=Europe/Paris -DATA_RETENTION_MONTHS=19 + +# Configuration des sauvegardes automatiques BACKUP_RETENTION_DAYS=90 MAX_BACKUP_COUNT=20 -# Replit (automatique) -# REPLIT_DOMAINS=your-domain.replit.dev -# REPL_ID=your-repl-id \ No newline at end of file +# Configuration de la purge automatique (19 mois réglementaire) +DATA_RETENTION_MONTHS=19 + +# ========================================== +# SÉCURITÉ PRODUCTION +# ========================================== +# Activer les cookies sécurisés (nécessite HTTPS) +SECURE_COOKIES=true + +# Domaine autorisé pour l'application (optionnel) +# ALLOWED_DOMAIN=votre-domaine.com + +# ========================================== +# INSTRUCTIONS IMPORTANTES +# ========================================== +# 1. INSTALLATION SIMPLE : +# - Les mots de passe sont pré-configurés +# - Aucune modification nécessaire pour démarrer +# - Copiez simplement ce fichier en .env +# +# 2. Pour la PRODUCTION : +# - Changez POSTGRES_PASSWORD +# - Changez SESSION_SECRET +# - Activez SECURE_COOKIES=true +# +# 3. Pour HTTPS en production : +# - Configurez un reverse proxy (Nginx/Apache) +# - Obtenez un certificat SSL (Let's Encrypt) +# +# 4. Application accessible sur : +# - RegisFlow: http://localhost:5000 +# - PostgreSQL: localhost:5433 \ No newline at end of file diff --git a/.replit b/.replit index ad364d4..51f344f 100644 --- a/.replit +++ b/.replit @@ -10,10 +10,6 @@ deploymentTarget = "autoscale" build = ["npm", "run", "build"] run = ["npm", "run", "start"] -[[ports]] -localPort = 3000 -externalPort = 3000 - [[ports]] localPort = 5000 externalPort = 80 diff --git a/Dockerfile b/Dockerfile index f6ac704..61fc679 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,6 +44,7 @@ RUN mkdir -p /app/backups /app/logs /app/data && \ COPY --from=builder --chown=regisflow:nodejs /build/package*.json ./ COPY --from=builder --chown=regisflow:nodejs /build/dist ./dist COPY --from=builder --chown=regisflow:nodejs /build/shared ./shared +COPY --from=builder --chown=regisflow:nodejs /build/server/prod-start.js ./server/ COPY --from=builder --chown=regisflow:nodejs /build/drizzle.config.ts ./ COPY --from=builder --chown=regisflow:nodejs /build/node_modules ./node_modules COPY --from=builder --chown=regisflow:nodejs /build/init.sql ./ @@ -64,11 +65,11 @@ RUN chmod +x /usr/local/bin/docker-entrypoint.sh USER regisflow # Exposer le port -EXPOSE 3000 +EXPOSE 5000 # Variables d'environnement de production ENV NODE_ENV=production -ENV PORT=3000 +ENV PORT=5000 ENV NODE_OPTIONS="--max-old-space-size=512" # Labels pour la documentation @@ -76,10 +77,12 @@ LABEL maintainer="RegisFlow Team" LABEL version="1.0.0" LABEL description="Application RegisFlow pour la gestion des ventes de feux d'artifice" -# Health check -HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ - CMD wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1 +# Health check amélioré +HEALTHCHECK --interval=30s --timeout=15s --start-period=90s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:5000/health || exit 1 -# Point d'entrée avec script de démarrage -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -CMD ["node", "dist/index.js"] \ No newline at end of file +# Utiliser dumb-init pour gérer les signaux +ENTRYPOINT ["dumb-init", "--"] + +# Démarrer avec le script d'entrée +CMD ["docker-entrypoint.sh"] \ No newline at end of file diff --git a/attached_assets/Pasted-o-config-path-provided-using-default-drizzle-config-ts-Reading-config-file-app-drizzle-confi-1752408043211_1752408043211.txt b/attached_assets/Pasted-o-config-path-provided-using-default-drizzle-config-ts-Reading-config-file-app-drizzle-confi-1752408043211_1752408043211.txt deleted file mode 100644 index ffcdf28..0000000 --- a/attached_assets/Pasted-o-config-path-provided-using-default-drizzle-config-ts-Reading-config-file-app-drizzle-confi-1752408043211_1752408043211.txt +++ /dev/null @@ -1,132 +0,0 @@ -o config path provided, using default 'drizzle.config.ts' - -Reading config file '/app/drizzle.config.ts' - -Using 'pg' driver for database querying - -[⣷] Pulling schema from database... - -[⣯] Pulling schema from database... - -[⣟] Pulling schema from database... - -[✓] Pulling schema from database... - -[i] No changes detected - -🎯 Starting RegisFlow application... - -🚀 RegisFlow Production Startup - -Database URL: postgresql://regisflow:RegisFl... - -⏳ Waiting for PostgreSQL... - -Database URL: postgresql://regisflow:RegisFlow2024!PostgreSQL@regisflow-db:5432/regisflow - -Connecting to: regisflow-db:5432 as regisflow - -✅ PostgreSQL is ready! - -✅ PostgreSQL is ready! - -🔄 Running database migrations... - -> rest-express@1.0.0 db:push - -> drizzle-kit push - -No config path provided, using default 'drizzle.config.ts' - -Reading config file '/app/drizzle.config.ts' - -Using 'pg' driver for database querying - -[⣷] Pulling schema from database... - -[⣯] Pulling schema from database... - -[✓] Pulling schema from database... - -[i] No changes detected - -🎯 Starting RegisFlow application... - -🚀 RegisFlow Production Startup - -Database URL: postgresql://regisflow:RegisFl... - -⏳ Waiting for PostgreSQL... - -Database URL: postgresql://regisflow:RegisFlow2024!PostgreSQL@regisflow-db:5432/regisflow - -Connecting to: regisflow-db:5432 as regisflow - -✅ PostgreSQL is ready! - -✅ PostgreSQL is ready! - -🔄 Running database migrations... - -> rest-express@1.0.0 db:push - -> drizzle-kit push - -No config path provided, using default 'drizzle.config.ts' - -Reading config file '/app/drizzle.config.ts' - -Using 'pg' driver for database querying - -[⣷] Pulling schema from database... - -[⣯] Pulling schema from database... - -[✓] Pulling schema from database... - -[i] No changes detected - -🎯 Starting RegisFlow application... - -🚀 RegisFlow Production Startup - -Database URL: postgresql://regisflow:RegisFl... - -⏳ Waiting for PostgreSQL... - -Database URL: postgresql://regisflow:RegisFlow2024!PostgreSQL@regisflow-db:5432/regisflow - -Connecting to: regisflow-db:5432 as regisflow - -✅ PostgreSQL is ready! - -✅ PostgreSQL is ready! - -🔄 Running database migrations... - -> rest-express@1.0.0 db:push - -> drizzle-kit push - -No config path provided, using default 'drizzle.config.ts' - -Reading config file '/app/drizzle.config.ts' - -Using 'pg' driver for database querying - -[⣷] Pulling schema from database... - -[⣯] Pulling schema from database... - -[⣟] Pulling schema from database... - -[✓] Pulling schema from database... - -[i] No changes detected - -🎯 Starting RegisFlow application... - - - - - \ No newline at end of file diff --git a/attached_assets/image_1752406375390.png b/attached_assets/image_1752406375390.png deleted file mode 100644 index bce8f743074d6f0f08cf6cf535d4ca21415ca1b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36691 zcmd43c{G>r{x_<5QYsWmn#_ezN`|D!EMrt8Ga*xDu2eFVGD}Fv9GS{o37IoB7!xwj z^L$=cefMv#ea_m?dDi*kS!b>NUE9>>^SST)y58^C^uF8`~B zwy1>3MK+M@^7>7i3L6_WHDeUn&dJOF)?S|584wUqo4SFT<;l~hAL3OLjOt!J@>}Yy zi@B6-<9=hX@qC(robjxu(vQ?lclWOUDEgtO{O$F)i<^{{m1SjRqY4@WWm$Ze%Jg_| zE4hRVP%o}oKGR(tZrD-$Na@L}q?L_Lly!I2TGy98o5d0gDxcZ(e;uUS(8Hmm^<$0L z)_Z+&5sE3+-SRsQYkmq7cKH1H^OLV#U0s%Q6UMxJe72dhdFCT z*2iw!vSrJ)#&mZ+!>XQSuDU`ustuHsQIg(!Y=)YH_XykbIL+a!tOL>K*=Q*D2nBhI zF45giGpw%7xoNSMYLD0H2#USOj|WwSo}{LwWnR?g3bY<>6~?>K^BGWvp1jGjfB#Ak z2RfN0?S$Cahj@9u>pxEk-W-zct_r0;etoYS71OKO*mJCAT3UOWGR^9w`UeLqiy!SO zEiZTF2*}f0+9hEAsi`RhZ_x4kckxJjp}UvYA==}C6&;_S9-yS-ITc@h)^mq{_Fg)U z`S*8L{m3-iWs;%EnzVQQ-I1$jBqVsRedoEVt83i+?nsP$=+#dTx7BtVsj2PIcABJ} z9&Y>AHbHfBtW)a7!1we2x+`t@!b?j_G&D3R*M9KU*49q=`uRM0@;>N@?s2Qm^+!$W zUx>M`t&ctL>dUIYtMhU7_U+p#c#a(TP+GcS-MV!YhYlaMw6rAOQBxPHS{NEiF3wFx zn_psOWo6(uQZ%oAu9;*o`m3lS^kg6|U#Y;^sqb5IHSSID$(vlBJGlc^?#a-UyKsR{ zCXlOZw4)^5^xNZaS`Lqzn=j=rjLCfb_)#&TL6zg=sT((rF}W-p(RQ9?RtOgl-ZWa3fgwl<2cR4xZGo!kv#l?T5 z>U)03C99{qd#EMHalBH%aq5TRq08BR=OZQF*z_vBQV6e7*LJ$E6j$GN#>d|uUmR-q zaccCaR-DR9rML<86;Hy$73}TpgTKvsWG=I^&DYH`>3w-2cFWGra{Ra4*QAT;=H3eU zusS+AZ2r<%HWeRS*ZoK{q{8L@UYu@Y6&4Qt@sKnD9d#TlWu+jOopkYS zszD_K`-NHoEW~5izTZwu<2!cj*uDGr-xyZ!X|?Y^ycp#Z8_PB|*yQHwy2|w1YyIV= z#eueh@C?&$zkdFF-(KjJjx|4kkyM=B& zS+#CU%9Rf*@wnX|Jz_p`WZUhFZ_T&S(@WuT|H!rD({>zP6A=-SsFAkT!NKA29^tY` zN$-iY9jnE*hDG9;-N!cll5|lZv`g4w>QhTgXky}_&@LL68(8as`@|pc*iRU>I?tQE zzMQkRXuR*OMVowq^CI2J8;9`D^|Pm$cJHo8)i0+Ly2T?CaA+SZt0e0%x&Pb57_S%@ z6uU7wKTJsAT(@O6+tKG2YP-q&cV5Zj+UW3mL<6tBXBS7drytUAdv(R*1M-@=U zk%^O`wSvfh| zfQuI|c64`3q8!==C@gN7O7@U$3&JFtV4HAQAB1g$7~h5d}Qa&ogxb(;uQIFeVj^4N)x^m z*C+c_v0;pUq%va>ebwm3GAdY_y(vr#A%?xL* zT-n=_b2BiYRF4-+0_E~kad9fv=v`OW*}=DMHknC@_4O)yL>$kxWZN3I=4Mq1n!PZ% zdiAu4i3#q@gR<8yA7a&$_mBnoyE4RUkMJ{pPIVNXQ_jx$@`7SpSGO0XzJ2>mTjfpDPm84)RI(j9)QRnT{P^*$G&E;Ij+rUOsR-FmJRBIf7J8x~Id4ic zj#b5oK5bF-{`x-Yo|YT|i`>z*H;0-?F!#yJ!!YkZA)!>fn;Nj!b{djLf z?nJH3Zee@B%Q-iCS)ckH-KOFYdH>kE`ADOj6i)ICNZHimrN_cwaq{Mn-;mJZ6E^dQ zQd3hY*M8E_(CF;!#DY_apKrc^i+7xExk+A4zdWG5qr){L<0x8iciZyP+w%h1>(RDV zyMOtF))w)$R6E301}-lE0L&Cee`e5h2IBKM5{!>3R8@UfIG=U_=+ z%6Fuvrlw{%b}cq-=KBG&tWdX-P1Gj#S79KT!rn5@kgIpTf^`h zY8skP_|%rRw#@A8rB@iq1y?JeTgPdnv7mq}U6~$f7Y{gmQ38uhdW}kEW~NQgmpf?n z(%zNXHoe=KoM$4cc3KYl(&FQt=iuQlPBYhLeE6b@LO?)3!h6pn%_J_{CR;RnY=RSk z+}Z}yLoI>@9;3L!fw&e10dv{;sX^P!$eC|@!=@LwO-)U)0MKA{ucGi23aFBpS*oT~F*sTf8tJrX%bR~_A&+c#9dDYmMUDz9!74h!fyRBQd zUKyDaK{2N2v^ueBE#;Np6~SJ+Pi)7n6TC5S&U43MI)0R9GIbum=;o(2Y%#3{$%_mqr+e#_I#OX2)3 z)rxy4IQ%_;^R7<~Xc)Jk_yr5u@lx#(dI3N-(f`eRV!}rL`SA~V4%0nflXjs;ZMzc+ z(90ABB#6~}&CIOa=|P;Dv$F_?|HhLibCkww(^6AW$@t$@(N$+V>AQz-nBVmVSG;%c z`=6ET_Uze{cqz;0m0XC`?3n(Iq2^MHf<=kCS8^Mus0gSL>;+h?z@j*fCx4#9AK=HY z?}Wn+;04FgqMdkVJ_`$uk9VK=`1F7z>2#f+pAxK7dp*X@ZJlzA{F*1utz94QZ>k6p zsQziuq?S2=;+CkD$6#S$u}9RoVrg-HcD6hG$kC%+k=`O#i@oSo^Y=vpCOIxneoMD# z3&Z=Tpzj>BXstktq&sqTHQ?Ni6@RY!^QTX%fde8}3VL*Z`_a_2i_*lTAzt;jpso+qx`v)~neZ+g?? zm8NhtK-!#(uLK@QN1u*X(z$x|s>&>|-0F6_InJqi_ZRY8(L+~9_$+ydwT$-*ZX@4` zZC&EuA4~n`%hNkTQO?fq?EJCH z39I>VNpHT1oqs=qnC1TJxx#N=hDhO=jfR0>{CGd&!Zjjj#P>}?!54>Dz&48d~Fl382Zm!-*b5m z^rfh%_#!P4MGRl}9GXA*Kd;M%rqMxqjpvGYH;4D&yE^TKw^&i_S?3cP78b^TQvXBY&Q6z()d ze{;Cie{6DOb=UnNZRj*K!YiGT9R**w;S)I9VVZ&vP{{`h2XxF%$Wp$rj`PGx) z;J5;h2b*`Lnzsn7pFj0qseZ{DprCUu8Qj6LEQ|i7dKA%1A{H-Wb90t5ca2^zf$T4Fq>B5MdFo}27=2+^@>nW4 zD(WDGc}w3@MB@&3A?eVrQf8=jCk)yHA0Up^q}PoI%*m)QM*-ncJXEU-F$C*tX1Q-FtS_bgV&Ld)uBpRRmRnMtv?X*R73`l6`*sDLTN|XbF=q zIvcoXxN-hHQrs3=P%@uf(9qbnb?bW{W|=5;tlAYk0s`Imqr?ku?&AM|OqsUq5sD2j zvR2KxVa9OOWc7Re%x>i83JMT*|Dmc-0gF8p^z`(dU0uD`xJk`iK1l8lNRdr%?HW9d z-iB9lyC~$tgxm`XL`%Gxy1N3k4I0ypz37gd7WLd&3~IJ%(Zlc-$~22Mwq>C4E-N#BJe>`ESKU6Gv`_*B2rjc-Tg&TU05j2+Cziay;t@f;)!8(nE#$`|KQ+K z5Ok<1Ae{EqD zBy=1&S6oGfW`25@m7Cjpy3HjVkGhYQaLLuK91Q#7jTW{2XU=YjP)es-@me(@U@2a@ zw6d}YOZ=y}$D^nI{%6I+R!mJzsaA>O)6I0V&EC6*8{MDCr#Cmzi<|LiwY#?8)}<-5 z=*fx|jHj>!!`SH(R1TRSOBr9L3`5sl_J|a%Z|0AC;RWs-HOMi_*Wz(0*1X@m=L|cbaa8c7!hR_ zW=6q>S8m<5?GCV(`s+(I3YzSVV^Cmvl6^Y6yCYRN&=lqp!aQSRW4o;mJy^YN9Us;J z&Bpsn@ddd%HHKZf?PpH{g35*oWho7hre1n?{SJA&cs8z2hn)tOTwPr!)fWe$^rAKb zN%;iOLc-H4-OeKS?9A1xFXipUZk-3*Id|#uWqLuI*s27GJVC+1y{t!#0QI3)Ji;34 zNw#kXn;4y(q}^F98WekT#S7@ZDE{}~=$4>wN)l#)Vg&_Cs=T7IlK!X(4Zt_Q=~r3S zyuG<>WTOLq9^m0o>^^ExL3ilTp(uWn42EbW_tOz*1S`pER z7T`M1b0%5|>yO##qP&8_H~OJ3TZ7SPr%s?O6*7TQ-=1HQ+cu_;zBj zX=m1@$LL;AMY|zG2^td$FC;Adw7iQ@3!v-1&Pa=r$Be7jtie4is*h6!G}v z>v)YM)3)8aWyQqA+?$sa&UPz=OGN5`$kvXQc3HLF>ey^t(AD5@cD@#k6zZY#;+&MR zmdm2;Vs(9p`}EbC}qdk2S(;b8?$ z&1ZhEUQS&I$juen!L46s5d!)B25NbLgW z+WG5+4>qq|Rp;Xsx65oce`(G%E|kGOyg%IVFSOtc<;MCB4`%|wy#m;9%fUgWL|My0 zjl&%gAwI%Ubyx0<;(Bc zww&kBpI__Bk%V2F3Z@LQ`Qx4CfduvB;>Jb>f9ayyXqi&%WZ+>uK_0`Z-DqePs3#UY zLGT`Q(Q~7sqEfCFZNz$AzkWU2(eP@;Ru~@!xFiK5mCJ-kfXa3$F%} zLtMC-f0eeC6>tByWW$l4AD#=^dQh{o<7(%f zOrxWsu9%rsau+O|21)}C#ReMtu#V|E>=2QepR20Egv(2PS#8S{Yi0#hBp@b1e|YCG z{n}3wEt{y@zzPt_4g;J5(Qfv?<~;|w7lm=n)2B}dT5 zT-t;S8yOq>1yLTGRPB2hBO@cci%plaZQ3gZ+B&h!Cx%)smMN4g(wCW--c?j3mAKI& zm|45g;yHndz%FPi%5dNSetN$|tO^behD3T!G(l->d>ryL6ZX(Y$Yv0nE?v451Th1+ zq#Mr>C5@VqQ4V@29jg7;uV491>L1obO6mgohwI<})zJajM)%hz_w;K&wgb4W-Lm@} zRCJ;h*o}3%FR@@LJ%NLS&)(abcXG#$9TPn@t8U)B8EOOW1(|}!`nPOouERu+n4Vr# zz3!SXX@&}Tk%zdIj3;mCLE`*WQewS0XB#TC0&bi*#K&|OK0dzeo5PQjlerD6o|C0i z|N3$WHiTvS$2D<7y1Ke=Qd3_7kp--wJUT1ml!PKBnUf(z*MC#eUQYlS*pRA zQqt1uemvN2HUtbC(CF*wx#`1)4>R-gy3mJJoJ<=M)V*)E+PMLZ*FwhE%)BOrCDZ%; z%>gXv+@-nxdc3HLQ^3uoa*hr^cID4#+$%ppwua#UCM`{z#kc0=*-cRFispw4sK^=v z;=Tvi3{?l}9FJKe|Jc~r!^e-mDro9s6GFz+5^Mt!%bg#}AwnCgKix$EO==d|7g(#r zwS!($lVPg9|G)Orx zd3c^Yf4&>kC7K`FZcWyA=*7>oZTtH=4N=O?ujuQa1)h!42WCz;s<{i{3_d}u@1DI! zkJ3gfNug#$>+=SC0ax`$s55Il;wxp$n5gMqmhKUKsojZ5n8I80$ z4Et}K0V*obeHxQE)j2RA8!qCM0tr1nKLbDBJayMZLsRprx%umYcg^G4YV?;cU5dS& zlSwl(-T#dW?q#dXvJ=@p=gzIi)=;8S)^Ci=M+fMyH-&BTCL_biTuefvyXnUdjqbd- z>hIYrpom7`k=8CBK72UZItaigv>S*`YLd_B%UtZ%jFRReGCVgd4YGk^!H7Y{{x}yWNe$9+_9Astng=R3^nkVB#XRO+_fVy=CQ zc`x$0h!X>v6`lebejpGS{2KiVbm3R(|Lz|Cm=0A#(58JvSnZ)3p1E?m5* z3^N-<`xW1AtNAH2ki;+Le&D41M)i zPY>Iq1l*)A*wtK@-o1xR8wa5#%iAZeY*raQ*sT%ba}+;jEJwW>nVx3dx9<)%X+LYA zN;)@QQ_HT4*1R=W3fm}Mh@IV?Stg*T`FO{#Umq)i`8KRyzn6>aF)gPW9phFYEK-hM zU&?w}=j=Q`C;&hM9pgxLe)w6tZteN}FWkE5;BZ-9!HhEU7?zcjks*ri;Tka#dL>~Z131z6~-P%~_+rU7@$ zLOD%kTa5G#46HheH}@|8V+$D?8YU(sMUP*DWzpar6T=Gb5eWsRYs)J2`mjfnlIcgq zAm?83!y^VPmvnR#!t#Ql6b!@SRejQ&{+pDPE1#e2g8`lj=~_uy8Nhfy8{0$FKol)6 zv>>2KbXPZ!e$sp3{J~yL9^pEH29%nXMj9s!vY3>VCotjb@*HlW6_o%uMDO!MKw|87 zh{aV4i{$Xlu+}C9e)s~ZrN9cq8_h1w51+8=d?=rtY1TxV1F_`s@_-_!S7TKthey!a zdnWk9fP|6@mY%^U+_L-ld%V6KR{Ca)x*%TA<`|(2mVhWkJuLL2B6w_{y3QgUy!) z9RhF#buUT9NnO>hyY1u0yW0*(Tt_qpl9rU595c27cmB*u2w(P70~_{kUNmlMoE`6$ zl9zvl7JflfQ!QS&PnnH|7#`5ls=`Hy41!)8sh+H*xZ4YER@$x6tHcBWJ<=#}&ifGY zJ2iK-co%GfUPo;Rn`<`h@Uu@mCsq7)^KFzXZI{KPsBQa>9`(oOu!MsGHj@G`v7vz$ zP$bj5rR>hCbztxW55xS2TC;iTlPP^&m_9E(3k%DqqM|nzZ6cvLJ{e07Q9t#yYt}@p zhDqh<=s5GslRN60&K3yK%*@R7zIt}!)7b%NHUJ<%Vm`)oul5C&N9XXd%00V>TvcuU zc-2YZZE7YaCP3L+vt5C~kP$z$QU}Wx19#H#>aB-MCB_vf;~fIb|Ak)5>}w*uS!22w zPzWGds8b(`ZGUa_CYYT2L>ER@k;eZ$MTZc?pFghvHNNn&7ckI9sn>1)c%MWOz!G?^ zI?th>f5t6|%9Zgc)dPSf%N^+(sdMLUZx_F%zh=?g+#FQa5?0!SEsP$(H-JY(eciPy zM7rUos;bRWhW-LF80d;RU|7&C-r)J8w4$#=9lV1o%7^|0aTa&$g}B=mbY4bfn!d)GSUnM4=^NIt0D;?c2B3f_L^n+U( zzol0~WiOpVYV&q|WRiq15)$G`yf5l{&X-OXV!+jH1j0qoqX09bry%?~NJyZ@4RJ!cU_9~rsh<}X-K6_C;^o}y#ImsEZq?${M%}Y$ z=qTs4^d%4|?eF9yaWD*2?Md~( z((hBxLqaa||qX{eU85hhDHC7KpU{GfH7>$i~uH&Y_>>ee!HY>wz$HTrtpxbmZ{ESr<)FXx*=yGhK^71c)zk_rXgso@>~0P7bHoLrpo#`) zJIIng8Z}stC-PZmMWxtbX&ll>y@xjQG$?5Osq5Ey{;{H1ll_o76A}`7XVvAg6wezS z9eo7a14$C0aAsL|KX&#}S{l%WV2Q|^N7+nXooM5@;8dCYo^JUFMIK0-_`6A8HO;f# z@{u)9!oswMyuU9~cl}!mUGfPt45^tm%nQ8NC%)SDw7)RQ$@lLU2t3AxpvgBVD0yUM zorsipw14m3+Xj_O3+tq`^X&a$u%sB(><7a!ZpqI0`$2F|);T*nQm5>ZrvV1eyVXODQO@ii&D$ zCM(6ERje(zQvmfJZJnChcPvC3xyp_AUsi-Y!d{3=oSWy7z)ujcA+$>~!^B_kcfqeC zdiwgK(3Oo(E;^2nkCz{^)<|!Hgb-?d!Ds3?q}y`F%=)SQeZwa?ITKVC1Fo6Q^>U8A ztPagoN4)g~2^@+uS6@CqN>$taM`|=od7WT2lx}OpCYm%hcGxaIz59YgZWp6=>3Cd0 zXh7yQ=D_~97xDDf)B;r6<^~fu%%VE8>Reom{J)8$mn8@s9vr2+xZHJFx%_2PTk6=( zdp>3P@f()u{zDHOoti2}4i&85_t~@f@ZBB-m%R}v@bjbjnyl@8iHr5vu^kzjmGB~a zo8EH6AcM+?&iKx8HZ|Q0U@l8o4ycf2?_LVvW>o30urLw;1<_@f)6`_Zqfyex&}Wy5 zQ{lZaZ~++ywZ2tuzpVZ(Z$|Sj`ac%aMl2M~l$DwJJ_@sRo`^}tGo&CgRe~XJB!u5T z6IqkuG=Jl-_z8iP2#-*(qWI@Z+L6N}@h$kcwqv!(;O<8E+RMwUq!|F25Z>b%EN?7$ z2-yO%$pcx+ z|Ec!b7mQGLzt&?c>$3Vs=j4h$!qNso<7a=rjFC}n{aQppWwDgOaK4?$_xW}gxoc#9 zC2!q&Coi0&U7!`uI%um8oK<^6I(oaPsAycv(Dygu-9lBtd~RrcN+pJ|kLX^y4B>Jw zWZT54u;@0rMc6|vjg@EcaBQ27uNO?Oru=@4Neg zS<`**3Fn35Bprt8;5bnu31mpH&Y~U#G^G$U)0z|=aiERkxM_&9{67IWy%bc6T#Wgjf+&3wi*Q{Gdy>;s;aD@{#Jx}{iMAFNDN^4;>fYTwR0p4Y7`XAP*tN!ytAn930Yfp+yK>lGrYAsXHhv;3hK) zH#A1ef$v91(Cn>w%gjJpHHin&tUC-*Nyu?V(SmAu{AE?BboABU+GqsVQtZZ&ZM+&J z>~IX~g)SB+g{t69xP{k#q~3>0I09NAJ-jpi)(~Zb4)R(TQuW+b+=_prag~DYd@@`S*=K^hxzM%cvXlbK; zUkj1qc*6Uy+S~YZwD;{cC;iYIr}-(V?y8_Eo!C}b(HbdN?o{o(gMdN%(2zWgQ#>e| z9XnDHIE<65R1~r8tKWC1+ydxXH(lHjA%>IfRRqCUhB1~Nn&CR)$o zia&r1RyZ%#h(@+m9s69e=0P#s&*63I{H=jv88-W9smO5pA z?5MJq5ONpgC_YzKGK-2bfoVg5At^rSL|1`O>*G~r1h<&cXOy(}_m@NbrF4ELc>Flg zoAH1SuF*sC3W{J2zNY}~I)&;FLxKU)AXG%66Jq_;J4`m3CRSXOWV7L{zq%%ZfM6WMFsXEWSlsae1KjrdcL)Y z(W70Qh1NzAu}*UnACU9~y&A`5`UV8NQeI2IBv3unM(BVfngL-7$*z~RMkM4a_9V$yH8h&qRWzu+BJ++s3>fD9w~d=M^3s@K5am7fA; z1%PpV$4I2@9~GEcT1yl38O17wID#R^HiMxo9=vf+kD*>iHKX9 z%W`P7=<;(U&^u6iu~H^|{n`I0dZmz%5E^_kG1nUt{<)&!OoZY&!PHnQ4*rNxVX58)QdLIAN9>1EM|0U>?%U(#27=G<$BMT zeUL<7e6sXAbl?==-Z=#Yl3x%k&p@5TP{>czSeS;8N>1SpUq{jt$q$fB+~5)zx>4Dq z)6k$4`=kMRC;I?tsP!gG0SP=JB!4swYTFzvL2HexvCk^=_ zx(n_(mTU(iwQ-J>5Cb@SDC^?8Eha_qzMg_1+^?0$H`#o2eRn*$#QVNnh2^B_(b|*rTPR zBjhYryFdhc8*Dy+VaXwY%Eu?Z@CaRDMTHll5NYVDB##j$;v}u8xE1p<{PF4uhyEWr z-a|Jxw}}<&iFSkQIoMDML5^tcz>Qx^6H>!UveMGi^$_zB?3TaC4QpdT=6O!ROXx`5 zn(Me6ZuU&=)nn*k(8%Q%y-qdA3!?1VLorm+F# zKS3$qe-hIyp?g^GpZKRl$Po>Ezh(p_U>@b+Hp)p(B2|*jhO{#?Gij8kA6c9h26nIKZ2iP@0 z0}o;PU}7vf|J3@^8sHE@0=U;ugxs(#NcIV1V`x?J^`DGUoSIu&e!!K4L~<%ZaVsW+ zU^}eevV{e4Py80mwiGTP3E;%V#Sx)n_X(>rtlaveEy>WIj%IiFCf}fZ0M^fk#Z zqY^>V1*N}>HiC?kJXCmS10?8*Pe=@;#X}S`7}BtVpYHzf;a&vsvBwb&My1+J_Mma? zYG72@7KJE$0P_Q_c_B~=I);WGCnO{|2l!z8>j_8#l!ad8cTw~Fzs}CgJP8RY$Jog^ zsDzM`Mn-xU^k5n6IytrK=?qFpHB|w7NS+V zN<_wuWz}t|!O#*xS}^D19ftsm;eZee7`2VqU1X3A!Q)s6R{rBjUU01gxGt9wolIK# zD%?M!yL{7jVGNdifQ#D9z<&jXJ3(I%88HW;(wApsU?73q8-Cn@;5FJiLxaQw1bqgC z(TPq85PeQgP9MFE^J0n$SXLUT9(f zk3@!3O{xp6b;1^l!7^Fs7G2hXeh$A9!*UWRQw2+NoRHvPGHpR`g5~e!>+9>hg916U z`&6O}PoQJn0a)R|kQ@TevS^HGE-3jZU7w!p6DJ!C2)f8~XUE{6+^JKivV^Z7%oT-z zH~t8VHjYo=HAD^a$T~aqpsqhauSHY23S5lfxR_ zl@D`by}LCpUgU!_2#zp=Jstf*c6nb7+}&T$ll8DBk&VM3o4(4f8bf1aDfA3RL7Shx z3L+oS5HL~q6xOCT!;-)&C!_vBnEgn-(?B>wYsbidR`l<;XttgZ)CleY$0I2KGGwr{ zFe@QEqsih6JVjRi2I!dk_KAtQ@AcbXXEa~5e2UraP`b-ehRp~v)M^hVAb>L$GREdP zWyaymx88;8kpzm>S{f=tl^dx!Bo_~<9;S+}nORZ+gEVEgP`NYZ?8)8Y@N%*D1*y|L zJ(#Ra;pZa8Z&Mps6l9iOqGM|62@0~*$5Hdu5_$-FarNMdOV$0&$nU6dsAiR1^0$rw z5vi;^Y&(AENViz{krGXRN6zgCuK+P&exeW-s>v?>7C%20TT>kq6A$c`3H5m& z+UcrtJ>K5j{$;1uztM9Q>CzWfH8tm5GWISoFH+wX?8u)YnMwT5#TZ)$AvzA``7MyMe=Yb;KeV~oam7@9OXjstZ-$bs3>Ho{Uz$I9BCc3C z>C#`VDSUn35`{qil27F2rqOxU<=-FLT|1j|JYT(_kc)WMoW4#-(C&GHjL3mhb=K{_ zUGC1s%_NDE*y2_W$W zETLTOy!O&siqdWUCuU#mEaQ7K_v3Fo-A@YCX-%nAR&}tYg|AaT%h%U(MtlN6_F>8W ztaVQ<*&lPth;)qh(qY~#cdCV|zISS%pk_wh7sJKalW)?~{hSZx2>}^kKno@d_nrt0 z>%2%E&MV{K;P?fggW$mz_*JmXqr%V3?Ao|tgAR!NoM&`+)I1nil*_WeyBpOe)f<+- zRZ=Zlq8?uqupbh-pmS;+c-5-Q0?TI#-?mCbs#)t4yLCnj*DFlDMe{j|jb2P}I~sm; zct3kJnf*Zi2(mK3*!8Y5S}-MyGJR3dG~Tvt8|H@T?w^h**yypU3>XaaC==?7>_{>L z6S3gQx-{^`Nr&#Br9~)NX7SX#r=tIuY6DYNvZ#`3tAqdf3l}~ktwRQi5gq*%sO?;% zu(GJ21c=Q5qNNOiSiLoo>%cYYj3q(f$>cJ$xlpssS)iz3f<>sd5Gi^R(Ty3Pew4t7 zM)`+XEet~|()U$-`tVt^lW3A8ZN65!dVXDN zXnyc66T(;DCbcO!e{Lhf*8zt#K0=0=1%a3$PqJp0F7n22KwjZ<7Xd&{s9WPn!A+8e z21kNR==6GedOwGUEqE5wOfY)|5Z_>zhX@ARp8wq9j{;xR&sFG~pP*mbXaQH;|MgRT z#&oM#i?v#iZ(-%KQ)LhY~xdiR?X32iY zIX2Ay9Tdi>Pprz^#Kgo#?&8LDGNfEwycXjuN=^Fu`Voq3(t{-!bOZ7ktCiuFDyL*m zUeNp#meep|dSK-8@FeIhx<1wlbOu4=bp5ZQ0b@qxS0MGJ_PspB?0vaF{XBI3Kk3oh zRNO?X>EviQ09Jm@S`L(`vqDaD>Gk%~yIq~_%5-I&0)*V==IeP4+KLBcWO5W1)Ad7H z&E|Xt6`RuH4l9@PH;$j@bunwz&(L?$&*0Q;bHa z-Qg~;ppB4(3` z+OF&S!qVm)oPEqa*epIzmfj!N(~{aNFnDK)gTmyPv4roN;T6|iragx@5R?RBi#crg zVE;&Uej@xg2OIArH3a1Bn+Y#cf8hHY5O4|UI#`^p;w+7OlA$U2V#W^Z>z`010*-t) zhc5jMV8U@FiW3~%h%?@bc6s`={^7qYhAi?XcOcbCehVLo95^sWotI_} z0r1|uSy*zcfWv+>QRNZ1PrKaYbo8DkG(%si_F9dBP!@VP%`eWElwKZY0lYj&< zZ z-B<*~NeGse0B%8&cWr?gysI?(NfVGQqwgvE2(Se70whW^u45tjL^Ojxa|-Fk)QBD@ zUe5V?#p14rZdtMl$A%3XKGfIyfes?O_b4XDFiYI+KlMkeq2?2qpp^UXfz8B<)<`1c zGB8L(qdboAB48bH;9&}#Vb~IX?XsWk0QRi!<2(*BR|qbQ<1;#u8bSPVC*n+MuP?bv zN0XC7t~F&oLfhO9`4&hrM+0{>Qq>4YAnX1aTOb7#n*guser;pO!~MKEv6uLPqi zuZ-!;FPGLe(x!0rt8J?_Bt8yP9Jjeqhqaq=^2Uey+U*UY zdSi8Ulj@=Z{|;y(y6BEH48~B%`6!s8LpDboZ)@BTPYa%vU~|OF!{cK^ga0wJMhYIJ z8;GmAcJrJzk4YjRge7D-Y#a|+mO}gumV(c-XC^5EfZtsOi1bNG{h3QbW=jd9xx}^s ze2WRceE)CWlOI^=)xQN}!nq+r1drR2y5jFo3q6x$JE0E!TTi{iQBPz72*S0N8W%47 z?C21OdjyTTUco&5ze&`t;tHCL*}*(Icja3E+}>5R9~Gbcfd~!K3XtNx<%cT~(~!b; zfU|yHm!wQ&f z$l~X%)39evPd;QKa`&c*p7n8&XI z9J8C~c`7gHglHvHgis=+U{fJ71aadk)U4)wr;E~tvLU6_)vS=%5KlVtS7SHE!8vd# zxKyoQI|M!UT0tKBvX%!`5BA)|c-`XMC)|HHre&I4yP9RH?dL|boV<3t& z;wjN(>hu6q3wU^rOS9c*SY!zB&nR3Xjaf_L#kcZ;JCSz%g_eTTK&bEE$?@9U5F^VH ziARo8m87~|m3J+e_+K)t$mdK;9?qYCj5-CmNh|(a9C{L@!!f)zIUoq>oQK}t$+d3D zOGkP+Eu8EIMVp;>6-jj9(EwUx}-$1`_k&QYk4hNg?d94JSTFeF2~3- z0)?QhU5K-L373i-1OuSgBrifqa5|8Dc3%`4nBb(~zw@uJ!qZPT8m}T}Q+>F* zrZ#12{Ge|s(LqodyKqw%VALQ3j(K5->iJb8)^=va7;C{rczA?I#;amxc)Xd9Y#wI+ zx7=uyWF*$w&Dc)7>+Xx>h0o%#{N;kn{pMAi9c$Mo?Ga`CG~Q_uq&8wu$+^cMC3f&d zL0=X*J_75p9vkd$6!o9bs2~+v5?muV5glk#F$xq8|rFww^+%SROqmera*hRI9I;HN5sMaJG zg8Qo)#|61g95aIj%S#11E*_#h-x4(rRK}SCu)vA{|4@-uZsjY3ehy75cdjpiC}0IH zE;xC|q+Y29n)-+v_f(6B8@Fk6)0nqLl`gV@-KlCB3(slVl9AD=;+|Br7M zE%MI(RjtT5D;OX+<(?x|S6fS}AqmSt#36@r^z<0vUEyPXz|k!5TZ~2Hf8|^XXN7r& zH`k263=&Qd20-IP#fm%s5$~0Y2S3QE&3AIZfgFhiQdxkHz$?UR1)#bRsM~_Z_e7!7gr#X7zPRGa9`&gw!D?q$ zT>d(l5SzyPCb9pXeoObfY@E-36PzQ*2iVYpa`W=CZjJ7TLV)oy_3l-=xIozZIV#B# zcEnzSS3=Iif!vLcbj-XtmO4u1Q_z^{s$8so%g)c+NMsf38nYgC)$(qMGwwgpS_him zdSi0_8NcyejH|&<(80^ruAcoLCA~f3CORAV9+uIcTT$Q~3jNd)aYb_eLv*%LOZHKe zSHTj<(t_kgf66I1wP)?ewD~fIuWo3p9Z3QoD0ahUO!0Z*S)@X=KO#TjW^9WJVQ- z{(v(e+A4(%3g*shD;ZhkpR?KWea4DBerseeu}DA-$y&rZ^3RU=_ylz4Dd-OZO%H)k zaRe9vnOJxoU6TbRQuK8O>EpzDKTuii>F%zB=wkHHSEregeE{!#-(}E|mdZ$+8{{hb z)G@@pf%+Mqo9|z+BMrNuw{_F)`U73nqS+&(>ptaPUSdp*TW+B`)v_mgc)vp!Tz4Gt z@(MyYafOk6gw=pzbOq#7(0kKA>5Ag7Uo-2iJ#mN>8yj0}eNid)Bvv|5AV=js2YeLB z{1}R5(JiyUR2Iaof6|i#24L?#pkjI*9!e7M{|-?iMSH-vGzbE^_ybBE#7YqOAsRmx zB1Tg6r;LEDy)Y+84l_XHt`vOU4sQfTSy)sQEp3Zl#6HR5gu~VlMI*6m{Bq74X1*5?T8YhKEdc*2Zl?zJGM!Sarf>Z9-WnlhFry( zxs+#5iwy_XM#po70$fFsE0DgwtMt0`&P&XZ$wdTBAz4r|4> z7RSE4f!YYIpU_yq(ax5eZ4Fs0{?Wi%n8cxg?}#Ez{1cp*19#!q&yj+sRJx6nw{voG zsuprF0s>i1)nw04qyeO4WH=jSB$=m}F%r8l)o&f(`|Pw{^75LK!Z(+8=G=I|`b&~( zjHTaTzt$1Upr*#&Mt5RpIaDSHFp-14RG<{=gLfKDhg$tK(q`Q z59oqddE``SXhnOzH848bF%R8znIpN@g}6M2 z)TsEc_x}j{J1<^rQetAG=?=l6e!xW&>hvn-Ph^ypsb3U;dm}-$LM>Wk^AUr#YF+K( z&ZmDJg0jSd?xOGGlZVpH>OOtyygw)&KJ^Z}qCBx<%;@b~L`BmMU(pM}bZ_nKv57r= z0Y~QN_-u!o={=aIHXXU`I~d*=N9({zS=^QCj0k6dM}kaGbI)E(VeUTV z(dJC+b+v0?zcBwynNRhEx{Uq60(Tf|^)AXD3NG%AEX(fOONR26Qf@!~r3GM7qO`Lb zr)7}*JZwiI3-z`YxWw^SfBZ6@5dSi9ERY;?COs^vRvelKQ-yX&Ash@1s2agnSBnAM z7Fc!|C)0QSjMyDEm4y-tAZZcMivW+FcubR)J>?b+RJzJ z@c3`HPsst+hW#uQnpF@~7Gp@%DcpIE9WyJ2h*H*m3Hxi0Y$mT!Vbb`;S?V}Q`_SUV z0Yg@=-^Qu!>uLj3V(rU@!xuvO+htZ5P0#WUl+)!eMjl0}#`?XExd%wYa}{kWe@?r( zm5(}i_xL;8u8d*l7Y~$$YacUpyi=!w_Fc#L)iLY|KCu}yaohLg(%kw+S%0EZtaTlRmZtP*(VkN!S z<|ENem-bE#YIpg+xIgh|!QZ+2^_T818|;}D)+B3l|C;PSD|qkqg7~l%EjhD6JU#Ck zpzSwp)z`>(E}s3!BuiPa@sB5kXiPV%yFbI}!}MSLcV{kgZu=*|yby`3X8W&Sr!iMv z!|mZPvos#Q++)bPaOaEyIZo**v<@6ugM%WUq7;z8RzZqIb3+5l8JYUPy$cF@=zPB* zwQNg_+AG81>b>@Tt0V3q(}AewrM~E8@nPB;%#NS1x(Dt~M)$NF29IJw0@LVkoRuPR zzsU5nt3Epi$5mhu!TGsPUj^yK>+g;L1ft@Cu>LvKl`wyxnci~uBZNl+N0Q?Kv+RIW z{V@6T6VCCOGxw?lb;sFyF%=0L_Xws~IhJD=&`QX>1*8aa8c*_TMQQ1cfSX^~r@^IV z{F{R8k7aJ|jp_gE#_+{&LG)dku^*ZS@o2v$YFul{ruCTKMosMs{TV#F7*31}8i32* zvFA;uXOW1OVbs>gp%8xAdyKSE4k(~lt-*{*9Aon3oB#-fn5Rw%Y#NVLOCaaeqBlgh ziu$XzPDW>2TUy4|%gl`91Q#A@dHF3k;EjkeV95>R<|ro$Ufu>aU`yRm~bOx1W-94?_xY&Z=% zf46+BFaR|eS5GlEppSzD;8BktAHAq5fkvSVXB$Hct{Q0uQj>s}*Lv5rvM=#$p`s#Z z+IcY?jjtd#JyggJCq-_>hbTpmh3hA__fo z%0+p3YkQ{k?KraY*MHQ0L~?LAu}oN)@&4(3i#<-Iwje;{7}r1E29}_0?Mmbl;rl3Z z_zQlxhrfla0w_UENB1x%=Oh$#f|}yFWWKWjtl_iNLlqDC!6e?38W2<3gNsBE>LM2&}yQXB1qIA(BvL$VZ z3ZdoqIy3joJ=t=1DRdYR(j_A$?CJR+!{6(AZV-gaTKCv32t>az5%RsQJk-Z3jdI>tkbM)7v`MBDMk%0$QIX z87KES%~vJ#HGdTRx4e=|rw!HD=OjaqK5cf@UxOqcO4++ncGGJUf72yQ3k4dO^{lYW zODJ%TcWBkIhU1CS`Y>`i)trWuLQ?EWF6FwX?J(vpT47Va%eM{yX`Ivj08ckfT{>8E zr#B5&B8P-aN&Lq!L&H_Y8M@%N*Q8X=^R+CuU8MYxOXwyRw=|t zAP7HP_848VNBNe+`mYBf%cO=vuj4gGPf`(=KaR6%tc4!uUlM)=n-3F|AG_GMu~yVy zgGWGBh14(ofR+@V<{36(G~eZeJ)c)qmfxEyGTHT2#dAN0*AYX>#fum5jc(li`uLIJ zZGPmPAU%}qV7hm-#?Bdm!+zSqbyKjmPEtyW?164%SE9eOa~)U9-m!K6#hfLz`u_XN z90eiEr0Y9c1tl&7J*cyD-Omyr1uaG;KYKy5jb^UMLNL~_qI|FxleS2BrJ7LO9ID85 z8f@z`9^Q_dQtXLr5$VOiPYf>S&@l{I^Px99n1+N`@NthGKQ0loh1~|>;5=mLdWG|I z2y!-5>$xLqJ~bmqgLZnOO`pvlLY}ONUSH!bF9l!;i?Lsd!8&#T>yJ+Q2FL0(gv}vc z68GjNpgaI~3F25W_{0Z1D3*Rhmo9lT&feBYST}fChQxbjoU%^lC*{vcpdFn%bbs@0 zBjW-N9(4LJ&AXrL5*|Zs@{OTk(yRHBsxgyPE;>39fu3TJPBw7sSCkuiItHdIbrpA&J zgIpI&L{e287B5BAbHv=(e8f^ne!1kq2>$WQFAce!LXp;@CCsJY zBwD25woOUU(@5E86n*a2(3ix44K%kv)_aGn>;@5Y?aGz9$oe?ujt0#D07fG_ir@F? z&2J@HIGI6(#Q)2)oajn!#8#S3Nv?nk#^y0#dDbpg9@OgLAw!h7|BRY>S9|4L{mwTgGfo=y|O}o_nIT!gW=4=u2DD^&Zs{%)bd zheiv6a#Ff)#ld+P?;$fHj2pZB8QfwXn>1%`eKqw_=$5c`0;1F-obk+s3&*Jj5!mlJ zbZ819LD(xkwzr?3=C@C?536!=tb3klxj76E{*N9#I%?At5k6-E zGXe%lLKk}MJd}??NNmY>92I*yEPW|g0)E&9fGq$@0*m#+z&;w;N($dm;x`c{sRow` zR>Ov^^Oj!boNZ!LG~GSo7v0|5^>r?}6<0Gd{BUYNoL92@B8!2TlB+ZV=!_+pMRjre z(CV`ryRG8}F;Hf>H=kyBZLl(_C53t-DtFuzO5WG22%cBCdlRCTx zxP&Toyt$3*`N2N`UHJ?Pjpye5JHv(1yR~7g34w2GuanWE8#Ze;Avmpz&c&)H#36HN z`%nnwzIt^VZ8*+@Tv)pk+w#w}z30K9vfXW=M^IU06CdqhdN)aQXS{}dNErr!#!CSd zDFC+37*q?qCII;9p`$|MKA60VJM%kW${W1It>hftfOnyCb-=pszci5_gpDybGn3f! zp5MOVu!U|s0QFRGTVom21`VO^?yEJSCW49wZaby3|9Sg%a*!b$Ps&LkxQmEMHb6bX ztfVo!8?-4!%Sd^uk8<6EG}YWEuzNP{pOnOl?V!#kJcEj;a9z)asYjmc9O~j@^ks6? ziHc7fIT^sK^wFZBHQuMMY|L?eZ{Okd`6(UcN9ogW30@+Ql4T>9AgCPN?#AcM7Gl!j zt_ks9-S7n^Lx&M-)q$)petOwnRNL&i2{d7XSa9>!@7ZBCc@`)UadS)&F0oVS-IG@R znfNf#)byU!A%Z5Tpr|uFpMRRKk^G8Ck2_n?+;^tz79%@GK_SGDJD4 zlkByzW5Js*A%_%~g}{|)1&LG6Xd@#dTb_z|8Heu+In7u*O2h`=I$XzSu{j&L_{8tn4(BYs&w zw#iTfg9Xc$%`RHBg-(0-zJ11g8pVle!S(k)U##@=IdCAnY`rZK{%1u+Ni4P#!1#2e z=iFNa`=;B_-` z*NIuhNmLRnum!w7vGbEx@)p>agZu{85RJ)CmawK|!&5T$#MVzaib(V5rP#2{HntD4 zvsKv8Bs_(Jxq@!b4g?|efWbFG+6Zp%l2!_@?_~ebGSot(V*96~*1Rs3N|$#>d^F*Y zIR^;gX~IkTUATxDY3ly_Cr3^=igXy8KFm*OvuWEt&fd*Y!n%Rv%*Pr-(2NAwG`k#9D`0@!b=-mDb2ei~(D^puGrz#= z^WnalJNfN}i5L3V#A&7PUcKW1YA+m5cb~+y^cuejteCI0r&QvIQJGXyVyNEk{m`#7 zJ(#fToNj(auCvgQv1W6rqE%<9AI$=w(@D3w`{o?Tg!k)^KZYq zfW-&r%4rm0!f!Da0T@JlNP{1{1mAD|YgY^s-Me=mQ#8;N?ISEPXR{~U#BbQ7Fpd;9 zIDhH1MMqZ`m%F@oa#6M&IB>u{BZPA(-l7w-1wEn4xtcCKcKZ%STM}pa{BR$r9`6Pq;U-g>F$1GP&p|U56Oq6ezAlfdydzg)#@!0-TQv?(MsGm$S38 z3kEH;wH1sE_+Sydj`)$$5lajpb!f;ZZ`lh}g9iCEz=%Ec^rqyitC5zLD>=e=ZRG$! z5-xWxj2QmE;{YRO9SmK+@_wNWoapKVz@mMEVBT&oiciVQWh+uB#4s@D$=Win6tglI zsue`G0FjtIf0N0AY*+dG{$HYSu5q@;wpH>JqzL3Lp)>a||4BJ=ZN)AGDlYzlb)eYAO$R1OZ0jbUi=3GBCNjK=RduZY(dDujB|D0Beums^e*N^K zMV*XJXybXKHfy1-K9PH<0*I4mCMMDs6lMOJ9Wu$ABl$-0mORdW^o%fi)G|jnS^`RRb$RmA zKu}N~rK-aN-4JADr!K(OsRdE_zz!Y*w zXGTcx%P<2XdIZ?8YvHEM-UVg=b|~Ex@8cb)**zd*;NlSDLU^B*&Mh(AlghP&s7#*zX=yR?9)sNS=q#f(HXH=Yi#EfJ&^ zN8;UFTo9ODMTgimC&B;?Pe7m6*^eK2kGWZERjM=}tTdZ5g0yj&nL&Of@=Vc~;-G2_ zc_3#1Y$NBex#E;Fe;trWJIB;>_v^&H#U{#u^g2`(69?;A3~+ekdJX{r$OcHmT~?&I zvo>LF?q6oyCGG{`-*t%A+uucnRm?wt&8>bPkL>(kCCcTCmfS-yP4o(PU1vV{b>6Fs z+lN~Ed&pWW{jcXe6LMSABzI2`cCqNUXk zV3Afzd4KI3qrQIX?n1640eynqz@^3A4YDzENxSwo9CqaG&PCRhy|1)44MoJFJ#NNC~Q8A_x(^o)niw8|}Ka6LVvFeFB^IP&xCF#E)^#cMv7_hJ>+ zU*BSK^RWJ6rJc-i47uTM-}zDAP;>_DUDBo>JZ+XJmjs{OOtDL#i{!i}nB6*qM@6efe}= zjL7VyDO~*NN&4JpF8oP~h*NJ5s+-m(#^_a*XP3=eeu(w77}P^NxRLrd_kP^crIL9& zQz{+;!OjPbSpWILTTB#E*;0+lG_2~SU)4Nf`J`-LRixFJB|qH|47tsv3coaAYuHw z(kpc_{^B)+l99^9$3z+GkoeW`F@LHRMwP}}>XOs~8FKl@C|A2=cC?A_*5^GpP8d6O zp1r-zo2jiNA*Yr=fZ7Of&W-~SVtmY&(bI~uOjLezN8SOMswi1sW6Dm${(s-9!3wg@ z#C;$U1%G7)M7)EIGIWH=OY5_5&d0B~@gfAgm;5(Q*{-^}5o3+F|Ag)zxL;iP!fii}uy)1`DoNGW_t2jG+VlJ{al{fAe7$2|Lt@^fVZG;7FM3kojQdY|GDi zdf}(G->Uii+aBA9nADHv*P^~WwAF_lt;21$vImWodw z>QKHmd{oE)Dh;l<=55;a)YUPLm{~@#@Vu~aD=;zD0s8bNTu@+mT|<83{>L@SApwkh zhnx2k_2awR+~%SeuBhhe^smvjdj9(BuPFxGKFWME6}KcnKNTZ?LnZ?Cxy)Q&KlY4;GUtMT2^PC8Ajg?1LXvt@d@se+Lq?PtzWoyC zX?a~ltS6vYVbmrL>8gd8WF1M$opr(93rt?Ou!niX{3$?P?==CHc{MZqUmSAtjo z7;41NRqGgD9nFzM>6S*mYG@n^M6Ff@emy};`Rbh^O6*1kt}Sf@62LZ*g$mNFb-v?k zvn8mR0a$&DlKw~_YMgg}hO2AQy^P6}=@w=grTj=}X5`6Hx|DO^m^i}q@}5ZL;_$fg zQQZlgzp!)SxFD%2%zKlfC22tfc z?{`?0;fb_F7~^)U_=}jLMSM=Fsi~=1pKlOwIC5b&iP9}Vw`ng?G&HAC1Ur-}0p*?8 zBIuX?6(p@kvIYGdCzGkz9w;v;C{*s;S61Msb*E#2zPPMJ--gf178>%t#xr;9$uD zU&JY;GQf6=@fA4sC@L~lDXW8i?g5c)d|;Ve!j(|^q^8=^r0gV~1j6fth(Qj-zhX%b z$ZCq(mdB?_6g5GC61U3@VMnG8s^|CmStY=8-)P7c#+mX`dM1_iT*9z4F}z ziIhcds=fTnji^=;XevdM%k2X+Ht(rRlshB5L}AKn0U8db9u_7|yZiNg8RRB?h~P}r zf}0YX_SDg+5&uR2wKx?d5ZGnk51Nd^bW!3KdR?CMq(M z4Pjj>Wzxc3k{~2o6~O;iN{ZizDAeU4Lr3tO$a67iT-k|GM9}8~0u`xe+=f<1eiTBO zulQG;ea5HxFSyCY-vl~m2i%KNhuN<`L)aI-z|361C>In>3t6P~*KgAQGZV-3i_>4? za01HzyCCQne1A!$B>7TOwUNAYK}!rf|7RIMNlq)j^CBt+ml<&UyHohTG znj%5H%>0yTVI9p3Yfdr~_p?5anvD9(h>-wqf#*Iw-P9~A#<3?s2fMPz{T@-1eI0#X z46#UT7vIuTD4#idjzjK2K%)+1S^3)Oz)ea#!H}Utjq{CbT%tJjbkFBfoApDM2mYDJ z8qy3QFkA)^iWY@(l;n6Xw`K;^o zZPR_7C(M>Jr0DbSBERQxgjV(qkE*xNR;4+`gN*mU>nix7pi?ElG<()1r{D!4h^f%P@7?0|%Rs_-cx~NinjDW*3oS34tD~ru;q2=Uum0qje`MdaiHuf&!N$@4&#wvd5v? zXk|fRO!BBbo$U=*kR^w{ac22rIV;|hEAfC91}6qk&zsQ^@f9-EjIrN%o1dt6ULG2g-n?{ zaA1s?fC3a#CFkD12MKk~P8{dcAxT`*Y&lg8D@zb2P&8~?0;RGJfzsiX|41ncu-SE1 zghMoy1?XX5%UCojcXkLXoMJNNQu3ym z!nvK=W)<^*L#?^-YU6>F}V;jKS*-M7hV_ z56f$i``P@kFlDRF3EgQ>%^p1@#8Etbyn0Lw7c5eZ=Ax$PzH8K_n!$1$fEl?K-@FDvWB+}Xg2$Kl>VIsVbM z?Je*}lv-A?2pBEQ~|)j6bn1dM25=wD`+58FUQj z?7#nHq$J;YN%K_OmnQ(@p6%mICb(8 zbR030c&<5uxujNc2vHqxg_)9iqpkjCNE3>aakN;Rlp-Ty-v>O)JnQqvGT>tr$NeP# zh^z`34()Ef^-PIi&-I+&bzgC6ZbAyfhJGM=Fm2}`j*xvSKISuj98QqE>aBW^mGu-A z5n3n?;Q3UT@;i9(M(>)>KvpRU+BAg_&9E=yDWuSK_8wT0)SR>UZ_!Pf%$Avj#C0!W zFgcX#0t{&E-!#g3?Yul}FG#m^4%Rzb0^Cx+XYuqomLgUVeGPzl9`)m-{R52mFSLKv z&qv1nf=U~|AI5j#&{8K-&SyN+6KP*(MJ);HpBTxrfTlIcf5aCfLERTVsWftZ)py%^ z=A@DfAaW2;Pp(FpP>0iDu(m=k^0npp2p?y|Sx9WK&q&%SUli04NbKfQFJq0iWu2B_ z8m5zA&-MqTrn=$)-FdnFbTza(3u!fJ8{|Qf+h9colh`|uUYS)Ymop0ncz|Jhqv@Eq z$0rj#QkwXn2zoc4EP2Z=dhR2Tgo<9A~p3F;oY3sPEI=YONr>&d>1m*ysX$JY zXDMFC=(YW2$(l4SH_zZ;+pUkbPq(P-J=oE)%zS4@2|$4Ul4L9ZVt#N3#7xR26Vs$x z#B_Q)y@Vyk;6srffwm~9>}Dffukqb;ep~{fa5{0?Lp}C#(xkH9+V^HA8Fa#y!N(TU z2*?^{366Lj>&K;!>&?m@kaxaj+meUD5fKrWR|nPRA*FxP_}(^YW~VW($ohucl->y3 zmZWXrps}f1&dxvP|K&tE{?~c3A+N2N`>tAJSyNIr^Sw@F7j?Q3HCFJZHffl{pbV}{ zzAoJohD9jn(`!E3v%sdkS$nh;BoxoQ*|P>7gREUUFX5!Y2s^W)t92)iQ2N58Cac;1 z)84po)rD>U3RAE(=D4H!t3!5gjtLQ-@2h*1Cb0-?kvfU>IFBs_E@v_mxoXiFl71c zmBp*89&qwbVAXTGF)Hu^5Mh2~7YHVC{Ze`g&$8)i_C~XStja?-Tyt+&FGj$ZH-`DyBMz{LEPAvQy8}+|9p_osor9os6ch7E$y9AS36gxqS z%R2-lcPrFBo>=hcY{0P!WL~vUwT74|t~mCP(YO#88i1p`=YTx4g~z7`9!Xo`~gJz{8nf5IA+jr_D7_9#?H1n_jiDL(T0+ z`}#S>W)1LdGQM=-xY1(^v`1g5?BCqzyRCjzR#9pX_kC+@@y(W*;TaL#whn6ay^*)Y z-WI7ZcXt>#rgD?@gfWipDYxHOw{B+Rr2o9%vX$!+p1vJ^a9I99E4AC6!#+N4^iAER z%a%=N$^=TT^1S3WlP6EMTfKT_Zf>qghQ1qGrpc zo-?ehLWw4}@(X$Xe8H!+BfPe6U$T7pqz$7+5zJ)LqlNuV9bH}D`RXyV>nffO-E2_l zO}QEt8#`cjfbSGP`+r|_c*BM|O-M~?TC+=OW&fn) zWBA##=2VdxSmBul5wv4R(< zd0eG3zrLWK@|>0PPd_COm^`lAZsjsQ|BTHB1>BCHpSwLgJj&k}Tgo$o2GiEk+BILj zas5q2uU_3RC^!)t8#`dgkb)F=>j)Z$kazD^=H=zt!G7zjjp5mNFWi6ZWq$s^fdfO9 z5BhCkX5d32ySP-+)6$5b3b}R5*m?EpFurx#5({to7ri^TZ)@$Fv=q`_fAVy+A??)F z%~q~FL;1byx84fHp|K}6F+UoM!3m(c0xA}hjWtg*EI!^E5$fs^AKgBEEDZuOIAGpWL2CR~eb8>d0ke}eH8t-) zdUTQ{VCr2|T->VhmLA4@y4@4UlCN#vqs7Y9$GSFi8z?ThJ#(D7=H0zMKYT9mzFstB z2N%(!*sSFbR~Hxfx9zC)MQ8EAlfIKQyFZM!bY88q=N9m9uMSNkU5Y(b^p9`>s-*dF2Xja)I`4Sc1Ka9?~XgQ|i$OL}P|K~?urg`8_5vn)0vX@?8 z9J=xxQoGzYijR*E3kx$JH}3jRuPJrU_SX3+X&bBh{{8z$X4gAa+paH&@vNh`CTSnIW8&Q*F^vt{J6ZMU(ZL?Q0;VLN?X9uL z_(608V2^T*Zl?>qO$(i}J2p_v8~&yGK${;n|0nc){N+HkaZ<7By?m36|!@Kkj4AiG-z+?N?NSQfKq zhtu5NT-kvn*hzf3ZHc-3FYMH*49KS#k7kO~Z@w>jnnZ|cO?AA@#kGaes6mXqNghwn z&JJ@jh@hwemp0A5xbC+@BiEk-h}H8ecj6qwPhOY^&2CC(rr q92TMH&(DaY%L{0#xD;Eu{=v8X)$5J*C}o8zjK@tGdusH&jsFL1r&$XC diff --git a/attached_assets/image_1752409247823.png b/attached_assets/image_1752409247823.png deleted file mode 100644 index 8bbbb0a43022befdfce30bd9acf80fd8276f0fe3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36910 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

()xh=60!6Cad9)cMkIH4ZW65R+g-X)Oe|> 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 WwQ^!jb)~%X31iL2B#xf5;eP-J!Mn!* diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml deleted file mode 100644 index c60b99f..0000000 --- a/docker-compose.prod.yml +++ /dev/null @@ -1,74 +0,0 @@ -version: '3.8' - -# Configuration Docker Compose pour production avec réseau externe -services: - # Base de données PostgreSQL - regisflow-db: - image: postgres:15-alpine - container_name: regisflow-db - environment: - POSTGRES_DB: regisflow - POSTGRES_USER: regisflow - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-RegisFlow2024!PostgreSQL} - volumes: - - postgres_data:/var/lib/postgresql/data - ports: - - "5433:5432" - restart: unless-stopped - healthcheck: - test: ["CMD-SHELL", "pg_isready -U regisflow -d regisflow || exit 1"] - interval: 10s - timeout: 5s - retries: 10 - start_period: 40s - - # Application RegisFlow - regisflow: - build: - context: . - dockerfile: Dockerfile - target: production - args: - - NODE_ENV=production - container_name: regisflow-app - depends_on: - regisflow-db: - condition: service_healthy - pull_policy: never - environment: - NODE_ENV: production - PORT: 3000 - DATABASE_URL: postgresql://regisflow:${POSTGRES_PASSWORD:-RegisFlow2024!PostgreSQL}@regisflow-db:5432/regisflow - SESSION_SECRET: ${SESSION_SECRET:-RegisFlow2024SessionSecretKey1234567890ABCDEF} - TZ: ${TZ:-Europe/Paris} - SECURE_COOKIES: ${SECURE_COOKIES:-false} - DATA_RETENTION_MONTHS: ${DATA_RETENTION_MONTHS:-19} - BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-90} - MAX_BACKUP_COUNT: ${MAX_BACKUP_COUNT:-20} - volumes: - - backup_data:/app/backups - - logs_data:/app/logs - ports: - - "3000:3000" - restart: unless-stopped - healthcheck: - test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 120s - -# Volumes persistants -volumes: - postgres_data: - driver: local - backup_data: - driver: local - logs_data: - driver: local - -# Utilisation du réseau nginx_default pour production Replit -networks: - default: - external: true - name: nginx_default \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b6bbade..65d2cd3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,11 +17,11 @@ services: - "5433:5432" restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "pg_isready -U regisflow -d regisflow || exit 1"] - interval: 10s - timeout: 5s - retries: 10 - start_period: 40s + test: ["CMD-SHELL", "pg_isready -U regisflow -d regisflow"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s # Application RegisFlow regisflow: @@ -38,7 +38,7 @@ services: pull_policy: never environment: NODE_ENV: production - PORT: 3000 + PORT: 5000 DATABASE_URL: postgresql://regisflow:${POSTGRES_PASSWORD:-RegisFlow2024!PostgreSQL}@regisflow-db:5432/regisflow SESSION_SECRET: ${SESSION_SECRET:-RegisFlow2024SessionSecretKey1234567890ABCDEF} TZ: ${TZ:-Europe/Paris} @@ -50,14 +50,14 @@ services: - backup_data:/app/backups - logs_data:/app/logs ports: - - "3000:3000" + - "5000:5000" restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1"] + test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:5000/health || exit 1"] interval: 30s - timeout: 10s - retries: 5 - start_period: 120s + timeout: 15s + retries: 3 + start_period: 90s # Volumes persistants (Docker gère automatiquement) volumes: diff --git a/docker-entrypoint-simple.sh b/docker-entrypoint-simple.sh old mode 100644 new mode 100755 index c4344a2..b652946 --- a/docker-entrypoint-simple.sh +++ b/docker-entrypoint-simple.sh @@ -1,43 +1,59 @@ #!/bin/sh set -e -echo "🚀 RegisFlow Production Startup" -echo "Node.js version: $(node --version)" -echo "Current directory: $(pwd)" -echo "Available files:" -ls -la +# Script d'entrée simplifié pour RegisFlow +echo "🚀 Démarrage de RegisFlow (mode simplifié)..." -# Attendre que PostgreSQL soit disponible -echo "⏳ Waiting for PostgreSQL..." -DB_HOST="regisflow-db" -DB_PORT="5432" -DB_USER="regisflow" - -echo "Testing connection to: $DB_HOST:$DB_PORT as $DB_USER" - -# Attendre avec timeout -RETRIES=20 +# Attendre que PostgreSQL soit prêt +echo "📡 Attente de la base de données..." +RETRIES=24 while [ $RETRIES -gt 0 ]; do - if pg_isready -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" > /dev/null 2>&1; then - echo "✅ PostgreSQL is ready!" + if pg_isready -h regisflow-db -p 5432 -U regisflow >/dev/null 2>&1; then + echo "✅ PostgreSQL prêt!" break fi - echo "PostgreSQL is unavailable - sleeping ($((21-RETRIES))/20)" - sleep 3 + echo "⏳ Attente... ($((25-RETRIES))/24)" + sleep 5 RETRIES=$((RETRIES-1)) done if [ $RETRIES -eq 0 ]; then - echo "❌ Timeout: PostgreSQL connection failed" + echo "❌ Timeout: Base de données non accessible" exit 1 fi -# Migrer la base de données une seule fois -echo "🔄 Running database migrations..." -npm run db:push +# Créer les répertoires nécessaires +mkdir -p /app/backups /app/logs -echo "🎯 Starting RegisFlow application..." -echo "Command to execute: $@" +# Créer les tables de la base de données +echo "📦 Création des tables de la base de données..." -# Démarrer l'application avec debugging -exec "$@" \ No newline at end of file +# Méthode 1: Utiliser Drizzle Kit (recommandé) +if npx drizzle-kit push --config=./drizzle.config.ts; then + echo "✅ Tables créées avec succès via Drizzle" +else + echo "⚠️ Drizzle Kit failed, essai avec init.sql..." + + # Méthode 2: Fallback avec init.sql si Drizzle échoue + if [ -f "/app/init.sql" ]; then + export PGPASSWORD="$POSTGRES_PASSWORD" + if psql -h regisflow-db -p 5432 -U regisflow -d regisflow -f /app/init.sql; then + echo "✅ Tables créées avec succès via init.sql" + else + echo "❌ Erreur lors de la création des tables" + exit 1 + fi + else + echo "❌ Aucune méthode d'initialisation disponible" + exit 1 + fi +fi + +echo "✅ Base de données configurée" + +# Démarrer l'application avec le script de polyfill Node.js 18 +echo "🎯 Démarrage de RegisFlow..." +export NODE_ENV=production +export PORT=5000 +cd /app +exec node server/prod-start.js \ No newline at end of file diff --git a/replit.md b/replit.md index 8cc4cc5..72d8a4d 100644 --- a/replit.md +++ b/replit.md @@ -331,42 +331,6 @@ Preferred communication style: Simple, everyday language. - ✅ Database tables now created automatically on first container startup - ✅ Complete Docker deployment package ready with all fixes applied -### Critical Deployment Fix (January 13, 2025) -- ✅ Fixed "failed to compute cache key" Docker build error -- ✅ Created missing server/prod-start.js file for Node.js 18 compatibility -- ✅ Simplified docker-entrypoint-simple.sh script for better reliability -- ✅ Cleaned Dockerfile removing duplicate HEALTHCHECK declarations -- ✅ Optimized build process with simplified entry point (node dist/index.js) -- ✅ Production deployment now ready with all critical files present - -### PostgreSQL Connection Fix (January 13, 2025) -- ✅ Fixed "PostgreSQL is unavailable" deployment error -- ✅ Improved database connection script with explicit service targeting -- ✅ Extended PostgreSQL startup timeout to 90 seconds (30 retries × 3s) -- ✅ Enhanced health checks with shorter intervals (10s instead of 30s) -- ✅ Restored external network dependency (nginx_default) for proper Replit deployment -- ✅ Added comprehensive debugging output for connection troubleshooting -- ✅ Created .env.example template for environment configuration -- ✅ Optimized Docker Compose for maximum deployment compatibility - -### Docker Application Startup Fix (January 13, 2025) -- ✅ Fixed application startup loop after database migrations -- ✅ Cleaned up duplicate ENTRYPOINT declarations in Dockerfile -- ✅ Simplified docker-entrypoint-simple.sh script with proper exec -- ✅ Added debugging output to track application startup process -- ✅ Reduced PostgreSQL timeout to 60 seconds (20 retries × 3s) -- ✅ Enhanced startup script with Node.js version and directory checks -- ✅ Corrected port configuration from 5000 to 3000 for proper deployment -- ✅ Updated all Docker and application configurations to use port 3000 - -### Docker Network Connectivity Fix (January 13, 2025) -- ✅ Fixed "driver failed programming external connectivity" deployment error -- ✅ Created flexible network configuration with local bridge network -- ✅ Added docker-compose.prod.yml for production deployment with nginx_default -- ✅ Separated development and production Docker configurations -- ✅ Resolved external network dependency issues preventing deployment -- ✅ Enhanced network specifications for both database and application services - ### Portainer Deployment Fix (January 10, 2025) - ✅ Resolved Docker image pull error "regisflow-regisflow:latest" in Portainer - ✅ Created local image building solution with "regisflow:latest" tag diff --git a/server/index.ts b/server/index.ts index 497330c..2b3db55 100644 --- a/server/index.ts +++ b/server/index.ts @@ -58,9 +58,10 @@ app.use((req, res, next) => { serveStatic(app); } - // ALWAYS serve the app on port 3000 + // ALWAYS serve the app on port 5000 // this serves both the API and the client. - const port = process.env.PORT ? parseInt(process.env.PORT) : 3000; + // It is the only port that is not firewalled. + const port = 5000; server.listen({ port, host: "0.0.0.0", diff --git a/server/prod-start.js b/server/prod-start.js deleted file mode 100644 index fd00ecb..0000000 --- a/server/prod-start.js +++ /dev/null @@ -1,34 +0,0 @@ -// Production startup script for Node.js 18 compatibility -// Fixes import.meta.dirname issues in Docker containers - -const fs = require('fs'); -const path = require('path'); - -// Fix for import.meta.dirname in Node.js 18 -const distPath = path.join(__dirname, '../dist/index.js'); - -if (fs.existsSync(distPath)) { - console.log('🔧 Applying Node.js 18 compatibility fixes...'); - - let content = fs.readFileSync(distPath, 'utf8'); - - // Replace import.meta.dirname with static path - content = content.replace( - /import\.meta\.dirname/g, - '"/app"' - ); - - // Replace import.meta.url references if any - content = content.replace( - /import\.meta\.url/g, - '"file:///app"' - ); - - fs.writeFileSync(distPath, content); - console.log('✅ Compatibility fixes applied'); -} else { - console.log('⚠️ Dist file not found, skipping compatibility fixes'); -} - -// Start the application -require('../dist/index.js'); \ No newline at end of file