33 lines
3.8 KiB
Markdown
33 lines
3.8 KiB
Markdown
# Kontrakt CMS FDMTech — v1
|
||
|
||
Właściciel schematu: backend CI4 w `/workspace/Sensory/sensory.fdmtech.pl`. Dedykowana baza CMS (grupa CI4 `cms`); renderer PDO nigdy nie korzysta z bazy ani tabel telemetrii. Brak konfiguracji/zmian produkcyjnych w ramach implementacji. Wszystkie daty CMS: UTC, `Y-m-d H:i:s`. Tabele bez prefiksu.
|
||
|
||
## `cms_pages`
|
||
`id` INT PK auto, `slug` VARCHAR(160) UNIQUE, `title` VARCHAR(200), `draft_json` MEDIUMTEXT (projekt GrapesJS), `draft_html` MEDIUMTEXT, `draft_css` MEDIUMTEXT, `draft_seo_title` VARCHAR(200), `draft_seo_description` VARCHAR(320), `published_html` MEDIUMTEXT NULL, `published_css` MEDIUMTEXT NULL, `seo_title` VARCHAR(200) NULL, `seo_description` VARCHAR(320) NULL, `published_title` VARCHAR(200) NULL, `status` VARCHAR(20) (`draft`/`published`), `published_at` DATETIME NULL, `version` INT (optymistyczna blokada), `created_by` INT, `updated_by` INT, `created_at`, `updated_at` DATETIME.
|
||
|
||
Slug pojedynczy: `[a-z0-9]+(?:-[a-z0-9]+)*`; `home` oznacza `/`. Slug jest stały po utworzeniu. `title` jest roboczy; publicznie używaj `published_title`. Zapis szkicu nie zmienia publicznych pól ani statusu. Publikacja atomowo ustawia HTML/CSS, tytuł, SEO i datę oraz tworzy rewizję. Wycofanie zmienia status na `draft`.
|
||
|
||
Odczyt PDO (parametryzowany):
|
||
```sql
|
||
SELECT id, slug, published_title AS title, published_html, published_css,
|
||
seo_title, seo_description, published_at
|
||
FROM cms_pages WHERE slug = :slug AND status = 'published'
|
||
AND published_at IS NOT NULL LIMIT 1;
|
||
```
|
||
Brak rekordu = 404 / jawny fallback aplikacji. Nigdy nie czytaj `draft_*`. Payload to fragment body HTML i osobny arkusz CSS po restrykcyjnej filtracji serwerowej. Renderer escapiuje tytuły/SEO, osadza HTML w kontenerze `<main id="cms-content">` (wymagane: CSS jest ograniczony do tego ID), CSS jako arkusz/element style; zalecany CSP bez skryptów treści. Nie wykonuje projektu JSON. Obrazy mają absolutne URL endpointu Sensory `/cms-media/{losowa-nazwa}`.
|
||
|
||
## `cms_settings`
|
||
`key` VARCHAR(80) PK, `value` TEXT (JSON), `updated_at` DATETIME.
|
||
Klucze: `site_name` (string), `contact_email` (string), `contact_phone` (string), `navigation` (tablica obiektów `{label:string,url:string}`). `SELECT \`key\`, \`value\` FROM cms_settings`. JSON dekodować i walidować typy, tekst/atrybuty escapować. Brak klucza: domyślna wartość renderera. Nawigacja dopuszcza lokalne ścieżki zaczynające się pojedynczym `/` i HTTPS.
|
||
|
||
## `cms_inquiries`
|
||
`id` INT PK auto, `name` VARCHAR(160), `email` VARCHAR(254), `company` VARCHAR(200) domyślnie pusty, `phone` VARCHAR(60) domyślnie pusty, `message` TEXT, `source` VARCHAR(160) domyślnie `audit`, `consent_at` DATETIME NOT NULL, `status` VARCHAR(20) domyślnie `new` (`new`, `in_progress`, `closed`), `created_at` DATETIME NOT NULL, `updated_at` DATETIME NOT NULL.
|
||
|
||
Renderer może INSERT wyłącznie jawnych pól: name, email, company, phone, message, source, consent_at, created_at, updated_at. Status nadawany przez DB. Walidacja: name 1–160, poprawny email <=254, company <=200, phone <=60, message 1–10000, source <=160. Zgoda wymagana; czas UTC po stronie serwera. CSRF, honeypot/rate limit i limity żądania są odpowiedzialnością formularza publicznego. Nie udostępniać odczytu skrzynki publicznie.
|
||
|
||
## Tabele prywatne
|
||
`cms_revisions` (snapshot projektu, HTML/CSS i metadanych przy publikacji), `cms_media` (metadane bezpiecznych obrazów). Renderer ich nie potrzebuje. Bez FK do użytkowników/telemetrii Sensory.
|
||
|
||
## Uprawnienia połączenia publicznego
|
||
SELECT tylko na `cms_pages` i `cms_settings`; INSERT tylko na `cms_inquiries`. Dla ścisłego oddzielenia szkiców nadać SELECT na wskazane kolumny publiczne `cms_pages` zamiast całej tabeli. Bez UPDATE/DELETE i bez dostępu do pozostałych baz. Dane dostępu PDO i CI4 dostarcza operator poza repo. Migracje uruchamia operator wyłącznie po weryfikacji docelowej bazy.
|