feat: provider-strict configs, slot-based templates, broadcast targets, email bots, command templates

Major architectural improvements:
- Provider-type enforcement: configs validated against provider type at assignment
- TemplateConfig migrated to slot-based pattern (TemplateSlot child table)
- Broadcast targets: TargetReceiver child table for multi-receiver dispatch
- EmailBot: first-class email sender entity with SMTP config, test connection
- CommandTemplateConfig: generic slot-based command response templates
- Provider capability registry: dynamic slot/event/command definitions per provider
- CommandTracker play/pause button matches NotificationTracker style
This commit is contained in:
2026-03-21 16:33:24 +03:00
parent 371ea70756
commit 846d480d38
27 changed files with 2355 additions and 205 deletions
@@ -94,6 +94,40 @@ async def create_provider(
return _provider_response(provider)
@router.get("/capabilities")
async def list_provider_capabilities():
"""List capabilities for all registered provider types."""
from notify_bridge_core.providers.capabilities import get_all_capabilities
result = {}
for pt, caps in get_all_capabilities().items():
result[pt] = {
"provider_type": caps.provider_type,
"display_name": caps.display_name,
"notification_slots": caps.notification_slots,
"command_slots": caps.command_slots,
"events": caps.events,
"commands": caps.commands,
}
return result
@router.get("/capabilities/{provider_type}")
async def get_provider_capabilities(provider_type: str):
"""Get capabilities for a provider type (events, slots, commands)."""
from notify_bridge_core.providers.capabilities import get_capabilities
caps = get_capabilities(provider_type)
if not caps:
raise HTTPException(status_code=404, detail=f"Unknown provider type: {provider_type}")
return {
"provider_type": caps.provider_type,
"display_name": caps.display_name,
"notification_slots": caps.notification_slots,
"command_slots": caps.command_slots,
"events": caps.events,
"commands": caps.commands,
}
@router.get("/{provider_id}")
async def get_provider(
provider_id: int,