24 KiB
📊 Monitoring & Alerts System - Consolidated Implementation Report
Date: 2025-11-30
Status: ✅ Skeleton Implemented (30% Complete)
Build: ✅ Success
📋 Executive Summary
اسکلت کامل سیستم Monitoring & Alerts پیادهسازی شد. این سیستم شامل دو بخش اصلی است:
- Alert System: اعلانهای مدیریتی (Critical/Warning/Success) برای Admin
- User Notification System: اعلانهای کاربری (SMS/Email/Push) برای Users
فعلاً فقط Logging فعال است. Integration های اصلی (Sentry, Slack, SMS) آماده پیادهسازی هستند.
🏗️ Architecture Overview
┌─────────────────────────────────────────────────────────┐
│ Application Layer │
│ ┌─────────────────────┐ ┌─────────────────────────┐ │
│ │ IAlertService │ │ IUserNotificationService│ │
│ │ - Critical │ │ - Commission Received │ │
│ │ - Warning │ │ - Club Activation │ │
│ │ - Success │ │ - Payout Error │ │
│ └─────────────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
↓ implements
┌─────────────────────────────────────────────────────────┐
│ Infrastructure Layer │
│ ┌─────────────────────┐ ┌─────────────────────────┐ │
│ │ AlertService │ │ UserNotificationService │ │
│ │ ✅ Logging │ │ ✅ Logging │ │
│ │ ⏳ Sentry │ │ ⏳ SMS Gateway │ │
│ │ ⏳ Slack │ │ ⏳ Email Service │ │
│ │ ⏳ Email │ │ ⏳ Push Notification │ │
│ └─────────────────────┘ └─────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ MonitoringSettings (Configuration) │ │
│ │ - SentryEnabled, SentryDsn │ │
│ │ - SlackEnabled, SlackWebhookUrl │ │
│ │ - EmailAlertsEnabled, AdminEmails │ │
│ │ - SmsNotificationsEnabled, SmsApiKey │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
↓ used by
┌─────────────────────────────────────────────────────────┐
│ Background Workers / Handlers │
│ ┌──────────────────────────────────────────────────┐ │
│ │ WeeklyNetworkCommissionWorker │ │
│ │ - On Success: SendSuccessNotificationAsync() │ │
│ │ - On Error: SendCriticalAlertAsync() │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ ProcessUserPayoutsCommandHandler │ │
│ │ - On Payout: SendCommissionReceivedNotification│ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
📦 Implementation Details
1️⃣ Alert Service (Admin Notifications)
Interface: CMSMicroservice.Application/Common/Interfaces/IAlertService.cs
public interface IAlertService
{
Task SendCriticalAlertAsync(string title, string message, Exception? exception, CancellationToken ct);
Task SendWarningAlertAsync(string title, string message, CancellationToken ct);
Task SendSuccessNotificationAsync(string title, string message, CancellationToken ct);
}
Implementation: CMSMicroservice.Infrastructure/Services/Monitoring/AlertService.cs
Current Behavior:
🚨 CRITICAL ALERT: {Title} - {Message}
⚠️ WARNING ALERT: {Title} - {Message}
✅ SUCCESS: {Title} - {Message}
Pending Integrations:
- Sentry: Exception tracking & aggregation (TODO:
SentrySdk.CaptureException()) - Slack: Real-time alerts to channel (TODO: HTTP POST to webhook)
- Email: Alert emails to admin list (TODO: SMTP integration)
2️⃣ User Notification Service
Interface: CMSMicroservice.Application/Common/Interfaces/IAlertService.cs (same file)
public interface IUserNotificationService
{
Task SendCommissionReceivedNotificationAsync(long userId, decimal amount, int weekNumber, CancellationToken ct);
Task SendClubActivationNotificationAsync(long userId, CancellationToken ct);
Task SendPayoutErrorNotificationAsync(long userId, string errorMessage, CancellationToken ct);
}
Implementation: CMSMicroservice.Infrastructure/Services/Monitoring/UserNotificationService.cs
Current Behavior:
📧 Sending commission notification: User={UserId}, Amount={Amount}, Week={WeekNumber}
🎉 Sending club activation notification: User={UserId}
⚠️ Sending payout error notification: User={UserId}, Error={Error}
Pending Integrations:
- SMS Gateway: Kavenegar/Ghasedak integration (TODO: HTTP API call)
- Email Service: SMTP/SendGrid integration (TODO: template-based emails)
- Push Notification: FCM/OneSignal integration (TODO: mobile app notifications)
3️⃣ Configuration Model
File: CMSMicroservice.Infrastructure/Services/Monitoring/MonitoringSettings.cs
public class MonitoringSettings
{
public const string SectionName = "Monitoring";
// Sentry
public bool SentryEnabled { get; set; }
public string? SentryDsn { get; set; }
// Slack
public bool SlackEnabled { get; set; }
public string? SlackWebhookUrl { get; set; }
// Email Alerts (Admin)
public bool EmailAlertsEnabled { get; set; }
public List<string> AdminEmails { get; set; }
// SMS (User Notifications)
public bool SmsNotificationsEnabled { get; set; }
public string? SmsApiKey { get; set; }
public string? SmsGatewayUrl { get; set; }
}
Config File: CMSMicroservice.WebApi/appsettings.json
{
"Monitoring": {
"SentryEnabled": false,
"SentryDsn": "",
"SlackEnabled": false,
"SlackWebhookUrl": "",
"EmailAlertsEnabled": false,
"AdminEmails": ["admin@example.com"],
"SmsNotificationsEnabled": false,
"SmsApiKey": "",
"SmsGatewayUrl": ""
}
}
4️⃣ Dependency Injection
File: CMSMicroservice.Infrastructure/ConfigureServices.cs
services.AddScoped<IAlertService, AlertService>();
services.AddScoped<IUserNotificationService, UserNotificationService>();
5️⃣ Worker Integration
File: CMSMicroservice.Infrastructure/BackgroundJobs/WeeklyNetworkCommissionWorker.cs
On Success:
await alertService.SendSuccessNotificationAsync(
"Weekly Commission Completed",
$"Week {previousWeekNumber}: {payoutsProcessed} payouts, {balancesToExpire.Count} balances expired");
On Error:
await alertService.SendCriticalAlertAsync(
"Weekly Commission Worker Failed",
$"Worker execution {executionId} failed for week {GetPreviousWeekNumber()}",
ex,
cancellationToken);
🔌 Integration Roadmap
Priority 1: Sentry (High - 1 hour)
Why: Critical error tracking & aggregation برای Production
Steps:
-
Install NuGet:
dotnet add package Sentry.AspNetCore -
Configure in
Program.cs:builder.WebHost.UseSentry(options => { options.Dsn = builder.Configuration["Monitoring:SentryDsn"]; options.Environment = builder.Environment.EnvironmentName; options.TracesSampleRate = 1.0; }); -
Update
AlertService.SendCriticalAlertAsync():if (_settings.SentryEnabled && exception != null) { SentrySdk.CaptureException(exception, scope => { scope.SetTag("alert.title", title); scope.SetExtra("message", message); }); } -
Set DSN in
appsettings.Production.json:{ "Monitoring": { "SentryEnabled": true, "SentryDsn": "https://xxxxx@sentry.io/12345" } }
Priority 2: Slack Webhook (Medium - 2 hours)
Why: Real-time alerts به تیم Development/DevOps
Steps:
-
Create Incoming Webhook در Slack:
- Go to:
https://api.slack.com/apps - Create app → Incoming Webhooks → Add to channel
- Copy Webhook URL
- Go to:
-
Update
AlertService:private readonly HttpClient _httpClient; public async Task SendCriticalAlertAsync(...) { _logger.LogCritical(exception, "🚨 {Title} - {Message}", title, message); if (_settings.SlackEnabled) { var payload = new { text = $"🚨 *{title}*", attachments = new[] { new { color = "danger", text = message, fields = exception != null ? new[] { new { title = "Exception", value = exception.Message, @short = false } } : null } } }; await _httpClient.PostAsJsonAsync(_settings.SlackWebhookUrl, payload); } } -
Set Webhook URL in config:
{ "Monitoring": { "SlackEnabled": true, "SlackWebhookUrl": "https://hooks.slack.com/services/T00/B00/XXX" } }
Priority 3: SMS Gateway - Kavenegar (Medium - 3 hours)
Why: اطلاعرسانی کمیسیون به کاربران
Steps:
-
Get API Key from Kavenegar:
- Sign up:
https://panel.kavenegar.com - API Key: Settings → API Key
- Sign up:
-
Create
ISmsGatewayService:public interface ISmsGatewayService { Task SendAsync(string mobile, string message, CancellationToken ct = default); } -
Implement
KavenegarSmsService:public class KavenegarSmsService : ISmsGatewayService { private readonly HttpClient _httpClient; private readonly string _apiKey; public async Task SendAsync(string mobile, string message, CancellationToken ct) { var url = $"https://api.kavenegar.com/v1/{_apiKey}/sms/send.json"; var payload = new { receptor = mobile, message = message }; var response = await _httpClient.PostAsJsonAsync(url, payload, ct); response.EnsureSuccessStatusCode(); } } -
Update
UserNotificationService.SendCommissionReceivedNotificationAsync():var user = await _context.Users.FindAsync(userId, ct); if (user.SmsNotifications && _settings.SmsNotificationsEnabled) { var message = $"کمیسیون شما: {amount:N0} ریال برای هفته {weekNumber} واریز شد."; await _smsGateway.SendAsync(user.Mobile, message, ct); } -
Configure:
{ "Monitoring": { "SmsNotificationsEnabled": true, "SmsApiKey": "your-kavenegar-api-key" } }
Priority 4: Email Alerts for Admins (Low - 2 hours)
Why: Backup notification channel
Options:
-
A) MailKit (SMTP):
using var client = new SmtpClient(); await client.ConnectAsync("smtp.gmail.com", 587, SecureSocketOptions.StartTls); await client.AuthenticateAsync("user@example.com", "password"); var message = new MimeMessage(); message.From.Add(new MailboxAddress("CMS Alerts", "noreply@foursat.ir")); message.To.Add(new MailboxAddress("Admin", adminEmail)); message.Subject = $"[ALERT] {title}"; message.Body = new TextPart("html") { Text = htmlMessage }; await client.SendAsync(message); -
B) SendGrid API:
var client = new SendGridClient(_settings.SendGridApiKey); var msg = MailHelper.CreateSingleEmail( from: new EmailAddress("noreply@foursat.ir", "CMS Alerts"), to: new EmailAddress(adminEmail), subject: $"[ALERT] {title}", plainTextContent: message, htmlContent: htmlMessage ); await client.SendEmailAsync(msg);
Config:
{
"Monitoring": {
"EmailAlertsEnabled": true,
"AdminEmails": ["admin@foursat.ir", "devops@foursat.ir"],
"SmtpServer": "smtp.gmail.com",
"SmtpPort": 587,
"SmtpUsername": "user@example.com",
"SmtpPassword": "password"
}
}
Priority 5: Retry Logic با Exponential Backoff (Low - 1 hour)
Why: بهبود Reliability در صورت خطاهای Transient
Implementation در Worker:
private async Task<T> RetryWithExponentialBackoffAsync<T>(
Func<Task<T>> operation,
int maxRetries = 3,
CancellationToken ct = default)
{
for (int attempt = 0; attempt <= maxRetries; attempt++)
{
try
{
return await operation();
}
catch (Exception ex) when (attempt < maxRetries && IsTransientError(ex))
{
var delay = TimeSpan.FromSeconds(Math.Pow(2, attempt)); // 2^n: 1s, 2s, 4s
_logger.LogWarning(ex,
"Attempt {Attempt}/{MaxRetries} failed. Retrying in {Delay}s...",
attempt + 1, maxRetries, delay.TotalSeconds);
await Task.Delay(delay, ct);
}
}
throw new InvalidOperationException($"Operation failed after {maxRetries} retries");
}
private bool IsTransientError(Exception ex)
{
return ex is TimeoutException
|| ex is HttpRequestException
|| (ex is SqlException sqlEx && sqlEx.IsTransient);
}
Usage:
// در ExecuteWeeklyCalculationAsync():
var balancesCalculated = await RetryWithExponentialBackoffAsync(async () =>
{
return await mediator.Send(new CalculateWeeklyBalancesCommand
{
WeekNumber = previousWeekNumber
}, cancellationToken);
}, maxRetries: 3, ct: cancellationToken);
🧪 Testing Guide
Test 1: Alert Service (Console Logging)
// در Controller یا Handler:
var alertService = _serviceProvider.GetRequiredService<IAlertService>();
await alertService.SendCriticalAlertAsync(
"Test Critical Alert",
"این یک تست برای Alert Service است",
new Exception("Sample exception"));
await alertService.SendSuccessNotificationAsync(
"Test Success",
"عملیات با موفقیت انجام شد");
Expected Output:
🚨 CRITICAL ALERT: Test Critical Alert - این یک تست برای Alert Service است
✅ SUCCESS: Test Success - عملیات با موفقیت انجام شد
Test 2: User Notification Service
var notificationService = _serviceProvider.GetRequiredService<IUserNotificationService>();
await notificationService.SendCommissionReceivedNotificationAsync(
userId: 123,
amount: 500_000,
weekNumber: 48);
Expected Output:
📧 Sending commission notification: User=123, Amount=500000, Week=48
Test 3: Worker Integration
# Run Worker manually (for testing)
# تغییر زمان اجرا به 1 دقیقه بعد برای تست:
# در Worker: var delay = TimeSpan.FromMinutes(1);
dotnet run --project CMSMicroservice.WebApi
Expected:
- Worker starts
- After 1 minute → Executes calculation
- On success → Logs:
✅ SUCCESS: Weekly Commission Completed - On error → Logs:
🚨 CRITICAL ALERT: Weekly Commission Worker Failed
Test 4: Sentry Integration (بعد از پیادهسازی)
// Throw یک exception برای تست:
throw new InvalidOperationException("Test Sentry integration");
Check: Sentry dashboard → Issues → باید exception جدید نمایش داده شود
Test 5: Slack Integration (بعد از پیادهسازی)
await alertService.SendCriticalAlertAsync("Test Slack", "Testing webhook integration", null);
Check: Slack channel → باید پیام جدید نمایش داده شود
Test 6: SMS Integration (بعد از پیادهسازی)
await notificationService.SendCommissionReceivedNotificationAsync(
userId: YOUR_USER_ID, // با شماره موبایل معتبر
amount: 100_000,
weekNumber: 48);
Check: موبایل کاربر → باید SMS دریافت شود
📊 Current Status & Progress
| Component | Status | Completion | Notes |
|---|---|---|---|
| Interfaces | ✅ Done | 100% | IAlertService, IUserNotificationService |
| Skeleton Implementations | ✅ Done | 100% | Logging only |
| Configuration Model | ✅ Done | 100% | MonitoringSettings |
| DI Registration | ✅ Done | 100% | In ConfigureServices.cs |
| Worker Integration | ✅ Done | 100% | Success + Error alerts |
| appsettings Structure | ✅ Done | 100% | Monitoring section added |
| Sentry Integration | ⏳ Pending | 0% | Install package + configure DSN |
| Slack Webhook | ⏳ Pending | 0% | Create webhook + implement POST |
| SMS Gateway | ⏳ Pending | 0% | Choose provider + get API key |
| Email Alerts | ⏳ Pending | 0% | SMTP/SendGrid integration |
| Retry Logic | ⏳ Pending | 0% | Exponential backoff implementation |
| Testing | ⏳ Pending | 0% | Unit + Integration tests |
Overall Progress: 30% ✅ | 70% ⏳
📝 Important Notes
1. Production Readiness
- ⚠️ فعلاً فقط Logging فعال است
- ⚠️ برای Production حداقل Sentry باید فعال شود
- ⚠️ برای Critical systems حتماً Slack هم اضافه شود
2. User Preferences
- SMS/Email/Push باید بر اساس تنظیمات کاربر (
User.SmsNotifications, etc.) ارسال شود - در
UserNotificationServiceباید ابتدا preferences چک شود
3. Rate Limiting
- برای SMS Gateway باید Rate Limiting در نظر گرفته شود
- پیشنهاد: استفاده از Queue (Hangfire/RabbitMQ) برای ارسال تعداد زیاد SMS
4. Cost Management
- SMS و Email هزینه دارند
- پیشنهاد: Batching برای ارسال گروهی
- پیشنهاد: Template-based messaging برای کاهش هزینه
5. Security
- API Keys در
appsettings.jsonنباید commit شوند - استفاده از Environment Variables یا Azure Key Vault
- مثال:
SmsApiKey: ${SMS_API_KEY}در appsettings
6. Monitoring the Monitor
- خود Alert System هم باید Monitor شود
- اگر Slack/SMS fail شد، باید Fallback به Email یا Log باشد
- پیشنهاد: Dead Letter Queue برای failed notifications
🔗 File Reference Map
CMS/
├── src/
│ ├── CMSMicroservice.Application/
│ │ └── Common/
│ │ └── Interfaces/
│ │ └── IAlertService.cs ⭐
│ │
│ ├── CMSMicroservice.Infrastructure/
│ │ ├── Services/
│ │ │ └── Monitoring/
│ │ │ ├── AlertService.cs ⭐
│ │ │ ├── UserNotificationService.cs ⭐
│ │ │ └── MonitoringSettings.cs ⭐
│ │ │
│ │ ├── BackgroundJobs/
│ │ │ └── WeeklyNetworkCommissionWorker.cs ✏️ (Modified)
│ │ │
│ │ └── ConfigureServices.cs ✏️ (Modified)
│ │
│ └── CMSMicroservice.WebApi/
│ └── appsettings.json ✏️ (Modified)
│
└── docs/
└── monitoring-alerts-implementation-report.md 📄 (This file)
Legend:
- ⭐ = New file created
- ✏️ = Existing file modified
- 📄 = Documentation
🚀 Next Action Items
Immediate (این هفته):
- ✅ Review this document
- ⏳ Decision: کدام Integration اول؟ (پیشنهاد: Sentry)
- ⏳ Get credentials:
- Sentry DSN
- Slack Webhook URL
- SMS Gateway API Key
Short-term (هفته آینده):
- ⏳ Implement Sentry integration
- ⏳ Implement Slack webhook
- ⏳ Test in Staging environment
Long-term (ماه آینده):
- ⏳ Implement SMS Gateway (Kavenegar)
- ⏳ Add Email alerts
- ⏳ Implement Retry logic
- ⏳ Write Unit/Integration tests
- ⏳ Deploy to Production
📞 Contact & Support
Implementation Questions:
- Developer: GitHub Copilot (این گزارش)
- Review: Development Team
Service Providers:
- Sentry: https://sentry.io (Error tracking)
- Slack: https://api.slack.com/messaging/webhooks (Webhooks)
- Kavenegar: https://kavenegar.com (SMS Gateway - Iran)
- Ghasedak: https://ghasedak.me (SMS Gateway Alternative)
- SendGrid: https://sendgrid.com (Email service)
Last Updated: 2025-11-30
Build Status: ✅ Success
Ready for: Integration implementation
🎯 TL;DR (خلاصه برای رجوع سریع)
چی ساخته شد:
- ✅
IAlertService+AlertService(Admin alerts) - ✅
IUserNotificationService+UserNotificationService(User notifications) - ✅
MonitoringSettings(Configuration model) - ✅ Worker integration (Success/Error alerts)
- ✅ DI registration
- ✅ appsettings structure
فعلاً چی کار میکنه:
- Logging به Console (🚨 Critical, ⚠️ Warning, ✅ Success)
چی باید اضافه بشه:
- Sentry - Error tracking (Priority: High)
- Slack - Real-time alerts (Priority: Medium)
- SMS Gateway - User notifications (Priority: Medium)
- Email - Backup channel (Priority: Low)
- Retry Logic - Reliability (Priority: Low)
کجا باید نگاه کنی:
- Interfaces:
CMSMicroservice.Application/Common/Interfaces/IAlertService.cs - Implementations:
CMSMicroservice.Infrastructure/Services/Monitoring/ - Worker:
CMSMicroservice.Infrastructure/BackgroundJobs/WeeklyNetworkCommissionWorker.cs - Config:
CMSMicroservice.WebApi/appsettings.json
چطوری تست کنی:
await alertService.SendCriticalAlertAsync("Test", "Message", null);
// Output: 🚨 CRITICAL ALERT: Test - Message
بعدش چیکار کنم:
- Get Sentry DSN → Update appsettings.Production.json
- Install
Sentry.AspNetCore→ Configure in Program.cs - Update
AlertService.SendCriticalAlertAsync()→ AddSentrySdk.CaptureException() - Test → Deploy