Skip to main content

Alert System UI Implementation Guide

This document provides everything needed to implement the frontend UI for the Fermentrack alert system.

Overview

The alert system monitors FermentLogs and triggers alerts when certain conditions are met (e.g., cooling not working, fermentation stalled, device disconnected). Each FermentLog can have multiple alert configurations, and each configuration tracks its own state (active/inactive).

Key Concepts:

  • Alert Evaluator: A type of alert (defined in code). Examples: "Cooling Not Effective", "Gravity Stall"
  • Alert Configuration: User's settings for a specific alert on a specific FermentLog
  • Alert State: Whether an alert is currently triggered (active) or not

API Endpoints

All endpoints require authentication. Base URL: /api/

1. List Alert Configurations for a FermentLog

GET /api/ferment_logs/log/{ferment_log_id}/alerts/configs/

Response:

[
{
"id": "uuid",
"ferment_log": "uuid",
"alert_code": "cooling_ineffective",
"enabled": true,
"custom_thresholds": {"duration_minutes": 45},
"trigger_control_off": false,
"current_state": {
"is_active": false,
"became_active_at": null,
"last_evaluated_at": "2024-01-15T10:30:00Z",
"trigger_context": {},
"control_action_taken": false
},
"evaluator_name": "Cooling Not Effective",
"evaluator_description": "Triggers when cooling runs too long without sufficient temperature drop",
"evaluator_category": "temperature",
"evaluator_severity": "warning",
"is_applicable": true,
"threshold_definitions": [
{
"key": "duration_minutes",
"label": "Duration threshold",
"type": "duration_minutes",
"default": 30,
"min_value": 10,
"max_value": 120,
"help_text": "How long cooling must run without effect",
"units": "minutes"
}
],
"effective_thresholds": {"duration_minutes": 45, "min_temp_drop": 0.5},
"created": "2024-01-10T08:00:00Z",
"modified": "2024-01-15T09:00:00Z"
}
]

2. Get Available Alerts for a FermentLog

Returns ALL alert types with their applicability and configuration status.

GET /api/ferment_logs/log/{ferment_log_id}/alerts/available/

Response:

[
{
"code": "cooling_ineffective",
"name": "Cooling Not Effective",
"description": "Triggers when cooling runs too long without sufficient temperature drop",
"category": "temperature",
"default_severity": "warning",
"is_applicable": true,
"enabled_by_default": true,
"can_trigger_control_action": true,
"threshold_definitions": [...],
"is_configured": true,
"configuration": {
"id": "uuid",
"enabled": true,
"custom_thresholds": {},
"effective_thresholds": {"duration_minutes": 30},
"trigger_control_off": false,
"current_state": {...}
}
},
{
"code": "gravity_stall",
"name": "Gravity Stall",
"description": "Triggers when gravity hasn't changed significantly",
"category": "fermentation",
"default_severity": "warning",
"is_applicable": false,
"enabled_by_default": true,
"can_trigger_control_action": false,
"threshold_definitions": [...],
"is_configured": false,
"configuration": null
}
]

3. Create Alert Configuration

POST /api/ferment_logs/log/{ferment_log_id}/alerts/configs/
Content-Type: application/json

{
"alert_code": "cooling_ineffective",
"enabled": true,
"custom_thresholds": {"duration_minutes": 45},
"trigger_control_off": false
}

4. Update Alert Configuration

PATCH /api/ferment_logs/log/{ferment_log_id}/alerts/configs/{config_id}/
Content-Type: application/json

{
"enabled": false,
"custom_thresholds": {"duration_minutes": 60}
}

5. Delete Alert Configuration

DELETE /api/ferment_logs/log/{ferment_log_id}/alerts/configs/{config_id}/

6. Create Default Configurations

Creates configurations for all applicable alerts with enabled_by_default=true.

POST /api/ferment_logs/log/{ferment_log_id}/alerts/create-defaults/

Response:

{
"created_count": 3,
"configurations": [...]
}

7. Manually Evaluate Alerts for a FermentLog

Triggers immediate evaluation (useful for testing or refresh).

POST /api/ferment_logs/log/{ferment_log_id}/alerts/evaluate/

Response:

{
"evaluated_count": 5,
"triggered_count": 1,
"alerts": [...]
}

8. Get All Active Alerts (Brewhouse-wide)

Returns all currently triggered alerts across all FermentLogs.

GET /api/alerts/active/

Response:

