# 📊 Monitoring & Alerts System - Consolidated Implementation Report **Date**: 2025-11-30 **Status**: ✅ Skeleton Implemented (30% Complete) **Build**: ✅ Success --- ## 📋 Executive Summary اسکلت کامل سیستم Monitoring & Alerts پیاده‌سازی شد. این سیستم شامل دو بخش اصلی است: 1. **Alert System**: اعلان‌های مدیریتی (Critical/Warning/Success) برای Admin 2. **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` ```csharp 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) ```csharp 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` ```csharp 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 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` ```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` ```csharp services.AddScoped(); services.AddScoped(); ``` --- ### 5️⃣ Worker Integration **File**: `CMSMicroservice.Infrastructure/BackgroundJobs/WeeklyNetworkCommissionWorker.cs` **On Success**: ```csharp await alertService.SendSuccessNotificationAsync( "Weekly Commission Completed", $"Week {previousWeekNumber}: {payoutsProcessed} payouts, {balancesToExpire.Count} balances expired"); ``` **On Error**: ```csharp 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**: 1. Install NuGet: ```bash dotnet add package Sentry.AspNetCore ``` 2. Configure in `Program.cs`: ```csharp builder.WebHost.UseSentry(options => { options.Dsn = builder.Configuration["Monitoring:SentryDsn"]; options.Environment = builder.Environment.EnvironmentName; options.TracesSampleRate = 1.0; }); ``` 3. Update `AlertService.SendCriticalAlertAsync()`: ```csharp if (_settings.SentryEnabled && exception != null) { SentrySdk.CaptureException(exception, scope => { scope.SetTag("alert.title", title); scope.SetExtra("message", message); }); } ``` 4. Set DSN in `appsettings.Production.json`: ```json { "Monitoring": { "SentryEnabled": true, "SentryDsn": "https://xxxxx@sentry.io/12345" } } ``` --- ### Priority 2: Slack Webhook (Medium - 2 hours) **Why**: Real-time alerts به تیم Development/DevOps **Steps**: 1. Create Incoming Webhook در Slack: - Go to: `https://api.slack.com/apps` - Create app → Incoming Webhooks → Add to channel - Copy Webhook URL 2. Update `AlertService`: ```csharp 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); } } ``` 3. Set Webhook URL in config: ```json { "Monitoring": { "SlackEnabled": true, "SlackWebhookUrl": "https://hooks.slack.com/services/T00/B00/XXX" } } ``` --- ### Priority 3: SMS Gateway - Kavenegar (Medium - 3 hours) **Why**: اطلاع‌رسانی کمیسیون به کاربران **Steps**: 1. Get API Key from Kavenegar: - Sign up: `https://panel.kavenegar.com` - API Key: Settings → API Key 2. Create `ISmsGatewayService`: ```csharp public interface ISmsGatewayService { Task SendAsync(string mobile, string message, CancellationToken ct = default); } ``` 3. Implement `KavenegarSmsService`: ```csharp 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(); } } ``` 4. Update `UserNotificationService.SendCommissionReceivedNotificationAsync()`: ```csharp 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); } ``` 5. Configure: ```json { "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)**: ```csharp 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**: ```csharp 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**: ```json { "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**: ```csharp private async Task RetryWithExponentialBackoffAsync( Func> 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**: ```csharp // در 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) ```csharp // در Controller یا Handler: var alertService = _serviceProvider.GetRequiredService(); 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 ```csharp var notificationService = _serviceProvider.GetRequiredService(); 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 ```bash # 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 (بعد از پیاده‌سازی) ```csharp // Throw یک exception برای تست: throw new InvalidOperationException("Test Sentry integration"); ``` **Check**: Sentry dashboard → Issues → باید exception جدید نمایش داده شود --- ### Test 5: Slack Integration (بعد از پیاده‌سازی) ```csharp await alertService.SendCriticalAlertAsync("Test Slack", "Testing webhook integration", null); ``` **Check**: Slack channel → باید پیام جدید نمایش داده شود --- ### Test 6: SMS Integration (بعد از پیاده‌سازی) ```csharp 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 (این هفته): 1. ✅ Review this document 2. ⏳ Decision: کدام Integration اول؟ (پیشنهاد: Sentry) 3. ⏳ Get credentials: - Sentry DSN - Slack Webhook URL - SMS Gateway API Key ### Short-term (هفته آینده): 4. ⏳ Implement Sentry integration 5. ⏳ Implement Slack webhook 6. ⏳ Test in Staging environment ### Long-term (ماه آینده): 7. ⏳ Implement SMS Gateway (Kavenegar) 8. ⏳ Add Email alerts 9. ⏳ Implement Retry logic 10. ⏳ Write Unit/Integration tests 11. ⏳ 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) ### چی باید اضافه بشه: 1. **Sentry** - Error tracking (Priority: High) 2. **Slack** - Real-time alerts (Priority: Medium) 3. **SMS Gateway** - User notifications (Priority: Medium) 4. **Email** - Backup channel (Priority: Low) 5. **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` ### چطوری تست کنی: ```csharp await alertService.SendCriticalAlertAsync("Test", "Message", null); // Output: 🚨 CRITICAL ALERT: Test - Message ``` ### بعدش چیکار کنم: 1. Get Sentry DSN → Update appsettings.Production.json 2. Install `Sentry.AspNetCore` → Configure in Program.cs 3. Update `AlertService.SendCriticalAlertAsync()` → Add `SentrySdk.CaptureException()` 4. Test → Deploy