# Plan implementacji zgodności RODO — Forno rezerwacje Stan: 2026-09-02. Aplikacja rezerwacji działa na Render, ale wymaga naprawy zgodności z RODO przed udostępnieniem klientom. Priorytety oznaczone 🔴 są krytyczne i muszą być gotowe przed startem. --- ## Kontekst — co zbiera aplikacja Formularz `views/forno-rezerwacja.ejs` zbiera: - imię i nazwisko (dane osobowe, RODO art. 4 pkt 1) - numer telefonu (dane osobowe — identyfikator) - liczbę osób (nie jest daną osobową) - uwagi (opcjonalnie — mogą zawierać dane osobowe) Dane zapisywane w `reservations.json` i commitowane do GitHub przez `github-sync.js`. SMS przypomnienie wysyłany przez `forno-notify.js` (6 h przed terminem opłaty, tylko do statusu `pending`). --- ## Zadanie 0 — Repo prywatne (ręcznie, poza kodem) 🔴 KRYTYCZNE **Problem:** `reservations.json` z imionami i telefonami klientów jest commitowany do publicznego repo `github.com/DamianMalenta/trzciamajka`. Każdy może pobrać plik i mieć bazę danych osobowych. **Akcja (wykonuje Damian ręcznie na GitHub):** 1. `github.com/DamianMalenta/trzciamajka` → Settings → *Change repository visibility* → **Private** 2. Render i GitHub Actions nadal działają (PAT ma uprawnienia do prywatnego repo) 3. Cron na GitHub Actions: prywatne repo ma 2000 min/mc darmowych — wystarczy **Weryfikacja:** otwórz `github.com/DamianMalenta/trzciamajka` w oknie prywatnym — powinien pokazać 404. Zalogowany nadal widzi repo. **Nie dotyka kodu** — to czysta akcja na GitHub UI. --- ## Zadanie 1 — Checkbox zgody + klauzula informacyjna 🔴 KRYTYCZNE **Plik:** `views/forno-rezerwacja.ejs` ### 1.1 Checkbox zgody (wymagany, przed przyciskiem submit) Dodać pole checkbox **wymagane** w formularzu, przed przyciskiem „Rezerwuję stolik": ```html ``` **Wymagania:** - checkbox `required` — nie zaznaczony = formularz nie przejdzie walidacji HTML5 - walidacja serwerowa też (Zadanie 2) — bo HTML5 można obejść - tekst zgody konkretny: kto (venue_name), co (dane), po co (rezerwacja + SMS) - zgoda **nie jest warunkiem** samej rezerwacji — to jest zgoda na przetwarzanie danych niezbędnych do umowy (art. 6 ust. 1 lit. b) + zgoda na SMS (art. 6 ust. 1 lit. a — komunikacja elektroniczna) ### 1.2 Krótka klauzula informacyjna pod formularzem Dodać pod formularzem (lub pod checkboxem) krótki blok informacyjny: ```html

🔒 Twoje dane

Administratorem Twoich danych jest <%= settings.venue_name %><% if (settings.address) { %> (<%= settings.address %>)<% } %>. Dane przetwarzamy w celu realizacji rezerwacji i obsługi płatności. Przechowujemy je do końca wydarzenia, a następnie przez 30 dni w celach rozliczeniowych. Masz prawo dostępu do swoich danych, ich sprostowania, usunięcia i ograniczenia przetwarzania. Szczegóły: polityka prywatności.

