Pokrytí projektové dokumentace
Každý požadavek z původní projektové dokumentace (interaktivní prezentace zadání) je zde
namapován na konkrétní implementaci v tomto kódu – soubor/službu, kde je pravidlo skutečně vynuceno.
Cílem je udržet aplikaci v souladu se zadáním 1:1 a mít vždy po ruce odpověď „kde přesně je to řešeno“.
Rezervační proces
Hotovo
Zobrazení dostupných lokalit s počtem volných boxů v reálném čase
GET /api/public/locations → reservationService.listLocationsWithAvailability
Hotovo
Přehled boxů v lokalitě – volné/obsazené s kapacitou a cenou/kaucí
GET /api/public/locations/:id/boxes → reservationService.listBoxesForLocation
Naplánováno
Interaktivní vizualizace výběru boxu (analogie boxbox.cz)
"Varianta B" v nabídce – samostatná položka nad rámec základního objednávkového formuláře (fáze 12/15 v plánu)
Hotovo
Dočasná blokace boxu na 15 minut po výběru
reservationService.selectBox (TEMP_HOLD_MINUTES = tvrdý strop) + jobs/clearTempHolds.js (každou minutu). Nad rámec zadání: box se uvolní hned při odchodu ze stránky (pagehide → POST /release) a nejpozději ~2 min po tom, co se formulář přestane hlásit (heartbeat každých 30 s, TEMP_HOLD_INACTIVITY_SECONDS)
Hotovo
Kalendář: povolený rozsah dat nástupu per provozovna, ostatní data zašedlá
reservationService.getLocationRules + setDatesAndDuration; ve formuláři /box/:id má datum min/max dle pravidel pobočky (box-order.js)
Hotovo
Kalkulace ceny v reálném čase, server jako jediný zdroj pravdy o ceně
pricingService.calculateReservationPrice/assertPriceMatches
Hotovo
Registrace/přihlášení zákazníka v průběhu rezervace (bez nutnosti účtu předem)
reservationService.setContactInfo + paymentService (účet vzniká až po platbě); přihlášení během rezervace přes /prihlaseni?next=/box/:id – blokace boxu zůstává (reservationService.selectBox znovu použije blokaci téže relace)
Hotovo
Platba přes Comgate (karta, QR kód, bankovní tlačítka)
comgateService.createPayment (mock i skeleton ostrého API)
Hotovo
Odsouhlasení obchodních podmínek před platbou
Krok Rekapitulace (box-order.js: tlačítko „Zaplatit“ aktivní až po zaškrtnutí) + server-side povinné termsAccepted=true (validation/schemas.createPaymentSchema na POST /api/reservations/:id/payment); odkaz na podmínky = Nastavení → business.termsUrl
Hotovo
Nastavení boxu jako nedostupný po úspěšné platbě
paymentService.handleReservationPaymentResult → boxesRepo.setStatus(occupied)
Zákazník a přístup
Hotovo
Registrace automaticky až PO úspěšné platbě (ne dříve) – u veřejného webu
paymentService.handleReservationPaymentResult (usersRepo.create z pending_* polí). Výjimka: admin/správce může účet i rezervaci založit ručně mimo web (viz Administrace a správa).
Hotovo
Kontrola duplicity emailu – vyzvání k přihlášení
reservationService.setContactInfo (ConflictError „přihlaste se prosím“) → v kroku Kontakt se zobrazí výzva s odkazem na přihlášení a návratem zpět do rozpracované rezervace (box-order.js)
Hotovo
Povinná pole: jméno, příjmení, adresa, email, telefon, číslo účtu; B2B: firma/IČO/DIČ skryté
validation/schemas.js contactSchema
Hotovo
Heslo negeneruje zákazník, dostane ho emailem po platbě
authService.generateRandomPassword + paymentService notifikace
Hotovo
Automatické odeslání SMS s přístupovým kódem (24/7, mimo denní okno)
notificationService.IMMEDIATE_24_7_TYPES + paymentService.sendReservationConfirmedNotifications
Hotovo
Přístupový kód platný po dobu rezervace, deaktivace po expiraci
jobs/expireReservations.js (access_code_active=false)
Hotovo
Zákaznický profil s historií rezervací a fakturami
Klientská zóna GET /ucet (views/customer/account.ejs + account.js) nad GET /api/account/reservations a /api/account/invoices; faktury PDF i ISDOC ke stažení (customerController.downloadInvoicePdf/downloadInvoiceIsdoc), úprava údajů, změna hesla, GDPR export
Hotovo
Prodloužení pronájmu online, opakovaně, bez nové kauce
paymentService.createExtensionPayment; v klientské zóně tlačítko „Prodloužit pronájem“ (volba délky dle ceníku boxu → Comgate → /rezervace/dokonceno)
Hotovo
Přihlašovací lockout (5 pokusů / 15 min) se zbývajícím počtem pokusů v hlášce
authService.login
Hotovo
Reset hesla emailem (platnost 60 min, jednorázové)
authService.requestPasswordReset/resetPassword; stránka /prihlaseni (pohledy přihlášení / zapomenuté heslo / nové heslo dle schválené předlohy), odkaz z emailu vede na /reset-hesla?token=
Hotovo
GDPR: export dat, výmaz s anonymizací (finanční záznamy zachovány)
customerController.gdprExport/gdprDelete + usersRepo.anonymize; na žádost zákazníka provede totéž admin v detailu zákazníka (adminController.deleteCustomer)
Platby a finance
Hotovo
Online platba kartou, QR kódem, bankovními tlačítky (Comgate)
comgateService (mock režim plně funkční, ostré API skeleton)
Hotovo
Kauce jako vratná záloha, konkrétní částka nastavená per box
boxes.deposit_amount (DB), pricingService
Hotovo
Automatické generování faktur s DPH (21 % pronájem, 0 % kauce)
invoicingService.createInvoice + invoicePdfBuilder
Hotovo
Faktura odeslána zákazníkovi (PDF), správci+ekonomovi (PDF+ISDOC)
paymentService.sendReservationConfirmedNotifications
Hotovo
„Neplaťte, faktura je uhrazena“, bez QR k platbě, s Comgate transID a číslem objednávky
invoicePdfBuilder.buildInvoicePdf
Hotovo
Vrácení kauce manuálně ekonomem po fyzické kontrole správcem
boxReturnService.recordDepositDecision; v administraci vede k oběma krokům přímá akce z dashboardu, seznamu boxů i detailu rezervace (barevný stavový pruh „co udělat“)
Hotovo
QR platba pro rychlé vrácení kauce ekonomem
qrPaymentService.generateDepositRefundQr (SPD formát, výpočet IBAN)
Hotovo
Export faktur pro účetnictví (CSV, ISDOC)
accountantController.exportInvoicesCsv/downloadInvoiceIsdoc
Administrace a správa
Hotovo
Administrační rozhraní s levým panelem, přihlášením a rozdělením dle role
/admin (routes/adminUi.routes.js, views/admin/*, public-assets/admin/*)
Hotovo
Přehled obsazenosti a tržeb v reálném čase (admin i správce)
/admin dashboard → adminController.dashboard, managerController.locationDashboard
Hotovo
Správa boxů (přidání ze šablony typu, úprava, deaktivace, stav V opravě)
/admin/boxy → adminController.createBox (velikost/m²/cena/kauce se přebírá ze zvolené šablony, server ji vždy ověří znovu) /updateBox/setBoxStatus
Hotovo
Role: zákazník, správce provozovny, ekonom, admin
config/constants.ROLES + middleware/auth.requireRole + middleware/webAuth
Hotovo
Více provozoven na správce, jemná oprávnění per provozovna
/admin/provozovny (Správci) → location_managers table + middleware/locationAccess
Hotovo
Export dat pro účetnictví
/admin/faktury → accountantController.exportInvoicesCsv
Hotovo
Ruční reset přístupového kódu správcem/adminem
/admin/boxy → adminController.resetAccessCode (sdíleno s manager.routes)
Hotovo
Nastavení ceníku a kauce per box provozovatelem
/admin/boxy → adminController.createBox/updateBox
Hotovo
Nabízené délky pronájmu per provozovna (strop + krok: čtvrtletně 1/3/6/9/12… dle zadání, nebo po měsících) a volitelná vlastní cena boxu pro každou nabízenou délku zobrazená zákazníkovi jako sleva
locations.max_duration_months + duration_step (migrace 1700000000011), utils/durations.js, pricingService.resolveRentalPrice(box, location, months), box_month_prices; /admin/provozovny/:id → „Délky pronájmu“, /admin/boxy/:id → „Tvorba ceny“
Hotovo
Nastavení číselné řady objednávek per provozovna
/admin/provozovny → locations.order_number_prefix + orderNumberRepo.nextOrderNumber
Hotovo
Editace údajů zákazníka adminem/správcem (jméno, adresa, telefon, číslo účtu) beze ztráty vazby na rezervace/faktury (stabilní customer_id)
/admin/zakaznici/:id → adminController.updateCustomerProfile/managerController.updateCustomerProfile (usersRepo.updateProfile)
Hotovo
Krátký popis provozovny (např. poznámka k příjezdu/trase)
/admin/provozovny/:id → locations.description (migrace 1700000000006)
Hotovo
Audit log administrátorských akcí + admin-wide prohlížeč logu (filtr dle entity/akce/aktora)
/admin/log → logController.js + auditLogRepo.findFiltered
Hotovo
Log plateb (potvrzené i zamítnuté, vč. prodloužení) a přihlášení (klient i zaměstnanec)
paymentService.js → auditService.logSystem; authController.login → auditService.log
Hotovo
Zobrazení aktivity účtu (přihlášení, GDPR, změny) v detailu zákazníka a zaměstnance + úpravy provedené zaměstnancem
detailViewService.buildCustomerDetail, adminController.getStaffDetail
Hotovo
Napojení externích služeb (Comgate, vyfakturuj.cz, SMSbrana.cz, SMTP) přímo z administrace vč. testu spojení, bez zásahu do kódu
/admin/nastaveni → settingsService.js (šifrováno AES-256-GCM v app_settings) + settingsController.js
Hotovo
Prokliknutí provozovna → boxy → detail boxu, rezervace → zákazník/faktury, box → provozovna
/admin/provozovny/:id, /admin/boxy/:id, /admin/rezervace/:id, /admin/zakaznici/:id → detailViewService.js
Hotovo
Přeřazení boxu na jinou provozovnu z jeho detailu (admin), blokováno u boxu s aktivní rezervací
/admin/boxy/:id → adminController.moveBoxLocation + boxesRepo.setLocation
Hotovo
Detail zaměstnance s editací údajů, role, hesla, aktivace a přiřazených provozoven
/admin/zamestnanci/:id → adminController.getStaffDetail/updateStaffProfile/updateStaffRole/setStaffPassword/setStaffActive
Hotovo
Založení libovolného počtu dalších administrátorů
/admin/zamestnanci → adminController.createStaff (role: admin)
Hotovo
Úprava vlastního jména/příjmení/telefonu administrátorem (i ostatními rolemi), nezávisle na změně hesla
PUT /api/auth/me → authController.updateProfile
Hotovo
Ruční založení zákaznického účtu adminem/správcem (mimo automatizovaný web) + vyhledávání/přehled zákazníků dle jména, příjmení, emailu i telefonu
/admin/zakaznici → adminController.listCustomers/createCustomer, usersRepo.searchCustomers
Hotovo
Historie boxu – kdo box v minulosti pronajímal (i ukončené/zrušené rezervace) a historie změn stavu/ceníku boxu
/admin/boxy/:id → detailViewService.buildBoxDetail, reservationsRepo.findByBox, auditLogRepo.findForEntity
Hotovo
Ruční založení rezervace mimo automatizovanou platbu (dohoda telefonicky/na místě), s možností dodatečně vygenerovat Comgate platební odkaz a poslat výzvu k platbě
/admin/boxy/:id → paymentService.createManualReservation/generatePaymentLink/sendPaymentRequestEmail
Hotovo
Ověření telefonu (SMS kód) a emailu (kód emailem) při ručním zakládání zákazníka správcem provozovny – bez obou ověření nelze účet dokončit; admin toto ověření obchází
verificationService.js (assertVerified) → adminController.createCustomer, verificationCodesRepo.js, /customers/verify/start a /customers/verify/confirm v admin.routes.js i manager.routes.js
Hotovo
Šablony boxů (typ s výchozí velikostí/cenou/kaucí) pro rychlé zakládání – jen předvyplnění, box na šabloně nezávisí
/admin/typy-boxu → boxTypesRepo.js + boxTypesController.js
Hotovo
Editovatelné texty emailů (předmět/tělo) s proměnnými, návrat na výchozí text
/admin/email-sablony → emailTemplateService.js
Automatizace
Hotovo
Fyzická kontrola stavu boxu správcem při vrácení (bez AI)
boxReturnService.recordReturnCheck
Hotovo
Box po expiraci → „V přípravě“ (ne rovnou volný), na FE stále „obsazený“
jobs/expireReservations.js + config/constants.BOX_STATUS_PUBLIC_LABEL
Hotovo
Automatické upomínky před expirací (konfigurovatelné dny, výchozí 5+3+1)
jobs/sendExpiryReminders.js + locations.expiry_reminder_days
Hotovo
SMS pouze v denní době (výchozí 8:00–22:00, konfigurovatelné)
notificationService.nextAllowedSendTime
Hotovo
Deaktivace boxu deaktivuje i notifikace
adminController.setBoxStatus → boxesRepo.deactivateAccessCode
Hotovo
Čištění vypršelých dočasných blokací (5 min interval)
jobs/clearTempHolds.js
Bezpečnost a GDPR
Hotovo
Hesla jen jako bcrypt hash
authService (bcryptjs, 12 rounds)
Hotovo
Číslo karty se nikde neukládá (řeší Comgate, PCI DSS)
comgateService – žádné číslo karty neprochází naší aplikací
Hotovo
Webhooku od Comgate se nevěří přímo – server-to-server ověření
comgateService.confirmPaymentStatus
Hotovo
API klíče a další tajemství nikdy v kódu/repozitáři – jen v .env, nebo šifrovaně v DB při nastavení z administrace
.env.example + .gitignore; app_settings.value šifrováno AES-256-GCM (settingsCrypto.js, klíč mimo repo v SETTINGS_ENCRYPTION_KEY)
Naplánováno
Šifrovaná komunikace (HTTPS/TLS) – zajišťuje produkční nasazení
Plesk/Let’s Encrypt SSL při nasazení (fáze 13)
Hotovo
Ochrana proti CSRF, XSS (CSP), brute-force, rate-limit
middleware/csrf.js, middleware/security.js, middleware/rateLimit.js
Hotovo
Faktury a účetní záznamy archivovány, GDPR výmaz zachovává finance
usersRepo.anonymize (osobní údaje pryč, invoices/reservations zůstávají)
Hotovo
Systém neloguje fyzické přístupy do boxu (mechanické zámky)
Záměrně nezaváděno – žádná tabulka/log pro fyzické otevření boxu
Propojení s prezentačním WordPress webem
Hotovo
WordPress plugin zobrazuje dostupnost poboček a boxů z appky
/wordpress-plugin/verejnesklady-connector – shortcody [verejnesklady_locations]/[verejnesklady_boxes], čte GET /api/wordpress/feed
Hotovo
Odkaz z volného boxu přímo na objednávkový formulář daného boxu v appce
wordpressService.buildFeed (reserveUrl per box, plugin přidá ?returnUrl=) → GET /box/:boxId (customerBookingController.boxOrderPage) – rezervační formulář 1:1 dle schválené předlohy rezervace.html, „Zpět na web“/„Změnit box“ vrací na stránku, odkud zákazník přišel
Hotovo
Návratová URL zpět na web (pro přerušení a nový začátek)
?returnUrl= na /box/:boxId, drženo v sessionStorage prohlížeče, zobrazeno jako odkaz "Zpět na web" v každém kroku i na stránce po platbě
Hotovo
Bez košíku – vždy jen jedna rezervace na relaci
Existující architektura jedné hold-session (middleware/holdSession.js) – žádná změna nebyla potřeba
Hotovo
Test propojení webu a appky z administrace
Administrace → Nastavení → WordPress → „Otestovat spojení“ (statusCheckService.checkWordpress) + tlačítko v nastavení pluginu na WordPressu
Hotovo
Data z appky na web se aktualizují téměř nepřetržitě
Okamžitý signál appky při každé změně dostupnosti (wordpressService.notifyAvailabilityChanged → /wp-json/verejnesklady/v1/invalidate), + záloha: WP-Cron obnovení na pozadí každé 2 min + krátký transient cache (výchozí 60 s) + trvalá záloha pro výpadek appky
Hotovo
Box se drží zablokovaný jen po nezbytně nutnou dobu (max. 15 min, nebo do opuštění stránky)
reservationService.selectBox (TEMP_HOLD_MINUTES) + releaseHold (POST /api/reservations/:id/release, volané z box-order.js při odchodu ze stránky)
Hotovo
Prezentační identita pobočky na webu (foto, 24/7 odznak, dopravní dostupnost, vlastnosti, odkaz na detail) dle schválené vizuální předlohy
Migrace 1700000000009, Administrace → Provozovny → detail (location-detail.js), vizuál v wordpress-plugin/.../class-shortcodes.php + assets/style.css dle schvalene-stranky/03-homepage-hifi.dc.html
Hotovo
Log synchronizací v pluginu (kdy naposledy, historie) s automatickým mazáním starším 14 dní
wordpress-plugin/.../includes/class-sync-log.php – zápis při každém načtení dat, denní WP-Cron úklid + průběžné čištění při zápisu
Vygenerováno ze src/docs/coverageData.js. Původní zadání viz interaktivní
prezentace projektu (samostatný repozitář dokumentace) – sekce „Zadání projektu“, „Změny 9. 4. 2026“ a
jednotlivé tematické stránky (Rezervace boxu, Platby a kauce, Fakturace, Kontrola stavu boxu, Správa a role,
Bezpečnost a data, Technické řešení).