Skip to content

Ft/smart alert email#35

Merged
ModithaM merged 2 commits intomainfrom
ft/smart-alert-email
Oct 11, 2025
Merged

Ft/smart alert email#35
ModithaM merged 2 commits intomainfrom
ft/smart-alert-email

Conversation

@anupaprabhasara
Copy link
Copy Markdown
Collaborator

Description

Please include a summary of the change and which issue is fixed or feature is added.

Checklist

  • Code builds and runs locally
  • Tests pass
  • Lint passes
  • PR description filled
image image

USE breathsafe;

-- Sample data for the 'user' table

INSERT INTO user (id, address, bio, created_at, date_of_birth, email, first_name, last_name, password, phone, profile_image, role, updated_at, username) VALUES
(1, '', '', '2025-10-04 10:53:40.307693', NULL, 'info@anupa.lk', 'Anupa', 'Prabhasara', '$2a$10$HZdNma4BL8m/Gg6lfcBqYeNLQXgWgI8OhW5Vz2yLr4y1lAMD/R3Bu', '', '', 'USER', NULL, 'user'),
(2, '', '', '2025-10-05 10:53:40.307693', NULL, 'admin@anupa.lk', 'Anupa', 'Prabhasara', '$2a$10$HZdNma4BL8m/Gg6lfcBqYeNLQXgWgI8OhW5Vz2yLr4y1lAMD/R3Bu', '', '', 'ADMIN', NULL, 'admin'),
(3, '', '', '2025-10-06 10:53:40.307693', NULL, 'sadmin@anupa.lk', 'Anupa', 'Prabhasara', '$2a$10$HZdNma4BL8m/Gg6lfcBqYeNLQXgWgI8OhW5Vz2yLr4y1lAMD/R3Bu', '', '', 'SENSOR_ADMIN', NULL, 'sadmin');

-- Sample data for the 'sensor' table

INSERT INTO sensor (name, location, latitude, longitude, status, installation_date, last_maintenance, battery_level, is_active) VALUES
('AQM-Central-01', 'Town Hall, Colombo', 6.9271, 79.8612, 'ONLINE', '2023-01-15 10:00:00', '2023-09-01 14:30:00', 95, true),
('AQM-Kandy-Lake-01', 'Kandy Lake Round', 7.2906, 80.6337, 'ONLINE', '2023-02-20 09:00:00', '2023-08-10 11:00:00', 88, true),
('AQM-Galle-Fort-01', 'Galle Fort Lighthouse', 6.0264, 80.2172, 'OFFLINE', '2022-11-05 15:00:00', '2023-10-25 09:00:00', 15, true),
('AQM-Industrial-Zone-01', 'Katunayake EPZ', 7.1793, 79.8821, 'MAINTENANCE', '2023-03-10 12:00:00', '2023-10-28 08:00:00', 100, true),
('AQM-North-Jaffna-01', 'Nallur Kovil Area', 9.6750, 80.0255, 'ERROR', '2023-05-22 11:30:00', '2023-09-15 16:00:00', 42, true),
('AQM-Decommissioned-01', 'Storage Warehouse', 6.8511, 79.9213, 'OFFLINE', '2022-01-10 14:00:00', '2023-01-01 10:00:00', 0, false);

-- Sample data for the 'subscription' table

INSERT INTO subscription (user_id, sensor_id, alert_threshold, email_notifications, is_active) VALUES
(1, 1, 100, true, true), -- User 1 subscribes to sensor 1 with default settings.
(1, 2, 120, true, true), -- User 1 subscribes to sensor 2 with a custom alert threshold.
(1, 3, 100, true, true), -- User 1 subscribes to sensor 3 but has disabled email notifications.
(1, 4, 100, true, true), -- User 1 has an inactive/paused subscription to sensor 4.
(1, 5, 150, true, true), -- User 1 subscribes to sensor 5 with a high alert threshold.
(1, 6, 80, true, true), -- User 1 subscribes to sensor 6 with a lower, more sensitive threshold.
(2, 1, 100, false, true), -- User 1 subscribes to sensor 1 with default settings.
(2, 2, 120, false, true), -- User 1 subscribes to sensor 2 with a custom alert threshold.
(2, 3, 100, false, true), -- User 1 subscribes to sensor 3 but has disabled email notifications.
(2, 4, 100, false, false), -- User 1 has an inactive/paused subscription to sensor 4.
(2, 5, 150, false, true), -- User 1 subscribes to sensor 5 with a high alert threshold.
(2, 6, 80, false, true), -- User 1 subscribes to sensor 6 with a lower, more sensitive threshold.
(3, 1, 100, false, true), -- User 1 subscribes to sensor 1 with default settings.
(3, 2, 120, false, true), -- User 1 subscribes to sensor 2 with a custom alert threshold.
(3, 3, 100, false, true), -- User 1 subscribes to sensor 3 but has disabled email notifications.
(3, 4, 100, false, false), -- User 1 has an inactive/paused subscription to sensor 4.
(3, 5, 150, false, true), -- User 1 subscribes to sensor 5 with a high alert threshold.
(3, 6, 80, false, true); -- User 1 subscribes to sensor 6 with a lower, more sensitive threshold.