[
{
"alert_code": "temp_controller_disconnected",
"alert_name": "Temperature Controller Disconnected",
"severity": "critical",
"ferment_log_id": "uuid",
"ferment_log_name": "IPA Batch #42",
"became_active_at": "2024-01-15T10:00:00Z",
"trigger_context": {
"message": "Temperature controller hasn't reported data for 25.3 minutes",
"disconnected_minutes": 25.3,
"threshold_minutes": 15
}
}
]

Important: Alert Lifecycle

Automatic Deletion When Log is Stopped

When a FermentLog is "stopped" (both temperature controller AND gravity sensor are removed), all alert configurations for that log are automatically deleted.

This happens automatically via a Django signal - the UI does not need to call any API endpoint. However, the UI should be aware of this behavior:

  • After stopping a log, any cached alert data for that log is stale
  • The alert configuration page should handle the case where configs no longer exist
  • Active alert banners should refresh after a log is stopped
// After stopping a log, clear any cached alert data
async function stopFermentLog(logId) {
await api.post(`/ferment_logs/log/${logId}/stop/`);

// Clear cached alerts for this log - they've been deleted server-side
clearAlertCache(logId);

// Refresh the active alerts list
await refreshActiveAlerts();
}

When to Call the API

On FermentLog Creation

After creating a new FermentLog, call the create-defaults endpoint to set up initial alert configurations:

// After creating a new FermentLog
const response = await api.post(`/ferment_logs/log/${newLogId}/alerts/create-defaults/`);
console.log(`Created ${response.data.created_count} default alert configurations`);

On FermentLog Detail Page Load

Fetch the configured alerts to display their status:

const configs = await api.get(`/ferment_logs/log/${logId}/alerts/configs/`);

On Alert Settings Page

Fetch all available alerts to show which ones can be configured:

const available = await api.get(`/ferment_logs/log/${logId}/alerts/available/`);

On Dashboard/Home Page

Fetch active alerts to show a notification banner:

const activeAlerts = await api.get('/alerts/active/');
if (activeAlerts.data.length > 0) {
showAlertBanner(activeAlerts.data);
}

Polling for Alert Updates

Poll periodically (every 30-60 seconds) on pages where alert status matters:

setInterval(async () => {
const activeAlerts = await api.get('/alerts/active/');
updateAlertIndicators(activeAlerts.data);
}, 30000);

Alert Categories and Severity

Categories

CategoryDescription
temperatureTemperature control issues
connectivityDevice connection issues
fermentationFermentation process issues
deviceHardware/firmware issues

Severity Levels

SeverityColor SuggestionDescription
criticalRedImmediate attention required
warningOrange/YellowPotential problem
infoBlueInformational notification

Available Alert Types

CodeNameCategorySeverityRequires
cooling_ineffectiveCooling Not EffectivetemperaturewarningTemp Controller
heating_ineffectiveHeating Not EffectivetemperaturewarningTemp Controller
temp_controller_disconnectedTemperature Controller DisconnectedconnectivitycriticalTemp Controller
gravity_sensor_disconnectedGravity Sensor DisconnectedconnectivitywarningGravity Sensor
gravity_stallGravity StallfermentationwarningGravity Sensor
fermentation_not_startedFermentation Not StartedfermentationwarningGravity Sensor
fermentation_completeFermentation CompletefermentationinfoGravity Sensor
profile_completeTemperature Profile CompletetemperatureinfoTemp Controller
firmware_update_availableFirmware Update AvailabledeviceinfoTemp Controller

UI Component Suggestions

1. Active Alerts Banner (Dashboard/Header)

Display prominently when there are active alerts.

┌─────────────────────────────────────────────────────────────────┐
│ ⚠️ 2 Active Alerts [View All]│
│ ────────────────────────────────────────────────────────────────│
│ 🔴 CRITICAL: Temperature Controller Disconnected - IPA Batch #42│
│ 🟠 WARNING: Gravity Stall detected - Hefeweizen │
└─────────────────────────────────────────────────────────────────┘

2. FermentLog Detail - Alert Status Card

Show on the FermentLog detail page.

┌─────────────────────────────────────────────────────────────────┐
│ Alerts [⚙️ Configure] │
│ ────────────────────────────────────────────────────────────────│
│ ✅ Cooling Monitor OK Last checked: 2 min ago │
│ ✅ Heating Monitor OK Last checked: 2 min ago │
│ 🔴 Controller Connection TRIGGERED Since: 10:00 AM │
│ ✅ Fermentation Progress OK Last checked: 2 min ago │
│ ────────────────────────────────────────────────────────────────│
│ 4 alerts configured • 1 triggered │
└─────────────────────────────────────────────────────────────────┘

