# Autorski CMS z AI

Autorski headless CMS i panel do zarządzania stronami, podstronami, tłumaczeniami i mediami z jednego miejsca — z AI podpiętym do pracy nad treścią przez MCP.

**Canonical:** https://spoko.space/pl/autorski-cms-z-ai/  
**Language:** pl  
**Published:** 2026-09-01  
**Updated:** 2026-10-15  
**Tags:** laravel, filament, astro, typescript, mariadb, rest-api, mcp  
**Category:** Portfolio

---
## W skrócie {#w-skrócie}

|  |  |
| --- | --- |
| Problem | Zestaw stron klienckich, każda na własnej instalacji CMS-a, każda z osobnymi aktualizacjami — i każda z formularzem logowania, bazą i PHP wystawionymi na publicznej domenie klienta. |
| Co powstało | Jeden wielofirmowy panel treści pod wszystkimi stronami: kreator stron z bloków, tłumaczenia, media, menu i przekierowania, a każda publiczna strona publikowana jako statyczny build. |
| Moja rola | Główny autor — model treści, silniki bloków i kolekcji, panel, warstwy REST i MCP, uruchamianie klientów i pakiet rdzenia frontu. |
| Co jest w tym ciekawego | CMS jest wystawiony przez MCP, więc tę samą treść można edytować w panelu albo pisać wprost z terminala — człowiek czy narzędzie AI, na tych samych uprawnieniach. |
| Efekt | Jeden kod do łatania zamiast wielu, żadnego CMS-a na domenie klienta i AI w procesie pracy nad treścią, a nie w osobnym oknie czatu. |

To, co firma nazywa „stroną internetową”, to zwykle dwie rzeczy: witryna, którą widzą odwiedzający, i miejsce, w którym ktoś siada i ją zmienia. Ten projekt to ta druga część — napisany od zera panel treści, z którego prowadzi się cały zestaw stron klienckich.

To praca komercyjna, więc nazwa klienta i produktu zostaje poza tym opisem. Wszystko poniżej dotyczy tego, co system robi i jak jest zbudowany.

## Co zastępuje {#co-zastępuje}

Domyślna odpowiedź na „potrzebujemy strony, którą klient sam edytuje” to jeden WordPress na klienta. Działa dokładnie do momentu, w którym masz ich kilkanaście. Wtedy każda strona to osobna instalacja z własnym rdzeniem, motywem i wtyczkami do aktualizowania; każda ma stronę logowania na publicznej domenie klienta; i każda wystawia bazę oraz PHP każdemu, kto ich poszuka. Nikt nie ma czasu pilnować kilkunastu takich instalacji, więc po cichu się starzeją — aż coś się zepsuje albo ktoś się włamie.

