feat: NUT (Network UPS Tools) service provider + provider-agnostic UI

Add full NUT support as a polling-based service provider:
- Async TCP client for upsd protocol (port 3493, configurable)
- 8 event types: online, on_battery, low_battery, battery_restored,
  comms_lost, comms_restored, replace_battery, overload
- 3 bot commands: /status, /devices, /battery
- 38 Jinja2 templates (EN+RU notification + command templates)
- Database: tracking config fields, migration, seeds
- Frontend: provider form with host/port/credentials, grid items, i18n

Provider-agnostic UI improvements:
- Remove hardcoded 'immich' defaults from all config forms
- Dynamic collection labels per provider type (Albums/Repos/Boards/UPS Devices)
- Capability-driven test types instead of provider type checks
- Template variable helpers for all providers (was Immich-only)
- Guard Immich-only shared link check to Immich providers
- Auto-clear stale global provider filter from localStorage
- EntitySelect search placeholder shows current selection
- Fix noneLabel in linked target config selectors

New CLAUDE.md rule #8: no provider-specific hardcoding
This commit is contained in:
2026-03-23 23:23:58 +03:00
parent c451f3dd72
commit 68ac13b452
73 changed files with 1385 additions and 45 deletions
+7
View File
@@ -25,3 +25,10 @@ Detailed context is split into focused documents under `.claude/docs/`. Read the
- Command slot mapping in `packages/core/src/notify_bridge_core/templates/command_defaults/loader.py` (`PROVIDER_COMMAND_SLOTS`)
- Provider capabilities in `packages/core/src/notify_bridge_core/providers/capabilities.py`
- Seed functions in `packages/server/src/notify_bridge_server/database/seeds.py` (notification templates, command templates, tracking configs, command configs)
- Template variable definitions in `packages/server/src/notify_bridge_server/api/template_configs.py` (`get_template_variables()`)
8. **No provider-specific hardcoding** — UI labels, icons, form defaults, and feature checks MUST be provider-agnostic. NEVER hardcode a specific provider type (e.g. `'immich'`) where multiple providers could appear:
- Form defaults: use `provider_type: ''` (empty), not `'immich'`
- Collection labels: use the `collectionMeta` lookup in `TrackerForm.svelte`, not hardcoded "Albums"
- Feature gating: check `capabilities.notification_slots` or `capabilities.commands`, not `provider.type === 'immich'`
- Provider-specific API calls (e.g. `/albums/.../shared-links`): guard with a provider type check
- Template variable helpers: ALL provider types must have entries in `get_template_variables()`