-- Sample data for the 'sensor_installation_requests' table (Enum Corrected)

INSERT INTO sensor_installation_requests (id, requested_location, latitude, longitude, justification, status, admin_comments, approved_at, rejected_at, created_at, updated_at, requester_id, approved_by, assigned_sensor_id) VALUES
(1, 'Viharamahadevi Park, Colombo', 6.9147, 79.8601, 'High foot traffic area with many families and children. Monitoring air quality here would be beneficial for public health awareness.', 'PENDING', NULL, NULL, NULL, '2025-10-01 09:15:00', '2025-10-01 09:15:00', 1, NULL, NULL),
(2, 'University of Moratuwa, Engineering Faculty', 6.7969, 79.9018, 'Request from the university to monitor air quality for a research project on urban pollution.', 'COMPLETED', 'Good initiative. Assigned and installed the new sensor.', '2025-09-25 14:00:00', NULL, '2025-09-20 11:30:00', '2025-10-05 16:00:00', 1, 2, 6),
(3, 'Private Residence, Wellawatte', 6.8773, 79.8631, 'Personal use for home air quality monitoring.', 'REJECTED', 'Requests are currently only approved for public spaces and research institutions.', NULL, '2025-09-28 17:20:00', '2025-09-26 15:00:00', '2025-09-28 17:20:00', 1, 3, NULL),
(4, 'Galle Face Green', 6.9213, 79.8449, 'Popular recreational area, important for monitoring tourist and local exposure to pollutants.', 'IN_PROGRESS', 'Approved. Team dispatched for installation.', '2025-10-06 10:00:00', NULL, '2025-10-02 12:00:00', '2025-10-06 10:00:00', 1, 2, NULL);

-- Sample data for the 'sensor_data' table (Enum Corrected)

-- Sensor 1: AQM-Central-01 (Colombo) - GOOD to MODERATE AQI
INSERT INTO sensor_data (id, temperature, humidity, co2_level, aqi_value, aqi_category, timestamp, sensor_id) VALUES
(1, 29.5, 78.0, 450.0, 45, 'GOOD', '2025-10-07 14:20:00', 1),
(2, 29.7, 79.0, 460.0, 52, 'MODERATE', '2025-10-07 14:25:00', 1),
(3, 29.6, 78.5, 455.0, 48, 'GOOD', '2025-10-07 14:30:00', 1);

-- Sensor 2: AQM-Kandy-Lake-01 - GOOD AQI
INSERT INTO sensor_data (id, temperature, humidity, co2_level, aqi_value, aqi_category, timestamp, sensor_id) VALUES
(4, 26.2, 82.0, 410.0, 35, 'GOOD', '2025-10-07 14:20:00', 2),
(5, 26.3, 82.5, 412.0, 38, 'GOOD', '2025-10-07 14:25:00', 2),
(6, 26.1, 82.2, 411.0, 36, 'GOOD', '2025-10-07 14:30:00', 2);

-- Sensor 4: AQM-Industrial-Zone-01 (Katunayake) - MODERATE to UNHEALTHY_SENSITIVE
INSERT INTO sensor_data (id, temperature, humidity, co2_level, aqi_value, aqi_category, timestamp, sensor_id) VALUES
(7, 30.1, 75.0, 550.0, 95, 'MODERATE', '2025-10-07 14:20:00', 4),
(8, 30.3, 76.0, 580.0, 115, 'UNHEALTHY_SENSITIVE', '2025-10-07 14:25:00', 4),
(9, 30.2, 75.5, 565.0, 102, 'UNHEALTHY_SENSITIVE', '2025-10-07 14:30:00', 4);

