# Practice Domain API > **Prefix:** `/api/v1/practice-domains`, `/api/v1/practice-domain` A practice domain is the field a clinic operates in — beauty, dentistry, orthopaedics. It is a configuration key, not a marketing label: treatment workflows bind to its `code`, so the code is immutable once created. It is deliberately **not** `Specialty`, which stays a descriptive label for the public booking site. The table is global (registered in `GlobalTables::ENTITIES`); a clinic points at zero or one of its rows through `clinics.practice_domain_id`, which is nullable. `NULL` means "not configured" and keeps today's behaviour — it is never an error. --- ## GET `/api/v1/practice-domains` List domains, ordered by `sort_order` then `name`. **Permission:** `IS_AUTHENTICATED_FULLY`. Callers without `ROLE_ADMIN` see only `active` rows, so a clinic manager cannot pick a domain the platform has retired. `ROLE_ADMIN` sees inactive ones too, to be able to switch them back on. ### Response `200` ```json { "success": true, "data": [ { "uuid": "8c7bfd18-9159-11f1-b98b-f28fd8aa5db5", "code": "beauty", "name": "کلینیک زیبایی", "sort_order": 0, "active": true, "has_workflow": true } ] } ``` `has_workflow` می‌گوید آیا پیاده‌سازیِ `TreatmentWorkflow` مخصوصِ این کد ثبت شده یا حوزه فقط رفتار پیش‌فرض می‌گیرد. حوزهٔ بی‌workflow کار می‌کند — دوره‌های چندجلسه‌ای‌اش باز می‌شوند — ولی رفتار اختصاصی ندارد، و پنل ادمین پلتفرم باید همین را نشان دهد نه اینکه مدیر حدس بزند. **Errors:** | Code | HTTP | توضیح | |------|------|-------| | ERR_AUTH_001 | 401 | بدون توکن | --- ## POST `/api/v1/practice-domains` Create a domain. **Permission:** `ROLE_ADMIN` (platform admin only). A clinic manager creating its own domain would produce a domain with no workflow behind it, and the misconfiguration would stay invisible until the first protocol-driven booking. ### Request Body (`application/json`) | Field | Type | Required | توضیح | |---|---|---|---| | `code` | string | ✅ | `^[a-z0-9_]{1,40}$`، یکتا در کل جدول، بعد از ساخت تغییرناپذیر | | `name` | string | ✅ | نام نمایشی فارسی | | `sort_order` | int | ❌ | پیش‌فرض `0` | ```json { "code": "dental", "name": "دندانپزشکی", "sort_order": 2 } ``` ### Response `201` ```json { "success": true, "data": { "uuid": "af5063de-753f-444a-ba95-05ec2ffe13be", "code": "dental", "name": "دندانپزشکی", "sort_order": 2, "active": true } } ``` **Errors:** | Code | HTTP | توضیح | |------|------|-------| | ERR_VALIDATION_001 | 422 | بدنهٔ نامعتبر، یا کد خارج از الگو، یا کد تکراری (field: `code`) | | ERR_VALIDATION_002 | 422 | `name` خالی است (field: `name`) | | ERR_FORBIDDEN_001 | 403 | کاربر `ROLE_ADMIN` نیست | | ERR_AUTH_001 | 401 | بدون توکن | Real 422 for a duplicate code: ```json {"success":false,"data":null,"errors":[{"code":"ERR_VALIDATION_001","message":"حوزه فعالیتی با این کد از قبل وجود دارد","field":"code"}]} ``` --- ## PATCH `/api/v1/practice-domain/{uuid}` Update a domain's display fields. **Permission:** `ROLE_ADMIN`. **`code` is ignored if sent.** Workflow implementations are resolved by code, so renaming it would silently detach a live clinic from its workflow. ### Request Body (`application/json`) | Field | Type | توضیح | |---|---|---| | `name` | string | فقط اگر ناتهی باشد اعمال می‌شود | | `sort_order` | int | | | `active` | bool | | ### Response `200` ```json { "success": true, "data": { "uuid": "af5063de-753f-444a-ba95-05ec2ffe13be", "code": "dental", "name": "دندان‌پزشکی", "sort_order": 5, "active": true } } ``` **Errors:** | Code | HTTP | توضیح | |------|------|-------| | ERR_VALIDATION_001 | 422 | بدنهٔ درخواست نامعتبر است | | ERR_VALIDATION_002 | 404 | حوزه فعالیت یافت نشد | | ERR_FORBIDDEN_001 | 403 | کاربر `ROLE_ADMIN` نیست | --- ## Assigning a domain to a clinic There is no dedicated endpoint. The existing `PATCH /api/v1/clinic/{uuid}` accepts one more key — see [clinic.md](./clinic.md). | Body | اثر | |---|---| | `"practice_domain_uuid": ""` | حوزه ست می‌شود | | `"practice_domain_uuid": ""` یا `null` | حوزه پاک می‌شود | | کلید اصلاً نباشد | حوزهٔ فعلی دست‌نخورده می‌ماند | An unknown uuid is rejected rather than ignored, because a silently dropped selection would only surface at the first protocol-driven booking: ```json {"success":false,"data":null,"errors":[{"code":"ERR_VALIDATION_002","message":"حوزه فعالیت یافت نشد","field":"practice_domain_uuid"}]} ``` `GET /api/v1/clinic/{uuid}` returns the current value under `data.data.practice_domain`, `null` when unset: ```json {"uuid":"8c7bfd18-9159-11f1-b98b-f28fd8aa5db5","code":"beauty","name":"کلینیک زیبایی","sort_order":0,"active":true} ```