# System Configs API - Frontend Documentation

## Overview

**System Configs API** cho phép lưu trữ và quản lý các cấu hình toàn hệ thống dưới dạng JSON. Đây là nơi centralized để lưu trữ các thiết lập chung của ứng dụng như thông tin công ty, chính sách thanh toán, cấu hình sự cố, v.v.

### Key Features
- ✅ Lưu trữ JSON cấu hình linh hoạt (không cần định nghĩa schema cứng)
- ✅ Nhóm cấu hình theo categories (BILLING, GENERAL, INCIDENT, PAYMENT, BRAND)
- ✅ Bộ lọc theo group và is_active
- ✅ Soft-delete hỗ trợ (force delete)
- ✅ Audit log tự động

---

## Data Types

### Config Groups

```typescript
type ConfigGroup = 'BILLING' | 'GENERAL' | 'INCIDENT' | 'PAYMENT' | 'BRAND';
```

| Group | Mục đích | Ví dụ key |
|-------|---------|----------|
| **BILLING** | Cấu hình thanh toán nợ | `DEBT_REMINDER_POLICY` |
| **GENERAL** | Cấu hình chung hệ thống | `GENERAL_SETTINGS` |
| **PAYMENT** | Cấu hình phương thức thanh toán | `PAYMENT_SETTINGS` |
| **BRAND** | Thông tin thương hiệu | `BRAND_SETTINGS` |

### SystemConfig Entity

```typescript
interface SystemConfig {
  id: string;                    // UUID, tự sinh
  config_key: string;            // Tên cấu hình (UNIQUE)
  config_group: ConfigGroup;     // Nhóm cấu hình
  description?: string;          // Mô tả (optional)
  config_value: object;          // JSON object value (bất kỳ cấu trúc nào)
  is_active: boolean;            // Kích hoạt? (default: true)
  created_at: string;            // ISO 8601 timestamp
  updated_at: string;            // ISO 8601 timestamp
}
```

### Example Response

```json
{
  "success": true,
  "statusCode": 200,
  "message": "OK",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "config_key": "GENERAL_SETTINGS",
    "config_group": "GENERAL",
    "description": "Các thiết lập chung cho toàn hệ thống BeKind Admin",
    "config_value": {
      "organization_info": {
        "name": "BeKind Property",
        "contact_email": "admin@bekind.vn",
        "hotline": "1900 123 456",
        "office_address": "123 Nguyễn Huệ, Q1, TP.HCM"
      },
      "localization": {
        "timezone": "Asia/Ho_Chi_Minh",
        "default_language": "Tiếng việt",
        "date_format": "DD/MM/YYYY"
      }
    },
    "is_active": true,
    "created_at": "2026-06-02T10:30:00Z",
    "updated_at": "2026-06-02T10:30:00Z"
  }
}
```

---

## API Endpoints

### 1. GET /api/v1/system-configs

Lấy danh sách tất cả cấu hình hệ thống (có phân trang).

**Request:**
```typescript
GET /api/v1/system-configs?page=1&pageSize=20&config_group=GENERAL&is_active=true
```

**Query Parameters:**

| Parameter | Type | Default | Mô tả |
|-----------|------|---------|-------|
| `page` | number | 1 | Trang hiện tại (1-indexed) |
| `pageSize` | number | 20 | Số item trên trang |
| `config_group` | string | (optional) | Lọc theo nhóm (BILLING, GENERAL, PAYMENT, BRAND) |
| `is_active` | boolean | (optional) | Lọc theo trạng thái kích hoạt |

**Response (200):**
```json
{
  "success": true,
  "statusCode": 200,
  "message": "OK",
  "data": {
    "count": 5,
    "page": 1,
    "pageSize": 20,
    "rows": [
      {
        "id": "...",
        "config_key": "GENERAL_SETTINGS",
        "config_group": "GENERAL",
        "description": "...",
        "config_value": {...},
        "is_active": true,
        "created_at": "...",
        "updated_at": "..."
      }
    ]
  }
}
```

**Error Responses:**
- `401`: Unauthorized (cần Bearer token)
- `403`: Forbidden (không phải admin)

**cURL Example:**
```bash
curl -X GET "http://localhost:3001/api/v1/system-configs?page=1&pageSize=10" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

---

### 2. POST /api/v1/system-configs

Tạo một cấu hình hệ thống mới.

**Request:**
```typescript
POST /api/v1/system-configs
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN

{
  "config_key": "NEW_CONFIG",
  "config_group": "GENERAL",
  "description": "Mô tả cấu hình",
  "config_value": {
    "key1": "value1",
    "key2": {
      "nested": "value"
    }
  },
  "is_active": true  // optional, default: true
}
```

**Response (200):**
```json
{
  "success": true,
  "statusCode": 200,
  "message": "OK",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "config_key": "NEW_CONFIG",
    "config_group": "GENERAL",
    "description": "Mô tả cấu hình",
    "config_value": {...},
    "is_active": true,
    "created_at": "2026-06-02T10:30:00Z",
    "updated_at": "2026-06-02T10:30:00Z"
  }
}
```

**Error Responses:**
- `400`: Bad Request (invalid JSON)
- `401`: Unauthorized
- `403`: Forbidden (không phải admin)
- `409`: Conflict (`config_key` đã tồn tại)

**cURL Example:**
```bash
curl -X POST "http://localhost:3001/api/v1/system-configs" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "config_key": "PAYMENT_SETTINGS",
    "config_group": "PAYMENT",
    "description": "Payment configuration",
    "config_value": {
      "currency": "VND",
      "late_fee_percent": 2,
      "grace_period_days": 3
    }
  }'