Wiem, jak to wygląda z drugiej strony — [ratowanie WordPressa](https://spoko.space/pl/naprawa-wordpress/) zaczyna się zwykle po tym, jak nieaktualizowana wtyczka wpuści kogoś do środka.

**Jeden panel, wiele statycznych stron**

- Jeden kod do łatania — aktualizacja bezpieczeństwa wychodzi raz i obejmuje każdą stronę.
- Po stronie klienta nie ma nic do aktualizowania ani panelu, o którym trzeba pamiętać.
- Publiczna strona to statyczny build: bez bazy, bez PHP, bez panelu na domenie klienta.
- Zero wtyczek z zewnątrz — każdy typ treści to kod, który sam utrzymuję.
- Jeden pipeline wdrożeniowy, używany przy każdym wydaniu, a nie raz na rok.

**Osobna instalacja CMS na klienta**

- N instalacji, każda z własnym rdzeniem, motywem i wtyczkami.
- Klient ma sam zauważyć komunikat o aktualizacji i coś z nim zrobić.
- Żywy CMS, baza i formularz logowania na każdej publicznej domenie.
- Wtyczki, nad których kodem i tempem aktualizacji nikt nie panuje.
- N ścieżek wdrożenia, w większości ręcznych i rozjeżdżających się.

## Co panel naprawdę daje osobie, która w nim pracuje {#co-panel-naprawdę-daje-osobie-która-w-nim-pracuje}

Zanim technologia zacznie mieć znaczenie: to miejsce, w którym osoba nietechniczna otwiera podstronę, zmienia ją i publikuje.

**W panelu**

- **Składasz stronę z bloków** — Hero, lista funkcji, cennik, FAQ, galeria, panel kontaktowy — przeciągasz je w odpowiednią kolejność i wypełniasz pola. Bez HTML-a i bez shortcode’ów.
- **Pilnujesz wszystkich języków** — Każda podstrona ma jedną wersję na język, a osobny ekran pokazuje, których tłumaczeń brakuje — razem z polami SEO, nie tylko treścią.
- **Wgrywasz zdjęcie raz** — Wersje pod www powstają w tle, więc redaktor wrzucający 4 MB z telefonu nie spowalnia po cichu całej strony.
- **Prowadzisz kolekcje, nie tylko podstrony** — Wpisy blogowe, case studies, usługi, plany cenowe, opinie, słownik pojęć — każda kolekcja ma własne pola, listing i kategorie.
- **Masz pod ręką całą hydraulikę** — Menu, przekierowania, raport 404, sitemapa i hreflang, obrazki do social mediów — to, od czego zależy widoczność, siedzi obok treści.
- **Rozdajesz właściwe klucze** — Trzy role, a autorowi można przydzielić dokładnie te kolekcje, nad którymi pracuje. Osoba od wpisów blogowych nie widzi cennika.

## Kreator stron {#kreator-stron}

Podstrona nie jest kawałkiem HTML-a. To uporządkowana lista typowanych bloków, trzymana osobno dla każdego języka, a każdy blok zna swoje pola. Typów bloków jest dziś 32 — hero, treść, funkcje, opinie, cennik, FAQ, galeria, zespół, godziny otwarcia, mapa, kontakt, wideo, zakładki, karuzela i reszta.

Dwie rzeczy z tej listy są ważniejsze niż jej długość:

- **Nowy typ bloku to wpis w konfiguracji, nie nowy moduł.** Paleta, którą widzi redaktor, opis przy każdym typie i pola w samym bloku pochodzą z jednego pliku konfiguracyjnego. Frontend rejestruje komponent pod tą nazwą i tyle.
- **Zdolność wspólną dla wielu bloków deklaruje się raz, a nie kopiuje do każdego.** Tło sekcji, wyrównanie, animacja pojawiania i identyfikator kotwicy mają jedną definicję, a blok tylko mówi, które z nich obsługuje — robi tak 26 z 32 typów.
- **Każdy blok dostaje trwałe id przy pierwszym zapisie.** Dzięki temu można podmienić jeden blok z zewnątrz — zapytaniem do API albo narzędziem AI — nie ruszając reszty podstrony.

Obok edytora stoi konspekt podstrony: jeden wiersz na blok, z fragmentem jego prawdziwej treści, więc długa strona daje się przeglądać zamiast zamieniać w ścianę zwiniętych paneli.

## Nowe typy treści bez pisania kodu {#nowe-typy-treści-bez-pisania-kodu}

Druga połowa silnika treści to kolekcje. Strona, która potrzebuje „case studies”, „godzin otwarcia dla każdego oddziału” albo „planów cenowych, ale w trzech osobnych zestawach”, nie dostaje pisanego pod siebie modułu. Kolekcję definiuje się w panelu — wybierasz typ elementu, włączasz pola, ustawiasz ikonę — i pojawia się w menu z własnym ekranem edycji, własnymi kategoriami i własnym endpointem API.

Każdy klient ma przy tym włączone tylko te kolekcje, z których faktycznie korzysta. Reszta jest wyłączona i nie zaśmieca mu menu.

## Tłumaczenia, których stan widać {#tłumaczenia-których-stan-widać}

Wielojęzyczność zwykle sypie się po cichu: ktoś dodaje angielską podstronę, nikt nie dodaje polskiej, a lukę wyłapuje po miesiącach przypadkowy odwiedzający. Panel zamiast tego cały czas liczy — ile podstron jest przetłumaczonych w danym języku, których brakuje i czy wypełniono także tytuł i opis SEO, nie tylko samą treść.

## Najciekawsza część: AI jako pełnoprawny klient CMS-a {#najciekawsza-część-ai-jako-pełnoprawny-klient-cms-a}

Wszystko, co panel potrafi odczytać, autorski CMS wystawia dwa razy — jako REST API i jako serwer **MCP**, za tym samym uwierzytelnieniem. MCP to protokół, którym asystenci AI rozmawiają z zewnętrznymi systemami, więc ta druga warstwa oznacza, że narzędzie AI pracuje bezpośrednio na treści, zamiast dostawać ją wklejoną z ręki.

Narzędzi jest tam dziś 82: wypisz i przeczytaj podstrony, przeszukaj treść, pobierz schemat bloków, utwórz podstronę, podmień pojedynczy blok po jego id, ustaw metadane, ogarnij kategorie, menu i przekierowania, wgraj media, uruchom przebudowę. Klient może podpiąć Claude'a do własnego panelu swoim własnym loginem — OAuth z PKCE, a nie token wklejony do pliku konfiguracyjnego — i poprosić o szkic podstrony, uzupełnienie brakujących opisów albo przetłumaczenie sekcji, a zmiany lądują w CMS-ie, nie w oknie czatu.

Ten sam sposób pracy, z dużo mniejszym zestawem narzędzi, działa też w WordPressie [bloga polo.blue](https://spoko.space/pl/modern-car-blog/#redagowanie-wordpressa-przez-mcp), gdzie serwer MCP doszedł do gotowego CMS-a jako wtyczka.

### Dwoje drzwi do tej samej treści {#dwoje-drzwi-do-tej-samej-treści}

Panel to jedno wejście. Terminal to drugie. MCP jest protokołem, a nie funkcją jednej aplikacji, więc te same narzędzia, które odpowiadają oknu czatu, odpowiadają też Claude Code — programista zostaje tam, gdzie już jest, i pisze do CMS-a z linii poleceń: tworzy podstronę, wypełnia jej bloki, ustawia metadane, uruchamia przebudowę.

To nie jest ścieżka na pokaz. Teksty na stronach postawionych na tym systemie weszły z terminala, a nie przez klikanie w panelu. Napisanie dwunastu podstron to inna robota, kiedy zamiast otwierać dwanaście formularzy podaje się brief i strukturę.

Oboje drzwi prowadzą do tej samej treści, tej samej walidacji i tych samych uprawnień. Osoba, która raz na kwartał poprawia stronę „O nas", dostaje panel, który niczego od niej nie wymaga; programista stawiający całą stronę dostaje linię poleceń. Żadne z nich nie musi udawać drugiego.

Ciekawym problemem inżynierskim nie były same narzędzia, tylko zabezpieczenia:

- **Poświadczenie nigdy nie jest szersze niż jego właściciel** — Każde chronione narzędzie sprawdza dwie rzeczy: czy osoba ma uprawnienie i czy poświadczenie ma pasujące pozwolenie. Poświadczenie tylko do odczytu nie uruchomi wdrożenia ani nie wyda cudzego limitu API.
- **Zawsze w granicach jednego klienta** — To właściciel poświadczenia decyduje, czyją treść ono widzi. Nie ma parametru z id klienta, który dałoby się podmienić, więc nie ma czego pomylić między najemcami.
- **Limity, które faktycznie ograniczają** — Narzędzia wydające prawdziwe pieniądze — wdrożenia, tagi wydań, limity zewnętrznych API — mają ostrzejszy przydział niż narzędzia do odczytu.
- **Spisany kontrakt do przeczytania** — Format bloków ma własną specyfikację, a typy na froncie są generowane ze schematu backendu. Narzędzie AI edytujące podstronę pracuje na tym samym dokumencie co programista.

## Od zmiany do strony na produkcji {#od-zmiany-do-strony-na-produkcji}

**Droga publikacji**

1. **Ktoś wprowadza zmianę** — Redaktor przestawia bloki i poprawia teksty w panelu — albo narzędzie AI podmienia jeden blok przez MCP. Te same dane, ta sama walidacja.
2. **Zapis jako treść o strukturze** — Bloki idą do bazy jako typowany JSON, osobno dla każdego języka, każdy z trwałym id. Nic nie jest zapisywane jako gotowy HTML, więc tę samą treść można później wyrenderować inaczej.
3. **Publikacja kolejkuje build** — Panel wprost mówi, że produkcja jest starsza niż treść, a jeden przycisk uruchamia przebudowę.
4. **Strona pyta API o swoje podstrony** — Statyczny build loguje się własnym poświadczeniem i pobiera gotowe podstrony — z blokami i rozwiązanymi referencjami — w jednym przebiegu.
5. **Nowy build wchodzi na produkcję** — Redaktorzy widzą kolejno: w kolejce → budowanie → wydane, a poprzednie wydanie zostaje, żeby dało się na nie wrócić.

Przebudowa trwa od 10 do 20 sekund. Ta liczba sprawia, że „to opublikujmy" jest zdaniem, które można powiedzieć klientowi od ręki, a nie tematem do ustalenia na później — a panel trzyma historię, więc powrót na dowolne wcześniejsze wydanie to jeden przycisk.

Odwiedzający dostaje na końcu stronę statyczną: HTML, CSS i obrazki z CDN-u. Żadnego zapytania do bazy, żadnego procesu PHP, nic, do czego można się zalogować. Treść mieszka w panelu, publiczna strona jest jej migawką.

Ponieważ kontraktem między jednym a drugim jest zwykły JSON po HTTP, front też nie jest zabetonowany. Dziś renderuje go [Astro](https://spoko.space/pl/slownik/astro/); strona w Next.js, Nuxcie czy SvelteKicie korzystałaby z dokładnie tych samych endpointów, a backend nie musiałby się zmienić.

## Uruchomienie nowej strony {#uruchomienie-nowej-strony}

Dodanie klienta to jeden formularz. Wszystko po nim dzieje się w tle, jako łańcuch kroków, z których każdy da się powtórzyć osobno: repozytorium, a przez API RunCloud — aplikacja na serwerze, podpięcie wdrożeń z gita i certyfikat Let's Encrypt. Panel pokazuje, na którym kroku jest, zamiast jednego „udało się / nie udało”, a nieudany przebieg można wznowić bez dublowania tego, co już powstało.

## Moja rola {#moja-rola}

Jestem głównym autorem tego [headless CMS-a](https://spoko.space/pl/slownik/headless-cms/): wielofirmowego modelu treści, silników bloków i kolekcji, panelu w Filamencie, warstw REST i MCP, łańcucha uruchamiania klientów, procesu obróbki obrazów i pakietu Astro, z którego budowane są strony klientów. W pierwszych dziesięciu tygodniach weszło około 1900 commitów, w większości moich, przy niewielkim zespole i code review na każdym pull requeście.

## Efekt {#efekt}

- **Jeden backend, wiele stron** — Aktualizacja bezpieczeństwa, nowy typ bloku albo nowa funkcja panelu trafiają od razu na wszystkie strony, zamiast być powtarzane instalacja po instalacji.
- **Na publicznej domenie nie ma czego atakować** — Żadnego CMS-a, bazy ani formularza logowania na stronie klienta — tylko statyczny build.
- **AI w procesie, a nie obok niego** — Treść może szkicować, poprawiać i publikować asystent AI pracujący bezpośrednio na CMS-ie, na tych samych uprawnieniach co człowiek.

## Technologie {#technologie}
