feat: Add Chatika integration and Club Features system documentation

- Implement Chatika account activation via background job
- Create IChatikaApiService interface and its implementation
- Add Club Features system documentation detailing features and entities
- Introduce ClubFeatureType enum to replace hardcoded IDs
- Update SQL scripts for Club Membership migration
- Fix various bugs in BackOffice UI and improve Products page functionality
This commit is contained in:
masoodafar-web
2025-12-24 01:07:49 +03:30
parent 002e99f6bf
commit e7d979117c
9 changed files with 1360 additions and 37 deletions
+424
View File
@@ -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)