Strukturovaný plán dílčích činností
Živý přehled fází vývoje aplikace „Veřejné sklady“. Aktualizuje se průběžně s postupem prací –
slouží jako trvalá reference vedle projektové dokumentace (viz stránka Pokrytí zadání).
0. Základ projektu a bezpečnost
Hotovo
Struktura Node.js/Express aplikace pro Plesk (app.js), konfigurace (.env + zod validace), DB schéma (PostgreSQL, bez závislosti na CREATE EXTENSION), bezpečnostní middleware.
✓
package.json, app.js (Plesk-kompatibilní vstupní bod), .env.example
✓
DB schéma a migrace (node-pg-migrate) – lokality, boxy, uživatelé, rezervace, faktury, notifikace, audit log
✓
Bezpečnostní middleware: helmet (CSP), CORS, rate-limit, CSRF (double-submit cookie), JWT auth s token_version
✓
Validace vstupů (zod) pro všechny API endpointy
1. Integrace externích služeb
Hotovo
Comgate (platby), vyfakturuj.cz (fakturace), SMSbrana.cz (SMS), SMTP (email) – vše plně funkční v mock režimu. Přístupy lze nastavit dvěma cestami: přes .env (výchozí), nebo přímo z administrace (/admin/nastaveni) za běhu bez restartu serveru.
✓
Comgate: create-payment + server-to-server ověření stavu (bez slepé důvěry webhooku)
✓
vyfakturuj.cz: generování faktury (2 položky, DPH 21 %/0 %), PDF (pdfkit) + zjednodušený ISDOC v mock režimu
✓
SMSbrana.cz: odesílání SMS (SMSConnect HTTP API)
✓
SMTP email (nodemailer) s přílohami
✓
Runtime nastavení přístupů z administrace (app_settings tabulka, tajemství šifrována AES-256-GCM, bez nutnosti restartu)
settingsService.js, settingsController.js, /admin/nastaveni – přepíše .env, dokud není v DB nastaveno jinak.
⏸
Napojení na REÁLNÉ produkční přístupy (Comgate merchant, vyfakturuj.cz účet, SMSbrana.cz účet, SMTP)
Čeká na dodání přístupů klientem/uživatelem – lze zadat přes .env.example nebo přímo v /admin/nastaveni.
2. Registrace, přihlášení, GDPR
Hotovo
Automatická registrace při první rezervaci (bez hesla), přihlášení s ochranou proti brute-force, reset hesla, GDPR export/výmaz.
✓
Účet vzniká AŽ po úspěšné platbě (ne dříve) – viz paymentService
✓
Kontrola duplicity emailu před rezervací (nabídka přihlášení)
✓
Lockout po 5 pokusech na 15 minut, hláška se zbývajícími pokusy
✓
Reset hesla emailem (token platný 60 min, jednorázový)
✓
GDPR export dat (JSON) a výmaz s anonymizací (finanční záznamy zachovány)
3. Rezervační flow
Hotovo
Lokality a boxy v reálném čase, dočasná blokace boxu (15 min), kalendář s povoleným rozsahem dat, kalkulace ceny výhradně na serveru.
✓
Veřejné API: lokality s počtem volných boxů, detail boxů (status, cena, kauce, popis)
✓
Výběr boxu -> temp_hold transakčně (SELECT...FOR UPDATE) proti souběhu dvou zákazníků
✓
Kalendář: nejdřívější/nejpozdější datum nástupu per provozovna
✓
Kontaktní/fakturační formulář vč. skryté B2B sekce (IČO/DIČ)
4. Platba a automatizace po platbě
Hotovo
Vytvoření platby, zpracování Comgate notifikace, aktivace rezervace, generování kódu, faktura, SMS+email – vše idempotentně.
✓
Anti-tamper kontrola ceny (server přepočítá z aktuálního ceníku boxu)
✓
Idempotentní zpracování platební notifikace (Comgate může volat vícekrát)
✓
Založení účtu + přiřazení rezervace + generování přístupového kódu + faktura
✓
SMS s kódem odchází okamžitě 24/7 (výjimka z denního okna)
✓
Faktura: zákazník (PDF), správce+ekonom (PDF+ISDOC)
5. Prodloužení pronájmu
Hotovo
Opakovatelné prodloužení přes Comgate bez nové kauce, kód se nemění.
✓
Nová platba za prodloužení, kauce se needbytuje
✓
Aktualizace date_to a nová faktura po potvrzení platby
6. Plánované úlohy (cron)
Hotovo
Úklid vypršelých blokací, denní expirace rezervací (box -> V přípravě), upomínky, odesílání odložených notifikací mimo denní okno.
✓
Úklid temp_hold: každou minutu ruší blokace starší 15 min (tvrdý strop) i blokace, jejichž formulář se přes 2 min neozval (heartbeat)
jobs/clearTempHolds.js – findExpiredTempHolds + findInactiveTempHolds(TEMP_HOLD_INACTIVITY_SECONDS); zámky box → rezervace, box se uvolní jen bez jiné živé blokace. Historie cron_runs se denně promazává (prune-cron-runs, 14 dní).
✓
Denní expirace: rezervace -> expired, box -> preparing (NE rovnou volný, viz AdminDocs/AIDocs)
✓
Upomínky před expirací dle konfigurace per provozovna (výchozí 5+3+1 dní)
✓
Dispatcher odložených notifikací (mimo SMS okno)
✓
Historie běhů úloh zapisována do cron_runs pro status stránku
7. Administrace (admin)
Hotovo
Správa provozoven, boxů, zaměstnanců a přiřazení správců s jemnými oprávněními.
✓
CRUD provozoven (kalendář, SMS okno, upomínky, číselná řada objednávek)
✓
CRUD boxů (cena, kauce, popis, foto, ilustrace, stav)
✓
Přiřazení správců k více provozovnám s granulárními oprávněními
✓
Vytváření účtů zaměstnanců (správce/ekonom/admin, libovolný počet dalších administrátorů)
✓
Dashboard s přehledem obsazenosti a tržeb napříč provozovnami
✓
Detail provozovny/rezervace/zákazníka/zaměstnance – prokliky mezi souvisejícími záznamy
detailViewService.js sdílí logiku mezi admin a manager controllery.
✓
Editace vlastního jména/příjmení/telefonu (admin i ostatní role) nezávisle na změně hesla
PUT /api/auth/me
8. Správce provozovny
Hotovo
Fyzická kontrola boxu po vrácení, ruční reset přístupového kódu, dashboard provozovny.
✓
Přehled boxů čekajících na fyzickou kontrolu
✓
Zápis stavu (v pořádku/opotřebení/poškozeno) + poznámka + přepnutí stavu boxu
✓
Notifikace ekonomovi po zápisu kontroly (vč. QR platby na vrácení kauce)
✓
Ruční reset přístupového kódu
Rozhodování o vrácení kauce, přehled a export faktur.
✓
Rozhodnutí o kauci (celá/částečná/zadržena) + upozornění zákazníka emailem
✓
QR platba (SPD formát, výpočet IBAN z čísla účtu) pro rychlé vrácení kauce
✓
Export faktur do CSV, stažení PDF/ISDOC
10. Dokumentační vrstva (tato sekce)
Hotovo
Plán, status/monitoring a pokrytí požadavků – trvale dostupné vedle aplikace jako živé zadání a kontrolní nástroj.
✓
Stránka Plán (/dokumentace/plan)
✓
Status/monitoring stránka s testy jednotlivých funkcí (/dokumentace/status)
✓
Stránka pokrytí požadavků vůči původní specifikaci (/dokumentace/pokryti)
✓
Dočasný rozcestník na "/" s prokliky (do doby, než vznikne zákaznický web)
11. Administrace (/admin) – server-rendered rozhraní
Hotovo
Praktické rozhraní pro admina, správce a ekonoma nad hotovým REST API – levý panel s navigací dle role, vizuální identita shodná se zákaznickými stránkami (Manrope, tmavě modrá #013A63, primární #0160A1, teplé pozadí – viz schvalene-stranky). Princip „vše proklikatelné a vždy je vidět, co je potřeba udělat“: dashboard s úkoly, barevné stavové pruhy v detailech, odznaky s počty úkolů v menu. Server-rendered EJS + vanilla JS (žádný build krok navíc, jednodušší a bezpečnější nasazení na Plesk).
✓
Přihlášení (/admin/login) + přesměrování na login při nepřihlášení
✓
Společný layout: levý panel s navigací dle role, top bar s nápovědou k sekci
✓
Dashboard dle role (admin/správce/ekonom) – „co se děje a co je potřeba udělat“
GET /api/staff/overview (overviewService.buildOverview, data zúžená na provozovny dané role): KPI (obsazenost, volné boxy, aktivní pronájmy, zaplaceno tento měsíc dle faktur, nájemné celkem), úkoly s přímou akcí (boxy čekající na kontrolu → „Provést kontrolu“, kauce k rozhodnutí → „Rozhodnout“, pronájmy končící do 7 dní, platby v běhu, boxy v opravě), tabulka provozoven s prokliky na filtrované boxy/rezervace, poslední rezervace. Odznaky s počty úkolů v levém menu (GET /api/staff/tasks).
✓
Stav boxu srozumitelně a s akcí: „Co se s boxem děje“ (kdo, dokdy, čeká na kontrolu/platbu/blokace) v seznamech i detailu, box v přípravě má rovnou tlačítko „Provést kontrolu“
detailViewService.attachOccupancy + reservationsRepo.findCurrentByLocation (aktivní pronájem / skončený čekající na kontrolu / platba v běhu / živá blokace), occupancyHtml + stateBannerHtml (box-detail.js). Barevný stavový pruh i v detailu rezervace (fáze: blokace → platba → aktivní → čeká na kontrolu → kauce k rozhodnutí → vyřízeno / zrušeno) s formulářem kontroly a rozhodnutí o kauci přímo na místě.
✓
Storno rezervace a předčasné ukončení pronájmu obsluhou
POST /api/admin|manager/reservations/:id/cancel (blokace / platba v běhu → zrušeno, box hned volný) a /:id/terminate (aktivní pronájem → ukončen dneškem, kód neplatí, box do kontroly, zákazník email + SMS, správci výzva ke kontrole, kauce standardně po kontrole) – reservationLifecycleService sdílený s denní expirací. Platba, která by dorazila ke stornované rezervaci, se zapíše do logu jako „⚠ Platba ke zrušené rezervaci“ (nutné ruční vrácení).
✓
Smazání zákazníka (GDPR anonymizace na žádost) a účtu zaměstnance
DELETE /api/admin/customers/:id (anonymizace jako u samoobslužného GDPR výmazu, blokováno při nevyřízené rezervaci) a DELETE /api/admin/staff/:id (jen účet bez provedených akcí – jinak deaktivace, aby v logu zůstalo jméno).
✓
Rezervace: záložky podle dalšího kroku (aktivní / čeká na kontrolu / kauce / platba v běhu / ukončené / zrušené) + filtr provozovny, seznam provozoven se statistikami a úkoly, detail provozovny s přehledem a frontou kontrol
✓
Provozovny – CRUD, kalendář, SMS okno, upomínky, krátký popis (např. poznámka k příjezdu), přiřazení správců s oprávněními
✓
Detail provozovny – boxy s obsazeností (kdo/dokdy) a filtrem stavu nahoře, rychlé založení boxu (vždy ze šablony), nejbližší předpokládané uvolnění, správci; nastavení provozovny sbalené jako accordion
✓
Boxy – zakládání vždy ze šablony typu (velikost/m²/cena/kauce se nevybírá ručně nezávisle), změna stavu, reset přístupového kódu (admin i správce dle oprávnění), sloupec obsazenosti (kdo/dokdy)
✓
Filtry v sekci Boxy – provozovna jako přehledné taby, stav jako drobné barevné tagy s počtem boxů u každého stavu (nahrazuje dřívější stejně velké hranaté dlaždice)
boxes.js (locationFilterGridHtml/statusFilterGridHtml), CSS .location-tab/.status-tag v adminStyles.ejs.
✓
Detail boxu – provozovna a ostatní boxy provozovny nahoře (s filtrem stavu), přístupový kód viditelný když aktivní, ruční vytvoření rezervace pro volný box, přeřazení na jinou provozovnu; nastavení boxu sbalené jako accordion
✓
Historie boxu – historie stavů/úprav (z audit_log) a historie všech rezervací (i ukončených, se jménem zákazníka) jako samostatné accordiony v detailu boxu
detailViewService.buildBoxDetail (sdíleno mezi admin a manager controllery), reservationsRepo.findByBox, box-detail.js (reservationHistoryHtml + activityTableHtml).
✓
Typy boxů (submenu pod Boxy) – šablony (velikost, m², cena, kauce, popis) jsou jediný způsob zadání výchozích hodnot při zakládání boxu; box po založení na šabloně nezávisí
✓
Délky pronájmu určuje provozovna (strop + krok nabídky: čtvrtletně 1/3/6/9/12/15… dle zadání, nebo po měsících 1/2/3…) a box má jen tvorbu ceny – pevná sazba za měsíc, nebo vlastní cena pro každou nabízenou délku ("tiered") zobrazená zákazníkovi jako sleva
Migrace 1700000000011 (locations.max_duration_months + duration_step; max_duration_months u boxů a šablon zrušeno, strop provozovny převzat z jejích boxů). utils/durations.js je jediný zdroj nabízených délek (server i admin-common.js), pricingService.resolveRentalPrice(box, location, months) validuje délku proti provozovně a řeší flat/tiered cenu. Nastavení v detailu provozovny („Délky pronájmu“ s živým náhledem), ceník v detailu boxu má řádky přesně pro nabízené délky; rezervační formulář, prodloužení v klientské zóně i ruční rezervace nabízejí jen tyto délky.
✓
Rezervace – přehled s filtry + fyzická kontrola vráceného boxu
✓
Detail rezervace – box, platba, kauce, prodloužení, zákazník, faktury, log notifikací, způsob založení (Comgate/manuální), ruční vygenerování platebního odkazu a odeslání výzvy k platbě zákazníkovi
✓
Manuální založení rezervace (mimo automatizovanou platbu) – vzniká rovnou jako aktivní, box se předává ihned, platba se řeší mimo systém nebo dodatečně přes vygenerovaný Comgate odkaz
paymentService.createManualReservation, reservations.payment_method (migrace 1700000000003).
✓
Sekce Zákazníci – vyhledávání/přehled všech zákazníků (dle jména, příjmení, emailu i telefonu) vč. aktuálního boxu, ruční založení účtu
usersRepo.searchCustomers rozšířeno o vyhledávání dle telefonu (dřív jen jméno/příjmení/email).
✓
Ruční založení zákazníka v rámci manuální rezervace: správce provozovny musí před dokončením registrace ověřit telefon (SMS kód) a email (kód emailem); admin toto ověření obchází
verificationService.js + verificationCodesRepo.js, tabulka verification_codes (migrace 1700000000007), endpointy POST /customers/verify/start a /customers/verify/confirm (admin.routes.js i manager.routes.js), vynuceno server-side v adminController.createCustomer (verificationService.assertVerified – přeskočeno pro roli admin). Krokové UI v admin-common.js (customerPickerFieldsHtml/wireCustomerPicker/resolveCustomerId), použito v detailu boxu i sekci Rezervace.
✓
Detail zákazníka – editace údajů (jméno, adresa, telefon, číslo účtu) beze změny id (rezervace/faktury zůstávají navázané), historie rezervací, faktury, log notifikací, aktivita účtu (přihlášení, GDPR), ruční nastavení hesla adminem
✓
Vrácení kaucí – rozhodnutí ekonoma s upozorněním zákazníka
✓
Faktury – přehled, stažení PDF/ISDOC, CSV export
✓
Zaměstnanci – založení účtu, detail s editací údajů/role/hesla/aktivace, přiřazení provozoven, aktivita účtu a provedené úpravy
✓
Nastavení/Integrace – napojení Comgate, vyfakturuj.cz, SMSbrana.cz, SMTP z administrace vč. testu spojení a odeslání testovacího emailu
✓
Log – admin-wide přehled audit_log (kdo/co/kdy), filtrovatelný dle entity/akce/aktora, vč. potvrzených/zamítnutých plateb
logController.js, auditLogRepo.findFiltered – doplněno logování plateb (payment_confirmed/failed, extension_payment_confirmed/failed) do paymentService.js, oprava chybějícího aktora u "login" akce.
✓
Emailové šablony – editovatelné texty emailů (předmět/tělo) s proměnnými {{promenna}}, návrat na výchozí text
emailTemplateService.js (stejný vzor jako settingsService – DB přepis, kód jako výchozí), email_templates tabulka (migrace 1700000000005).
✓
Můj profil – editace vlastního jména/příjmení/telefonu, změna hesla
Ověřeno: syntax check všech souborů, HTTP smoke test auth gatingu na všech routách, a plná živá verifikace proti reálné Supabase PostgreSQL databázi (přihlášení, načtení všech stránek, CRUD operace přes API vč. detailů provozovny/rezervace/zákazníka/zaměstnance/boxu, manuální rezervace end-to-end vč. platebního odkazu, přepsání emailové šablony ověřeno na skutečně odeslané notifikaci). Ověření telefonu/emailu při ručním zakládání zákazníka ověřeno živě přes curl (admin obchází, správce má vynuceno server-side i při vypnutém JS, cooldown na opakované odeslání, zámek po 5 špatných pokusech) i v reálném prohlížeči přes Playwright (celý kroková UI tok u správce vč. odemykání kroků).
12. Zákaznický veřejný web
Rozpracováno
Zákaznická část aplikace 1:1 dle schválených předloh (/schvalene-stranky): rezervace boxu v 6 krocích (Box → Délka → Kontakt → Fakturace → Rekapitulace → Hotovo) navazující na tlačítko REZERVOVAT na WordPress webu (fáze 15), přihlášení zákazníka (vč. zapomenutého/nového hesla) a klientská zóna (přístupové kódy, boxy, prodloužení, faktury PDF/ISDOC, moje údaje, změna hesla). Hotovo a otestováno end-to-end. Naplánované zůstává jen prohlížení nabídky přímo v appce a interaktivní vizualizace výběru boxu ("Varianta B" v nabídce).
✓
Rezervace boxu 1:1 dle schválené předlohy rezervace.html – 6 kroků: Box → Délka → Kontakt → Fakturace → Rekapitulace → Hotovo
GET /box/:boxId?returnUrl=… (customerBookingController.boxOrderPage, views/customer/box-order.ejs + public-assets/customer/box-order.js, sdílený vizuál customer.css). Odpočet 15min blokace, výběr délky z nabídky provozovny (1/3/6/9/12… nebo po měsících) s výpočtem slevy z ceníku boxu (GET /api/public/boxes/:id/prices), datum nástupu omezené pravidly pobočky, průběžná kalkulace (cena vždy ze serveru – POST /api/reservations/:id/dates), kontakt s validací a výzvou k přihlášení u známého e-mailu, fakturace (firma/IČO/DIČ), rekapitulace s cenovým rozpisem, výběr způsobu platby (karta / QR / bankovní tlačítka → Comgate), povinný souhlas s podmínkami (server-side termsAccepted). Obnovení stránky ani odskok na přihlášení blokaci neztratí (selectBox znovu použije blokaci téže relace, propadlou blokaci uklidí sám), box se uvolní jen při skutečném odchodu ze stránky.
✓
Krok Hotovo – stránka po návratu z platební brány (rezervace i prodloužení)
GET /rezervace/dokonceno?paymentId=… (reservationCompletePage, views/customer/reservation-complete.ejs): přístupový kód, souhrn, „Co jsme pro vás připravili“, stažení faktury PDF/ISDOC ještě před prvním přihlášením (GET /api/reservations/:id/invoice/pdf|isdoc, ověření vlastnictví přes hold cookie/účet), proklik do klientské zóny. Stavy: zaplaceno / čeká na potvrzení platby (automaticky se obnovuje) / platba neproběhla (box uvolněn, možnost zkusit znovu). Cizí platbu stránka nezobrazí (403). Mock Comgate po simulaci vrací zákazníka stejně jako ostrá brána.
✓
Přihlášení zákazníka dle předlohy prihlaseni.html (přihlášení / zapomenuté heslo / nové heslo)
GET /prihlaseni?view=login|forgot|reset&next=… (customerBookingController.authPage, views/customer/auth.ejs + auth.js) nad /api/auth/login, password-reset/request, password-reset/confirm. „Zůstat přihlášen“ = trvalá cookie 30 dní, jinak jen do zavření prohlížeče (loginSchema.remember). Odkaz z emailu /reset-hesla?token=… a /zapomenute-heslo vedou na tutéž stránku; zaměstnanci se odsud přesměrují do /admin. Původní strohé stránky admin/forgot-password a reset-password nahrazeny.
✓
Klientská zóna dle předlohy klientska-zona.html
GET /ucet (customerBookingController.accountPage, views/customer/account.ejs + account.js; nepřihlášený → /prihlaseni?next=/ucet). Oslovení 5. pádem (utils/vocative.js), přístupové kódy aktivních pronájmů (zobrazit/skrýt), statistiky (aktivní boxy, nejbližší konec pronájmu, složené kauce, stav účtu), karty boxů s upozorněním na blížící se konec a prodloužením na místě (délka dle ceníku boxu → POST /api/payments/reservations/:id/extend → Comgate), historie ukončených pronájmů, tabulka plateb/faktur s PDF i ISDOC (nově GET /api/account/invoices/:id/isdoc), způsob platby (info o Comgate, žádné uložené karty), moje údaje (úprava PUT /api/account/me) a změna hesla (POST /api/auth/change-password), odhlášení, GDPR export. Záměrně mimo: automatické obnovování/strhávání z karty a „Ukončit pronájem“ tlačítkem – v zadání nejsou (pronájem končí datem, ukončení řeší správce), předloha je má jen jako ilustraci.
✓
Kontakt na zákaznických stránkách z nastavení
Administrace → Nastavení → Fakturační údaje firmy: telefon pro zákazníky, kontaktní e-mail, URL obchodních podmínek (settingsService business.phone/email/termsUrl, env BUSINESS_PHONE/EMAIL/TERMS_URL). „Zpět na web“ míří na URL prezentačního webu (wordpress.siteUrl), u rezervace na stránku, odkud zákazník přišel (?returnUrl=, jen stejná doména).
○
Interaktivní vizualizace výběru boxu (analogie boxbox.cz) – "Varianta B" v nabídce, samostatná položka
○
Prohlížení nabídky (lokality → boxy) přímo v appce místo jen přes WordPress
Zatím řeší WordPress web (fáze 15) – appka přijímá zákazníka až na konkrétní již vybraný box.
15. Propojení s prezentačním WordPress webem
Hotovo
WordPress plugin (samostatný, mimo tento Node projekt – viz /wordpress-plugin) čte z appky dostupnost poboček/boxů (vč. prezentačních údajů – foto, 24/7 odznak, dopravní dostupnost, vlastnosti – vizuál dle schválené předlohy) a odkazuje zpět na objednávkový formulář (fáze 12). Autentizace sdíleným API klíčem, obousměrný test spojení. Data se aktualizují dvěma cestami zároveň: appka pošlou webu okamžitý signál při každé změně dostupnosti boxu (bez čekání), a jako záloha se navíc pravidelně obnovují na pozadí (WP-Cron, cca 2 min).
✓
Veřejné API pro WP plugin: GET /api/wordpress/feed (pobočky + boxy + hotová reserveUrl na každý box + seskupení boxů dle m² s počty) a GET /api/wordpress/ping, autentizace hlavičkou X-Api-Key
wordpressService.js (buildFeed/summarizeBoxesBySize), wordpressController.js, routes/wordpress.routes.js. Klíč se generuje/ukládá v Administraci → Nastavení → WordPress (settingsService skupina "wordpress", settings.js).
✓
Test spojení oběma směry přímo v administraci
Appka → web: Administrace → Nastavení → WordPress → „Otestovat spojení“ (statusCheckService.checkWordpress volá wordpressService.healthCheck, ten pingne /wp-json/verejnesklady/v1/ping na WP webu). Web → appka: v nastavení pluginu na WordPressu tlačítko „Otestovat spojení“ (volá GET /api/wordpress/ping).
✓
Okamžitá synchronizace při změně dostupnosti boxu (ne jen pravidelný cron)
wordpressService.notifyAvailabilityChanged() – "fire-and-forget" POST na /wp-json/verejnesklady/v1/invalidate na WP webu, který si hned zahodí cache a natáhne čerstvá data. Zavoláno při: zablokování boxu zákazníkem (reservationService.selectBox), uvolnění blokace (releaseHold i cron clearTempHolds), aktivaci po platbě i zrušení platby (paymentService), fyzické kontrole s výsledkem "volný" (boxReturnService), ruční změně stavu/založení boxu adminem (adminController). Chyby se jen logují, nikdy neblokují samotnou akci.
✓
Prezentační údaje provozovny pro web (foto, 24/7 odznak, dopravní dostupnost, vlastnosti, odkaz "Zobrazit pobočku")
Migrace 1700000000009 (locations.photo_url/access_247/travel_note/features/detail_url), pole v Administraci → Provozovny → detail → "Prezentace na webu" (location-detail.js). Vizuál v pluginu (barvy, karta, odznaky) odpovídá 1:1 schválené předloze homepage (schvalene-stranky/03-homepage-hifi.dc.html).
✓
WordPress plugin (PHP, samostatný balíček)
/wordpress-plugin/verejnesklady-connector – nastavení (URL appky, API klíč, délka cache) s "Otestovat spojení" a "Obnovit data teď", shortcody [verejnesklady_locations] a [verejnesklady_boxes location="..."] stylované dle schválené předlohy, log synchronizací s časem poslední a historií (záznamy starší 14 dní se automaticky mažou přes denní WP-Cron), WP-Cron obnovování dat na pozadí + krátkodobý transient cache + trvalá záloha pro případ výpadku appky. Nelze automaticky odzkoušet v tomto vývojovém prostředí (není dostupné PHP/WordPress) – nutné ověřit po instalaci na reálném webu klienta.
✓
Veřejná adresa aplikace pro odkazy z webu, Comgate a emailů (APP_BASE_URL) – kontrola a pojistka
utils/baseUrl.js: bez nastaveného APP_BASE_URL si appka při prvním veřejném požadavku zapamatuje adresu, pod kterou běží (Host + X-Forwarded-Proto za Plesk proxy), a použije ji pro reserveUrl ve feedu, návrat z Comgate, reset hesla i doménu v hlavičce zákaznických stránek; zároveň varuje v logu, na /dokumentace/status (Bezpečnost) a v Administraci → Nastavení → WordPress. Plugin (1.1.0) navíc odkaz „Rezervovat“ na localhost nahradí adresou aplikace ze svého nastavení a v testu spojení na chybějící APP_BASE_URL upozorní; v nastavení pluginu je seznam hotových shortcodů pro každou pobočku.
✓
Box se uvolní hned, když zákazník opustí objednávkový formulář (ne až po 15 min)
Dvě vrstvy: (1) při odchodu ze stránky (zavření karty, Zpět na web, jiná adresa) pošle prohlížeč POST /api/reservations/:id/release – fetch keepalive, ve starších prohlížečích navigator.sendBeacon s CSRF tokenem v těle (middleware/csrf.js); (2) otevřený formulář se každých 30 s hlásí přes POST /api/reservations/:id/heartbeat (hold_last_seen_at, migrace 1700000000010) a cron clear-temp-holds každou minutu zruší blokace bez ozvěny delší než TEMP_HOLD_INACTIVITY_SECONDS (výchozí 120 s) – pokryje i spadlý prohlížeč, zamčený mobil nebo odskok na přihlášení bez návratu. Po návratu na stránku se blokace tiše obnoví (select-box znovu použije blokaci téže relace, nebo vytvoří novou, je-li box volný). Chyby stavu blokace mají kódy HOLD_EXPIRED / HOLD_GONE / HOLD_LOCKED, podle nichž formulář reaguje.
✓
Žádný košík – jedna rezervace na relaci
Vyplývá z existující architektury (jedna anonymní hold-session, viz middleware/holdSession.js) – zákazník přichází z WP vždy rovnou na jeden konkrétní box, appka nemá žádné UI pro přidání druhého boxu do téže rezervace.
13. Automatizované testy
Rozpracováno
Testy klíčových business pravidel (ceny, blokace, idempotence plateb, DPH výpočty, IBAN/QR, lockout).
✓
Unit testy: pricingService, accessCodeService, qrPaymentService (IBAN/SPD), notificationService (časové okno), authService (hash), csv export
tests/*.test.js, node --test – 24 testů, viz npm test.
○
Integrační testy nad reálnou/testovací PostgreSQL (rezervace -> platba -> aktivace, idempotence webhooku)
Zatím ověřováno manuálně proti živé Supabase DB při každé větší změně, ne jako automatizovaná sada.
✓
Seed skript s demo daty pro ruční testování a předvádění klientovi (zákazníci, boxy, rezervace vč. historie)
npm run seed – doplní demo zákazníky/boxy/rezervace do existujících provozoven (nezakládá nové provozovny ani zaměstnance, aby nekolidoval s reálným nastavením). Idempotentní (kontrola dle emailu prvního demo zákazníka). Během běhu dočasně zapne smtp.mockMode/sms.mockMode, aby neodeslal reálné emaily/SMS, po doběhnutí je vrátí zpět.
14. Bezpečnostní hardening a nasazení
Naplánováno
Závěrečná bezpečnostní kontrola a příprava provozu na Plesku (SSL, zálohy, monitoring, tajemství).
○
Revize CSP, cookie flagů, rate-limitů v produkčním nastavení
✓
Kontrola, že žádný tajný klíč není v repozitáři (.env, storage/ mimo git)
○
Návod na nasazení na Plesk (Node.js app, PostgreSQL, cron, zálohy, SSL)
○
Nastavení pravidelných DB záloh a plánu obnovy
Vygenerováno ze src/docs/planData.js – upravujte tento soubor při každé významnější změně rozsahu prací.