Skip to content

Architektura systému ​

Tato kapitola popisuje vnitřní uspořádání platformy Než zazvoní CMS, její softwarové komponenty a princip sdílené instalace pro více škol. Informace jsou určeny pro správce systému a technické pracovníky, kteří zodpovídají za provoz, infrastrukturu a bezpečnost.

Základní myšlenkou je provozovat jednu centrální instanci redakčního systému i prezentačního webu pro všechny zapojené školy. Tento přístup umožňuje snadnou správu, jednotné aktualizace a nízké provozní náklady při zachování důsledného oddělení dat jednotlivých škol.

Hlavní komponenty platformy ​

Celý systém běží na jednom virtuálním serveru v prostředí Docker Compose. Skládá se ze čtyř hlavních služeb a jednoho sdíleného diskového svazku.

SlužbaTechnologieÚčel a zapojení v systému
caddyCaddy 2 (Alpine)Vstupní reverzní proxy pro veškerý provoz z internetu. Zajišťuje automatické vystavování TLS certifikátů přes Let's Encrypt, vynucuje bezpečnostní hlavičky HSTS a komprimuje odpovědi.
webNext.js 16 (App Router)Samostatný webový server obsluhující veřejné stránky škol. Vybírá školu podle domény požadavku, dotazuje se na data do CMS a sestavuje výsledné HTML stránky.
cmsStrapi 5 (TypeScript)Aplikační jádro platformy. Poskytuje administrační rozhraní na adrese /admin a aplikační rozhraní REST API na portu 1337.
dbPostgreSQL 16 (Alpine)Centrální relační databáze pro veškerá strukturovaná data, uživatelské účty a auditní záznamy. Běží výhradně ve vnitřní síti Dockeru bez přístupu z internetu.
Svazek uploadsLokální souborový svazekTrvalé diskové úložiště pro obrázky, dokumenty PDF a další multimediální soubory nahrané v Knihovně médií.

Veřejně dostupné jsou pouze porty 80 a 443 na reverzní proxy Caddy. Databáze PostgreSQL i aplikační server Strapi zůstávají před vnějším světem zcela skryté.

Tok požadavků a dat ​

Komunikace v systému se dělí na dvě oddělené trasy: tok návštěvníka veřejného webu a tok přihlášeného redaktora v administraci.

