Files
FDMTech/FRONTEND_CONTRACT.md

29 lines
3.7 KiB
Markdown

# FDMTech — interfejs PHP dla projektanta (v1)
Projektant jest właścicielem `templates/layout.php`, `templates/home.php`, `public/assets/css/site.css`, `public/assets/js/site.js` i logo. Renderer nie edytuje tych plików. PHP 8.2+, bez frameworka. `public/` jest document root.
## Zmienne w obu szablonach
- `$site`: tablica `name`, `contact_email`, `contact_phone`, `navigation` (lista `{label, url}`). Puste dane kontaktowe są dozwolone, nie wymyślamy adresów.
- `$page`: `slug`, `title`, `seo_title`, `seo_description`, `published_html`, `published_css`, `published_at` (string/null). Tylko opublikowane dane.
- `$meta`: `title`, `description`, `canonical` (pełny URL lub pusty), `robots`.
- `$isDemo`: bool. Demo należy oznaczyć widocznym komunikatem „Tryb demonstracyjny — formularz nie wysyła zgłoszeń”.
- `$csrfToken`: string; `$formAction`: `/inquiries`; `$formValues`: name/email/company/phone/message/consent; `$formErrors`: mapa błędów; `$formNotice`: string lub null, sukces mówi wyłącznie o zapisie; `$formStatus`: `idle|invalid|saved|unavailable|limited`; `$smtpStatus`: `disabled`.
- `$statusCode`: HTTP status; `$nonce`: nonce CSP, jeśli potrzebny dla zaufanego lokalnego skryptu. Skrypty lokalne z `defer` są dozwolone; inline wymagają nonce.
- `$e($value)`: HTML/attribute escaping. Wszystkie teksty, atrybuty, meta i URL wyświetlać przez `$e`. Tylko `$content`, `$cmsHtml` i `$cmsStyleTag` są gotowym bezpiecznym HTML.
- `$cmsHtml`: przefiltrowany fragment publikacji; `$cmsStyleTag`: gotowy element style z nonce i CSS ograniczonym do `#cms-content` (albo pusty).
## Sposób renderowania
`templates/home.php` jest używany **tylko w jawnym demo na `/`** jako zaprojektowana strona pokazowa. Produkcyjna strona główna pochodzi z publikacji slug `home`, tak jak pozostałe strony. Aplikacja buduje `$content` jako `<main id="cms-content">…</main>` zawierający treść publikacji. W demo na `/` zawartość `home.php` trafia do tego samego main: szablon home nie dodaje własnego main ani ID cms-content.
`templates/layout.php` otrzymuje `$content` i tworzy cały dokument: head (escaped SEO, canonical, robots, `$cmsStyleTag`, CSS), globalny header/nav, `<?= $content ?>`, footer, lokalny JS. Nawigacja i kontakt pochodzą z `$site`. Nie umieszczać URL panelu Sensory. `layout.php` jest używany także dla błędów i formularza.
Formularz aplikacji dostępny pod `/kontakt` (trasa zarezerwowana, zawsze działa bez JS); linki CTA można kierować na `/kontakt`. Własny formularz w home: POST `$formAction`, hidden `_csrf=$csrfToken`, hidden `source=home`, pola `name`, `email`, opcjonalne `company`, `phone`, `message`, checkbox `consent=1` wymagany. Honeypot `website` ma pozostać pusty (ukryty, tabindex=-1, autocomplete=off). Błędy walidacji wracają na stronę formularza z kodem 422 i zachowanymi wartościami; po zapisie jest 303 do `/kontakt`, notice jednokrotny. Demo POST zwraca 503, nigdy fikcyjny sukces.
## Jawne demo i brak szablonów
`APP_DEMO=true` w środowisku/.env uruchamia dane demonstracyjne bez łączenia z DB. Domyślnie false. Demo otrzymuje `noindex, nofollow`. Awaria DB w produkcyjnym trybie zawsze zwraca 503. Brak home.php: semantyczna strona demo aplikacji. Brak layout.php: techniczny dokument HTML z globalną nawigacją i stopką z `app/View.php`, bez prac nad stylistyką.
Zasoby lokalne `/assets/...` (wersjonowane query `?v=N`, bo serwer wysyła długi cache). CSP blokuje skrypty publikacji, inline event handlers, zewnętrzne skrypty, iframes i obiekty. Obrazy HTTPS są dopuszczone (media CMS muszą być publicznie dostępne). Nie używać inline style w home; CSS projektanta pozostaje w site.css. Fonty marki wyłącznie lokalnie w `/assets/fonts/` (latin-ext obowiązkowo); brak ładowania z Google Fonts.