Centrální administrace
Centrální administrace je samostatná aplikace SvelteKit pro správu obsahu na více webech WBengine. Ke každému webu se připojuje přes volitelné API v2; není součástí PHP ani Composer balíčku.
Tato stránka popisuje, co centrální administrace umí a jak se web připojí, a pak jak ji nainstalovat a provozovat. Části v pořadí:
- Samostatná aplikace, připojené weby; co může redaktor spravovat; uživatelé a nastavení webu; co administrace nenahrazuje
- Připojení webu krok za krokem
- Instalace a nastavení: požadavky, nastavení (proměnné prostředí), spuštění pomocí Docker Compose, reverzní proxy s HTTPS, první správce
- Účty a přístup: přihlášení, role, uživatelé a pozvánky, pozvánka emailem
- Provoz administrace: hlavní klíč a zálohy, příkazový řádek, aktualizace
- Jazyky a překlady
Samostatná aplikace, připojené weby
Každý web WBengine si ponechává vlastní PHP aplikaci, databázi MySQL, soubory a veřejné stránky. Centrální administrace běží odděleně jako služba Node.js s vlastní databází. Ukládá účty správců, seznam připojených webů a zašifrované integrační údaje. Nepřipojuje se přímo do vzdálené databáze webu a nekopíruje jeho zdrojový kód.
Spojení probíhá mezi servery přes HTTPS. Provozovatel webu zapne API v2, vydá integrační klíč jen s potřebnými scopes a bezpečně jej předá centrální službě. Ta ověří cílovou adresu i TLS certifikát, ponechá klíč na serveru a volá pouze podporované operace API. Klíč se nikdy nedostane do prohlížeče. Web může klíč odvolat a výpadek centrální služby neodstaví veřejný web.
Co může redaktor spravovat
Podle možností API daného webu a role centrálního účtu může redaktor spravovat články, stránky, položky menu, sekce, registrované boxy, překlady a podporované obrázky na více webech. Úpravy článků se ukládají jako koncepty. Redaktor si může zobrazit soukromý náhled a potom koncept výslovně publikovat. Starší revize lze obnovit jako nový koncept.
Každý zápis uvádí verzi, ze které vychází. Pokud stejný obsah změnil další redaktor nebo místní proces, API nahlásí konflikt místo tichého přepsání. Administrace zachová rozepsaný text a umožní porovnat aktuální vzdálenou verzi před novým výslovným uložením.
Podporované obrázky jsou veřejná rastrová média, nikoli soukromé přílohy konceptu. Nabídka boxů pochází z allowlistu na webu. Centrální klient nemůže vybírat libovolné PHP třídy, metody, SQL, šablony ani cesty k souborům.
Uživatelé a nastavení webu
Pro správce webu centrální administrace pokrývá také účty, které se přihlašují přímo na webu, a dvě akce na straně serveru, pokud je web povolí.
- Uživatelé webu: seznam a hledání účtů, založení účtu, změna role (uživatel, editor nebo administrátor), zakázání a povolení. Nový účet nemá heslo: administrace jednou zobrazí jednorázový odkaz a majitel ho otevře na přihlašovací stránce webu a zvolí si heslo. Hesla centrální administrace nikdy nenastavuje, nečte ani neukládá a posledního aktivního administrátora webu nelze degradovat ani zakázat.
- Nastavení webu: platné nastavení webu pouze ke čtení, s tajnými hodnotami zobrazenými jen jako nastavené, a tlačítko, které vyprázdní cache webu. Samotné nastavení se mění na serveru.
Obě stránky vyžadují integrační klíč vydaný s odpovídajícími oprávněními; klíč bez nich vyzve k výměně.
Stránka Aktivita pouze pro čtení vypisuje změny provedené na webu (kdo co a kdy změnil) z jeho záznamu změn. Vyžaduje oprávnění audit:read. Rozhraní centrální administrace je dostupné v angličtině, češtině, němčině a polštině a každý si jazyk volí ve svém profilu.
Co administrace nenahrazuje
Centrální služba je volitelný obsahový klient. Nenahrazuje WBengine, databázi webu, správu zdrojového kódu, nasazovací postup ani správu serveru. Vývojář mění PHP třídy a šablony v projektu webu a nasazuje je jeho běžným postupem. Weby dál fungují, i když centrální administrace není dostupná.
Administrace se distribuuje odděleně od PHP frameworku. Její zdrojový kód je veřejný na GitHubu pod licencí MIT. Nejde o balíček Composeru a nepublikuje se hotový kontejnerový obraz: obraz se sestaví ze zdrojového kódu pomocí Docker Compose. Instalaci, všechna nastavení a provoz popisují části Instalace a nastavení, Účty a přístup a Provoz administrace níže.
Připojení webu krok za krokem
Centrální WBengine Admin je samostatná aplikace (například na https://admin.example.org), která spravuje více webů přes API v2. Web se připojuje jednou, poté redaktoři pracují v centrální aplikaci.
Požadavky na webu: v Settings.json nastavené apiV2.enabled na true, HTTPS, použité databázové aktualizace frameworku (sh bin/update-database.sh, ověřte příkazem vendor/bin/wbengine.php migration:status) a účet s rolí admin (viz Uživatelé a první přihlášení na stránce Začínáme).
- Na webu se přihlaste jako správce a otevřete
/integrations/. Pokud něco chybí, stránka vypíše, co je třeba opravit, než klíč vydá. - Zvolte skupiny oprávnění, které smí klíč používat (Obsah, Publikování, Struktura, Obrázky, Správa webu, Historie a volitelně Analytika; výchozí volba povolí všechny), potvrďte heslo, ponechte navržený název a vydejte klíč. Klíč, adresa webu a navržený název se zobrazí jen jednou. Web ukládá pouze hash klíče, takže ztracený klíč nelze znovu zobrazit: vydejte nový.
- V centrálním Adminu se přihlaste heslem a jednorázovým kódem z autentizační aplikace. Každý centrální účet používá vícefázové ověření. První globální správce se vytvoří na serveru Adminu příkazem
npm run admin -- invite EMAIL global; další lidi pak zve globální správce na stránce Uživatelé, volitelně emailem (viz Uživatelé a pozvánky níže), a osoba účet aktivuje na/accept. - Otevřete Weby, zvolte Přidat web a vyplňte název, HTTPS adresu a klíč. Před uložením Admin klíč ověří proti webu (
capabilitiesaidentitya že klíč povoluje alespoň jednu skupinu oprávnění). Klíč se poté uloží šifrovaně a do prohlížeče se už nikdy nevrací. - Web se ihned objeví v seznamu. Klíč vyměníte tak, že na webu vydáte nový, vložíte jej v Adminu do části Vyměnit integrační klíč a teprve potom odvoláte starý klíč na stránce
/integrations/webu.
Klíč lze také vázat na adresy, ze kterých smí být volán. Formulář klíče má volitelné pole pro IP adresy nebo rozsahy a po prvním použití karta klíče ukáže adresu, ze které byl použit, s formulářem pro omezení klíče na ni. Volání z jiné adresy je odmítnuto. Za reverzní proxy musí mít web nastavené http.trustedProxies, aby viděl skutečnou adresu volajícího.
AI asistent, který podporuje Model Context Protocol, například Claude Code, může psát a publikovat články webu. MCP server WBengine je jediný soubor wbengine-mcp.phar z vydání frameworku. Běží na počítači asistenta a volá API v2 webu s integračním klíčem. Formulář klíče nabízí předvolby pro takový klíč (Redaktor se strukturou a statistikami, Agent pro obsah, Agent jen koncepty, Jen čtení) a po vydání klíče stránka jednou ukáže konfiguraci klienta s klíčem. Předvolba pro redaktora dovolí asistentovi také spravovat stránky, menu, boxy a obrázky a číst statistiky a asistent redaktorovi, který nerozumí technice, vysvětlí, jak web funguje. Články se ukládají jako koncepty a publikují se jen na žádost a publikovaný článek lze znovu skrýt. Text přečtený z webu se asistentovi předává jako data, ne jako pokyny.
Web, který stránku integrací ještě nemá, ji získá jedním příkazem spuštěným v adresáři webu: vendor/bin/wbengine.php integrations:install --config=src/Config/Settings.json. Bez dalších voleb jen vypíše, co by vytvořil. S volbou --apply vytvoří stránku /integrations/ (jen pro přihlášené), sekci a záznam boxu. Třída v aplikaci není potřeba: box je součástí frameworku. Existující záznamy nikdy nemění, takže příkaz lze spustit opakovaně. Vypíše také, co ještě brání vydání klíče, například vypnuté API v2 nebo chybějící databázové aktualizace.
Typické potíže a jejich význam:
- Klíč není platný nebo byl odvolán: vydejte na webu nový klíč.
- Klíč nepovoluje nic, co by Admin mohl spravovat: vydejte nový klíč s alespoň jednou skupinou oprávnění. Stránka, kterou klíč nepokrývá, vyzve k novému klíči s chybějící skupinou.
- API v2 není dostupné: zapněte
apiV2, použijte databázové aktualizace frameworku a načtěte stránku znovu. - Příliš mnoho neúspěšných pokusů: web omezuje neúspěchy podle adresy, počkejte několik minut.
- Web už je zaregistrovaný: adresa je v centrálním Adminu jednoznačná.
Instalace a nastavení
Tato část je o provozu samotné administrace: aplikace v SvelteKitu s vlastní databází SQLite (jeden soubor, žádný databázový server), spouštěná pomocí Docker Compose ze zdrojového kódu na GitHubu.
Požadavky
- Docker s Docker Compose. Repozitář obsahuje
Dockerfile(Node 24) acompose.yaml, který spustí aplikaci s jedním svazkem pro její data. - Doménové jméno administrace a před ní reverzní proxy s HTTPS (viz níže).
- Node.js 22.18 nebo novější jen tehdy, když spouštíte testy nebo příkazový řádek mimo Docker.
Nastavení (proměnné prostředí)
Všechna nastavení jsou proměnné prostředí. Zkopírujte .env.example na .env vedle compose.yaml a vyplňte ho. Soubor obsahuje tajné údaje: nedávejte ho do Gitu a nechte ho čitelný jen pro uživatele, který nasazuje (na serveru s právy 0600). Compose proměnné předá aplikaci.
| Proměnná | Povinná | Význam |
|---|---|---|
DATABASE_PATH |
nastaví Compose | Cesta k souboru SQLite, /app/data/admin.sqlite ve svazku admin-data. Žádný databázový server ani heslo k databázi se nenastavuje. |
MASTER_KEY |
ano | 32 náhodných bajtů jako 64 hexadecimálních znaků, například z openssl rand -hex 32. Šifruje v databázi integrační klíče webů a tajné údaje dvoufázového ověření. |
ORIGIN |
ano | Přesná adresa administrace s HTTPS bez lomítka na konci, například https://admin.example.com. Aplikace s ní porovnává požadavky a odkaz v pozvánce emailem se staví z ní. |
REMOTE_IP_ALLOWLIST |
ne, prázdná | Přesné IP adresy, oddělené čárkami, webů v privátní síti, které provozovatel schválil. Žádné rozsahy a žádná jména hostitelů. Bez ní lze zaregistrovat jen weby na veřejných adresách. |
MAIL_SMTP_HOST |
ne | Server SMTP pro pozvánky emailem, u Googlu smtp.gmail.com. |
MAIL_SMTP_PORT |
ne, 587 |
587 (STARTTLS) nebo 465 (TLS od začátku). |
MAIL_SMTP_USER |
ne | Účet pro přihlášení k serveru SMTP, u Googlu celá adresa. |
MAIL_SMTP_PASSWORD |
ne | Jeho heslo, u Googlu heslo aplikace. |
MAIL_FROM |
ne | Adresa odesílatele pozvánky. |
Compose navíc nastavuje adresu a port, na kterých aplikace v kontejneru naslouchá, a limit těla požadavku (1 MiB); není co konfigurovat. Proměnné MAIL_* fungují společně: viz Pozvánka emailem níže.
Spuštění pomocí Docker Compose
git clone https://github.com/rrsoftcz/wbengine-admin.git
cd wbengine-admin
cp .env.example .env # vyplňte MASTER_KEY a ORIGIN
docker compose run --rm app npm run admin -- migrate
docker compose up -d --build app
Aplikace databázi sama nemění. Příkaz migrate použije každý soubor z migrations/ jednou a zaznamená ho, proto ho spusťte před spuštěním verze, která novou migraci obsahuje. Aplikace naslouchá na 127.0.0.1:13000.
Reverzní proxy s HTTPS
Aplikace předpokládá, že reverzní proxy (Nginx, Caddy a podobně) ukončuje HTTPS a předává požadavky na 127.0.0.1:13000. ORIGIN musí být přesně adresa, kterou používají návštěvníci. Proxy musí předávat správnou hlavičku Host a přijaté předávací hlavičky odstranit nebo přepsat, protože aplikace hlavičkám proxy nevěří. Cookies jsou vždy Secure, i při vývoji, takže i místní běh potřebuje před sebou proxy s HTTPS.
První správce
Neexistuje veřejná registrace ani výchozí účet. První globální správce se vytvoří na serveru příkazovým řádkem:
docker compose run --rm app npm run admin -- invite you@example.com global
Příkaz vypíše jednorázový kód s platností 48 hodin. Otevřete /accept administrace, zadejte kód a zvolte heslo (14 až 256 znaků). Dalším krokem je nastavení dvoufázového ověření.
Účty a přístup
Kdo se může přihlásit, co smí která role a jak se lidé zvou.
Přihlášení
- Heslo a kód z autentizační aplikace (TOTP, 6 číslic, 30 sekund). Dvoufázové ověření je povinné pro každý účet.
- Deset záložních kódů se zobrazí jednou při nastavení ověření. Záložní kód nahradí kód z telefonu, když telefon ztratíte. Ověření nelze na webu vypnout a samotné heslo ho nikdy nenahradí.
- Neúspěšné pokusy jsou omezené: 8 pokusů s heslem a 12 pokusů s ověřením za 15 minut.
- Relace trvá 8 hodin.
- Zapomenuté heslo se obnoví jednorázovým kódem s platností 30 minut, který pro účet vydá globální správce (stránka Uživatelé nebo příkaz
recover). Nové heslo odhlásí účet všude a ověření zachová.
Role
Člověk má roli pro každý web zvlášť. Každá operace navíc vyžaduje odpovídající oprávnění integračního klíče webu a schopnost webu.
| Role | Co smí |
|---|---|
| Redaktor | Číst web, upravovat koncepty článků a jejich překlady, nahrávat obrázky. |
| Správce webu | Vše, co redaktor, a navíc měnit strukturu (stránky, menu, sekce, boxy), publikovat a odstraňovat obsah a vidět uživatele, nastavení a stránku Aktivita webu. |
| Globální správce | Vše výše na všech webech a navíc spravovat seznam webů (přidat web, vyměnit klíč) a účty administrace. |
Uživatelé a pozvánky
Globální správce spravuje účty na /users: hledání, pozvání, zakázání a povolení, povýšení a degradace globálních správců, vydání obnovovacího kódu, reset dvoufázového ověření a odebrání přístupu k webu. Nikdo si tam nemůže změnit vlastní roli ani stav a poslední globální správce zůstává zachován.
Pozvání: zadejte email, zvolte úroveň (člen týmu nebo globální správce) a u člena týmu volitelně první web a roli na něm (redaktor nebo správce webu). Administrace jednou ukáže jednorázový kód s platností 48 hodin. Předejte ho bezpečným kanálem. Osoba otevře /accept, zadá kód, zvolí heslo a nastaví ověření. Email, který už má účet, nelze pozvat znovu.
Pozvánka emailem
Ve výchozím stavu se kód předává ručně. Je-li nastavený server SMTP, formulář pozvánky dostane druhé tlačítko, Vytvořit a odeslat emailem. Pošle osobě uvítací text, odkaz na stránku pozvánky (sestavený z ORIGIN), kód a informaci, že kód platí jednou a 48 hodin. Kód se dál zobrazí i na obrazovce, takže ho můžete vždy předat sami. Email je napsaný v jazyce rozhraní správce, který ho odesílá (angličtina, čeština, němčina nebo polština). Bez nastavení se tlačítko nezobrazí a nic jiného se nemění.
Nastavte MAIL_SMTP_HOST, MAIL_SMTP_USER, MAIL_SMTP_PASSWORD a MAIL_FROM společně; MAIL_SMTP_PORT je 587, pokud ho nenastavíte. Chybí-li některá, funkce zůstane vypnutá a administrace při startu zapíše jedno varování. Spojení je vždy šifrované a certifikát serveru se vždy ověřuje.
S Googlem (výhodnější je účet Google Workspace na vlastní doméně, funguje i osobní účet Google):
- Zapněte dvoufázové ověření odesílajícího účtu.
- Vytvořte pro něj heslo aplikace a použijte ho, nikdy ne heslo účtu. Google může pravidla hesel aplikací i limity měnit, proto zkontrolujte jeho aktuální dokumentaci.
- Hodnoty vložte do
.envna serveru:MAIL_SMTP_HOST=smtp.gmail.com,MAIL_SMTP_PORT=587,MAIL_SMTP_USERadresa účtu,MAIL_SMTP_PASSWORDheslo aplikace aMAIL_FROMadresa účtu nebo alias ověřený v Googlu jako alias pro odesílání (jinou adresu odesílatele Google nahradí). - Restartujte aplikaci:
docker compose up -d --build app.
"Odesláno" znamená, že server SMTP zprávu přijal. Neslibuje, že email dorazí do schránky: to závisí na poštovním nastavení domény odesílatele (SPF, DKIM a DMARC). Když odeslání selže, stránka řekne proč: poštovní server odmítl přihlášení, adresa byla odmítnuta, nelze se připojit k poštovnímu serveru, poštovní server neodpověděl včas, nebo neznámá chyba (podrobnosti jsou v logu serveru). Pozvánka zůstává platná v každém případě, takže kód lze předat ručně. Heslo poštovního účtu se nikdy nezapisuje do logu ani nezobrazuje. Odeslání i neúspěšný pokus se zapisují do auditu.
Provoz administrace
Tajné údaje, zálohy, příkazový řádek a aktualizace.
Hlavní klíč a zálohy
Databáze administrace je jeden soubor SQLite, admin.sqlite, ve svazku admin-data kontejneru. Obsahuje účty, seznam webů, oprávnění a audit. Integrační klíče webů a tajné údaje dvoufázového ověření jsou uložené zašifrované pomocí MASTER_KEY.
MASTER_KEYuchovávejte v úložišti tajných údajů mimo databázi i mimo zálohy databáze. Obnovená databáze je čitelná jen se stejným klíčem.- Změna klíče je řízené přešifrování uložených dat. Administrace nemá automatickou rotaci.
- Databázi pravidelně zálohujte příkazem
docker compose run --rm app npm run admin -- backup /app/data/backups/admin.sqlite. Zapíše konzistentní kopii za běhu aplikace; kopii může číst jen její vlastník. Kopie obsahuje zašifrované klíče a hashe hesel, proto ji nikdy neukládejte společně sMASTER_KEY. Při obnově aplikaci zastavte, kopii vložte na místoadmin.sqliteve svazkuadmin-dataa aplikaci znovu spusťte. - Provozujte vždy právě jednu instanci aplikace. Soubor databáze patří na místní svazek, ne na síťové sdílení.
- Když se klíč webu ztratí nebo unikne, vydejte na webu nový, zadejte ho v Adminu pod Vyměnit integrační klíč a teprve potom na webu zrušte starý.
Příkazový řádek
Příkazový řádek pracuje přímo na serveru s prostředím aplikace. Přístup k němu je privilegovaný. Nikdy neposílá email.
docker compose run --rm app npm run admin -- migrate
docker compose run --rm app npm run admin -- invite EMAIL global
docker compose run --rm app npm run admin -- invite EMAIL member ID_WEBU editor
docker compose run --rm app npm run admin -- recover EMAIL
docker compose run --rm app npm run admin -- users
docker compose run --rm app npm run admin -- revoke ID_UZIVATELE ID_WEBU
docker compose run --rm app npm run admin -- backup /app/data/backups/admin.sqlite
printf '%s' "$KLIC" | docker compose run --rm -T app npm run admin -- site-add 'Název webu' https://example.com/
migrate použije databázové migrace. invite a recover vypíšou jednorázový kód (48 hodin a 30 minut). users vypíše účty. revoke odebere účtu oprávnění k webu. backup zapíše konzistentní kopii databáze (viz výše). site-add zaregistruje web; integrační klíč se čte ze standardního vstupu, aby se nikdy neobjevil v příkazovém řádku ani v historii shellu. Obvyklá cesta k přidání webu je stránka Weby v administraci.
Aktualizace
Stáhněte novou verzi (git pull), spusťte migrate jako výše a pak docker compose up -d --build app.
Jazyky a překlady
Web na WBengine může obsah nabízet ve více jazycích. Jazyky jsou konfigurace webu, ne obsah: definují se v sekci i18n souboru src/Config/Settings.json a nikde jinde (ne v databázi ani přes API). Centrální Admin je pouze čte.
"i18n": {
"enabled": true,
"default": "en",
"locales": ["en", "cs"],
"detect": ["url"]
}
defaultje jazyk původního obsahu. Články, stránky a položky menu jsou v tomto jazyce uložené v běžných tabulkách.localesje seznam všech jazyků, které web nabízí, včetně výchozího. Používejte krátké kódy jakoen,csnebopt_BR.detecturčuje, jak se jazyk požadavku vybírá:url(předpona například/cs/blog/),cookie(poslední volba) aheader(jazyk prohlížeče), v tomto pořadí důležitosti.
Jak jsou překlady uložené
Překlad není nový článek ani nová adresa. Je to další řádek ke stejnému článku, stránce nebo položce menu, určený ID záznamu a kódem jazyka (tabulky cms_article_translations, cms_site_translations a cms_menu_translations). Pole, které je v překladu prázdné, se zobrazí ve výchozím jazyce, takže i částečně přeložený záznam je kompletní.
Výchozí jazyk se obsluhuje bez předpony (/blog/) a každý další s kódem jazyka jako předponou (/cs/blog/). Obě verze používají stejnou stránku a stejný článek.
Přidání jazyka
- Doplňte kód do
localesvSettings.jsona aplikaci znovu načtěte. Centrální Admin nový jazyk nabídne po dalším připojení k webu. - Pokud šablony a tlačítka webu používají přeložené texty rozhraní, přidejte jazykový soubor do adresáře
Locale(viz volbadirvi18n). Bez něj zůstanou texty rozhraní ve výchozím jazyce. - Obsah přeložte v centrálním Adminu.
Změna výchozího jazyka
Upravte default v Settings.json. Pozor: veškerý stávající obsah je uložený ve starém výchozím jazyce, takže po změně by se stejné texty považovaly za nový jazyk. Nejprve obsah přeložte nebo zkopírujte a teprve pak změňte default.
Překlad obsahu v centrálním Adminu
V seznamech článků, stránek a menu je sloupec Jazyky, například „3 z 20 jazyků“. Po rozkliknutí se ukáže, které jazyky chybí. V záznamu je nad formulářem roletka Jazyk obsahu, která jazyky seskupuje na originál, přeloženo a chybí. Po výběru jazyka se jeho obsah načte do téhož formuláře. Posledních pět změn je v pravém panelu, úplná historie s obnovou se otevře odkazem Všechny změny a obnova. Překlad se ukládá ke stejnému záznamu. Překlady článků se ukládají nejprve do konceptu a s článkem se zveřejní při jeho publikování.