Devince
AI,  Development

Jedna komenda zamiast 20 minut klikania

Date Published

Jedna komenda zamiast 20 minut klikania

Miałem kurs do dodania na stronę. Tytuł, opis, 9 bloków treści, hero image, SEO. W admin panelu Payload CMS to jakieś 20 minut klikania: tworzysz dokument, dodajesz blok, kopiujesz tekst, formatujesz, dodajesz kolejny blok, i tak dalej. Dla jednej strony to akceptowalne. Dla dziesiątek, z poziomu agenta AI, który i tak już ma tę treść w kontekście — bezsensowne.

Postanowiłem zbudować pipeline, w którym Claude Code tworzy pełną stronę jedną komendą MCP. Metadane, bloki layoutu, konwersja markdown do Lexical, hero image z Replicate, publikacja. Cały wieczór. Oto jak to wyglądało.

Punkt startu: MCP server, który umie za mało

Mam MCP server na mcp.devince.dev obsługujący Streamable HTTP transport. Działają toole do postów i projektów (create_post, create_project, upload_media). Strona kursowa (kolekcja program w Payload) nie miała nic — dodanie kursu wymagało admin panelu.

Pierwszym krokiem było odwzorowanie wzorca z postów i projektów: endpointy REST (POST + PATCH) plus odpowiadające MCP toole. Payload CMS ma Local API, więc payload.create() robi robotę. Walidacja pól type, format, pricing po stronie endpointu, konwersja draft/published do flagi Payload — standardowa robota.

Po godzinie miałem create_program i update_program na prodzie. Stworzyłem kurs, ustawiłem metadane, opublikowałem. Ale strona kursu wyglądała pusto, bo metadane to jedno, a treść (bloki layoutu) to drugie. No i właśnie tutaj zaczęła się ciekawsza część.

Problem: jak programatycznie ustawić bloki layoutu

Payload CMS przechowuje treść stron jako tablicę bloków w polu layout. Każdy blok to obiekt z polem blockType i własnymi polami. Blok content ma kolumny z rich textem, features ma siatkę kart z ikonami, cta ma linki. Wewnątrz rich text siedzi Lexical JSON — format edytora, nie markdown.

Wyzwanie: chcę pisać treść bloków w markdown (bo tak pisze agent AI), a Payload oczekuje Lexical. Potrzebuję warstwy konwersji.

Okazało się, że richtext-lexical eksportuje convertMarkdownToLexical(). W projekcie był już wrapper markdownToLexical() używany przez endpointy postów. Wystarczyło go reużyć do pól rich text wewnątrz bloków.

Mapowanie pól markdown per blockType

Nie każdy blok ma rich text. Zrobiłem data-driven mapping zamiast if/else chain — obiekt mapujący blockType na listę pól do konwersji (cta -> richText, glassHero -> subheadline, contactCTA -> description, itd.). Blok content potrzebował osobnej obsługi bo ma zagnieżdżone kolumny. Reszta to prosta pętla: jeśli pole jest stringiem, konwertuj; jeśli obiektem, przepuść. Cała funkcja przetwarza bloki równolegle przez Promise.all.

Nowy endpoint: PUT /layout

Zdecydowałem się na osobny endpoint zamiast rozszerzania istniejącego create_program:

  • Layout blocks to full replace (PUT), nie partial update (PATCH)
  • Struktura jest złożona (tablica z 10 typami bloków), nie pasuje do prostego CRUD
  • Endpoint można wywoływać wielokrotnie (iteracyjne budowanie strony)

Markdown w polach richText jest konwertowany do Lexical server-side. Agent AI wysyła czysty markdown i nie musi wiedzieć o Lexical.

Dwie operacje (sprawdzenie czy program istnieje + konwersja markdown) lecą równolegle przez Promise.all. Po co czekać sekwencyjnie, skoro jedno nie zależy od drugiego?

Test na produkcji (i cold shower ze slugiem)

Zmergowałem PR, Coolify zaczął deploy. MCP server przebudowałem ręcznie na Hetznerze (git pull + docker compose up -d --build). Po 5 minutach oba systemy były gotowe.

Pierwsze wywołanie create_program przez MCP zwróciło slug od-pomysu-do-wdroenia---kurs-ai-krok-po-kroku. Payload automatycznie generuje slug z tytułu, ale polskie znaki po prostu wycinał zamiast transliterować. Poprawiłem ręcznie przez Payload REST API.

Potem wysłałem 9 bloków layoutu jednym callem set_program_layout. Kurs z pełną treścią pojawił się w admin panelu i na stronie. Od zera do opublikowanego kursu bez kliknięcia w admin.

Ten sam wzorzec dla stron (homepage rewrite)

Skoro działa dla programów, to samo można zrobić dla stron. Dodałem analogiczny endpoint i MCP tool set_page_layout z jedną różnicą: Pages mają blok featuredProjects, którego Program nie ma.

Przetestowałem na żywym organizmie. Stara strona główna była mocno sprzedażowa. Nowa jest luźniejsza: "Bartek Filipiuk. Buduję aplikacje webowe, integruję AI i pomagam dowozić projekty." Plus sekcja "Jak pracuję" zamiast "Dlaczego warto współpracować".

Jedno wywołanie set_page_layout z 6 blokami i homepage się zmienił. Szczerze mówiąc, to było satysfakcjonujące.

Portfolio pipeline: Obsidian, MCP, Replicate

Przy okazji zbudowałem pipeline do dodawania projektów. Dane o projektach trzymam w Obsidian (vault BRAIN, katalog PROJECTS). Każdy projekt ma ABOUT.md z tech stackiem, URLem repo i ścieżką na dysku.

Proces:

  1. Agent czyta ABOUT.md z Obsidian i źródła projektu
  2. Pisze opis portfolio oparty na realnym kodzie (nie na marketingu)
  3. Generuje hero image przez Replicate API (flux-2-pro, tematyczne, nie screenshoty UI)
  4. Upload image przez MCP upload_media
  5. Tworzy projekt przez MCP create_project z obrazem, technologiami i URLami

5 projektów dodanych w kilka minut, każdy z porządnym opisem wyciągniętym z codebase'u.

Co z tego wynika

| Przed | Po |
|-------|-----|
| Dodanie kursu = 20 min klikania w admin | Jeden call set_program_layout |
| Zmiana homepage = logowanie, szukanie bloków, edycja | Jeden call set_page_layout |
| Dodanie projektu = ręcznie tytuł, opis, tech, upload | Pipeline: Obsidian + Replicate + MCP |
| Blog post = pisanie, formatowanie, upload, SEO | Skill /blog-by-session (tak, ten artykuł) |
| Generowanie hero image = stocki, przycinanie, upload | Replicate API + MCP upload_media |

Cały MCP server ma teraz 10 toolów: CRUD na postach, projektach, programach, layout blocks na programach i stronach, upload mediów. Agent AI może zbudować kompletną stronę bez otwierania przeglądarki.

Payload CMS nadal robi to, w czym jest dobry: zarządzanie treścią, wersjonowanie, drafty, podgląd na żywo, lokalizacja. MCP dodaje programatyczny dostęp dla agentów AI. Admin panel zostaje dla ręcznej edycji i podglądu. Obie ścieżki współistnieją.

Czy warto budować taki pipeline? Jeśli masz jedną stronę i aktualizujesz ją raz na miesiąc — raczej nie. Jeśli budujesz treść regularnie, pracujesz z agentami AI i chcesz żeby content pipeline był tak zautomatyzowany jak CI/CD — zdecydowanie tak. U mnie ten wieczór pracy zwraca się przy każdym kolejnym kursie, projekcie i blog poście.