``` ### 1.3 CSS dla checkboxa i klauzuli **Plik:** `public/forno.css` Dodać style dla `.field--consent`, `.consent` (checkbox + tekst obok), zgodnie z istniejącą szatą graficzną (kolory z zmiennych CSS, czytelne na mobile). --- ## Zadanie 2 — Walidacja zgody po stronie serwera 🔴 KRYTYCZNE **Plik:** `forno-data.js` — funkcja `validateReservationInput` ### 2.1 Dodać pole `consent` do walidacji W `validateReservationInput` dodać sprawdzanie zgody: ```js const consent = String(src.consent || '').trim(); if (consent !== '1' && consent !== 'true' && consent !== 'on') { errors.consent = 'Musisz wyrazić zgodę na przetwarzanie danych, aby zarezerwować stolik.'; } ``` ### 2.2 Dodać `consent` do zwracanego `value` W obiekcie `value` zwracanym przez `validateReservationInput` dodać: `consent: consent === '1' || consent === 'true' || consent === 'on'` ### 2.3 Zapisać zgodę w rezerwacji W `createReservation` dodać pole `consent: true` i `consent_at: createdAt.toISOString()` — dowód, że klient zaznaczył zgodę i kiedy (ważne dla audytu RODO). ### 2.4 Testy **Plik:** `test/forno-data.test.js` (lub nowy `test/forno-consent.test.js`) Dodać testy: - `validateReservationInput` bez `consent` → `errors.consent` ustawione, `ok: false` - `validateReservationInput` z `consent: '1'` → brak błędu zgody - `createReservation` → rezerwacja ma `consent: true` i `consent_at` - `POST /rezerwacja` bez zaznaczonego checkboxa → 400 + komunikat błędu --- ## Zadanie 3 — Podstrona polityki prywatności 🔴 KRYTYCZNE **Pliki:** `views/forno-prywatnosc.ejs` + routing w `forno-server.js` ### 3.1 Nowy widok `views/forno-prywatnosc.ejs` Pełna klauzula informacyjna RODO art. 13/14. Struktura: 1. **Administrator danych** — nazwa lokalu, adres, telefon kontaktowy (z `settings.address`, `settings.contact_phone`) 2. **Cele przetwarzania** — realizacja rezerwacji, obsługa płatności, przypomnienia SMS 3. **Podstawa prawna** — art. 6 ust. 1 lit. b (umowa) + lit. a (zgoda na SMS) 4. **Odbiorcy danych** — pracownicy lokalu (obsługa rezerwacji), dostawca SMS Gateway (sms-gate.app — procesor), hosting (Render — procesor) 5. **Okres przechowywania** — do końca wydarzenia + 30 dni (rozliczenia), potem usunięcie 6. **Prawa użytkownika** — dostęp, sprostowanie, usunięcie, ograniczenie, przenoszenie, sprzeciw, wycofanie zgody, skarga do UODO (Urząd Ochrony Danych Osobowych, ul. Postępu 2, 02-676 Warszawa) 7. **Wymóg podania danych** — dobrowolne, ale niezbędne do rezerwacji 8. **Automatyczne podejmowanie decyzji** — brak (profilowanie nie występuje) 9. **Transfer danych poza EOG** — Render (USA), sms-gate.app (UE) — Render jako procesor z umową DPA (Data Processing Agreement) **Szablon:** zgodny z `forno-rezerwacja.ejs` (hero, card, footer, CSS z `forno.css`), link powrotu do `/`. ### 3.2 Routing w `forno-server.js` Dodać route **przed** handlerem 404: ```js app.get('/prywatnosc', (req, res) => { res.render('forno-prywatnosc', { settings: data.loadSettings() }); }); ``` ### 3.3 Link w stopce **Plik:** `views/partials/forno-footer.ejs` Dodać link do polityki prywatności w stopce: ```html

Polityka prywatności

