Skip to content

Kontrakty a předvolby

Konfigurovatelné části Dveřníku (zařízení, produkty, ceníky, klíče app_config) mají kontrakt (schéma + sémantická pravidla) a vestavěné předvolby. Specifikace a historie návrhu: tasks/66-config-presets.md. Pohled administrátora je v Předvolby a kontrola konfigurace.

Principy

  • Zdrojem pravdy je Go backend. Kontrakty jsou deklarované v Go (internal/contract, JSON Schema + volitelná sémantická funkce). Webové rozhraní formuláře a kontroly sestavuje ze schémat (GET /api/v1/admin/contracts) a z chyb vrácených backendem; žádná pravidla se nekopírují do TypeScriptu.
  • Předvolby jsou jen v kódu. Vestavěné JSON soubory (go:embed) verzované s aplikací; uživatelské předvolby v databázi neexistují.
  • Kontrola je jen strukturální a jen při zápisu. Nikdy se neověřuje dosažitelnost zařízení ani to, zda je aktivní (neaktivní zařízení se kontroluje stejně). Běh aplikace (tvorba adaptérů, čtení parametrů strategií, gettery konfigurace) se kvůli kontraktu nemění.
  • Zpětná kompatibilita. Při vytvoření se kontroluje vždy; při úpravě jen když se změnilo kontrolované pole (přejmenování nebo přepnutí is_active starého záznamu s nevyhovující konfigurací musí dál fungovat). Kontrakt přijímá vše, co běh považuje za platné. Existující záznamy, které kontrakt nesplňují, vypisuje GET /api/v1/admin/config/health.
  • Chyby mají cestu (pin_mapping.open.pins[0].state), takže je formulář zobrazí u pole. Varování (severity: warning, např. zbylá zástupná hodnota CHANGE_ME) ukládání neblokují.

Kde co leží

Co Kde
Typy Contract, Issue internal/contract
Jediné místo, které ví, který kontrakt kontroluje který druh (hooky, dry-run, health, testy) internal/configcheck (Validate, ValidateRequest, ListPresets, ValidatePreset, AllContracts)
Kontrakty zařízení (adapter_config) internal/device/adapters/*_contract.go, adapters.RegisterContract
Kontrakty parametrů produktů soubor každé strategie v internal/product/, product.RegisterContract
Kontrakty cenových pravidel a sad pravidel internal/pricingrule
Registr klíčů app_config (typ, výchozí hodnota, tajnost, skupina, validátor) internal/config/registry.go
Metadata platebních poskytovatelů providers.RegisterProviderMeta v internal/payment/providers/
Předvolby internal/presets/<druh>/*.json (druhy: device, product, region, zone_pricing, device_pricing)
Ukládací hooky a koncové body internal/app/config_validation.go, routes_pricing_presets.go, routes_installation.go

REST koncové body (admin): GET /api/v1/admin/contracts, GET /api/v1/admin/presets, POST /api/v1/admin/contracts/validate, GET /api/v1/admin/config/health; stejné služby volají MCP nástroje list_presets, validate_config, get_config_health (MCP API).

Záruční testy

Přidání komponenty nebo změna kontraktu, která něco rozbije, shodí make all:

  • TestAllPresetsValid — každá předvolba projde přesně stejnou kontrolou jako ukládací hook, má všechny 4 jazyky, unikátní ID a platný cíl.
  • TestRegistryCompleteness* — každý adaptér zařízení a každá strategie produktů má kontrakt a aspoň jednu předvolbu; každý platební poskytovatel (kromě testovacího dummy) má metadata; každá cenová strategie je hodnotou výčtu kontraktu a má tarifní šablonu.
  • internal/config/characterization_test.go — gettery a SeedDefaults vracejí byte-shodné hodnoty jako dřív (žádná výchozí hodnota se nemění).

Jak přidat předvolbu

  1. Vytvořte internal/presets/<druh>/<id>.json:

    {
      "id": "device.lock.my_preset",
      "kind": "device",
      "target": {"device_type": "lock", "communication_adapter": "rest_api"},
      "name": {"cs": "…", "en": "…", "pl": "…", "ua": "…"},
      "description": {"cs": "…", "en": "…", "pl": "…", "ua": "…"},
      "values": {"adapter_config": {}}
    }
    
  2. Všechny 4 jazyky jsou povinné, id musí být unikátní a adresář musí odpovídat kind. Secrety a adresy zapište jako zástupné hodnoty (Bearer CHANGE_ME, http://192.168.1.50:9999).

  3. Spusťte go test ./internal/configcheck ./internal/presets — TestAllPresetsValid řekne, co kontrakt odmítá (včetně cesty).
  4. Aktualizujte tabulku předvoleb v Předvolby a kontrola konfigurace. Web nové předvolby zobrazí sám.

Předvolby produktů nenesou název jako hodnotu (název produktu je obsah uživatele): formulář použije lokalizovaný name předvolby. Tarifní šablony obsahují values.rules a každé pravidlo i jeho název ve 4 jazycích.

Jak přidat novou komponentu

Postup krok za krokem (registrace, nowFunc, testy) je v dovednosti new-component. Ke kontraktům: adaptér zařízení volá adapters.RegisterContract, strategie produktu product.RegisterContract (a implementuje ParametersValidator přes validateWithContract), platební poskytovatel providers.RegisterProviderMeta (klíče musí existovat v registru app_config), cenová strategie se přidá do pricingrule.DevicePricingModels / ZoneRuleTypes. Každá komponenta musí dodat i aspoň jednu předvolbu — jinak selže TestRegistryCompleteness*. Nový klíč app_config patří do internal/config/registry.go; výchozí hodnotu existujícího klíče nikdy neměňte.

Jak bezpečně změnit kontrakt

  1. Nic neměňte v běhu. Kontrakt se uplatňuje jen při zápisu a musí přijímat vše, co běh dnes zpracuje; chování adaptérů, strategií a getterů zůstává beze změny.
  2. Napište charakterizační test toho, co dnes kontrola přijímá (viz internal/product/parameters_characterization_test.go, internal/config/characterization_test.go), a ověřte ho na starém kódu. Po změně musí projít beze změny.
  3. Zpřísnění jen pro nové zápisy. Hook kontroluje při vytvoření a při změně kontrolovaného pole; nepřidávejte kontrolu na nesouvisející úpravy (přejmenování, is_active). Přidáte-li do aktualizační brány nové pole, dopište test, že starý záznam zůstává upravitelný.
  4. Existující záznamy. Projděte GET /api/v1/admin/config/health na kopii (nikdy ne na produkčních datech) a rozhodněte: buď kontrakt zmírněte, nebo záznamy opravte migrací (migrations/, viz dovednost new-migration; migrace smí jen uvolňovat, hodnoty výběrových polí neodebírá — např. mqtt zůstává v databázi, jen se nové nastavení odmítne). Dokumentujte to v úkolu tasks/NN-*.md.
  5. Opravte předvolby, které kontrakt rozbil (TestAllPresetsValid), a aktualizujte dokumentaci (admin i tuto stránku).
  6. Spusťte make all včetně integračních testů hooků.

Bundle instalace

Export/import celé instalace (GET/POST /api/v1/admin/installation/export|import) používá stejné kontrakty (configcheck) jako ukládací hooky; neexistuje paralelní validace. Postup je v Nová instalace. Přes MCP se export ani import záměrně nenabízí.