Tok požadavku návštěvníka ​

  1. Návštěvník zadá do prohlížeče adresu školy (například https://oapv.cz/kontakty).
  2. Požadavek přijme Caddy, ověří šifrování TLS a předá požadavek službě web.
  3. Vstupní filtr v souboru proxy.ts zkontroluje limit požadavků na IP adresu, vygeneruje unikátní nonce pro Content Security Policy a vyřeší případná přesměrování starých adres z původního webu.
  4. Funkce findSchool vyhledá příslušnou školu podle domény v HTTP hlavičce Host.
  5. Server Next.js odešle interní dotaz na REST API do kontejneru cms. Odpovědi z CMS se ukládají do datové mezipaměti na 60 sekund.
  6. Server vygeneruje HTML stránku s designem školy a odešle ji návštěvníkovi. Média si prohlížeč stahuje přímo z adresy /uploads/... přes Caddy a CMS.

Tok požadavku redaktora ​

  1. Redaktor otevře přihlašovací stránku administrace na adrese https://cms.<doména>/admin.
  2. Po zadání e-mailu a hesla vystaví systém zabezpečený JWT token a nastaví httpOnly cookie s příznakem Secure.
  3. V levém menu se zobrazí pouze položky povolené pro roli Redaktor školy.
  4. Při otevření sekce Obsah webu první vrstva řízení přístupu (RBAC) automaticky profiltruje záznamy tak, aby redaktor viděl výhradně obsah své školy.
  5. Každý pokus o uložení nebo publikaci projde druhou vrstvou kontroly v Document Service guardu.
  6. Po úspěšné kontrole se data zapíší do databáze PostgreSQL a do systémové tabulky se uloží záznam o provedené změně.

Model jedné instance pro více škol ​

Platforma hostuje všechny školy v jedné společné instanci systému Strapi a jedné databázi. Toto rozhodnutí vychází z potřeby spravovat systém jedním technikem s minimální režií.

Provozování samostatného kontejneru pro každou školu by znamenalo desítky oddělených systémů, nutnost provádět desítky aktualizací současně a vysokou spotřebu paměti (každé Strapi spotřebuje v klidu 300 až 500 MB RAM). Jedna sdílená instance se aktualizuje i zálohuje centrálně.

Datový model oddělení škol stojí na čtyřech pravidlech:

  • Záznam školy: Každá škola má samostatný záznam typu Škola (api::school.school), kde jsou uloženy identifikační údaje, doména, barvy, písma a struktura menu.
  • Příslušnost obsahu: Typy obsahu Stránka (api::page.page), Aktualita (api::post.post) a Kategorie (api::category.category) mají povinnou vazbu na záznam školy.
  • Knihovna médií: Soubory každé školy jsou uloženy v kořenové složce pojmenované podle zkratky (slugu) dané školy.
  • Přiřazení redaktora: Uživatel s rolí Redaktor školy je propojen se svou školou prostřednictvím záznamu Redaktor školy (api::editor.editor). Příslušnost se neodvozuje z názvu role, což umožňuje používat jedinou sdílenou roli pro celou platformu.

Čtyři vrstvy oddělení škol ​

Aby bylo zajištěno, že redaktor za žádných okolností neuvidí ani neupraví data jiné školy, využívá systém čtyři na sobě nezávislé bezpečnostní vrstvy.

VrstvaKde je implementovánaCo přesně zajišťuje
1. RBAC podmínkycms/src/tenant/roles.tsFiltruje zobrazení v administraci. Podmínky own-school a own-school-media zajišťují, že redaktor v seznamech vidí pouze obsah a soubory své školy.
2. Document Service guardcms/src/tenant/guard.tsHloubková kontrola na úrovni jádra Strapi. Prověřuje všechny akce (čtení, vytváření, úpravy, mazání, klonování, publikování, zrušení publikace i zahození změn). Zabraňuje navázání cizích stránek do stromu nebo vložení cizích médií.
3. Upload a správa médiícms/src/tenant/upload-guard.tsŘídí ukládání souborů. Automaticky směruje nahrávané soubory do složky školy, hlídá diskovou kvótu (2 GB na školu) a zakazuje redaktorům vytvářet podsložky, hromadně přesouvat soubory nebo nahrávat média z externích adres URL.
4. Veřejné REST APIcms/src/tenant/public-api.tsOmezuje veřejný přístup. Autentizační strategie public-read povoluje anonymním návštěvníkům pouze čtení publikovaných dat vybraných typů. Zápisové operace přes veřejné API jsou zcela vyloučeny.

V seznamu rolí v administraci vidíte oddělení pravomocí mezi správcem platformy a redaktory škol.

Seznam rolí v administraci

Kromě těchto čtyř vrstev obsahuje systém také samostatný auditní protokol. Všechny operace zápisu, úpravy, publikování i mazání se zaznamenávají do typu obsahu Historie změn (api::audit-log.audit-log). Zápis do auditního protokolu probíhá přímo na úrovni databázové vrstvy, takže případná chyba při logování neohrozí dokončení požadavku.

Všechny operace a úpravy napříč celým systémem sleduje vestavěná Historie změn.

Přehled historie změn v administraci

Tipy a doporučení ​

Pravidelné testy izolace

Před každým nasazením nové verze do produkce spusťte testovací sadu node tests/tenant-test.mjs. Tento skript automaticky prověřuje více než sto různých scénářů pokusu o přístup k cizím datům (čtení, zápis, klonování cizí stránky, přesun médií i podvržení relací).

Zpoždění mezipaměti na webu

Veřejný web Next.js drží odpovědi z CMS v paměti po dobu 60 sekund. Pokud redaktor v administraci klikne na tlačítko Publikovat, změna se na webu projeví nejpozději do jedné minuty.

Export dat školy

Skript export-site.js pro export jednotlivé školy do formátu site.json je na produktové roadmapě. Do jeho zavedení se export dat školy řeší výběrem z databáze a zkopírováním souborů ze složky médií.

Související ​