refactor: provider descriptor registry — eliminate provider-specific hardcoding

Replace all if/else chains keyed on provider type strings with a
descriptor-driven architecture. Each provider type (immich, gitea,
planka, scheduler, nut, google_photos) has a descriptor in
frontend/src/lib/providers/ that declares config fields, event
tracking fields, collection metadata, validation, and hooks.

Components now use getDescriptor(type) and render dynamically.
Dashboard provider card shows provider name + type when global
filter is active. Grid-items derived from registry.
This commit is contained in:
2026-03-24 12:40:33 +03:00
parent c6bb2b5b51
commit 8cb836e16c
19 changed files with 904 additions and 353 deletions
+7 -4
View File
@@ -26,9 +26,12 @@ Detailed context is split into focused documents under `.claude/docs/`. Read the
- 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"
8. **No provider-specific hardcoding**ALL provider-specific UI logic lives in **provider descriptors** (`frontend/src/lib/providers/`). NEVER add `if (type === 'xyz')` in components.
- Form fields, validation, config building → defined in the descriptor's `configFields` / `buildConfig` / `hasConfigChanged`
- Event tracking checkboxes → `eventFields`; extra controls → `extraTrackingFields`; feature sections (periodic/scheduled/memory) → `featureSections`
- Collection labels/icons → `collectionMeta`; webhook URL display → `webhookUrlPattern`
- Pre-save hooks (e.g. shared-link validation) → `onBeforeSave`
- Components use `getDescriptor(type)` and render dynamically from the descriptor
- 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()`
9. **New provider descriptor checklist** — when adding a new service provider, create a descriptor file in `frontend/src/lib/providers/{name}.ts` and register it in `index.ts`. The descriptor must define: `type`, `defaultName`, `icon`, `hasUrl`, `configFields`, `buildConfig()`, `hasConfigChanged()`, `eventFields`, `collectionMeta` (or `null`). Optional: `extraTrackingFields`, `featureSections`, `webhookUrlPattern`, `webhookBased`, `onBeforeSave`. Also add i18n keys: `providers.type{PascalName}` and `gridDesc.provider{PascalName}` in both `en.json` and `ru.json`.