3. Alert Configuration Page

Allow users to enable/disable alerts and customize thresholds.

┌─────────────────────────────────────────────────────────────────┐
│ Alert Configuration - IPA Batch #42 │
│ ════════════════════════════════════════════════════════════════│
│ │
│ TEMPERATURE ALERTS │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ [✓] Cooling Not Effective WARNING │ │
│ │ Triggers when cooling runs too long without effect │ │
│ │ │ │
│ │ Duration threshold: [30 ] minutes (10-120) │ │
│ │ Min temp drop: [0.5 ] °F (0.1-2.0) │ │
│ │ │ │
│ │ [✓] Turn off controller when triggered │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ [✓] Heating Not Effective WARNING │ │
│ │ Triggers when heating runs too long without effect │ │
│ │ ... │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ CONNECTIVITY ALERTS │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ [✓] Controller Disconnected CRITICAL │ │
│ │ Triggers when no data received for too long │ │
│ │ │ │
│ │ Disconnection threshold: [15 ] minutes (5-60) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ FERMENTATION ALERTS │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ [ ] Gravity Stall NOT APPLICABLE │ │
│ │ ⚠️ Requires a gravity sensor to be attached │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ [Cancel] [Save Changes]│
└─────────────────────────────────────────────────────────────────┘

4. Triggered Alert Detail Modal

Show when user clicks on an active alert.

┌─────────────────────────────────────────────────────────────────┐
│ 🔴 Temperature Controller Disconnected [X] │
│ ════════════════════════════════════════════════════════════════│
│ │
│ FermentLog: IPA Batch #42 │
│ Triggered: January 15, 2024 at 10:00 AM (25 minutes ago) │
│ │
│ ────────────────────────────────────────────────────────────────│
│ DETAILS │
│ │
│ Temperature controller hasn't reported data for 25.3 minutes │
│ (threshold: 15 minutes) │
│ │
│ Last check-in: January 15, 2024 at 9:35 AM │
│ │
│ ────────────────────────────────────────────────────────────────│
│ SUGGESTED ACTIONS │
│ │
│ • Check if the controller is powered on │
│ • Verify network connectivity │
│ • Check the controller's web interface │
│ │
│ [View FermentLog] [Dismiss] │
└─────────────────────────────────────────────────────────────────┘

5. Alert History (Future Enhancement)

┌─────────────────────────────────────────────────────────────────┐
│ Alert History - IPA Batch #42 │
│ ────────────────────────────────────────────────────────────────│
│ Jan 15, 10:00 AM 🔴 Controller Disconnected ACTIVE │
│ Jan 14, 3:30 PM 🟢 Cooling Not Effective Resolved (45m) │
│ Jan 13, 8:15 AM 🟢 Controller Disconnected Resolved (5m) │
│ Jan 10, 2:00 PM ℹ️ Fermentation Complete Acknowledged │
└─────────────────────────────────────────────────────────────────┘

Threshold Input Types

When rendering threshold configuration inputs, use the type field:

TypeInput TypeNotes
duration_minutesNumber inputShow "minutes" label
duration_hoursNumber inputShow "hours" label
decimalNumber inputAllow decimal values, step="0.001"
integerNumber inputWhole numbers only

Always respect min_value and max_value for validation.

Error Handling

Common Error Responses

400 Bad Request - Invalid data:

{
"alert_code": ["Unknown alert code: invalid_code"],
"custom_thresholds": ["Duration threshold: value must be at least 10"]
}

404 Not Found - FermentLog doesn't exist or doesn't belong to user's brewhouse.

403 Forbidden - User not authenticated.

State Management Recommendations

  1. Cache active alerts at the app level and update via polling

  2. Invalidate cache when:

    • User modifies alert configurations
    • User manually triggers evaluation
    • WebSocket notification received (future)
  3. Optimistic updates for enable/disable toggles

Future Considerations

The following features are planned but not yet implemented:

  1. Notifications - Email/push notifications when alerts trigger
  2. Alert History - Historical record of past alerts
  3. Acknowledgment - Allow users to acknowledge/dismiss alerts
  4. Snooze - Temporarily disable alerts

The API is designed to accommodate these features without breaking changes.