app.bettersight.io/backend/services/alert_service.py

74 lines
2.6 KiB
Python

import os
import logging
import requests
from repositories.monitoring_repository import monitoring_repository
from repositories.alert_repository import alert_repository
logger = logging.getLogger(__name__)
GOTIFY_URL = os.getenv('GOTIFY_URL')
GOTIFY_APP_TOKEN = os.getenv('GOTIFY_APP_TOKEN')
def send_gotify(title, message, priority=5):
"""
Sends a push notification via Gotify to the owner's phone. Logs the
alert attempt to monitoring_events regardless of delivery success.
Never shown to clients — owner monitoring only, per CLAUDE.md §3/§27.
Data flow:
title + message + priority →
HTTP POST {GOTIFY_URL}/message →
monitoring_events record created (alert_sent reflects HTTP outcome)
"""
delivered = False
try:
response = requests.post(
f'{GOTIFY_URL}/message',
headers={'X-Gotify-Key': GOTIFY_APP_TOKEN},
json={'title': title, 'message': message, 'priority': priority},
timeout=5
)
delivered = response.status_code < 300
except Exception as e:
# Side-effect failure — must never propagate into the caller's
# primary operation (a job completing, a threshold check, etc.).
logger.error(f'Gotify alert failed: {str(e)}')
monitoring_repository.log_event(
event_type='api_health' if priority >= 10 else 'failure_rate',
severity='critical' if priority >= 10 else ('warning' if priority >= 7 else 'advisory'),
message=f'{title}: {message}',
alert_sent=delivered,
)
def create_alert(tenant_id, competitor_id, alert_type, message, product_id=None,
change_amount=None, change_percent=None):
"""
Creates a tenant-facing alert record — always visible on the
dashboard activity feed immediately (delivered_dashboard is always
true). Email/Slack/Teams/WhatsApp delivery flags are set later by
the digest workflows that actually deliver through those channels.
Data flow:
alert fields → alerts table record created with
delivered_dashboard=true, all other delivered_* flags false →
created alert record returned
"""
return alert_repository.create({
'tenant_id': tenant_id,
'competitor_id': competitor_id,
'product_id': product_id,
'alert_type': alert_type,
'message': message,
'change_amount': change_amount,
'change_percent': change_percent,
'delivered_dashboard': True,
'delivered_email': False,
'delivered_slack': False,
'delivered_teams': False,
'delivered_whatsapp': False,
'read': False,
})