feat: add ROLE_REPRESENTATION access to admin panel for managing doctors and clinics

- Updated authStore to include 'representation' role.
- Modified DoctorFormPage and DoctorsPage to handle different endpoints based on user role.
- Created new RepresentationActionController for handling doctor and clinic creation by representatives.
- Added new API endpoints for representatives to manage doctors, clinics, and view appointments.
- Updated documentation to reflect new role and API changes.
This commit is contained in:
hamed
2026-06-19 13:20:40 +03:30
parent a8d36d7455
commit fe73fa1a05
14 changed files with 778 additions and 19 deletions
+2
View File
@@ -282,6 +282,8 @@ Delete a user.
## Doctor Management
> **نماینده (ROLE_REPRESENTATION):** افزودن پزشک و کلینیک برای نماینده از طریق endpointهای جدا انجام می‌شود — `POST /api/v1/representation/doctor` و `POST /api/v1/representation/clinic` (به `docs/api/representation.md` مراجعه کنید). در نسخه‌ی نماینده، `representation_id` پزشک خودکار روی نماینده‌ی کاربر جاری ست می‌شود. endpointهای `/api/v1/admin/*` همچنان فقط `ROLE_ADMIN` هستند.
### GET `/api/v1/admin/doctors`
List all doctors with pagination.
+2 -1
View File
@@ -276,7 +276,7 @@ Authorization: Bearer <token>
| فیلد | نوع | توضیح |
|------|-----|-------|
| `primary_role` | string | نقش اصلی: `admin` \| `clinic` \| `doctor` \| `secretary` \| `user` |
| `primary_role` | string | نقش اصلی: `admin` \| `clinic` \| `doctor` \| `secretary` \| `representation` \| `user` |
| `db_uuid` | string\|null | UUID موجودیت فعال (null = هنوز context انتخاب نشده) |
| `db_key` | string\|null | `HMAC-SHA256(db_uuid, APP_SECRET)` برای اعتبارسنجی |
| `doctor_uuid` | string\|null | UUID دکتر — ثابت است حتی در context کلینیک که `db_uuid` برابر UUID کلینیک است. برای کاربران غیر دکتر: `null` |
@@ -288,6 +288,7 @@ Authorization: Bearer <token>
- `ROLE_CLINIC``"clinic"`
- `ROLE_DOCTOR``"doctor"`
- `ROLE_SECRETARY``"secretary"`
- `ROLE_REPRESENTATION``"representation"` (نماینده؛ دسترسی محدود به پنل ادمین: افزودن پزشک/کلینیک، نوبت‌های پزشکانِ زیرمجموعه، داشبورد نماینده)
- بقیه → `"user"`
**قانون `context.role`** — نقشی که در آن محیط کاری فعال است:
+132
View File
@@ -225,3 +225,135 @@ Get yearly earnings dashboard for a representation.
}
}
```
---
## پنل نماینده (ROLE_REPRESENTATION)
این endpointها برای کاربرِ دارای نقش `ROLE_REPRESENTATION` در پنل ادمین (`/admin`) هستند. مالکیت همیشه از کاربر جاری (`#[CurrentUser]` + `findByUser`) تعیین می‌شود؛ هیچ uuid/id ورودی برای تعیین مالکیت پذیرفته نمی‌شود.
> **Permission (همه‌ی این بخش):** `ROLE_REPRESENTATION`
### GET `/api/v1/representation/me`
پروفایل نماینده‌ی کاربر جاری.
#### Response `200`
```json
{
"success": true,
"data": {
"data": {
"uuid": "...",
"full_name": "حامد حسینی",
"mobile_number": "09120671756",
"city_id": 132,
"commission_percent": "10.00",
"bank_account": null,
"active": true,
"created_at": 1718000000
}
}
}
```
> double-nested: مقدار با `data.data` استخراج می‌شود.
#### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_NOT_FOUND_001` | 404 | کاربر جاری نماینده نیست |
---
### POST `/api/v1/representation/doctor`
افزودن پزشک توسط نماینده. `representation_id` پزشک به‌صورت خودکار روی نماینده‌ی کاربر جاری ست می‌شود.
#### Request Body
```json
{ "mobile": "0935...", "name": "دکتر ...", "gender": "man", "degree": "...", "medical_system_code": "...", "specialties": [1,2] }
```
| Field | Type | Required |
|-------|------|----------|
| `mobile` | string | ✅ |
| `name` | string | ✅ |
| `gender` / `degree` / `medical_system_code` / `info` | string | ❌ |
| `specialties` | integer[] | ❌ |
#### Response `201`
```json
{ "success": true, "data": { "uuid": "..." } }
```
#### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_VALIDATION_002` | 422 | موبایل یا نام خالی |
| `ERR_CONFLICT_001` | 409 | این کاربر قبلاً پزشک است |
---
### POST `/api/v1/representation/clinic`
افزودن کلینیک توسط نماینده.
#### Request Body
```json
{ "owner_mobile": "0935...", "name": "کلینیک ...", "telephone": "...", "address": "..." }
```
| Field | Type | Required |
|-------|------|----------|
| `owner_mobile` | string | ✅ |
| `name` | string | ✅ |
| `telephone` / `address` / `info` | string | ❌ |
#### Response `200`
```json
{ "success": true, "data": { "uuid": "...", "name": "...", "is_active": true } }
```
#### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_VALIDATION_002` | 422 | موبایل یا نام خالی |
---
### GET `/api/v1/representation/appointments`
نوبت‌های همه‌ی پزشکانی که `representation_id` آن‌ها = نماینده‌ی کاربر جاری است (paginated، با شکل آیتمِ یکسان با `/api/v1/admin/appointments`).
#### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | پیش‌فرض 1 |
| `limit` | integer | ❌ | پیش‌فرض 15، حداکثر 500 |
| `status` | string | ❌ | فیلتر وضعیت |
| `date` | string (YYYY-MM-DD) | ❌ | فیلتر تاریخِ نوبت |
| `search` | string | ❌ | جستجو در موبایل/نام بیمار یا نام پزشک |
#### Response `200`
```json
{
"success": true,
"data": [
{
"uuid": "...",
"patient_name": "...",
"patient_mobile": "0912...",
"doctor_uuid": "...",
"doctor_name": "دکتر ...",
"slot_start": 1718000000,
"slot_end": 1718001800,
"appointment_date": "2025-06-15",
"appointment_time": "10:00",
"end_time": "10:30",
"status": "confirmed",
"created_at": 1717900000
}
],
"meta": { "totalRecords": 12, "totalPages": 1, "currentPage": 1 }
}
```
#### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_NOT_FOUND_001` | 404 | کاربر جاری نماینده نیست |