Files
clinicpro/docs/api/admin.md
T
hamed 8ad983310c feat: add clinic management and financial reporting features
- Implemented ClinicFormPage for adding new clinics with validation.
- Created MyFinancialPage to display financial summaries and charts.
- Developed MyPatientsPage for managing patient data with search and pagination.
- Added PreRegistrationsPage for handling pre-registration requests with approval and rejection functionalities.
- Introduced database migration for pre_registrations table.
- Built PreRegistrationController for managing pre-registration logic, including submission, approval, and rejection.
- Created PreRegistration entity and repository for handling pre-registration data.
2026-06-12 12:31:27 +03:30

874 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Admin API
> **Prefix:** `/api/v1/admin`
> **Permission:** ALL endpoints in this file require `ROLE_ADMIN`
> **Headers:** `Authorization: Bearer <admin_jwt_token>`
---
## Dashboard
### GET `/api/v1/admin/dashboard/stats`
Get key performance indicators (KPIs) for the dashboard.
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{
"success": true,
"data": {
"total_users": 1200,
"active_doctors": 85,
"total_doctors": 92,
"total_clinics": 34,
"today_appointments": 47,
"total_appointments": 8540,
"today_payments_count": 30,
"today_payments_amount": 15000000,
"total_payments_amount": 425000000,
"pending_comments": 12,
"pending_settlements": 5,
"this_month_revenue": 52000000,
"this_month_appointments": 620
}
}
```
---
### GET `/api/v1/admin/dashboard/charts`
Get chart data for the last 30 days.
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{
"success": true,
"data": {
"appointments_30d": [
{ "date": "2024-06-01", "count": 42 }
],
"revenue_30d": [
{ "date": "2024-06-01", "amount_rials": 21000000 }
],
"appointment_status": {
"confirmed": 350,
"completed": 180,
"cancelled": 45,
"pending": 20,
"no_show": 25
},
"top_specialties": [
{ "name": "قلب و عروق", "count": 120 }
]
}
}
```
---
### GET `/api/v1/admin/dashboard/recent`
Get recent activity (last 10 of each type).
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{
"success": true,
"data": {
"appointments": [
{
"uuid": "...",
"doctor_title": "دکتر علی احمدی",
"patient_name": "محمد رضایی",
"slot_start": 1718438400,
"status": "confirmed"
}
],
"payments": [
{
"uuid": "...",
"amount_rials": 500000,
"gateway": "mellat",
"status": "paid",
"created_at": 1717000000
}
],
"users": [
{
"uuid": "...",
"real_name": "محمد رضایی",
"mobile_number": "09...",
"roles": ["ROLE_USER"],
"created_at": 1717000000
}
]
}
}
```
---
## User Management
### GET `/api/v1/admin/users`
List all users with pagination and filters.
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search by name or mobile |
| `role` | string | ❌ | Filter: `ROLE_USER`, `ROLE_DOCTOR`, `ROLE_ADMIN`, etc. |
| `status` | string | ❌ | `"active"` or `"inactive"` |
| `sort` | string | ❌ | `"created_at"` (default desc) |
### Response `200`
```json
{
"success": true,
"data": [
{
"uuid": "...",
"real_name": "علی احمدی",
"mobile_number": "09123456789",
"roles": ["ROLE_USER"],
"status": "active",
"created_at": 1717000000
}
],
"meta": { "totalRecords": 1200, "totalPages": 60, "currentPage": 1 }
}
```
---
### GET `/api/v1/admin/users/{uuid}`
Get detailed user info.
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{
"success": true,
"data": {
"uuid": "...",
"real_name": "علی احمدی",
"mobile_number": "09123456789",
"roles": ["ROLE_USER"],
"status": "active",
"wallet_balance_rials": 500000,
"appointments_count": 5,
"created_at": 1717000000
}
}
```
### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_NOT_FOUND_001` | 404 | User not found |
---
### GET `/api/v1/admin/users/stats`
Get user statistics.
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{
"success": true,
"data": {
"total": 1200,
"active": 1150,
"inactive": 50,
"admins": 3,
"doctors": 92,
"patients": 1100
}
}
```
---
### PUT `/api/v1/admin/users/{uuid}`
Update user info (name, email, password).
**Permission:** `ROLE_ADMIN`
### Request Body (`application/json`)
```json
{
"real_name": "علی احمدی جدید",
"password": "newPassword123"
}
```
### Response `200`
Updated user object.
---
### PUT `/api/v1/admin/users/{uuid}/role`
Change a user's role.
**Permission:** `ROLE_ADMIN`
### Request Body (`application/json`)
```json
{
"role": "ROLE_DOCTOR"
}
```
| Field | Type | Required | Allowed Values |
|-------|------|----------|----------------|
| `role` | string | ✅ | `ROLE_USER`, `ROLE_DOCTOR`, `ROLE_CLINIC`, `ROLE_SECRETARY`, `ROLE_ADMIN` |
### Response `200`
```json
{ "success": true, "data": { "message": "نقش کاربر تغییر کرد", "roles": ["ROLE_DOCTOR"] } }
```
---
### POST `/api/v1/admin/users/{uuid}/status`
Toggle user active/inactive status.
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{ "success": true, "data": { "status": "inactive" } }
```
---
### DELETE `/api/v1/admin/users/{uuid}`
Delete a user.
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{ "success": true, "data": { "message": "کاربر حذف شد" } }
```
### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_NOT_FOUND_001` | 404 | User not found |
---
## Doctor Management
### GET `/api/v1/admin/doctors`
List all doctors with pagination.
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search in title |
| `status` | string | ❌ | `"active"` or `"inactive"` |
| `gender` | string | ❌ | `"male"` or `"female"` |
| `specialty_id` | integer | ❌ | Filter by specialty |
| `sort` | string | ❌ | Sort field |
### Response `200`
```json
{
"success": true,
"data": [
{
"uuid": "...",
"title": "دکتر علی احمدی",
"degree": "متخصص",
"gender": "male",
"doctor_rate": 4.5,
"active_doctor_appointment": true
}
],
"meta": { "totalRecords": 92, "totalPages": 5, "currentPage": 1 }
}
```
---
### GET `/api/v1/admin/doctors/stats`
Get doctor statistics.
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{
"success": true,
"data": {
"total": 92,
"active": 85,
"inactive": 7,
"male": 60,
"female": 32,
"top_specialty": "قلب و عروق"
}
}
```
---
### POST `/api/v1/admin/doctors/{uuid}/status`
Toggle doctor active status.
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{ "success": true, "data": { "active": false } }
```
---
## Clinic Management
### GET `/api/v1/admin/clinics`
List all clinics with pagination.
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search by clinic name |
| `status` | string | ❌ | `"active"` or `"inactive"` |
### Response `200`
```json
{
"success": true,
"data": [
{
"uuid": "...",
"name": "کلینیک الوند",
"city": "تهران",
"telephone": "02112345678",
"is_active": true,
"created_at": 1717000000
}
],
"meta": { "totalRecords": 34, "totalPages": 2, "currentPage": 1 }
}
```
---
### PATCH `/api/v1/admin/clinic/{uuid}/status`
Toggle clinic active/inactive.
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{ "success": true, "data": { "is_active": false } }
```
### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_NOT_FOUND_001` | 404 | Clinic not found |
---
### DELETE `/api/v1/admin/clinic/{uuid}`
Delete a clinic.
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{ "success": true, "data": { "message": "کلینیک حذف شد" } }
```
---
## Appointment Management
### GET `/api/v1/admin/appointments/today-stats`
Get appointment statistics for a specific date (defaults to today).
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `date` | string (YYYY-MM-DD) | ❌ | Default: today |
### Response `200`
```json
{
"success": true,
"data": {
"total": 47,
"completed": 20,
"waiting": 18,
"cancelled": 9
}
}
```
---
### GET `/api/v1/admin/appointments`
List appointments filtered by date and/or doctor. Sorted by `slot_start ASC`.
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 15, max: 500 |
| `search` | string | ❌ | Search by patient name/mobile or doctor name |
| `status` | string | ❌ | Filter by status |
| `date` | string (YYYY-MM-DD) | ❌ | Filter by slot date |
| `doctor_uuid` | string | ❌ | Filter by doctor UUID |
### Response `200`
```json
{
"success": true,
"data": [
{
"uuid": "appt-uuid",
"patient_name": "محمد رضایی",
"patient_mobile": "09123456789",
"doctor_uuid": "doctor-uuid",
"doctor_name": "دکتر علی احمدی",
"slot_start": 1718438400,
"slot_end": 1718439600,
"appointment_date": "2025-06-15",
"appointment_time": "09:00",
"end_time": "09:20",
"status": "confirmed",
"version": 1,
"created_at": "2025-06-14T10:30:00+03:30"
}
],
"meta": { "totalRecords": 47, "totalPages": 1, "currentPage": 1 }
}
```
**Status values:** `pending` | `confirmed` | `completed` | `cancelled_by_doctor` | `cancelled_by_user` | `no_show` | `expired`
---
### POST `/api/v1/admin/appointment`
Create a new appointment for a patient. If no user exists with the given mobile, a new user account is created automatically.
**Permission:** `ROLE_ADMIN`
### Request Body
```json
{
"doctor_uuid": "doctor-uuid",
"slot_start": 1718438400,
"slot_end": 1718439600,
"patient_mobile": "09123456789",
"patient_name": "علی محمدی",
"note": "optional note"
}
```
> `patient_mobile` و `patient_name` هر دو اجباری هستند. اگر کاربری با این شماره موبایل نداشته باشیم، یک کاربر جدید با نقش `ROLE_USER` ساخته می‌شود.
### Response `201`
```json
{
"success": true,
"data": {
"uuid": "appt-uuid",
"slot_start": 1718438400,
"slot_end": 1718439600,
"status": "pending"
}
}
```
### Error Responses
| Code | HTTP | Description |
|------|------|-------------|
| `VALIDATION` | 422 | Missing required fields (doctor_uuid, slot_start, slot_end, patient_mobile, patient_name) |
| `DOCTOR_NOT_FOUND` | 404 | Doctor UUID not found |
| `SLOT_TAKEN` | 409 | Slot already booked |
---
## Payment Management
### GET `/api/v1/admin/payments`
List all payments.
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `status` | string | ❌ | `"pending"`, `"paid"`, `"failed"`, `"cancelled"` |
### Response `200`
```json
{
"success": true,
"data": [
{
"uuid": "...",
"order_id": "CLINICPRO-...",
"amount_rials": 500000,
"status": "paid",
"gateway": "mellat",
"created_at": 1717000000
}
],
"meta": { "totalRecords": 7800, "totalPages": 390, "currentPage": 1 }
}
```
---
## Settlement Management
### GET `/api/v1/admin/settlements`
List all settlement requests.
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `status` | string | ❌ | `"pending"`, `"approved"`, `"rejected"` |
### Response `200`
```json
{
"success": true,
"data": [
{
"uuid": "...",
"user": { "uuid": "...", "real_name": "دکتر علی احمدی" },
"amount_rials": 1000000,
"status": "pending",
"bank_account": { "bank_name": "بانک ملت", "owner_name": "..." },
"created_at": 1717000000
}
],
"meta": { "totalRecords": 45, "totalPages": 3, "currentPage": 1 }
}
```
> To approve or reject, use the Settlement API: `POST /api/v1/settlement/{uuid}/approve` or `/reject`
---
## Representation Management
### GET `/api/v1/admin/representations`
List all representations.
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search by name |
| `city_id` | integer | ❌ | Filter by city |
### Response `200`
Paginated representation list.
---
## Secretary Management
### GET `/api/v1/admin/secretaries`
List all secretaries.
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search by mobile |
### Response `200`
Paginated secretary list with linked doctor info.
---
## Rating & Comment Management
### GET `/api/v1/admin/rates`
List all ratings.
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search by doctor/patient |
---
### GET `/api/v1/admin/comments`
List all comments (all statuses).
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search in body |
| `status` | string | ❌ | `"pending"`, `"approved"`, `"rejected"` |
> To approve/reject comments, use the Rating API: `POST /api/v1/admin/comment/{uuid}/approve` or `/reject`
---
## SMS Management (Admin)
### GET `/api/v1/admin/sms/logs`
List SMS send logs.
**Permission:** `ROLE_ADMIN`
### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
### Response `200`
```json
{
"success": true,
"data": [
{
"id": 1,
"mobile": "09123456789",
"message": "کد تأیید: 123456",
"provider": "kavenegar",
"success": true,
"created_at": 1717000000
}
],
"meta": { "totalRecords": 5000, "totalPages": 250, "currentPage": 1 }
}
```
---
### GET `/api/v1/admin/sms/templates`
List all SMS templates.
**Permission:** `ROLE_ADMIN`
### Response `200`
```json
{
"success": true,
"data": [
{
"uuid": "...",
"name": "تأیید نوبت",
"status": "approved",
"provider_code": "verify_appointment",
"created_at": 1717000000
}
]
}
```
> To create/approve/reject templates, see [sms.md](sms.md)
---
## Clinic Invitation Management
> See [clinic-invitation.md](clinic-invitation.md) for full endpoint details.
| Endpoint | Description |
|----------|-------------|
| `POST /api/v1/admin/clinic/{uuid}/invite-doctor` | Send invitation |
| `GET /api/v1/admin/clinic/{uuid}/invitations` | List invitations |
| `POST /api/v1/admin/clinic/invitation/{invUuid}/resend` | Resend SMS |
| `PATCH /api/v1/admin/clinic/invitation/{invUuid}/status` | Change status |
| `DELETE /api/v1/admin/clinic/invitation/{invUuid}` | Delete |
---
## Settings
### GET /api/v1/admin/settings
Returns all site configuration values.
**Response `200`**
```json
{
"success": true,
"data": {
"commission_enabled": "0",
"commission_percent": "0",
"site_name": "ClinicPro",
"support_phone": "",
"max_cancel_hours_before": "24",
"appointment_reminder_hours": "2"
}
}
```
All values are strings. Missing keys return their default values.
### PATCH /api/v1/admin/settings
Update one or more settings. Unknown keys are silently ignored.
**Request body** (partial update — send only keys to change):
```json
{
"commission_enabled": "1",
"commission_percent": "5",
"site_name": "کلینیک‌پرو"
}
```
**Response `200`** — same shape as GET, returns all settings after save.
**Commission rules:**
- `commission_enabled``"1"` = active, `"0"` = inactive
- `commission_percent` — integer string, `0``100`
- Commission applies only to regular users (`booked_by = user`); secretaries are exempt
---
## Pre-Registration Management
### GET `/api/v1/admin/pre-registrations`
List pre-registration requests. **Permission:** `ROLE_ADMIN`
**Query params:**
| Param | Default | Notes |
|-------|---------|-------|
| `page` | 1 | |
| `limit` | 20 | max 50 |
| `status` | `pending` | `pending` \| `approved` \| `rejected` \| `all` |
**Response `200`** (paginated):
```json
{
"success": true,
"data": [
{
"uuid": "...",
"type": "independent_doctor",
"name": "دکتر احمدی",
"mobile": "09121234567",
"info": "متخصص داخلی",
"status": "pending",
"admin_note": null,
"created_at": 1718000000
}
],
"meta": { "totalRecords": 5, "totalPages": 1, "currentPage": 1 }
}
```
---
### POST `/api/v1/admin/pre-registrations/{uuid}/approve`
Approve a pending request. Creates User + Doctor/Clinic entity based on `type`, resets password, sends SMS. **Permission:** `ROLE_ADMIN`
**Response `200`:**
```json
{ "success": true, "data": { "message": "تأیید شد و اطلاعات ورود ارسال گردید" } }
```
**Error Codes:**
| Code | HTTP | Meaning |
|------|------|---------|
| `NOT_FOUND` | 404 | UUID not found |
| `ALREADY_PROCESSED` | 409 | Status is not pending |
---
### POST `/api/v1/admin/pre-registrations/{uuid}/reject`
Reject a pending request. **Permission:** `ROLE_ADMIN`
**Request body** (optional):
```json
{ "note": "مدارک ناقص است" }
```
**Response `200`:**
```json
{ "success": true, "data": { "message": "درخواست رد شد" } }
```