``` ### 3.4 Testy - `GET /prywatnosc` → 200, zawiera „Administrator", „UODO", „prawo dostępu" - Link w stopce widoczny na wszystkich stronach --- ## Zadanie 4 — Retencja danych (usuwanie starych rezerwacji) 🟡 ŚREDNI **Pliki:** `forno-data.js`, `forno-server.js` ### 4.1 Funkcja `removeOldReservations` w `forno-data.js` ```js /** * Usuwa rezerwacje starsze niż retentionDays po dacie wydarzenia. * Zwraca liczbę usuniętych. Nie usuwa paid (dowód zapłaty do rozliczenia). */ function removeOldReservations(reservations, settings, retentionDays = 30, now = new Date()) { const eventEnd = new Date(settings.event_date).getTime(); if (Number.isNaN(eventEnd)) return 0; const cutoff = eventEnd + retentionDays * 24 * 60 * 60 * 1000; const nowMs = now instanceof Date ? now.getTime() : Number(now); if (nowMs < cutoff) return 0; const before = reservations.length; const kept = reservations.filter((r) => { // Zachowaj paid (rozliczenia) — usuń tylko expired/cancelled/pending stare if (r.status === 'paid') return true; return false; // expired/cancelled/pending po cutoff → usuń }); reservations.length = 0; reservations.push(...kept); return before - kept.length; } ``` **Eksportować** z `forno-data.js`. ### 4.2 Wywołanie w `runTasks` (`forno-server.js`) W `runTasks` dodać po `expireOverdue`: ```js const removed = data.removeOldReservations(reservations, settings); if (removed > 0) { outcome.removed = removed; // commit osobno jeśli coś usunięto } ``` ### 4.3 Testy - `removeOldReservations` przed cutoff → 0 usuniętych - `removeOldReservations` po cutoff → expired/cancelled usunięte, paid zachowane - `runTasks` z `removeOldReservations` → commit „Forno: usunięto N starych rezerwacji" --- ## Zadanie 5 — Aktualizacja `info_text` w ustawieniach 🟢 NISKI **Plik:** `forno-settings.json` (przez panel lub ręcznie) Zaktualizować `info_text` o wzmiankę o zgodzie i prywatności: ``` Rezerwację opłacisz na miejscu w pizzerii Forno w ciągu 24 godzin od zgłoszenia. Nieopłacona rezerwacja wygasa automatycznie. Twoje dane przetwarzamy w celu realizacji rezerwacji — szczegóły w polityce prywatności. ``` **Można zrobić przez panel `/panel` → Ustawienia → zapisać (commit do GitHub).** --- ## Zadanie 6 — Aktualizacja testów i `npm test` 🟢 NISKI ### 6.1 Dodać testy dla nowych funkcjonalności - `test/forno-consent.test.js` — walidacja zgody, checkbox, rezerwacja z `consent` - `test/forno-privacy.test.js` — `GET /prywatnosc` 200, treść klauzuli - Rozszerzyć `test/forno-data.test.js` o `removeOldReservations` - Rozszerzyć `test/forno-server.test.js` o `POST /rezerwacja` bez zgody → 400 ### 6.2 Uruchomić `npm test` — wszystkie testy muszą przechodzić --- ## Kolejność implementacji 1. **Zadanie 0** (Damian ręcznie) — repo prywatne — **natychmiast** 2. **Zadanie 1** — checkbox + klauzula w formularzu 3. **Zadanie 2** — walidacja serwerowa zgody + testy 4. **Zadanie 3** — podstrona `/prywatnosc` + link w stopce 5. **Zadanie 4** — retencja danych 6. **Zadanie 5** — aktualizacja `info_text` 7. **Zadanie 6** — pełne testy, `npm test` zielone **Zadania 1–3 są wymagane przed startem** (jutro). Zadania 4–6 można dokończyć po starcie (do końca tygodnia). --- ## Pliki do modyfikacji | Plik | Zadania | |---|---| | `views/forno-rezerwacja.ejs` | 1 (checkbox + klauzula) | | `views/forno-prywatnosc.ejs` | 3 (nowy plik) | | `views/partials/forno-footer.ejs` | 3 (link do polityki) | | `public/forno.css` | 1 (style checkboxa) | | `forno-data.js` | 2 (walidacja consent), 4 (retencja) | | `forno-server.js` | 2 (przekazanie consent), 3 (route /prywatnosc), 4 (runTasks) | | `forno-settings.json` | 5 (info_text) | | `test/forno-data.test.js` | 2, 4 (nowe testy) | | `test/forno-server.test.js` | 2, 3 (nowe testy) | | `test/forno-consent.test.js` | 2 (nowy plik) | | `test/forno-privacy.test.js` | 3 (nowy plik) | --- ## Weryfikacja po implementacji - [ ] `npm test` — wszystkie testy zielone - [ ] Formularz bez zaznaczonego checkboxa → błąd walidacji - [ ] Formularz z checkboxem → rezerwacja tworzona z `consent: true` - [ ] `GET /prywatnosc` → 200, pełna klauzula RODO - [ ] Link do polityki prywatności w stopce każdej strony - [ ] `reservations.json` ma pole `consent` i `consent_at` w nowych rezerwacjach - [ ] Repo GitHub jest prywatne (404 w oknie prywatnym) - [ ] Cron `runTasks` usuwa stare rezerwacje po cutoff - [ ] `info_text` wspomina o prywatności