```

---

### 3. GET /api/v1/system-configs/{id}

Lấy chi tiết một cấu hình theo ID.

**Request:**
```typescript
GET /api/v1/system-configs/550e8400-e29b-41d4-a716-446655440000
```

**Response (200):**
```json
{
  "success": true,
  "statusCode": 200,
  "message": "OK",
  "data": { ... SystemConfig object ... }
}
```

**Error Responses:**
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not Found (config với ID không tồn tại)

**cURL Example:**
```bash
curl -X GET "http://localhost:3001/api/v1/system-configs/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

---

### 4. PUT /api/v1/system-configs/{id}

Cập nhật một cấu hình hệ thống.

**Request:**
```typescript
PUT /api/v1/system-configs/550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN

{
  "config_key": "GENERAL_SETTINGS",    // optional
  "config_group": "GENERAL",           // optional
  "description": "Updated description", // optional
  "config_value": {                    // optional
    "new_key": "new_value"
  },
  "is_active": false                   // optional
}
```

**Response (200):**
```json
{
  "success": true,
  "statusCode": 200,
  "message": "OK",
  "data": { ... cập nhật SystemConfig object ... }
}
```

**Error Responses:**
- `400`: Bad Request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not Found
- `409`: Conflict (nếu thay đổi `config_key` sang một key đã tồn tại)

**cURL Example:**
```bash
curl -X PUT "http://localhost:3001/api/v1/system-configs/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "config_value": {
      "timezone": "Asia/Bangkok"
    },
    "is_active": true
  }'
```

---

### 5. DELETE /api/v1/system-configs/{id}

Xóa một cấu hình hệ thống.

**Request:**
```typescript
DELETE /api/v1/system-configs/550e8400-e29b-41d4-a716-446655440000
```

**Response (200):**
```json
{
  "success": true,
  "statusCode": 200,
  "message": "OK",
  "data": {
    "message": "System config deleted successfully"
  }
}
```

**Error Responses:**
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not Found

**cURL Example:**
```bash
curl -X DELETE "http://localhost:3001/api/v1/system-configs/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

---

## Seed Configurations

Khi migration chạy, 5 cấu hình mặc định sẽ được tạo:

### 1. DEBT_REMINDER_POLICY (BILLING)

Quản lý lịch và nội dung nhắc nhở thanh toán nợ.

```json
{
  "config_key": "DEBT_REMINDER_POLICY",
  "config_group": "BILLING",
  "config_value": {
    "before_due": {
      "days_before": 7,
      "channels": ["SMS", "APP_PUSH"],
      "template": "Hóa đơn tháng {month} của bạn sắp đến hạn vào {due_date}..."
    },
    "overdue": {
      "template": "Hóa đơn tháng {month} của bạn đã quá hạn {days_overdue} ngày...",
      "schedules": [
        {"days_offset": 0, "channels": ["SMS", "APP_PUSH"]},
        {"days_offset": 3, "channels": ["SMS", "APP_PUSH"]},
        ...
      ]
    }
  }
}
```

### 2. GENERAL_SETTINGS (GENERAL)

Thiết lập chung của hệ thống.

```json
{
  "config_key": "GENERAL_SETTINGS",
  "config_group": "GENERAL",
  "config_value": {
    "organization_info": {
      "name": "BeKind Property",
      "contact_email": "admin@bekind.vn",
      "hotline": "1900 123 456",
      "office_address": "123 Nguyễn Huệ, Q1, TP.HCM"
    },
    "localization": {
      "timezone": "Asia/Ho_Chi_Minh",
      "default_language": "Tiếng việt",
      "date_format": "DD/MM/YYYY"
    }
  }
}
```

### 3. INCIDENT_SETTINGS (INCIDENT)

Cấu hình xử lý sự cố.

```json
{
  "config_key": "INCIDENT_SETTINGS",
  "config_group": "INCIDENT",
  "config_value": {
    "auto_assign": false,
    "default_priority": "MEDIUM",
    "escalation_after_hours": 24,
    "notify_admin_on_create": true,
    "allowed_file_types": ["jpg", "jpeg", "png", "pdf"],
    "max_file_size_mb": 10
  }
}
```

### 4. PAYMENT_SETTINGS (PAYMENT)

Cấu hình thanh toán.

```json
{
  "config_key": "PAYMENT_SETTINGS",
  "config_group": "PAYMENT",
  "config_value": {
    "currency": "VND",
    "late_fee_percent": 2,
    "grace_period_days": 3,
    "payment_methods": ["CASH", "BANK_TRANSFER", "MOMO", "VNPAY"],
    "bank_account": {
      "bank_name": "",
      "account_number": "",
      "account_name": ""
    },
    "auto_generate_bill_day": 1,
    "bill_due_day": 15
  }
}
```

### 5. BRAND_SETTINGS (BRAND)

Thông tin thương hiệu.

```json
{
  "config_key": "BRAND_SETTINGS",
  "config_group": "BRAND",
  "config_value": {
    "company_name": "BeKind",
    "logo_url": null,
    "primary_color": "#1890ff",
    "contact_email": "",
    "contact_phone": "",
    "website": ""
  }
}
```

---

## Usage Patterns

### 1. Lấy cấu hình toàn bộ GENERAL settings

```typescript
// Frontend
const response = await fetch('/api/v1/system-configs?config_group=GENERAL&is_active=true', {
  headers: { 'Authorization': `Bearer ${token}` }
});
const { data } = await response.json();
const generalSettings = data.rows[0]?.config_value;

