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_activestaré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í, vypisujeGET /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á hodnotaCHANGE_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íhodummy) má metadata; každá cenová strategie je hodnotou výčtu kontraktu a má tarifní šablonu.internal/config/characterization_test.go— gettery aSeedDefaultsvracejí byte-shodné hodnoty jako dřív (žádná výchozí hodnota se nemění).
Jak přidat předvolbu¶
-
Vytvořte
internal/presets/<druh>/<id>.json: -
Všechny 4 jazyky jsou povinné,
idmusí být unikátní a adresář musí odpovídatkind. Secrety a adresy zapište jako zástupné hodnoty (Bearer CHANGE_ME,http://192.168.1.50:9999). - Spusťte
go test ./internal/configcheck ./internal/presets—TestAllPresetsValidřekne, co kontrakt odmítá (včetně cesty). - 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¶
- 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.
- 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. - 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ý. - Existující záznamy. Projděte
GET /api/v1/admin/config/healthna kopii (nikdy ne na produkčních datech) a rozhodněte: buď kontrakt zmírněte, nebo záznamy opravte migrací (migrations/, viz dovednostnew-migration; migrace smí jen uvolňovat, hodnoty výběrových polí neodebírá — např.mqttzůstává v databázi, jen se nové nastavení odmítne). Dokumentujte to v úkolutasks/NN-*.md. - Opravte předvolby, které kontrakt rozbil (
TestAllPresetsValid), a aktualizujte dokumentaci (admin i tuto stránku). - Spusťte
make allvč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í.