Připojení libovolného webu do sítě Entangle (bez WordPressu)
Jak napojit web postavený na čemkoli (Drupal, Django, Next.js, statický web + serverless, vlastní CMS) do sítě Entangle. Kontrakt hub↔web je CMS-neutrální — WordPress plugin je jen referenční klient. Detailní referenci endpointů má
API.md; tohle je integrační průvodce.
Kanonická base všech endpointů hubu je /entangle/v1/…. Cesty /wp-json/entangle/v1/…
jsou jen alias, který si přidává WordPress přes rest_url() — ignorujte je. V příkladech
níže je {hub} = základ hubu (např. https://entangle.cz) a {web} = váš web.
Integrace má tři nezávislé části; vezměte si jen ty, které potřebujete:
- Publikace obsahu (novinky, události, participace) → push přes podepsané webhooky. Nutné pro feed a notifikace.
- Profil + feed projektů → hub si je sám stahuje z vašeho webu. Nutné pro mapu a galerii.
- Přihlášení přes Entangle (OAuth 2.0 / OIDC). Volitelné.
1. Kanonická identita webu
Váš web má jednu stabilní kanonickou URL ve tvaru scheme://host[:port][/cesta]
(malými písmeny host i schéma, bez koncového lomítka, bez query a fragmentu).
Tuto URL musíte posílat bajtově stejnou:
- při registraci (
site_url), - v každé publikaci (hlavička
X-Entangle-Site), - jako
client_idu OAuth.
Hub obě strany normalizuje a pak je porovná; posílejte URL v jednom stabilním
kanonickém tvaru, ať se shoda nerozjede. Nesedící web → 401 (neznámý web).
Cesta se zachovává, takže různé podadresáře jsou různé weby
(https://mesto.cz/spolek-a a https://mesto.cz/spolek-b jsou dva nezávislé weby;
WP multisite je jen jeden příklad tohoto vzoru).
2. Registrace a získání secretu
POST {hub}/entangle/v1/hub/register-site
Content-Type: application/json
{ "site_url": "https://spolek.cz", "name": "Spolek Zelené Údolí" }
Odpověď 201 obsahuje secret (48 znaků) — vydá se právě jednou:
{ "message": "Web zaregistrován.", "secret": "AbC…48znaků…xyz" }
- Uložte secret do bezpečného server-side úložiště (env proměnná, secret manager,
šifrovaný sloupec). Ukazuje se jen teď; při dalších registracích je
secret: null. - Tentýž secret slouží k HMAC podpisu publikací i jako
client_secretpro OAuth. - Endpointy
/registera/sources(s tělem{url, name}asuccess:true) jsou legacy WP-kompat — necíleny je, použijte kanonické/hub/register-site.
3. HMAC podpis požadavků
Každá publikace (a retract/withdraw) se podepisuje sdíleným secretem. Tři hlavičky:
| Hlavička | Hodnota |
|---|---|
X-Entangle-Site |
vaše kanonická site_url |
X-Entangle-Timestamp |
unixový čas odeslání (tolerance ±300 s) |
X-Entangle-Signature |
sha256= + hex z HMAC_SHA256(secret, timestamp + "." + raw_body) |
Recept (jazykově neutrální):
ts = aktuální unixový čas (celé sekundy)
raw_body = PŘESNÉ bajty JSON těla, které odešlete
signature = "sha256=" + hex( HMAC_SHA256( secret, ts + "." + raw_body ) )
⚠️ Podepisují se přesně ty bajty, které pošlete. Serializujte JSON jednou do
proměnné, tu podepište i odešlete — nepřegenerovávejte JSON mezi podpisem a odesláním
(jiné pořadí klíčů/mezer = jiný podpis = 403).
4. Publikace obsahu
POST {hub}/entangle/v1/hub/publish (podepsané dle §3)
Společná pole těla:
| Pole | Význam |
|---|---|
type |
post (výchozí) · event · update · participation |
title |
titulek (povinný, když chybí content) |
content |
text; je bráno jako HTML-source — entity (&, …) se dekódují, tagy se u titulků notifikací mohou strhnout. Posílejte HTML (jako WP), nebo prostý text bez doslovných entit. |
url |
kanonický permalink (váš, pod site_url). Same-origin je striktně vynuceno u retract/withdraw a u feedu projektů; u publish se URL uloží tak, jak přijde — posílejte vlastní permalinky. |
image |
reprezentativní/hero obrázek (absolutní http(s) URL). Když chybí, hub sám zkusí og:image z url. (Není to nutně „featured image" — to je jen WP název.) |
Odpověď 202 {status: delivered, notified: n}. Chyby: 400 chybí site · 401 neznámý
web · 403 špatný podpis/čas · 422 validace.
Události (type: event) navíc: starts_at (ISO, povinné), url (povinné, dedupe
klíč), ends_at?, location?, is_online?. Hub událost uloží a vystaví ji jako
strukturovaný community.lexicon.calendar.event do atproto (viz API.md §2).
Participace (type: participation, např. anketa/hlasování): url povinné,
kind? (druh, max 30 znaků), starts_at? (smí být v budoucnu — spuštění naplánuje
scheduler), ends_at?.
Backfill historie: položce lze přidat published_at (ISO, původní datum) a
silent: true (uloží bez notifikací). Pro hromadný import je
POST {hub}/entangle/v1/hub/publish-batch s { items: [...] } (max 100, jen
post/update, vždy tiché, idempotentní podle source_url + url).
Re-publikace stejného permalinku = update na místě (drží původní datum).
5. Stažení obsahu
POST {hub}/entangle/v1/hub/retract—{ "url": "…" }stáhne jednu položku (post/událost/participace + notifikace o ní).urlmusí být same-origin podsite_url.POST {hub}/entangle/v1/hub/withdraw— (prázdné tělo, podepsané) stáhne veškerý obsah webu ze sítě. Registrace zůstává, publikovat lze kdykoli znovu.
6. Profil pro mapu (murmurations.json)
Aby se web objevil na mapě a v adresáři, hostujte profil ve formátu
Murmurations organizations_schema-v1.0.0:
GET {web}/murmurations.json
{
"linked_schemas": ["organizations_schema-v1.0.0"],
"name": "Spolek Zelené Údolí",
"primary_url": "https://spolek.cz",
"description": "Komunitní spolek v Zeleném Údolí.",
"full_address": "Náves 1, Zelené Údolí",
"geolocation": { "lat": 49.5, "lon": 15.3 },
"tags": ["entangle", "entangle:actor:community", "entangle:oblast:bezpecnost"],
"image": "https://spolek.cz/logo.png",
"projects_url": "https://spolek.cz/api/projekty.json"
}
- Hub profil sám stahuje (hodinově + hned po
POST /hub/refresh-profile). Autorita dat je váš web. - Tagy:
entangle(příslušnost k síti) ·entangle:actor:<typ>·entangle:oblast:<slug>(typy a oblasti viz §8). Bezgeolocationweb na mapě nebude (bude v adresáři). projects_urlje volitelné (viz §7). Starší weby mohou profil servírovat i na REST aliasu/wp-json/entangle/v1/murmurations-profile.
7. Feed projektů
Jednotlivé projekty (s vlastními piny a filtrací) hostujte jako JSON feed. Hub jeho umístění zjistí v tomto pořadí:
projects_urldeklarované ve vašemmurmurations.json(absolutní, same-origin) — doporučeno, umístíte feed kam chcete;- jinak neutrální
GET {web}/entangle/projects.json; - jinak legacy
GET {web}/wp-json/entangle/v1/projects(WP plugin).
{
"projects": [
{
"id": 1,
"title": "Revitalizace hřiště",
"url": "https://spolek.cz/projekty/hriste",
"excerpt": "Krátké shrnutí projektu.",
"thumbnail": "https://spolek.cz/img/hriste.jpg",
"geolocation": { "lat": 49.6, "lon": 15.4 },
"areas": [{ "slug": "verejny-prostor-a-zelen-priroda-v-intravilanu", "name": "Veřejný prostor a zeleň" }],
"tags": ["entangle:oblast:verejny-prostor-a-zelen-priroda-v-intravilanu"],
"status": "v-realizaci"
}
]
}
urlmusí být same-origin podsite_url; cizí permalinky se přeskočí.- Názvy
excerpt/thumbnail/ permalink jsou zděděné z WordPressu a znamenají prostě shrnutí / obrázek / kanonická URL — naplňte je z čehokoli. - Prázdný feed
{"projects": []}je autoritativní = smaže dřívější projekty webu. Nedostupný/neexistující feed (žádná z cest neodpoví platně) dřívější projekty ponechá. - Projekty bez
geolocationjsou jen v galerii, ne na mapě.
8. Řízený slovník (kategorie)
Slugy areas[] a status nelze odvozovat — zkopírujte je verbatim z hubu:
GET {hub}/entangle/v1/taxonomy
Vrací typy aktérů (entangle:actor:<typ>), oblasti (entangle:oblast:<slug> / areas)
a stavy projektu. status musí být síťový slug: v-priprave · v-realizaci · dokonceny.
9. (Volitelné) Přihlášení přes Entangle — OAuth 2.0 / OIDC
Standardní OAuth 2.0 authorization-code flow; funguje s jakoukoli OAuth knihovnou.
client_id= vaše přesná kanonickásite_url.client_secret= secret z registrace (§2).redirect_urimusí ležet pod vašísite_url(tj.site_urlje jeho prefix —{site_url}/auth/callbackprojde, nadřazená cesta ne). Decoupled/headless web: nasměrujte{site_url}/auth/callbackpřes reverse-proxy/CDN na svou serverless funkci.
GET {hub}/entangle/v1/hub/oauth/authorize?redirect_uri=…&scope=…&state=… (v prohlížeči)
POST {hub}/entangle/v1/hub/oauth/token { code, client_id, client_secret }
GET {hub}/entangle/v1/hub/oauth/userinfo Authorization: Bearer …
- Scopes (mezerami):
profile(výchozí) ·verification(LoA, ověření občana) ·residency(obec bydliště, nikdy ulice/č.p.). - Důvěrný klient — secret držte na serveru. Zatím bez PKCE/refresh, access token platí 30 dní. Čistě prohlížečoví/SPA klienti (bez server-side backendu na secret) zatím nejsou podporováni.
10. Ověření vlastnictví webu (TOFU)
Registrace je dnes trust-on-first-use: kdo si kanonickou URL zaregistruje první, dostane secret; vlastnictví se zatím neověřuje (stejně pro WP i ne-WP weby). → Zaregistrujte si svou URL dřív, než to za vás udělá někdo jiný.
Do budoucna je plánovaný CMS-neutrální challenge: hub vydá nonce a stáhne ho
z {site_url}/.well-known/entangle-challenge. Až bude, přibude sem postup.
11. Rychlý checklist + minimální end-to-end příklad
Checklist připojení:
- Zaregistrovat web (
/hub/register-site) a bezpečně uložitsecret. - Umět HMAC-podepsat a poslat
POST /hub/publishpři každé nové novince/události. - Hostovat
{web}/murmurations.jsona deklarovat v němprojects_url. - Hostovat feed projektů; slugy
areas/statusz/entangle/v1/taxonomy. - (Volitelně) napojit „Přihlásit přes Entangle".
Publikace novinky (ilustrační bash + openssl):
HUB="https://entangle.cz"
SITE="https://spolek.cz"
SECRET="…secret z registrace…"
BODY='{"type":"post","title":"Zahajujeme sběr podnětů","url":"https://spolek.cz/aktuality/podnety"}'
TS=$(date +%s)
SIG="sha256=$(printf '%s' "$TS.$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')"
curl -X POST "$HUB/entangle/v1/hub/publish" \
-H "Content-Type: application/json" \
-H "X-Entangle-Site: $SITE" \
-H "X-Entangle-Timestamp: $TS" \
-H "X-Entangle-Signature: $SIG" \
--data "$BODY"
# → 202 {"status":"delivered","notified":N}
Po tomto: novinka je ve feedu sítě a odběratelé webu dostanou notifikaci; jakmile hub
stáhne váš murmurations.json + feed projektů, objeví se web na mapě a projekty v galerii.