// Sử dụng
const timezone = generalSettings?.localization?.timezone;
const language = generalSettings?.localization?.default_language;
```

### 2. Cập nhật một phần cấu hình

```typescript
// Backend đã lưu toàn bộ config_value
// Frontend muốn cập nhật chỉ một phần

const currentConfig = await getSystemConfigById(id);
const updatedValue = {
  ...currentConfig.config_value,
  newKey: 'new_value'
};

const response = await fetch(`/api/v1/system-configs/${id}`, {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    config_value: updatedValue
  })
});
```

### 3. Lọc và hiển thị cấu hình theo nhóm

```typescript
// Frontend
const fetchConfigsByGroup = async (group: string) => {
  const response = await fetch(
    `/api/v1/system-configs?config_group=${group}&is_active=true`,
    { headers: { 'Authorization': `Bearer ${token}` } }
  );
  const { data } = await response.json();
  return data.rows;
};

// Sử dụng
const paymentConfigs = await fetchConfigsByGroup('PAYMENT');
paymentConfigs.forEach(config => {
  console.log(`${config.config_key}:`, config.config_value);
});
```

---

## Error Handling

### Common Errors

| Status | Code | Mô tả | Giải pháp |
|--------|------|-------|----------|
| 400 | Bad Request | JSON invalid hoặc missing required fields | Kiểm tra request body |
| 401 | Unauthorized | Bearer token không hợp lệ/hết hạn | Xin token mới |
| 403 | Forbidden | User không phải admin | Chỉ admin mới có quyền |
| 404 | Not Found | Config ID không tồn tại | Kiểm tra ID |
| 409 | Conflict | `config_key` đã tồn tại | Dùng config_key khác |

### Example Error Response

```json
{
  "success": false,
  "statusCode": 409,
  "message": "Conflict",
  "error": {
    "code": "CONFLICT",
    "details": "System config key already exists"
  }
}
```

---

## Best Practices

### For Frontend Developers

1. **Cache Configs Locally** - Nếu config không thay đổi thường xuyên, hãy cache nó trong localStorage hoặc state management
   ```typescript
   // Redux / Zustand
   const useSystemConfigs = create((set) => ({
     configs: {},
     fetchConfig: async (key: string) => {
       const cached = localStorage.getItem(`config_${key}`);
       if (cached) return JSON.parse(cached);
       
       const response = await fetch(`/api/v1/system-configs?config_key=${key}`);
       const { data } = await response.json();
       localStorage.setItem(`config_${key}`, JSON.stringify(data));
       return data;
     }
   }));
   ```

2. **Validate Before Display** - config_value là JSON linh hoạt, hãy validate trước khi dùng
   ```typescript
   const getConfig = (configs: SystemConfig[], key: string) => {
     const config = configs.find(c => c.config_key === key);
     if (!config || !config.is_active) return null;
     return config.config_value;
   };
   ```

3. **Handle Missing Configs** - Cấu hình có thể bị disable, hãy có fallback
   ```typescript
   const getOrganizationName = (configs) => {
     return configs?.organization_info?.name ?? 'BeKind';
   };
   ```

4. **Batch Fetch** - Lấy tất cả cấu hình một lần, không fetch từng cái
   ```typescript
   // ✅ Good
   const allConfigs = await fetch('/api/v1/system-configs?pageSize=100');
   
   // ❌ Avoid
   for (const key of keys) {
     await fetch(`/api/v1/system-configs?config_key=${key}`);
   }
   ```

---

## Related Documentation

- [Notification Templates API](notification-templates-api.md) - Template system for notifications
- [Backend Architecture](../backend/architecture.md) - System design overview
- [Testing Guide](../backend/testing.md) - How to test API endpoints

---

## Support

Nếu gặp vấn đề:
1. Kiểm tra Bearer token có hợp lệ không
2. Xác nhận user là admin (role)
3. Kiểm tra config_key có tồn tại không
4. Xem logs tại `/storage/logs/` để debug