-- Sensor 5: AQM-North-Jaffna-01 - UNHEALTHY to VERY_UNHEALTHY
INSERT INTO sensor_data (id, temperature, humidity, co2_level, aqi_value, aqi_category, timestamp, sensor_id) VALUES
(10, 31.0, 70.0, 650.0, 165, 'UNHEALTHY', '2025-10-07 14:20:00', 5),
(11, 31.5, 68.0, 750.0, 205, 'VERY_UNHEALTHY', '2025-10-07 14:25:00', 5),
(12, 31.2, 69.0, 680.0, 175, 'UNHEALTHY', '2025-10-07 14:30:00', 5);

Fixes #[issue_number] (if applicable)

@anupaprabhasara anupaprabhasara self-assigned this Oct 11, 2025
Copilot AI review requested due to automatic review settings October 11, 2025 15:58
@anupaprabhasara anupaprabhasara added the enhancement New feature or request label Oct 11, 2025
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements a smart email alert system that automatically notifies users when air quality readings from their subscribed sensors exceed their configured thresholds. The system uses scheduled tasks to periodically check sensor data and sends personalized health advisories via email.

Key changes include:

  • Addition of scheduled alert service with configurable timing
  • Enhanced repository methods for efficient subscription and sensor data retrieval
  • Email template with personalized health recommendations
  • Configuration properties for alert scheduling intervals

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/main/resources/application.properties Adds configuration for alert scheduling interval
src/main/java/com/itp/breathsafe/subscription/repository/SubscriptionRepository.java Adds query method to fetch active email subscriptions with user/sensor details
src/main/java/com/itp/breathsafe/data/repository/SensorDataRepository.java Adds method to retrieve latest sensor data by sensor ID
src/main/java/com/itp/breathsafe/common/smartalert/ScheduledAlertService.java Implements core scheduled alert functionality with email notifications
src/main/java/com/itp/breathsafe/BreatheSafeServerApplication.java Enables Spring scheduling support

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +115 to +118
private boolean hasBeenAlertedRecently(Long subscriptionId, LocalDateTime dataTimestamp) {
LocalDateTime lastAlertTimestamp = recentlyAlerted.get(subscriptionId);
return lastAlertTimestamp != null && lastAlertTimestamp.equals(dataTimestamp);
}
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation only prevents duplicate alerts for the exact same data timestamp. Consider adding a time-based cooldown period to prevent alert spam when new data points continue to exceed the threshold within a short timeframe.

Copilot uses AI. Check for mistakes.

// In-memory cache to prevent sending duplicate alerts for the same sensor data point.
// Key: Subscription ID, Value: Timestamp of the SensorData record that triggered the last alert.
private final Map<Long, LocalDateTime> recentlyAlerted = new ConcurrentHashMap<>();
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The in-memory cache will lose data on application restart, potentially causing duplicate alerts. Consider persisting alert history or implementing a time-based cleanup mechanism to prevent unbounded memory growth.

Copilot uses AI. Check for mistakes.
Comment on lines +107 to +111
} catch (CustomException | MessagingException e) {
logger.error("Failed to process alert for subscription ID {}: {}", sub.getId(), e.getMessage());
// Continue to the next subscription even if one fails.
}
}
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider catching specific exceptions separately to provide more targeted error handling. For example, messaging failures might warrant retry logic while custom exceptions might indicate data issues.

Suggested change
} catch (CustomException | MessagingException e) {
logger.error("Failed to process alert for subscription ID {}: {}", sub.getId(), e.getMessage());
// Continue to the next subscription even if one fails.
}
}
} catch (MessagingException e) {
logger.error("Messaging failure for subscription ID {}: {}. Consider retrying.", sub.getId(), e.getMessage());
// Could implement retry logic here if desired.
} catch (CustomException e) {
logger.error("Custom exception for subscription ID {}: {}", sub.getId(), e.getMessage());
// Data issue, skip to next subscription.
}

Copilot uses AI. Check for mistakes.
@ModithaM ModithaM merged commit 9b8bef1 into main Oct 11, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants