Twój pierwszy blok na żywo
Jedna ścieżka, bez skrótów: świeża aplikacja Next.js, okablowanie cmssy, Twoja lokalna strona osadzona w edytorze, własny blok edytowany w miejscu, potem deploy, promocja, publikacja - i webhook, dzięki któremu publikacja pokazuje się od razu, a nie po wygaśnięciu cache'u. Każdy krok poniżej został przejechany od początku do końca 2026-09-20 z @cmssy/cli 16.11.0 i Next.js 16.3.
Pozostałe strony tej sekcji tłumaczą każdy element z osobna. Ta przechodzi całą ścieżkę po kolei, z dokładnymi komendami i dokładnymi etykietami, które zobaczysz. Na końcu masz stronę w Next.js renderującą Twój workspace, własny blok na opublikowanej stronie i workspace, który mówi Twojej stronie, kiedy się odświeżyć.
1. Utwórz aplikację i okabluj cmssy
Zacznij od generatora swojego frameworka, a potem pozwól CLI cmssy dodać okablowanie. Next.js wykrywa z package.json. CLI wołaj zawsze jako @cmssy/cli@latest: inaczej stara globalna instalacja wygra i wywali się z Cannot query field "myWorkspaces".
npx create-next-app@latest my-site # App Router: yes
cd my-site
npx @cmssy/cli@latest init
pnpm installinit zapisuje 16 plików i nigdy nie nadpisuje bez --force:
cmssy.config.ts- czytaCMSSY_ORG_SLUG,CMSSY_WORKSPACE_SLUGiCMSSY_DRAFT_SECRETprosto zprocess.env, więc brakująca zmienna wywala się przy starcie z nazwą, a nie gdzieś dalej bez związku..env.exampleje wylicza; prawdziwy.env.localwypełnilinkw następnym kroku.proxy.ts- preset middleware: prefiksy języków, zweryfikowane przepisanie do trybu edycji i CSP, które pozwala osadzać stronę tylko panelowi cmssy.cmssy/blocks.ts- rejestr bloków, z przykładowym blokiemherowblocks/hero/. Obok:cmssy/editor.tsx(ładuje rejestr leniwie po stronie klienta),cmssy/editable-layout.tsx(nagłówek i stopka przez mostek edycji) icmssy/site-providers.tsx(jedyne miejsce na Twoje providery).app/[[...path]]/page.tsxilayout.tsx- publiczna trasa catch-all renderująca każdą stronę cmssy, plusservices/pages.ts, z którego czyta.app/page.tsxiapp/layout.tsxz generatora lądują w.cmssy-backup/.app/cmssy-edit/[[...path]]/- trasa, na którą przepisywany jest edytor, z własnym root layoutem; oba layouty importująglobals.css, więc trzymaj je w zgodzie, gdy dodajesz CSS albo metadane.app/api/draft/route.tsiapp/api/revalidate/route.ts- podgląd roboczy i webhook publikacji, który podłączysz w kroku 8.
init wpina też @cmssy/eslint-plugin do eslint.config.mjs i dodaje @cmssy/next, @cmssy/react, @cmssy/core oraz plugin do package.json w swojej wersji - dlatego instalacja jest po nim.
2. Podłącz aplikację do workspace'u
npx @cmssy/cli@latest link --token cs_...link pobiera tokenem slug organizacji, slug workspace'u i sekret draftu, zapisuje całą trójkę do .env.local, sprawdza, że workspace odpowiada, sekret się zgadza i /api/draft jest zamontowane, a na końcu drukuje link do edytora tego workspace'u. Jeśli workspace nie ma jeszcze manifestu bloków, wypycha go z Twojego rejestru, żeby paleta edytora znała Twoje bloki przed pierwszym deployem. Gdy token widzi kilka workspace'ów, zapyta, o który chodzi - w powłoce nieinteraktywnej zamiast tego się zatrzyma, więc podaj --workspace <slug>. Na końcu wypisuje linki podglądu roboczego z wbudowanym sekretem: nie wklejaj ich nigdzie publicznie.
Wybieraj link zamiast przepisywania ręcznego. Jeśli jednak przepisujesz, wszystko jest w Settings → Headless: Organization, Workspace i Draft preview secret z przyciskiem Copy. Regenerate natychmiast unieważnia stary sekret - zaktualizuj wtedy .env.local.
3. Środowisko w jednym miejscu
| Zmienna | Ustawia | Do czego |
|---|---|---|
CMSSY_ORG_SLUG | link | Slug organizacji. Wymagana. |
CMSSY_WORKSPACE_SLUG | link | Slug workspace'u. Wymagana. |
CMSSY_DRAFT_SECRET | link | Tylko po stronie serwera. Pilnuje podglądu roboczego i trybu edycji: edytor go wysyła, proxy.ts weryfikuje. Wymagana. |
CMSSY_WEBHOOK_SECRET | Ty, krok 8 | Sekret podpisu webhooka content.changed, który trafia w /api/revalidate. Bez niego trasa odpowiada 500. |
CMSSY_API_TOKEN | opcjonalna | Pozwala pominąć --token w komendach CLI. Działająca strona nigdy jej nie potrzebuje. |
NEXT_PUBLIC_SITE_URL | opcjonalna | Twój publiczny adres, jeśli budujesz canonical, hreflang albo sitemapę jak starter. cmssy przechowuje treść kanoniczną, nigdy Twoją domenę. |
Te same nazwy ustaw w środowisku hostingu przy deployu (krok 7). Nie dodawaj fallbacków ?? "": pusty slug to ciche 404, nazwana brakująca zmienna to poprawka.
4. Uruchom i osadź w edytorze
pnpm dev # http://localhost:3000Sam localhost:3000 renderuje treść opublikowaną - świeży workspace pokazuje stronę startera Nothing published yet at / i tak ma być. Edycja na żywo dzieje się w edytorze cmssy, który osadza Twoją działającą aplikację:
- Otwórz link do edytora, który wydrukował
link(albo Pages w panelu) i otwórz stronę - utwórz ją, jeśli workspace jest pusty. - W nagłówku edytora kliknij Dev host. Włącz Enable dev host, wpisz
http://localhost:3000w polu Local dev host i kliknij Apply. Jeśli strona ma niezapisane zmiany, potwierdzisz Enter dev preview?.
Pojawia się niebieski baner: Dev preview - changes save to your isolated dev buffer, not production. Canvas pokazuje teraz Twoją lokalną aplikację, a paleta bloków (Add block albo zakładka Blocks w lewym panelu) listuje to, co eksportuje cmssy/blocks.ts - na razie sam Hero. Edytor czyta schematy z osadzonej strony przy każdym handshake'u. Trzy rzeczy o Dev hoście:
- Przyjmuje tylko adresy localhost (
localhost,127.0.0.1,::1,*.localhost), http lub https. Chrome osadza zwykłe http z edytora na https; Firefox i Safari mogą to blokować - tam użyj tunelu. - Jest tylko Twój. Adres żyje w sesji przeglądarki, a włącznik jest per użytkownik. Zespół dalej używa zapisanego Preview URL (Settings → Headless), którego Dev host nie rusza.
- Dopóki jest włączony, zmiany idą do Twojego bufora dev, nie do wspólnego draftu strony, a Publish jest wyłączony. Krok 7 przenosi bufor do prawdziwego draftu. Przeładowanie edytora nie szkodzi: osadzona strona ładuje wspólny draft, a edytor odkłada bloki z Twojego bufora z powrotem na canvas, gdy tylko strona się zgłosi.
5. Napisz blok
Niech CLI go wygeneruje; nazwa musi być w kebab-case:
npx @cmssy/cli@latest add block feature-cardPowstają dwa pliki, a blok zostaje zarejestrowany w cmssy/blocks.ts za Ciebie:
// blocks/feature-card/FeatureCard.tsx
import { fields, type BlockProps } from "@cmssy/react";
export const featureCardProps = {
heading: fields.text({ label: "Heading", required: true }),
text: fields.textarea({ label: "Text" }),
};
export default function FeatureCard({
content,
}: BlockProps<typeof featureCardProps>) {
return (
<section>
<h2>{content.heading}</h2>
{content.text ? <p>{content.text}</p> : null}
</section>
);
}// blocks/feature-card/block.ts
import { defineBlock } from "@cmssy/react";
import FeatureCard, { featureCardProps } from "./FeatureCard";
export const featureCardBlock = defineBlock({
type: "feature-card",
label: "Feature card",
component: FeatureCard,
props: featureCardProps,
});Schemat jest jedynym miejscem, w którym pole ma nazwę: BlockProps<typeof featureCardProps> typuje z niego content, więc zmiana nazwy heading to błąd kompilacji, a nie pusta karta. Nadaj scaffoldowi jakiś kształt, zanim wrócisz do edytora - przychodzi bez stylów, a pusty <h2> ma zero pikseli wysokości, więc do momentu wpisania tekstu nic nie zobaczysz:
<section className="mx-auto max-w-2xl px-6 py-16">
<h2 className="text-3xl font-semibold">{content.heading}</h2>
{content.text ? <p className="mt-4 text-lg">{content.text}</p> : null}
</section>Restart nie jest potrzebny: hot reload przeładowuje osadzoną stronę, a edytor czyta schematy na nowo - Feature Card pojawia się w palecie w kilka sekund. Jeśli nie, przeładuj raz stronę edytora. Reszta o polach, loaderach i blokach layoutu jest w Przewodniku tworzenia bloków.
6. Wrzuć go na stronę i edytuj na żywo
Z powrotem w edytorze (Dev host wciąż włączony): przeciągnij Feature Card z palety na canvas, wypełnij Heading i Text w panelu właściwości i patrz, jak sekcja w Twojej aplikacji aktualizuje się w trakcie pisania. Zmień markup komponentu w swoim edytorze kodu, a canvas pójdzie za tym przy hot reloadzie.
Dla nowego bloku nie pojawia się żadne ostrzeżenie: edytor traktuje typ zadeklarowany przez osadzoną stronę jako znany, choć manifest bloków workspace'u pozna go dopiero w kroku 7. Jeśli żółte ostrzeżenie jednak wymienia jakiś typ, działająca strona naprawdę go nie renderuje - przywróć blok w kodzie albo usuń go ze strony.
Kliknij Save page. Toast mówi Saved to your dev buffer: to Twoja prywatna kopia robocza, więc blok, którego nie ma jeszcze na wdrożonej stronie, nie zepsuje nikomu podglądu.
7. Wdróż blok, promuj, opublikuj
Trzy rzeczy muszą znać feature-card, zanim jego treść pójdzie publicznie: wdrożona strona (żeby odwiedzający ją wyrenderowali), wspólny podgląd edytora (który osadza zapisany Preview URL) i manifest bloków workspace'u (względem którego Promote to draft waliduje). W tej kolejności:
- Wdróż aplikację (np.
vercelalbo push do podłączonego repozytorium) z tymi samymi zmiennymi z kroku 3 ustawionymi w środowisku hostingu. - Skieruj Preview URL na deploy - Settings → Headless → Preview URL, albo
npx @cmssy/cli@latest link --token cs_... --preview-url https://my-site.vercel.app. - Zaktualizuj manifest bloków z kodu, który właśnie wdrożyłeś:
npx @cmssy/cli@latest sync-manifest --token cs_.... Wypisuje dokładnie, co się zmienia (tu: adds feature-card) i aktywuje nowy manifest. Alternatywa bez CLI: wyłącz raz Dev host - edytor czyta bloki wdrożonej strony i, bo ta zmiana tylko dodaje typ, aktywuje ją sam; zmiana, która usuwa albo przebudowuje typy, jest tylko proponowana i czeka na przegląd w Settings → Headless → Block manifest. - Z powrotem w edytorze z włączonym Dev hostem kliknij Promote to draft w niebieskim banerze. Twój bufor dev staje się prawdziwym draftem strony. Pominięcie punktu 3 kończy się toastem z nazwą brakującego typu - Typ bloku feature-card nie jest jeszcze w manifeście bloków workspace'u - i tymi samymi dwiema drogami wyjścia.
- Wyłącz Dev host (Dev host → przełącznik; potwierdź Exit dev preview?, jeśli zapyta). Canvas osadza teraz wdrożoną stronę i renderuje tam Twój blok.
- Kliknij Publish.
Publikacja niczego nie wdraża - blok poszedł na produkcję w punkcie 1; publikacja tylko przełącza treść na publiczną.
8. Żeby publikacja pokazała się od razu: webhook rewalidacji
Trasa catch-all wygenerowana przez init cache'uje: export const revalidate = 3600. Bez pomocy opublikowana strona serwuje starą kopię nawet przez godzinę. cmssy zamyka tę lukę, wołając Twoją stronę przy każdej publikacji - Ty tylko rejestrujesz endpoint.
- W panelu otwórz Settings → Webhooks i kliknij Add endpoint.
- URL:
https://twoja-strona.com/api/revalidate. Zdarzenia: content.changed (jedno zdarzenie odpalane przy każdej zmianie strony, rekordu, mediów i ustawień; do cache'u nie potrzebujesz tych szczegółowych). - Skopiuj sekret od razu - pokazuje się tylko raz. Ustaw go jako
CMSSY_WEBHOOK_SECRETw środowisku hostingu i zrób redeploy.
Co dzieje się przy publikacji: cmssy podpisuje payload HMAC-SHA256 z timestamp.body i wysyła go z nagłówkiem x-cmssy-signature: t=…,v1=…. createCmssyRevalidateRoute w app/api/revalidate/route.ts weryfikuje podpis Twoim sekretem i unieważnia tagi cache'u treści cmssy, więc następne żądanie renderuje świeżą treść. Recent deliveries na tej samej stronie ustawień pokazuje każde wywołanie i odpowiedź; Rotate secret jest tam, gdy potrzebujesz nowego - stary przestaje działać natychmiast, więc aktualizuj środowisko w tym samym ruchu.
Żeby sprawdzić to przed deployem, wystaw serwer dev tunelem (cloudflared tunnel --url http://localhost:3000 albo ngrok), zarejestruj adres tunelu jako endpoint, wpisz sekret do .env.local i zrestartuj pnpm dev (zmiany env nie są hot-reloadowane). Publikacja pokaże się wtedy jako POST /api/revalidate 200 w terminalu i jako wiersz success w Recent deliveries.
9. Jeśli coś się nie zgadza
- Bloku nie ma w palecie. Czy Dev host jest włączony i wskazuje port, na którym działa aplikacja? Czy blok jest w tablicy
blockswcmssy/blocks.ts? Przeładuj raz stronę edytora. - Blok jest na liście warstw, ale canvas nic nie pokazuje. Blok jest pusty albo bez paddingu (pusty nagłówek nie ma wysokości) albo schowany pod żółtym ostrzeżeniem - wpisz nagłówek, zamknij ostrzeżenie, dodaj padding.
- Canvas pokazuje treść opublikowaną zamiast trybu edycji. Sekret draftu wysłany przez edytor nie zgadza się z Twoim
CMSSY_DRAFT_SECRET- uruchomlinkjeszcze raz. Niezweryfikowane żądanie edycji celowo renderuje publiczną stronę. - Promote to draft mówi, że typu bloku nie ma jeszcze w manifeście bloków workspace'u. Manifest jest starszy niż Twój blok. Uruchom
sync-manifestz wdrożonego kodu albo wyłącz raz Dev host, gdy Preview URL wskazuje deploy z tym blokiem, i promuj ponownie. - Publish jest wyszarzony. Jesteś w dev preview. Promote to draft, wyjdź z Dev hosta, publikuj.
- Opublikowane, ale strona pokazuje starą wersję. Sprawdź Recent deliveries w Settings → Webhooks. 500 znaczy, że na hostingu brakuje
CMSSY_WEBHOOK_SECRET; 401 - że się nie zgadza; brak jakiejkolwiek dostawy - że endpoint nie subskrybujecontent.changed. linkmówi, że workspace ma już manifest. Normalne po pierwszym uruchomieniu.sync-manifestpodmienia go, gdy chcesz, żeby paleta odpowiadała zmienionemu rejestrowi bez otwierania edytora.npx @cmssy/clipada z „Cannot query field myWorkspaces”. Odpowiedziało stare globalne@cmssy/clizamiast aktualnego. Użyjnpx @cmssy/cli@latestalbo usuń globalną instalację.
Dalej
- Schema i typy pól - każde pole, repeatery, pola warunkowe.
- Loadery serwerowe - pobieranie podczas SSR bez wysyłania zapytania do klienta.
- Podgląd roboczy - trzy sposoby oglądania nieopublikowanej treści i czemu samo
?cmssyEdit=1nic nie robi. - Webhooki - wszystkie zdarzenia i podpis w szczegółach.
- CLI -
init,link,add block,sync-manifest.