EKO2-1 sběrnice událostí a EKO2-3 doporučený další krok (kolo 2, schváleno 2026-11-11)
Vše za příznaky, výchozí vypnuto. Webhooky E2 zůstávají v platnosti; sběrnice je doplněk, ne náhrada, dokud ji všechny projekty nepoužívají.
EKO2-1 NATS JetStream (Apache-2.0)
- Server: NATS 2.10+ s JetStream, jeden stream
ONHOST, subjektycz.onhost.>, uložení file, 30 dní, max 1 MB zpráva, okno duplicit 2 min (NatsJetStreamBus::streamConfig()). - Subjekt = typ CloudEvent (
cz.onhost.<projekt>.<entita>.<akce>.vN).Nats-Msg-Id= id události. - Oprávnění: každý projekt má účet/uživatele NATS, který smí
publishjencz.onhost.<slug>.>asubscribejen na své consumery. Kit to hlídá i na straně klienta. - Odběr: durable pull consumer per projekt (
consumerConfig()),ack_policy: explicit,max_deliver: 20. Příjemce musí být idempotentní (IdempotencyGuard podle id události). - Osobní údaje: v
datajen identifikátory (pairwisesub, id záznamu), nikdy jména, e-maily ani zdravotní údaje. - Spojení jen TLS, přihlášení NKey/JWT. Server, DNS a tajemství nastavuje Adrian po svém „ano“; do té doby lokálně (
docker run nats:2.10 -js). - Kit:
Bus\EventBus,Bus\NullBus(výchozí),Bus\NatsJetStreamBus(transport jako closure).
EKO2-3 Doporučený další krok
- Pravidla:
rules/next-steps.v1.json(schemaonhost-next-steps/1):when(typ,*za jeden segment), volitelněif(rovnost vdata),offer_service+offer_id,reason_cs,priority. NextStep\NextStepEngine::suggest(event, offersByService, activeServices)vrátí nejvýš 3 doporučení. Nabídka musí existovat voffers[]manifestu služby (EKO-4) a mít https URL. Neukazuje služby, které klient už má, ani službu, která událost poslala.- Zobrazení jen v klientské zóně projektu (dlaždice „Doporučujeme“), žádné e-maily, žádné sledování, klient může doporučení skrýt. Zdrojem událostí je sběrnice (EKO2-1) nebo webhooky.
EKO2-2 Onboarding „jeden formulář“
- Klient zadá IČO jednou. Projekt předvyplní údaje přes
Onboarding\CompanyProfile::fromAres()(ARES REST API, otevřená data) nebo z OnPass claimucompany(fromOnPassClaim()), pokud uživatel při přihlášení OnPass udělil scopecompany. - OnPass claim
company=CompanyProfile::toArray():ico, name, dic, address, city, postal_code, legal_form, vat_payer, source. Jen veřejné údaje rejstříku, žádné osobní údaje navíc. - Předvyplnění je návrh: klient údaje vždy vidí a potvrdí. Plátcovství DPH z ARES je orientační a projekt ho neověřuje jako závazné.
- ARES: timeout 5 s, cache 24 h, negativní cache 1 h, payload se neloguje. Kontrola IČO
Onboarding\Ico(mod 11) proběhne vždy.
EKO2-4 Katalog šablon dokumentů
- Šablony leží v
templates/<druh>/<id>/<verze>.mdv tomto repozitáři (Markdown s proměnnými{{ provozovatel.nazev }}), rejstřík jetemplates/index.json(schema: onhost-templates/1). - Druhy:
vop,gdpr-informace,souhlas,smlouva. Každá verze mástatus: koncept|schvaleno. Projekt smí zobrazit jenschvaleno. Schvaluje Adrian po právní revizi. - Projekty (OnVet, OnClinic, lawyer, útulky) stahují šablony při buildu nebo přes
GET https://raw…/templates/index.json. Žádné runtime volání třetí strany. Proměnné doplní z konfigurace právního subjektu (EKO-10). - Změna šablony = nová verze, staré se nemažou (prokazatelnost souhlasu podle verze).
- Položka rejstříku:
id,kind,project,title,versions[]sversion(celé číslo),path(=templates/<kind>/<id>/<version>.md),status,sha256obsahu acreated.tests/test_templates.pyhlídá cestu, hash, unikátní id a verze a soubory mimo rejstřík. - Projekt ověří
sha256staženého souboru proti rejstříku a při neshodě šablonu nepoužije (zůstane u vlastní vestavěné verze). - Útulky (2026-11-11): adopční smlouva pes a kočka, darovací smlouva, smlouva o dočasné péči a informace GDPR pro zájemce, vše
koncept.
EKO2-10 Kontraktní testy mezi projekty
- Pakty v
pacts/*.json(schema: onhost-pact/1), ve stylu Pact (MIT). Kvůli lokální gate bez FFI knihovny je verifikátor v kitu:Contract\PactVerifier::verify($pact, $send). - Tělo odpovědi se kontroluje jako „alespoň tohle“: klíče musí existovat se stejným typem, přesná hodnota jen u
"=hodnota". Přidaný klíč tedy nic nerozbije, odebraný nebo přejmenovaný ano. - Poskytovatel má v Pest testu: pro každý pakt, kde je providerem, pošle interakce na svou aplikaci (
$this->call(...)) a očekává prázdný seznam chyb. Consumer přidá nebo změní pakt PR do tohoto repa. - Výchozí pakty:
gateway-any-service.manifest.json(manifest E5 u každé služby),onpass-client.webhooks.json(endpoint klienta OnPass bez podpisu → 401; spolu s ReceiverConformance).
EKO2-5 Sdílené vyhledávání (Meilisearch, MIT)
- Jedna instance a index pro každý projekt a entitu (
MeiliTenantToken::indexName('onvet','patients')=onvet_patients). Každý dokument mátenant_id. - Zápis jen ze serveru projektu klíčem s akcemi
documents.*jen na indexy projektu. Prohlížeč dostane tenant token (MeiliTenantToken::issue) s filtrem na tenant, nejdéle na 1 h (výchozí 15 min). - Zdravotní údaje (OnVet, OnClinic) se neindexují ve fulltextu. Indexují se jen jména zvířat nebo pacientů a čísla záznamů, a to jen se zapnutým příznakem projektu. Server a klíče nastavuje Adrian po svém „ano“.
EKO2-6 Jednotné příznaky (OpenFeature, OFREP)
Flags\FlagClient($local, $ofrepBase, $transport): vzdálené vyhodnocení přes OFREP (Flipt jako samostatná služba, GPL-3 se tak nešíří do projektů). Když služba neodpoví, platí lokální konfigurace. Výchozí stav je vypnuto.- Kontext: jen
targetingKey(tenant nebo pairwise id),project,environment. Admin vidí všechny příznaky ve Flipt UI. Zapnutí ostré funkce dál vyžaduje Adrianovo „ano“.
EKO2-7 Sdílené úložiště S3 (Garage, AGPL) – ⚠ jen simulace
- Návrh: bucket pro každý projekt, klíč pro každý projekt jen na jeho bucket, kontrola nahraných souborů přes ClamAV (clamd) před zpřístupněním, presigned URL na nejvýš 15 min. Dokud server neschválí Adrian, projekty používají lokální disk a adaptér
Storage::disk('ecosystem')se simulací.
EKO2-8 Podpisový tok přes OnPass
- Projekt spočítá SHA-256 dokumentu a pošle OnPass
POST /api/v1/signatures{document_sha256, title, return_url, sub?}. Ověření aplikace výhradněclient_secret_basic(Authorization: Basic base64(urlencode(client_id):urlencode(client_secret)), tytéž údaje jako pro/oauth/token) – žádný access token, scope,client_credentialsaniprivate_key_jwt; tajemství v těle nebo v adrese →401. Stejně proGET /api/v1/signatures/{id}(stav a doklad). Aplikaci musí správce OnPass povolit (allow_signatures), jinak403. Kit:Signatures\SignatureRequest. Obsah dokumentu do OnPass nechodí. - Uživatel v OnPass potvrdí podpis po čerstvém ověření (step-up/passkey). OnPass vrátí podpisový doklad (JWS ES256:
subpairwise,document_sha256,signed_at,method,client_id) a pošle událostcz.onhost.onpass.signature.completed.v1. - Projekt uloží doklad k dokumentu a ověří ho veřejným klíčem z
{issuer}/oauth/signatures/jwks(odděleně od JWKS ID tokenů). Doklad si vyzvedne přesGET /api/v1/signatures/{id}, v návratové adrese je jensignature_idastatus. Jde o prostý elektronický podpis s auditní stopou, ne o kvalifikovaný podpis. U smluv, kde zákon vyžaduje vyšší úroveň, se to musí uvést.
EKO2-9 PWA „ONhost app“
- Statická PWA (bez frameworku, bez CDN) na
app.onhost.czs přihlášením přes OnPass. Dlaždice vznikají z registru brány (GET /v1/ecosystem/services) a ze služeb, které uživatel používá (OnPass, claimservices). - Dlaždice vede deep-linkem do služby (
links.appv manifestu, https na hostu služby). Notifikace přes Web Push (VAPID) projdou jen po výslovném souhlasu uživatele v aplikaci. Doména, DNS a klíče VAPID až po Adrianově „ano“.
Stav v OnPass (onhost-id #16, příznaky company_claim, signatures, services_claim vypnuto)
- company:
CompanyProfile::toArray()sesource:"onpass"a navícbasis(typed|organization|organization_verified),verifiedafetched_at. Přiverified=false(isPrefillOnly()) smí aplikace údaje použít jen jako návrh k předvyplnění. Nikdy jimi nedokládá oprávnění jednat za firmu, protože uživatel mohl zadat cizí IČO. - signatures:
POST /api/v1/signaturessmí volat jen důvěrný klient, kterému admin povolilallow_signatures. Návrat nareturn_urlnese jensignature_idastatus. Doklad si aplikace stáhne přesGET /api/v1/signatures/{id}a ověří klíči ES256 z/oauth/signatures/jwks(v discovery jakoonpass_signatures_jwks_uri). Událost:cz.onhost.onpass.signature.completed.v1. - services: claim
services=[{slug, name, url}], obsahuje jen služby, které uživatel aktivně používá, a nikdy aplikaci, která se ptá. Nedá se delegovat a vždy vyžaduje souhlas.