Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -0,0 +1,424 @@
|
||||
# 🤖 Chatika Integration Guide
|
||||
|
||||
> **آخرین بروزرسانی**: ۳ دی ۱۴۰۴ (23 December 2025)
|
||||
> **وضعیت**: ✅ Production Ready
|
||||
|
||||
---
|
||||
|
||||
## 📋 فهرست
|
||||
|
||||
1. [معرفی](#معرفی)
|
||||
2. [معماری](#معماری)
|
||||
3. [API چتیکا](#api-چتیکا)
|
||||
4. [پیادهسازی](#پیادهسازی)
|
||||
5. [تنظیمات](#تنظیمات)
|
||||
6. [نحوه کار Worker](#نحوه-کار-worker)
|
||||
7. [Troubleshooting](#troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
## معرفی
|
||||
|
||||
چتیکا یک سرویس هوش مصنوعی است که به عنوان اولین فیچر باشگاه مشتریان به کاربران ارائه میشود. هنگام فعالسازی باشگاه، به صورت خودکار یک حساب در چتیکا برای کاربر ایجاد میشود.
|
||||
|
||||
### ویژگیها:
|
||||
- ✅ فعالسازی خودکار حساب
|
||||
- ✅ جلوگیری از ثبت تکراری
|
||||
- ✅ Retry با Exponential Backoff
|
||||
- ✅ Logging کامل
|
||||
|
||||
---
|
||||
|
||||
## معماری
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
||||
│ User Activates │───▶│ ClubMembership │───▶│ UserClubFeature │
|
||||
│ Club Package │ │ (IsActive=true) │ │ (Chatika, Id=1)│
|
||||
└─────────────────┘ └──────────────────┘ │ Notes = NULL │
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Hangfire Scheduler │
|
||||
│ Cron: */5 * * * * (Every 5 minutes) │
|
||||
└─────────────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ChatikaAccountActivationJob │
|
||||
│ │
|
||||
│ Query: SELECT * FROM UserClubFeatures │
|
||||
│ WHERE ClubFeatureId = 1 (Chatika) │
|
||||
│ AND ClubMembership.IsActive = true │
|
||||
│ AND Notes IS NULL │
|
||||
└─────────────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ChatikaApiService │
|
||||
│ POST https://api.chatika.ir/api/v1/organizations/register-user │
|
||||
│ Header: X-API-Key: {ApiKey} │
|
||||
│ Body: { "mobile_number": "09123456789" } │
|
||||
└─────────────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Update UserClubFeature │
|
||||
│ Notes = "🎉 تبریک! حساب هوش مصنوعی چتیکا شما فعال شد..." │
|
||||
│ IsActive = true │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API چتیکا
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
POST /api/v1/organizations/register-user
|
||||
```
|
||||
|
||||
### Headers
|
||||
|
||||
| Header | Value |
|
||||
|--------|-------|
|
||||
| `X-API-Key` | Organization API Key |
|
||||
| `Content-Type` | `application/json` |
|
||||
|
||||
### Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"mobile_number": "09123456789"
|
||||
}
|
||||
```
|
||||
|
||||
### Success Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"mobile_number": "09123456789",
|
||||
"organization_id": 1,
|
||||
"organization_title": "FourSat",
|
||||
"wallet_balance": 100.0,
|
||||
"is_new_user": true,
|
||||
"credit_charged": 100.0
|
||||
}
|
||||
```
|
||||
|
||||
### Error Responses
|
||||
|
||||
| Status | Error Code | Description |
|
||||
|--------|-----------|-------------|
|
||||
| 401 | `INVALID_API_KEY` | API Key نامعتبر |
|
||||
| 403 | `ORGANIZATION_DISABLED` | سازمان غیرفعال شده |
|
||||
| 403 | `ORGANIZATION_EXPIRED` | سازمان منقضی شده |
|
||||
| 400 | `INVALID_MOBILE_FORMAT` | فرمت شماره موبایل نامعتبر |
|
||||
|
||||
---
|
||||
|
||||
## پیادهسازی
|
||||
|
||||
### 1. Interface
|
||||
|
||||
**فایل**: `CMSMicroservice.Application/Common/Interfaces/IChatikaApiService.cs`
|
||||
|
||||
```csharp
|
||||
public interface IChatikaApiService
|
||||
{
|
||||
Task<ChatikaAccountResult> CreateAccountAsync(
|
||||
string mobileNumber,
|
||||
string fullName,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public class ChatikaAccountResult
|
||||
{
|
||||
public bool IsSuccess { get; set; }
|
||||
public string? ErrorMessage { get; set; }
|
||||
public string? ChatikaUserId { get; set; }
|
||||
public string? AccessUrl { get; set; }
|
||||
|
||||
public static ChatikaAccountResult Success(...) => ...;
|
||||
public static ChatikaAccountResult Failure(string error) => ...;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Service Implementation
|
||||
|
||||
**فایل**: `CMSMicroservice.Infrastructure/Services/ChatikaApiService.cs`
|
||||
|
||||
```csharp
|
||||
public class ChatikaApiService : IChatikaApiService
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILogger<ChatikaApiService> _logger;
|
||||
|
||||
public async Task<ChatikaAccountResult> CreateAccountAsync(
|
||||
string mobileNumber,
|
||||
string fullName,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new { mobile_number = mobileNumber };
|
||||
|
||||
var response = await _httpClient.PostAsJsonAsync(
|
||||
"/api/v1/organizations/register-user",
|
||||
request,
|
||||
cancellationToken);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var result = await response.Content.ReadFromJsonAsync<ChatikaRegisterResponse>();
|
||||
return ChatikaAccountResult.Success(result?.Id.ToString(), "https://chatika.ir");
|
||||
}
|
||||
|
||||
return ChatikaAccountResult.Failure($"Error: {response.StatusCode}");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Background Job
|
||||
|
||||
**فایل**: `CMSMicroservice.Infrastructure/BackgroundJobs/ChatikaAccountActivationJob.cs`
|
||||
|
||||
```csharp
|
||||
public class ChatikaAccountActivationJob
|
||||
{
|
||||
private const string ChatikaFeatureDescription =
|
||||
"🎉 تبریک! حساب هوش مصنوعی چتیکا شما فعال شد.\n\n" +
|
||||
"برای استفاده از امکانات رایگان چتیکا:\n" +
|
||||
"1️⃣ به وبسایت chatika.ir مراجعه کنید\n" +
|
||||
"2️⃣ شماره موبایل خود را وارد کنید\n" +
|
||||
"3️⃣ از دستیار هوشمند چتیکا لذت ببرید!\n\n" +
|
||||
"🔗 لینک ورود: https://chatika.ir";
|
||||
|
||||
public async Task ExecuteAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 1. پیدا کردن کاربران در انتظار
|
||||
var pendingUsers = await _context.UserClubFeatures
|
||||
.Include(ucf => ucf.User)
|
||||
.Include(ucf => ucf.ClubMembership)
|
||||
.Where(ucf =>
|
||||
ucf.ClubFeatureId == (long)ClubFeatureType.Chatika &&
|
||||
ucf.ClubMembership.IsActive &&
|
||||
!ucf.IsDeleted &&
|
||||
ucf.IsActive &&
|
||||
(ucf.Notes == null || ucf.Notes == ""))
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
// 2. پردازش هر کاربر
|
||||
foreach (var userFeature in pendingUsers)
|
||||
{
|
||||
var user = userFeature.User;
|
||||
var fullName = $"{user.FirstName} {user.LastName}".Trim();
|
||||
|
||||
// 3. کال API با Retry
|
||||
var result = await _retryPipeline.ExecuteAsync(
|
||||
async ct => await _chatikaApiService.CreateAccountAsync(
|
||||
user.Mobile, fullName, ct),
|
||||
cancellationToken);
|
||||
|
||||
// 4. آپدیت فیچر
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
userFeature.Notes = ChatikaFeatureDescription;
|
||||
userFeature.IsActive = true;
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## تنظیمات
|
||||
|
||||
### appsettings.json
|
||||
|
||||
```json
|
||||
{
|
||||
"Chatika": {
|
||||
"BaseUrl": "https://api.chatika.ir",
|
||||
"ApiKey": "YOUR_ORGANIZATION_API_KEY"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### DI Registration
|
||||
|
||||
**فایل**: `ConfigureServices.cs`
|
||||
|
||||
```csharp
|
||||
// Chatika API Service
|
||||
services.AddHttpClient<IChatikaApiService, ChatikaApiService>()
|
||||
.SetHandlerLifetime(TimeSpan.FromMinutes(5))
|
||||
.ConfigureHttpClient((sp, client) =>
|
||||
{
|
||||
client.Timeout = TimeSpan.FromSeconds(30);
|
||||
});
|
||||
|
||||
// Background Job
|
||||
services.AddScoped<ChatikaAccountActivationJob>();
|
||||
```
|
||||
|
||||
### Hangfire Registration
|
||||
|
||||
**فایل**: `Program.cs`
|
||||
|
||||
```csharp
|
||||
// Chatika Account Activation: Every 5 minutes
|
||||
recurringJobManager.AddOrUpdate<ChatikaAccountActivationJob>(
|
||||
recurringJobId: "chatika-account-activation",
|
||||
methodCall: job => job.ExecuteAsync(CancellationToken.None),
|
||||
cronExpression: "*/5 * * * *",
|
||||
options: new RecurringJobOptions { TimeZone = TimeZoneInfo.Utc });
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## نحوه کار Worker
|
||||
|
||||
### Flowchart
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ START (Every 5 min) │
|
||||
└──────────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Query: Users with Chatika feature & Notes = NULL │
|
||||
└──────────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────┐
|
||||
│ Any Users? │
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌────────────┴────────────┐
|
||||
│ NO │ YES
|
||||
▼ ▼
|
||||
┌──────────┐ ┌───────────────┐
|
||||
│ END │ │ For each user │
|
||||
└──────────┘ └───────┬───────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────┐
|
||||
│ Call Chatika API │
|
||||
│ (with 3x Retry) │
|
||||
└────────┬───────────┘
|
||||
│
|
||||
┌─────────┴─────────┐
|
||||
│ SUCCESS │ FAILURE
|
||||
▼ ▼
|
||||
┌───────────────┐ ┌───────────────┐
|
||||
│ Update Notes │ │ Log Warning │
|
||||
│ IsActive=true │ │ Continue │
|
||||
└───────────────┘ └───────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────┐
|
||||
│ Next User │
|
||||
└────────────────┘
|
||||
```
|
||||
|
||||
### Retry Policy
|
||||
|
||||
```csharp
|
||||
// Polly Retry: 3 attempts with exponential backoff
|
||||
_retryPipeline = new ResiliencePipelineBuilder()
|
||||
.AddRetry(new RetryStrategyOptions
|
||||
{
|
||||
MaxRetryAttempts = 3,
|
||||
Delay = TimeSpan.FromSeconds(30),
|
||||
BackoffType = DelayBackoffType.Exponential,
|
||||
UseJitter = true
|
||||
})
|
||||
.Build();
|
||||
```
|
||||
|
||||
**Retry Timeline:**
|
||||
- Attempt 1: Immediate
|
||||
- Attempt 2: ~30 seconds later
|
||||
- Attempt 3: ~60 seconds later
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### 1. API Key Invalid
|
||||
|
||||
**خطا**: `INVALID_API_KEY`
|
||||
|
||||
**راهحل**:
|
||||
1. بررسی `appsettings.json`
|
||||
2. تأیید API Key در داشبورد چتیکا
|
||||
3. چک کردن header name: باید `X-API-Key` باشد
|
||||
|
||||
### 2. Users Not Being Processed
|
||||
|
||||
**علت احتمالی**:
|
||||
1. `ClubMembership.IsActive = false`
|
||||
2. `UserClubFeature.Notes` قبلاً پر شده
|
||||
3. `ClubFeatureId != 1`
|
||||
|
||||
**Debug Query**:
|
||||
```sql
|
||||
SELECT ucf.*, u.Mobile, cm.IsActive
|
||||
FROM UserClubFeatures ucf
|
||||
JOIN Users u ON ucf.UserId = u.Id
|
||||
JOIN ClubMemberships cm ON ucf.ClubMembershipId = cm.Id
|
||||
WHERE ucf.ClubFeatureId = 1
|
||||
AND ucf.IsDeleted = 0
|
||||
AND (ucf.Notes IS NULL OR ucf.Notes = '')
|
||||
```
|
||||
|
||||
### 3. Hangfire Job Not Running
|
||||
|
||||
**راهحل**:
|
||||
1. چک کردن Hangfire Dashboard: `/hangfire`
|
||||
2. بررسی لاگها در Seq
|
||||
3. تأیید ثبت Job در `Program.cs`
|
||||
|
||||
### 4. Network Timeout
|
||||
|
||||
**علت**: سرور چتیکا در دسترس نیست
|
||||
|
||||
**راهحل**:
|
||||
- Retry Policy خودکار 3 بار تلاش میکند
|
||||
- بررسی لاگها برای خطای دقیق
|
||||
- تماس با پشتیبانی چتیکا
|
||||
|
||||
---
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### Logs to Watch
|
||||
|
||||
```
|
||||
🚀 Starting Chatika account activation job
|
||||
📋 Found {Count} users pending Chatika activation
|
||||
🤖 Creating Chatika account for mobile: 0912***
|
||||
✅ Chatika account activated for user {UserId}
|
||||
⚠️ Failed to create Chatika account for user {UserId}: {Error}
|
||||
❌ Network error calling Chatika API
|
||||
🏁 Chatika activation job completed. Success: {X}, Failed: {Y}
|
||||
```
|
||||
|
||||
### Seq Query
|
||||
|
||||
```
|
||||
ApplicationName = "CMSMicroservice" AND Message LIKE "%Chatika%"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 مستندات مرتبط
|
||||
|
||||
- [Club Features System](./club-features-system.md)
|
||||
- [Hangfire Jobs Guide](./hangfire-jobs.md)
|
||||
- [Commission System](./commission-system.md)
|
||||
Reference in New Issue
Block a user