From cd3d9608521697994df97dfb7b2800ed321dbe65 Mon Sep 17 00:00:00 2001 From: jpmvaz Date: Sun, 13 Sep 2026 20:18:51 +0100 Subject: [PATCH] v_1 --- .dockerignore | 8 + Martinhal_Contact_Site.7z | Bin 0 -> 76725 bytes Readme.md | 183 ++++++++++++++++ credentials.json | 10 + docker-compose.yml | 16 ++ dockerfile | 24 +++ index.html | 425 ++++++++++++++++++++++++++++++++++++++ package.json | 13 ++ server.js | 95 +++++++++ 9 files changed, 774 insertions(+) create mode 100644 .dockerignore create mode 100644 Martinhal_Contact_Site.7z create mode 100644 Readme.md create mode 100644 credentials.json create mode 100644 docker-compose.yml create mode 100644 dockerfile create mode 100644 index.html create mode 100644 package.json create mode 100644 server.js diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..615380d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +node_modules +npm-debug.log +.git +.gitignore +README.md +.env +.DS_Store +backup_*.json \ No newline at end of file diff --git a/Martinhal_Contact_Site.7z b/Martinhal_Contact_Site.7z new file mode 100644 index 0000000000000000000000000000000000000000..90d4f6f609ebc23118cf0e2c789eacc41308ecce GIT binary patch literal 76725 zcmeFa2UJsA^C%9eC{Yx9$7ARvq1X@vML-2pLMyw$=JK{VPAN}@ zVT$y`1hFI@AFvZCg3$s6PA7xHOy2%`jPFiXg+rM<7>ukLXjd`E|w{Qm}ZPp%HRz6T%<9H&jG-WKS4L@XcHxt*eK#S zMjRu?RlX>x)PRt1o$Vr3j7kxFVgVdoLoSuc#lQtBsEjyQT&b@0K{+j0XgnZxdEWiwKdm-^ZP%< z4RkFPCm1oo5_|$=B23?A85A0Do0JS>84}OIU5Y|L zxKJ#CNkoKj15A`a$cTj^0RzutMG}!*kYLS3CDWy3pgTa9@~RL5SgN^+pqm+xE+rKQ z(1S!m1O0kCQx;7T$eF&LK@qOOLH+y!B0Swae1n+bi~`2!ahc)68PK&LIP{r|3wg|e@jG_xRhW^(ihsxGGXjQc<1p+~ft9VZLrFIgcc8dfHfCvZ5)Am|FE zTpX=*BEP2!>Boeh~uCiq@f@o0` zC@Hj3ami79vD7A&9cE)eg%+h4*h?W3!6_!o7@-J^9vHez7?L=^(=@F7?Q-(YW+ zI)7{^l9EO8be`%|xGZo)$&4ykNsKral$Bh>k5ME_CFnFUc%C*WwhEi-^UdIF64M!T zWA-Gh8Dpe;1l@TAp}Yl1MK9NYz5@wsRjDF44mf@A^1v;^(+9f>3Mw$j-6J3XWW|1crjMT*bIVNM`~NE%}xT?8Iygc8rv8FVE5 z8%9P5#d32C*a(i3iBWkwy;FE1p}Dctf}DaL6}t$zNRgbNgvUIW%;*GZbbOXI(<_twNfba< z7J|z{f+7~xX0bS!8A0pXQJBT1)RA&dYmq{fg zTuDk(D{Djyn3`LidAT;Q8WEj7;8ugwfZ_sfW(SKwje=3GK1D4tdjBFW=tdj&WI94X zhO_`-NR~?&HGA`1Kppd3khnY-p(q-nHFJ;{iaVSG%NpuE5-wEjQ3j|%w1d{oe2Ar6 zKX3O4LSXiHPhV@sOf{3?4Fi8zBISYSqEx1X2cd^jg!+O4uz*kxH}A+8cVxA}zif>% zp{InnR1`5$8h}@j2$VWwsUkBFY=MF(edJQ~WEE%)2saa3gFF=-Cy>Mf<*AMNS=SQB zO9FO;gh1%>BKLyjOAw0Wpty_>NDz2_(cqDROQVP*KAkl~5lBY6Lh$606}YTNhc*BX z8+{0Xi7@1%Xptm39h^R)D2-@8Q3BX;26UiMj8QU#QxF>x^TGvNo*-0kaae*FLpT-) zl_h+PyHxF2l90|vb1(TBsVcewFp)eFrXn&i$#Q@w2dgCk7Y9ODvIVMEzd?9xd|VZc0; z#=uFM$Pt@q9S*2vQOqgJI5RzZaP>TV-4SWMFfMtD>Z!WG!IR8t;BY~hpr<+nM<$Gm z%*742CXY2pNOXEc9YN&T)0a_?qDqy046~?lRjWC)h^)%AabkL?)PV~cK3L&5{t4kI zq9lOzDXgk}{nl8hhW=(>s*iu(8c{eQtn2JZVn_4>sagd2mq=NorSeGrMF$b}s#=b) zGqTaYts<6y=Ye{ixW~Y!DhPk3_#nUm_gzsnjd32qK+Kj2cI3ZS@xSsYSVa#W1VL0~ z`^m|RBU4zGiC2KOHrp=|?Ra2hP=GHX2iIDZG z5;8jPw}$r*eAQ~k7w~2EG7wGWUjCc?g-QQF=$ed1$EsNOk6Z%+9ogm|M3fK$B2u+K z_eY9{ZdUEk)l@R@cL*zo5Wqt4CrC&Yq$^la)CdQ``9a+mBbGztNp-dYtP{*B3gO95L83;LJfVP*}b^1pS~^lW|^AeeJ)xEAPvSGTXkdJ=J02NQ&AXbe>|f-$#X zP!XuyO>jNI=>DV^t8d{?G_9Ij*`vp3j0P_?qCZx18ME;|284hE30jBxp}I6nRHQ4+ zFkNNLK8Q|_O%+SbSkTr71QaD~h77S8VuN}mixEM& zgXkz#Yzgy_AesmPTzKl}7|nu23bFgr9EMx`)2uI>7KAK|41#B{XH_Kz%+e4?6WJQF z0>b3PC_q{u0i!Eds**u}obG_ig_1|J5ttMwNoy1V`UrC4a#)5Zmc&T^7m(lqgfCgP1~wOByu{JfbQ%G?fn(m^dE&h~a^_;7IlI7MvI{ zrky=wm~?3}AqEN*DUOh`oNJ()rzf#ZG%kjc78pkmKBy3gX?+Z=CDdg395M+?c>+bW zSj^TDATGqDCXc5~mx-JqL7hMgUHoc;Ef9qOD9WKn$NCV6hC(R>ea@%4!w$0WIL=Kj z1Ah>_nAIWAy#tt<;DtAGYI6;hTBxM4n32?Fs z#?IDE!Kf=4O1XtKO?@B~q=X_V8B6sn0-$rTJRb+z3Kjq`P?b+Wrw4~ZHUbJ=B!x~; z122bEZ76>tLxUN>WCo8H4Negp1muArQ07S?ApyUW5#SyH37uUTUIt^V;{V~85cYP9 zaP{_fcEhdngp64j!y6Gk#1>39lNt?G9t)D&Vr2{}Nf6Et@$l=z@xb`Rk#SWjQHBWX zkg8mD)*-nOkZ4kzf*cFvSuhy`YzM{RL&{VMR1v0u@AJ0dZM80wF07;$MiKPz3{p6o?7Q zM3P%_Z{wh9NEw^>S_*3_1mvWlk_r5c z0;Q2wLaxWm9V^GE7ptE+K~jD8>ci#n{zn~yUl<(He!-Ts|4-W+$d_R~8xotJQ zx&F41ge|q`oTw_&D5S23)kunU>j$lnp0kNc%NQgbw_!6*|499@EP;AlxaJWG@HHlClhxP>t zRDV@=0+*p=VwfH@Q3(A@E~?+bti$gt-t+_Z5B#L+R1~zC2^_^#JR;I>!CHPwS;*~I zVUKzZQPS*fqE;MmB`3-a@$~01=0vlDMFY(bZ3YU31?XhDJ~-cYTn_Y>!7uh)4hLJA zSpTP*^Th-42LL_P-WOOXuvundw!H2FUQDI;5luKK#aIxb%~n^2D~4TAC?e86UcNT5znTimQk+XnWppxI}M3vl&_y$7;X;R8?Er2s-OY3oCV20>I{FTzg% zu^HeO0IRU$^Q%Kgn}xX_H)2-M!-4Z-LBIzT7JEGCpF=4Ix~wD&N+#Ps0u!)jgdop_ zI+U6!Fih2q1>{tdLfs_7?L)k73CY24BJ1Gqf_bp5 zVg1~svUF%aG|%|*2?7ezrwBv-Ae z%_ZHHk3Dn&6-+j20;b(HJ}WqVJ664s{yNsN4urpZ;u`K!a`xCZDz0%;6T@ifkZ;O26Is? zdvd^mi4aR7=%3Eyw5l{7TW5C$?}C&@htgqclp--Qr7mLzJgf!_dQ*uhslt~ch-UxS z$T$H}A<%;06#NdT;y}wGC_r+8cI*j86UHXY4j)sO4wiwl0;u4g%OK8yMn&WijlE+= zUt{aY;634ZVlW+#F%jEd3h1L-qvktodBpHC0w+Y+)gX?V7DH9%W1Pu~P!=`~LdYDc zG2Q+*)2Sbg|Nq5w6?M7B8hB7sTlD}0j#8Q>KRNFjt3h`qdCXwCxER|{+k0+*?TIk#LQ78!tM!ApvIPXKQX5U0aY>s`&8#A zu+x&^K_4gJh*f7Q7f?pS?zb>otm%{I&{z!`j%%qJfgu9xU8vNw1~ZW(S7~%d+B$?_ z%uO^<$C_uNKt^);dNxDNRoE2$%erbdMQ*@OVHQI*>ru`l(hvC?cR#lX(hot>GOST1K7~RMBZ`I86lB>b6HpDR zvd3`(wrf;n5?O~qt@FXWN`#oA0lxuV{uu1ohOSrWbq9k=wGrl0EEzv+HmzYf&;cWO zQUN__KtfV8NJVh62~=bmlI_8zHF=+=UsVT4(7*%-unq7Q>*T4DBxGp;WHCu&yee}` zGP$s|-jJ)1qSVt9VNnu6A{}{(5Rw2uR8$0&iy#pMi4O2LIOfm;{d=ksg4Xn&)UrVU z2VtawYmrPZiQW-1!}wt03z!{q`Pht4F{<)?$n0MTHe{68>@>|*Ckmi;O2ZY^4#-q0 z639MqaRG=1xompu$i-CdfiK7%Fko#}dLA&PhpE~H)DS@1X{Z}@{~+nE1WiII%le9t zFT%q_B!v-;hFV)YVe#cSxp#UJ`cNF7_W2#SpK{!Se$S=m= zBluE{j0R}xZ>Bf>5I?8w@>K(?gB|kIKovmz8AVWZBV$w}S%8|ueg)EoP#xy~D*;tw z)Fyz#;ka7E7SMjVkvL7$sNjthw1BSUS{YtKixH=>9l5|bm;+!1pL(#YP9k%9lQ}VB z(1tYO>`8OVKT91uS7o#j6;>PLzVJ_A7ZTBKvZQ1kH?j_D02Y-h6M^Y~1W2lK zpr}|~>(ZbHDp&*_tCR4)VGP!qfFigmbp3)n!QD$v@1GV9LIa%$xl|DYsvDVDRemPv zEmb@-lu{Ed)^A3zJV8d#I07zV!IevF#DbfCB&0j`>OS0sMml`$hQq2YLGWM!5L}`v$4vNU<|qyQT?dHdQR< zGCas6{dS%nW|s9x7Z(?rQjPB^x&b{HIslavUJYkVm1V4LJ|j?#gKp$5~fJ);2BBnK*RzWU2`#G1z{F^PSU85 zDEL$U037hLBr!5H9Mr4_AeU4xPq8s0TROzUMb}ML(jm1^)-fS|9?WNi7YfPv>x1uyABxZ^$)tBq*W`_X*kj zE^x9C^bPinMnk(k)h*y8z%Yoz*bYZMoEljgF+WNW4;2^4*3d)&ZB{o=v>6IlHUIfc zZTNf`W@Kz*fw_YkSU~9wh=VMl{)l2@ZH%}Om1M*)*2A&k13g%4yrm3ZzeW&F0@XVG zqL^|?`#nQ4sVsw3?^scDN+itGLsu8DwSlTSTs6b?WGgGi87^A=3V8-p9IOVd?Bo|! z%KGO!*>u-I9{=^VY~VLwVv!uQo|1>Rb`qdI4b?BPga>4S@CMqo=u;phdvW_GQiC99 zriasY;^k_oj0b-I9*^3@G|0F!j}VR4==>j_75S7DMkR*CWzj!Bmu3%Y<~jvPeCc52S?LonC~D|W)XsoLuVI22EB@7Xx&zW4#ZuC zmJQMqMCn!K8>sgR05o??HJ}qciztX-|7CsZzXA|Mfd$H{QS$lE=l`gZR5- zG}NC#`{9l;;1$cNw!&t7Gz}R!I*16+rNdLiPHH)*Oah6eA^?aILB>K1w%iE}U@FO` z5X2xa1fOBTQ7$5xD>M|u;Hi$FYAS#MHyrQMleg7Cs|l7zFjmHMhBiMj%w?~}L(>~H zZ>U(EHU2E0Q1GmkC)xh0-V%)*9ZNJso-z|~O)P0VgKgrD3BL***|(jbL4dKIZ@hE@@vD5NAL!2A0&?!cE6P`8Qp4Z@yrGUl~Z{0F&G zybb}^3^Fy#YQ~o8suQiD`9Xq}B1vKdWJGnk5j!`bsgoRPP54yc=tU9q3D~=sQE-!< zl#ua)Bzx)#NZ-P}QSc!EMNHrztbZY`1}oy|swN0F6x1N7#*1_43HJeVu)Y9cZt7%V z#)u7XunB;MhXNsJdQgeHWQLbWinpNgp_c`B1fB;ptKl|8iOFa!$sGFrBb6>fNH7vn z#MWATr43D11G@nba^xya3z$=0Q>IGks=%v>s26^P3vrbo>kCW_Nl%bKT!Z9!018e} z0B}%7uvh$xCYXUF`f3S~%wV9~W z>Anyl^Z{6%1u3gkd>I8kRxQfV7eJClO>HX!iwKrOMQ?JOP~u z7*rrB)xn=8xiyo6s_ZGG`Y4ycFN8qQ)U4V@^|>Sii#{w#1_K!dLIE@yU<#6ukX*c$ zV{a;EN8xQ=uqAR+L`eEoxzR#M&4Rm*S74As)b9wvw=-eh30)MzYg9H>Ez9s886JK2 z7!NKp!}|#EMQZR2lp1Ct+43#9niVX=!y#o=azgBVb}lJuslg*p@i2r$DA1@44fnrZ zK@)TctNN();iX7S(j717kL`OoKLj0*x?|DA@vqM&+N%mQj^(5mJzkTbZ^L5|&x z^fe&cQ_iVor%>QgyA!e^BUGgcv&RmQC|s4J^UN!{`mdD(dcL&8{)B zEV{!)0nq9gs(7kig8n%Dg}WiJcq%$TP60Qg>8v6Ws1V340xEDsp%WE|G&2_gCTJJI zf5B^3*sH2;^#Nd->Q>!z#=1Xf+R)yhPYuma;H81?1aFKa7NAr~4jFALpK-+&W&p>c zidr7tdk~E^O-ON~#sS{2P$_)!`XqX!U;+>#h6L1*qsBv+08FKK)wyTYQC9UHQ+Ho| zQ3uVj=5d*kXgT$TuLKTYm|IcxP{k7p@^kmY%N5b0IP$IyRYFVS6>;S7 z!T7?fH;4s5p(C{^eDRe?h}vC+W<)gl>=Doxi%BKwKB6+FopR7tipx2w5ui@(&r6x3 zfx%a80soQJ!K8posz+W-3C&yTV>9A zUMKM35EOZZ8NDuwmv;UPaq4D(Z6Ju@Jh~OK3G$3DOZeqZ*hWlBvj1#3^oyn7oly`~ zi-Pro>no&eX^lo4?Xp6d4kPJ_f*n^z^EI&nErc&2fx6QF%oj2HY@!_V>VeR7;^E`! z=}ppJG_~##fL&XvOMFypYF>Y1xt?Wuzz^Tv^E(Q2Iq@BTuOyke3$nV$f_7@+1Fo$vtG$Nzk(c7%RYU z#Crt_8+i2s{(?Va@MmZmnvN!;J9=^$a3xq23iM{ndOR zRQA7jf}-GB0bFmBz}w%X7+yopMG(ujUx8NvmJ{9y2M}r$Z!|+2wuGa;07KrEONu#) zIDs7xEDFS9@C*28|6z%aI(w{N;zmdbs8F>8zo5&dp!e@IHUJ;sYimLO;$2znfB^<0 zHAJuh5SrB7s>%%jF(U7_RTU=)oT>;6dsozHJTxchpJ2Tq3Yw#;;X?fhAmhJaLdKy! zCKUe}4P4~EMuNQ1G5z0>fYu~!q=Cf)LSY|FC!J;Qi_L zRiVDxA*(ux|CR)pxTURge}oFvvydU7JBB0q2`7LEzAfFoDqEwVe(x>`%)Vt8Yv`eX*)dI@*S@U|J<5Bx$m;{xx3rOVKgGw3IcZLpMp8oHG3i_Wh4 zn*#Z1o5}bRZ76mBcGaI3Rh$aa=Rp~ zOR=mAIStC4pk?5e7+ZMMm`Dna@Ul}B70nl|K>PV{cm*ExDNxR}w6tXW>1zx$aUd0Y z%;QjH1zZcZpgLP<-fba5O16V%k9l*D2V=^9DAKm@1yJctkaJo2$#~OS@%x!1DX$l;su*cQmVE?lRqrMRT5~e zT981c{U`95!Uiprjioi+D>jcnnM=Z}<}<)U$bQI`c&U;oHseh8HzT7e7}&MWZjCUa zhB#GwVS`Gcsrp^;e1jlTt+^`n|5sZTj)gW>RkI=RtjdtH$FB)F7?SS9$)p1Xij+3i<&& z|5rk|W7jG=4%B%62Rr^pEMaMiV$E~aJTSHFSHlv#P?EO9t5MLY0_4P)h4_FjRc}h6 zFKVfA=aWm07U*uKnqmf~llBHel%RmOCRI@xyPn7dA5y>i4``qPxzkwg4 zS5^J46&lVTyt50x_bSez1&2od)%~b`flQ#K&lf_B36UiE_ixB>6&&)jqSC(#h9-YEd%iOL3FV=svz$;)%rtt+T4Wi_s^FOZgk_!x#x%Z756{4U(q8< zs|npEz6S)m3Hk8v>!|Qi;YWVn9Ph4rUY&m0$*1<(T(vygAh7NbalPS%28Z3OKJ3zh z8|_Fw%txx`5jYQwFRFg3o>zw_Z0R3=Zs_b|$8(%Y%BQdV;dXhSzVek8hZK4EampI_ zJwLjiz=NN^hNrC`)o=A`y)k35w=qj6?ua$%`?}i?d#wi8)&s6MOGBJX;JlCPrTY16 zcm^F?ogA3mweHS}jgQ?vFFPqaDP8=*QA-c97?3~)a9UU!gSoA>9N;ehk9)oDuS~SD z+Vn-dOt)eLaR5)|qRAic&6A($wQ zbV>5CbmC0jjE?Wlvtb{DyXOrd5y~VMz_BTWmZ{B*z$Af`qWc5<0=aG@rVrE{pl-yv zoQd$FJ_sKnZR$qL3{@or+NF-=5!(HS*)C}eKwwwJEHR{6BnrkHO2~8tjOO5KR8=g7 z?j;ls$aClhH)1ULVNyXj{xX7t?&zOx(e-WyT&-! zbrE(F#>8~*ZrjDKlYpWBh!fL;{_F*^28hA+%WmE5y4u^>cJ9Jh;evYbT1^Q=V5AbI z`d2i7_W$X>2=yn(%dz7Q{TD(>p%Uj3v)ET>%rf8fB4OTasSPCeVF(E#qS2Num4-$`molYem8`%|F3^H zsyAYNP+o53S{wJIxn9Th6_5HFp8Ay!_A9&1&Dee5UDqvb+BDc5^1WBijLjo*EuH;R z*Kc$k75w*vhi~nMFB6x&xzOQPKFP2AMuFXcY~2t2bVmrs9+#%PoW9?5Tc2O~AHVX& zGC1oViZiD-S=i#d?#JdAZho3Ez;R1v?esjWh4pM+&wO#^;M$fZ`#N|3mA~~XU-4J2 zM~Q*%vSW=-E}Zpj{E@!H?_3|H6O=d6x=qCTb*~C7v~O-~5WzWWm*`(tR5*6m+Z>;} zlX!j;kKcZEV#1KAo}dB~LBz*uX_#oRAUtml>UF1EEcV=v?L62U31#O$(Y0$CY<=cj7+BerM z&+ArDFK^0+f!w{vXZzOQ%HP^-XXES%qq>KlKYc0TVrBP3TPx;F%F8(2wf6mXCL2;0 z3_BOPetq=BVGp}V;wK)vbmQ&l3)3H%9xK?@+ScT4pq|B%!_PbIOZ;GW@5jWw5^uL# z+~UlOmxpUVuj}$<4nfM5Q)Fx4@u7Rkt$}BSvtpVUylP^|TsRZCy36W5EtlRH)AFU% z@Wo;2hI;M~!XGrbme*|7RAW2in`?bmUR`xPTG-&6wP|%H?7;vbSpBb_daFOmB&4Hnf~Z`Iyq-p z>t4q^m!7qJI?d@#9myo;S#vl@E?3T2TLY~Z=_Pl9vv&ehb=ngJLMy-^6i@DHA`FEsk5zZC%XY> z`=9VT!H=AoZUwHpP z^CxqI=Ge+EZsH8u`tXrFYktwXp=N2>5e27~Ojz&3_ww;9wL0N_+TzkF%QI!sdoE?J zn09-F@7AzS?MA=sK7Ps)r%%}{hIM@Z#Pq>~7WZ1NeH?uMzU{rQnJJGFn*AtLw7l8= z;=b=s=RfVe$hcX#IH&u%25VCv-#lM%sOf3L*(U~U54p8``}+@x{=qrv7VDa4v^MFr zU1yukQ6HBPQET3v+wd*>htti=rD3lduV2sDb$7CJZhoi8c>3!8-4`t^=w@*`{^qRw z$KOwUJ=i!XJZac~LBksRw;o%(Zi}ST`%M)U`{m!e{0KU{?rZm(o3z$_8-MVj&S;CY z#oFdt6+e#a9M+j(YgiQ({z_xb41VJ>tZ~_%I%$hfo$~XXT2|_3QR>ONUwP8%c)5?K zkEKt=sS|z=D$n;XvmQMo=TZ76k9GTpxaLpeAIQ(xYtifW#r^ioqbBV-4AGg_-^=?9 zpEs%EJQA{&R-IPuI&FQUowj&qNU5Z4H-iK9&pLVE8JpN~*5b>OC3P~k@XUNiJLFdy z$JsP4>@RNpVpiBJt3l51&Kge9@fh{-lGd|z6^5Vtq>pjw9ee!S?A4|Xr|7!4-#ab) z_-c_frs9^xg@MNxn8@;0iB^;}KVjOV@_dm@V(qu0ey!$1<@#=tHyi&Rw)@hhTQ6?j z_!^wwbLP=)#)5(7dTnES1X+CU+vDonqw%u!d+*=8UsUgu&%R)fW;bT{)h@miWBTxe zQS*gE@9oNLmDlt3t|uekx1Bc8vUJYvWUb4`eWv|bRLe1`Rwu#T^J#}lR|gN8TN<*r zo{b>x)pH-Gs|Rk5^?hKm?_Q+5RFE&9bY)JhJ`=X~v)wWyGWvRq#l(JbhJ#l>a9w*r zGPTdj6f2(gvk8X&W5ov#j`;BXbLLko-`sws!6SRVmCb)#dSTVxu;m?110L1sHo8^B zyQqC}hQkbRKhc}F;70sPp`uLY>@g%_(fz2SMg51rKKZerLC}y}!Nt~!eOv6B)+?^F z)@^~u#X*wbDUCWbdAq2N?z2m^#=K%$>J2_#@2{~7BNcYz?-jT|9h0-?@4>aTUNTdd337;tU1flcjYuDPc7$Bqzc{hd_l<-YO6;;56lXFj%i z;yz(<1M}TYc3m^wUGMtH!tk|cp$40|`~?flPOQH$D&mzvK~er5of(7Pz0O-I{V_^=Uh~EB#M&nl zUOlX1w8rv;XUQIGQNLQj9fdcp*IqS#$r<_N6vw=Zh}l_NAAGg-Y1p=Y38!V~`_RMP zA8|`^Z>Gn5<`*pw>e|Xmf5fT!j3~Wx$&{wiX44z{?WxSacedn2Z~b|DD~^Z1Y1Xna zr|bPxOD2Ehs0Xc|*YBRx`PydjzYc()Xd^Jq6XXS?hP(wgo62kd)nS(XlKu_DQ`#2o|JM3_)Ba`gC3EU_mfwDO z=a|)HhXEcDvNtDZ=bpS?9^0UMO!Gp2LDM;#gmLM*AI8dCjBPrnPsM|}3lefe$9)J8 zJI8olADNip<@dRMN5hL9b$hI|@SQMbk!~yd{-?IaugK~C;o0&98z$siO84-(PBKx1{JmrUQ{~MCNIXtx?9k- zb%!#N`vk73voa$|C(eIT9p`z0_ID;MlD#Z>m^Hnu%x|L0MpG|=d5=%S8n%^l@0FWg z+1F8bU5^$`1K#$YGGJu=D<+GU*qhoLlI-3mFa3dOIEyqN!bdXsL^Z=$xox;XWS-%|Z)L)$Oe|1r1E z1!>0npm~*FE>3oP6*RTZIEz#IclMWG3zzcOn!9{Fp|$TrhaQQqKYiQR;r6KhE^Ev} z?j8;Cta#S_`$xgyt~R&Yyzjr-#^;;p&YZ*+iqDbeh0_=0bbEYguk-ASoBsajSrpJL z?$N8_ym9>=_th!UpFHExgf(K{cYlSXtyy#X>~#l=)WmBJH=94(v&*ovZrg=pA2&Wa zRlmruLATrx(b!!P_mAG;ZQHx=;Dcs|Qw%%pn^qqE;-hT$r^_W5RxQ+CzjxKHQF9+G zyWQ|asoxK+>$`uXJqyWhk+yhs;Hmg#o~>d{bNUW5CUtHALtll0-KtA3@ApylDeFKm0B{Azj8wp$08N#-}4(;JsO zK4!e>R;`4ExnDjMj(GRwz>8()_c`xA+B7aPx1i1nuhlwhTg80b7F%F??D=4+{Mq4| z0dd`*g7cPb#Z7{iX@{ul`d-j~3Ah!1m**#3xWJtF?VSR0+H?z{e zgna7rJbTUfl3`IhT5Qi-a!AN;d{Wk+n`hmK0sF4+D!x$syp~;d_7zUdW0P(Zx)*HS zXd}=I;O;VB8=!5LqrRpwMY_@t1oKZ;!6U$?5lfms@y) z_E(KY_Z+stf78-VNsX)v?hPw{oN=c7cKZQmHn^GOym)^0xgTfEk=k6l9oxT_I_7r% zD(c!`-+|A912)^%^-1_{IN^TCldK86v^C|EErNWXUD4)>1S}XgF@8n>vxt8zvDfB*zI@AedSu=syZ7_^ zUNov#YTbKThJEqoiVJ#meGkv}EXq1pRJrKx<e{mAnr8)i-kimW|1 z_R?O1WAhd@-J|c=qGb1uxU2_b-hDETir!XidA0TXf>V1}mOp9HMY*AWc)m~9HdD_& zh`2ZXbEj3uJI!s|a&SJMUuk)#Prk)Wv+k?+^WRMAX*4Hp`HqX8bv|u~ZxhOiI4!kd zX84^Qs2_Chq*dKo#tA+z_58;cj<~)2^9`-A74u@hSmZyrc4xo{@BPQ6-%PedZi}+_ zO7Q;J=i}28kM6ddUbb|Ryw$Tb-T4VRVRfBaJZtpzUax@ZpH6eN4%sKpKK5O^!7)Xp zPn%(3lUH=zB_92*OI)``OX}4r82YmBo3f%gY2k5G+L!1hZ3}I>p`_sBhCHuRZ|+?0 zD|S7!;Xs45#T)Kd2Kf71`kuBJur0vlZr;$&BD?dz^V(MZtWK6$ zd6xFqwp_2Pr!}6_Bs=@mo9te_y(E?0`#k3hR&?Zl^7U<;@9Vl(_keF}$&#%5k`HC1kYrJ#R1=a6@IhlRVDPU<5NJkl{1S~aY<%xmTJmAO|7zY89n2&*OT zy1wG*_Oor;72edqtuKohPIDv9kw;O z8sS#==*lmBS|0jgINt4Wy$&nxw*2&|=s^DpU9A?KPoFkDmlnG8L`Lmx)9&UCzY_eV z$-MNXei6~PTYa1qC_H|1<1L=v-C1G%hWnYlIQT@C^lbNGV1sh!@afn3$zSMx?ch)( zGGAiyINGI$Rik50@nzf_Y0pkf&Dwk9y3l9lrpC_AJZH@5qS!X7$32UBP1?1XXxwX5 z*4`fXI^65tv+{ed_hzfs7c5E`;n^nh{UzO$iKQ`H3)UAD94N5pAaTz6bgx|M=eNVt z{@t|aH=T+%+#mFP^_9pGV>1?1-by~%r2lrafz7rTC+r{bF8RUoneV?`nv*j%mA`1B z>zvM=onAJ*U+enyGP#2O)8d! zE`49yKQyIDhm=oEwI)A1uHTe5En&Nz=PX;plzp9g?l0*4H1g`yR-;B<>G|-?nuZ7M zip*s(DR*=a*d=G(O}y^l_*8D)_RbTB!<{EKb#iI=V!ly)@qWqT&;!xwqss~|ZnZPL z_G)Ueym0Rmr<8U^XQmF#sK0!ut>Wm?=61Qo8S&w%&Z*5(ZysII>3PGyoL81z)3qJm zcFHC0i_q=H{Wi`#R^ViNdRjZPw=wf=y+6Or*DZX1=ZU23VTV?k7rP$qw0ZE+@O8IW z9@=|&!`%ZHh8#<9cb&nQU$=5M?$$9cqbR?ri!^Wl^5;q07L+`--rD5Sgrg_YPCpfj zzjKoB&m47jfwXTo!Rw1&)}8F8_wkJEGJD|X%YwbfvW*J{xm)LW9EdSFT(8&sU2`ut zz4EA5|5KvRpOX!oD_fn8xqe`nw(jVPRTXzH8BI4CEPVWVWs*UcS4X>KPQUJU?B#-y zIo^hQ8yW7%t$Tk^lfBuuAhI) zj-n4QrpCH#YWB>b!J_NJs`q86joR^uOebAEAyM=tu+RJ&`uXPqhEut@J$`k)5JH z_H66M0edcu8rSaJuy$MBb2-Deo*uQJmgLAm_bp9t1ZgE%+;d%B&(A&6WXpnOO>b%MUKu)h@qw*}9!ko*t(m>T27ZyLY6`PDQC{ zo3^1(8f**<>{js6-oN%x7v0RZA2XhOcQ(qgJ=j`%xsycV(MMM9WjesNqF3lu&t{`N z&PUXq+_hoMft9f_;|w~7ooY7TE!y+s!iG&|+h6p~9dvYj*G`=_)H6*Gj=u3_+Gx(i z-V&!i3F%Yx8g97lW;N}B>pk-&`q?b?i7{%2eruO(rJ{SNpb4bNg#Xd#Sx3 zx7N$dzl^n3x%oFU@mXS=dwbFHM+>?Bg&q#`6D3oPE9DI?Opy)`^RAa+pl6VC>AKwY z!0=fG10SZePaFNV@tScl#^Y0J?`YQZLFm5^3letlkCgm-51oEY-7~2kKk?o z)6C~bjm|pkd?JkiOO#*ZENT{qlez& z6(c^sZZIzChv9^F%bkvl|30qo$t58M10TBm&2cNM+?XQ1ZLQs=*6iEeVr?Q?*>#Ue z9e!cRD!$*$_cNS!pRTvOgIm_!HrtmTJ3mFY@Rn(GW>`b>cHd@RaZ8-}I?l^=S6T2$ zhb~FJfzR}|Z$7?Z!HRam?9)E|H>TTryqvH{-zPA9UhQEsvQKXExnWbW)=})+>xgqB z=3?hgXY6|~Jb!!V;QA%5oakH!*UmQ&nbi8+B5H-po124{K8c&vu<-Ht9$h?oAOA74 z<^H%=h9=E|maRFxtC#Vufs+R-zqVeT&fTdqv%8ayaGh=3na(}8A4*>z+tISfqM+IK z6IUgFotdRLq@90JY^uILUq;@LhX67^}6 zP4x5Wvfg`4nl#$`)488GIyO*D3YF!;T{@TFw z%(i<*1WMyGp5)G5t@CE4-u16X7ntycb}N}ZpBoNL4b+|#tYx+3K>sl>?&wA9m3iKO zwfBIi?k%y+={F_Umo}(dC|cC!oAVV1^R6jgw)+ZAyq5QCFmB2%yOL3F24ouUZY!6x z<$WsZA#XaNVN2H=#~^rwYH`A9q}I#^37YRImGjuP2Saoa#0y#nykl zJSJ(y^>syhy|-$8=G0$aTF0-^gw!n(;qzO)j3!*R{`5>H>-DT{y|WXtw;Ei2xjeB` znNyt?6K{;z(#+yy&Nzkh%a=n9^vk{!y6)?FS=uNi#m1n)+sv--Od_Rwdby9BIR5+X zhUT(}XRUf2W9n)b90+`RIoRp_^61Tzq9dN29U%WKx0ux~pw4m6g&lIAEZ=MrT-RsK z!?(>BO)$J=zMz|Tow64hl{1-oLz6 z|H`|P!)}Qqr6Jc^zg_W!w?Dx_`^&8GuwItUi&re#_CkKtT6f3rHA{T{7V7kh*w^D7 zzu`xZ%{^{u)g3o~YO4r-gPc?EvL~m9SyfiH{O}_D`qV4quYAn0-W)W&&8bC`Z|@7T zsk9PCz019^H*m+G8GU^H@?Ed_tXVU7)K31jt3_cm`>nOlHovys`#_$Bz3uG6{$9yO z0ZGH(bn(7)IH}p7Za$-CuY6PNm9vy7=xy=Jv-jK1yk~VJiw_Me`7n3Nsy+doE5nYq zzH#)yr_3Q?#|3Ll2FwVlRWxQwuX4+Rc$>7jqRS7uIGBn~w%cyzn5Wg`LgFr?^CRyW zaz`Ww3Rg5pxN}4ia^&z(fW443{>Ks_2z6`K!T~6k&(5X5BmH_Mhyqb)?_>Sb<^6i-;cgTZ)@p%dpbV z)3=>}A!dWg*j`UhRk|4rifZU33}|sOc+gRfWN~p$)Anx4LrtA?=k0&F*u!sQtEZi6 z7v=0(ujRf~o*kXYdo4O)8};H)Pq%j2n^GoB`MPoO_qvS?C!epo|4i_x)N>>Ew|RZP zwYJ-xDHC{tu!C=w`D{1uojdsC>8{_Gj7+HTV)Ke684W&`$GjYAKl;b`O=q_(j5O&}FnRf$S6Z`O_lVr<&cBs9uUqsUvjw|*4$se7>AU#!xeMh6i+l|0I~#2OH0qf9rmw3+3yV@q zPX<~JyBt#xt~;gImmx21ZWtXn#cX`w-5m)pytAC-D?eG_BFn4y!im=R0rt z)M8w4`#7IXPtNS`lswAsUd}Ry)_MJG$Gmu|Wv;tnNn_#rHp!wUXV@JvgRzo0sP~PEJ!TO%8eYYgZa4Sz-P9 zq{UA8^3@Zx+PKDDk?0f_2I=oV<*k43?vkN*`yKyK_Tzh_A0K-D;1qp*HF4zkMp^4D zd+U3o<*iy5*6{S25yv{WH#*fWSOy84rE?8y1G%8aZMn(>&&A&2EJ-`E_4EqcAS ztn0026K?!)So6_qnfax81;5qAbaydqwgFY63bEKAYWZR&jAyAMy6r zM?P(IKah9mdtShfQvnyptX$E9Q+rioZlz9Oqx9iASLCa-x#KN|G&}Wf+9!Ltc6O&? ztItPTy}hw7NRrxb#=Q+K?JazFpRVmPc=H}bxF9^i%4eU)V44U1+>w;H<;XyM*5FF!JM(W%kKAPv0k3!c{8#b>wK-ofBYhMJrhO7A7X;0l z<<`PvNhJ4BxoJnwme005$;>Z1)V1#Wx$j*YK5|_1xwg-NZF_At-d}&KU3;4=OAmyu zUcIv6;vucAgZ9i0`toqvtjY0_gG_=0uH5RVJD`01wnZhY!s?uCV6-`B(V8n(<6F;N z=hHJ}y?JYkG1n^#W|;K&G~fPI=(o>?9$cF-JAzI%+B4U=*rDFb(qWtCtj=#M?%(|U zK&_Xy4@dq8`(nC9=UK(27du_0TSi{4jBY-qRsTU*#htz_b6uV9l^jxTW^S@+!z=xP zT6!dG|1rE<>L$PL@( zPkoZ^wBIr$e9A`tUC)z6>+jsFdddgDPMp}%4D&yVj+SRD2B z)3=_(n%rFfI3}a`xkUGy+0Y3j^KPc92>~q1kYo{JGXnXH?@Mh1}jWXKS9)13F z%fOrE^A-h68WXYpyzQ9GP(e||g_g!`vU+bTlJ5(AGAnuHmE(0SPChX6xpaR+?$zN| zM>CH+)NdSj@br6GWnaVQT^?TFZK9N!b?C~AUw`iL>#tj;a_Z=f+`7YPE5FaXzm3a` z%DI%8FL%Q_I z?_J{1VZ-*hVH*YpU)pwHhVMR$I)QT}H@mmJJZ^NrxW{jXeQp?QV$|B+=aYp=)}_?6 zpcS>E7Met+FTK!+A2PT8_NWmfTx>b{CoQ*6_gmyE5(S;EGtc#4*{*>2*LRA#t=L)D zD*IZ=jEi%oHNCe>?q0x8HM%q{q9ptDK-tTYgG#4-{Jy=3zQp0hn{6crzqwWlPL$`L zJoEkQJg@Gt^7$!V1s%%0f(^?XN4Si1={jZ4$8p|4e2FLTqUnJC^VV

i6}p!rhm8 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 Q-L@;D?O(gvW81X(Uk*==$^ZZW literal 0 HcmV?d00001 diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..0f56b9c --- /dev/null +++ b/Readme.md @@ -0,0 +1,183 @@ +# Martinhal Contact Management System - Docker Setup + +## 🐳 Docker Installation (Recommended) + +### Prerequisites +- Docker installed: https://docs.docker.com/get-docker/ +- Docker Compose installed (usually comes with Docker Desktop) + +### Quick Start with Docker + +1. **Make sure you have all files in the same directory:** +``` +martinhal-contacts/ +├── Dockerfile +├── docker-compose.yml +├── .dockerignore +├── index.html +├── credentials.json +├── server.js +├── package.json +└── contacts_data.json (will be created automatically) +``` + +2. **Build and start the container:** +```bash +docker-compose up -d +``` + +3. **Access the application:** +Open your browser and go to: `http://localhost:8000` + +4. **Stop the application:** +```bash +docker-compose down +``` + +5. **View logs:** +```bash +docker-compose logs -f +``` + +### Docker Commands Reference + +**Start the application:** +```bash +docker-compose up -d +``` + +**Stop the application:** +```bash +docker-compose down +``` + +**Restart the application:** +```bash +docker-compose restart +``` + +**View logs:** +```bash +docker-compose logs -f martinhal-contacts +``` + +**Rebuild after code changes:** +```bash +docker-compose down +docker-compose build +docker-compose up -d +``` + +**Access container shell:** +```bash +docker exec -it martinhal-contacts sh +``` + +## 📦 Data Persistence + +Docker volumes ensure your data persists: +- **contacts_data.json** - Your contact database (automatically backed up) +- **backups/** - Directory for backup files + +Even if you delete and recreate containers, your data remains safe! + +## 🔄 Updating the Application + +1. Update your files (index.html, server.js, etc.) +2. Rebuild and restart: +```bash +docker-compose down +docker-compose build +docker-compose up -d +``` + +## 🔐 Current Passwords + +- **Frontend Password**: `ZaAhdf4h8k79598pHD5H3` +- **Backend Username**: `admin` +- **Backend Password**: `yt33PdH9WgAGR5z4SFDf6` + +## 🛠 Troubleshooting + +**Port 8000 already in use:** +Edit `docker-compose.yml` and change the port mapping: +```yaml +ports: + - "3000:8000" # Access via http://localhost:3000 +``` + +**Container won't start:** +```bash +docker-compose logs martinhal-contacts +``` + +**Remove everything and start fresh:** +```bash +docker-compose down +docker system prune -a +docker-compose up -d +``` + +## 📋 Alternative: Manual Setup (No Docker) + +If you don't want to use Docker: + +### Step 1: Install Node.js +Download from: https://nodejs.org/ + +### Step 2: Install Dependencies +```bash +npm install +``` + +### Step 3: Start Server +```bash +npm start +``` + +### Step 4: Open Browser +``` +http://localhost:8000 +``` + +## 🎯 Production Deployment + +For production deployment with Docker: + +1. **Use environment variables for sensitive data** +2. **Set up HTTPS with reverse proxy (nginx)** +3. **Configure automated backups** +4. **Set resource limits in docker-compose.yml** + +Example production docker-compose.yml: +```yaml +version: '3.8' +services: + martinhal-contacts: + build: . + container_name: martinhal-contacts + ports: + - "8000:8000" + volumes: + - ./contacts_data.json:/app/contacts_data.json + - ./backups:/app/backups + restart: always + environment: + - NODE_ENV=production + deploy: + resources: + limits: + cpus: '0.5' + memory: 512M +``` + +## ✅ Benefits of Docker + +- ✅ **Consistent environment** - Works the same everywhere +- ✅ **Easy deployment** - One command to start +- ✅ **Isolated** - Doesn't interfere with other apps +- ✅ **Easy updates** - Rebuild and restart +- ✅ **Data persistence** - Your data is safe +- ✅ **Easy backups** - Just copy the volume + +That's it! Your Martinhal Contact Management System is now running in Docker! 🎉 \ No newline at end of file diff --git a/credentials.json b/credentials.json new file mode 100644 index 0000000..079905e --- /dev/null +++ b/credentials.json @@ -0,0 +1,10 @@ +{ + "salt": "Mh7pQ2xR9nF8sT4vY3", + "frontend": { + "password": "Fwl2GDVUTDoBBXEBRm0MBhF3eCAE" + }, + "backend": { + "username": "LAxaGT8=", + "password": "NBwEQwFWMGtuCQd/IWFOQgp1CQ4B" + } +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..32c08ae --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +version: '3.8' + +services: + martinhal-contacts: + build: . + container_name: martinhal-contacts + ports: + - "8000:8000" + volumes: + - contacts-data:/app/data + restart: unless-stopped + environment: + - NODE_ENV=production + +volumes: + contacts-data: \ No newline at end of file diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..6236aa2 --- /dev/null +++ b/dockerfile @@ -0,0 +1,24 @@ +FROM node:18-alpine + +# Set working directory +WORKDIR /app + +# Copy package files +COPY package.json ./ + +# Install dependencies +RUN npm install + +# Copy application files +COPY index.html ./ +COPY credentials.json ./ +COPY server.js ./ + +# Create backups directory +RUN mkdir -p /app/backups + +# Expose port +EXPOSE 8000 + +# Start the server +CMD ["npm", "start"] \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..2475bdc --- /dev/null +++ b/index.html @@ -0,0 +1,425 @@ + + + + + +Martinhal Contacts + + + + + + + + + +

+ + + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..4c7649a --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "martinhal-contacts", + "version": "1.0.0", + "description": "Martinhal Contact Management System", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "express": "^4.18.2", + "cors": "^2.8.5" + } +} \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 0000000..a75f0c9 --- /dev/null +++ b/server.js @@ -0,0 +1,95 @@ +const express = require('express'); +const fs = require('fs'); +const path = require('path'); +const cors = require('cors'); + +const app = express(); +const PORT = 8000; + +// Middleware +app.use(cors()); +app.use(express.json({ limit: '50mb' })); // Increased limit for base64 images +app.use(express.static(__dirname)); // Serve static files from current directory + +const DATA_FILE = path.join(__dirname, 'contacts_data.json'); +const CREDENTIALS_FILE = path.join(__dirname, 'credentials.json'); + +// Initialize data file if it doesn't exist +if (!fs.existsSync(DATA_FILE)) { + const initialData = { + contacts: [ + { id: 1, name: 'John Smith', unit: 'Marketing', phone: '+351 123 456 789', mobile: '+351 987 654 321', email: 'john.smith@company.com', department: 'IT', locations: ['Martinhal Oriente'], photo: 'https://i.pravatar.cc/150?img=12' }, + { id: 2, name: 'Maria Santos', unit: 'Finance', phone: '+351 123 456 790', mobile: '+351 987 654 322', email: 'maria.santos@company.com', department: 'Accounting', locations: ['Martinhal Lisbon', 'Martinhal Quinta'], photo: 'https://i.pravatar.cc/150?img=5' }, + { id: 3, name: 'Pedro Costa', unit: 'Operations', phone: '+351 123 456 791', mobile: '+351 987 654 323', email: 'pedro.costa@company.com', department: 'Maintenance', locations: ['Martinhal Sagres'], photo: 'https://i.pravatar.cc/150?img=33' } + ], + departments: ['IT', 'Accounting', 'Board', 'Housekeeping', 'Maintenance'], + locations: ['Martinhal Oriente', 'Martinhal Lisbon', 'Martinhal Quinta', 'Martinhal Sagres'] + }; + fs.writeFileSync(DATA_FILE, JSON.stringify(initialData, null, 2)); + console.log('Created initial data file:', DATA_FILE); +} + +// Check if credentials.json exists +if (!fs.existsSync(CREDENTIALS_FILE)) { + console.error('WARNING: credentials.json not found!'); + console.error('Please make sure credentials.json is in the same directory as server.js'); +} + +// Get credentials (for debugging) +app.get('/api/credentials', (req, res) => { + try { + if (!fs.existsSync(CREDENTIALS_FILE)) { + return res.status(404).json({ error: 'credentials.json not found' }); + } + const credentials = JSON.parse(fs.readFileSync(CREDENTIALS_FILE, 'utf8')); + res.json(credentials); + } catch (error) { + console.error('Error reading credentials:', error); + res.status(500).json({ error: 'Failed to read credentials' }); + } +}); + +// Get all data +app.get('/api/data', (req, res) => { + try { + const data = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8')); + res.json(data); + } catch (error) { + console.error('Error reading data:', error); + res.status(500).json({ error: 'Failed to read data' }); + } +}); + +// Save all data +app.post('/api/data', (req, res) => { + try { + fs.writeFileSync(DATA_FILE, JSON.stringify(req.body, null, 2)); + res.json({ success: true }); + } catch (error) { + console.error('Error saving data:', error); + res.status(500).json({ error: 'Failed to save data' }); + } +}); + +// Backup endpoint (optional - creates timestamped backup) +app.post('/api/backup', (req, res) => { + try { + const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); + const backupFile = path.join(__dirname, `backup_${timestamp}.json`); + const data = fs.readFileSync(DATA_FILE, 'utf8'); + fs.writeFileSync(backupFile, data); + res.json({ success: true, file: backupFile }); + } catch (error) { + console.error('Error creating backup:', error); + res.status(500).json({ error: 'Failed to create backup' }); + } +}); + +app.listen(PORT, () => { + console.log('================================='); + console.log(`Server running at http://localhost:${PORT}`); + console.log(`Data file: ${DATA_FILE}`); + console.log(`Credentials file: ${CREDENTIALS_FILE}`); + console.log(`Credentials exists: ${fs.existsSync(CREDENTIALS_FILE)}`); + console.log('================================='); +}); \ No newline at end of file