Files
clinicpro/docs/api/treatment.md
T
hamedandClaude Opus 5 e2e3e6b43b feat(treatment): add treatment protocols, the multi-session course of a service
A protocol says a course of a service runs over several sessions, when each
falls due, which doctor supervises it and which staff may perform it. The row
existing IS the "طول درمان" switch, so there is no separate boolean that could
disagree with the step list.

Each step's offset is measured from the previous session rather than from the
start of the course: laser spacing is a clinical requirement — hair regrows
relative to the last treatment — so a late patient shifts the rest of their
course instead of getting the next session early. That also lets one course use
uneven gaps, which a single min/ideal/max triple cannot express: a botox course
is session 1, then +15 days, then monthly.

Steps and staff are cleared and rewritten in two flushes inside a transaction.
A single flush sends inserts before deletes and the replacement row collides
with the unique (protocol, step_number) index — caught by the replace test.

Removes docs/api/course.md and the task-12 folder. They documented src/Course/,
a module deleted in 65d5831c whose commit message only mentions removing two
test files; that design is superseded by this one.

ServiceItem::$sessionCount is marked deprecated. It never had logic behind it
and session count now comes from the protocol; the column stays in payloads so
existing clients keep working.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 16:36:04 +03:30

6.5 KiB
Raw Blame History

Treatment API

Prefix: /api/v1/service-item/{uuid}/treatment-protocol

A treatment protocol is the "طول درمان" of a service: it says a course of that service runs over several sessions, when each one falls due, which doctor supervises it, and which staff may perform it. A service without a protocol row is single-session — the row's existence is the switch, which is why there is no separate boolean.

ServiceItem.session_count is deprecated. It never had logic behind it; session count now comes from the protocol's step list. The column still appears in service payloads so existing clients do not break, but nothing should read it.

Superseded design note: an earlier src/Course/ module (CourseProtocol / TreatmentCourse) was deleted in 65d5831c and its docs removed. It modelled the gap between sessions as one min/ideal/max triple for the whole course, which cannot express a course whose intervals differ per session — a botox course is session 1, then +15 days, then monthly. This design stores an explicit offset per step instead.


The step model

Each step carries offset_days, and that offset is measured from the previous session, not from the start of the course. The spacing of a laser course is a clinical requirement — hair regrows relative to the last treatment, not relative to when the file was opened — so a patient who arrives late shifts the rest of their course rather than getting the next session too early.

Rule چرا
حداقل ۲ گام یک گام یعنی سرویس تک‌جلسه‌ای؛ سوییچ اصلاً نباید روشن باشد
حداکثر ۶۰ گام سقف عقلانی، جلوی ورودی اشتباه را می‌گیرد
step_number پیوسته از ۱ «جلسهٔ ۳ از ۸» فقط وقتی معنی دارد که گامی جا نیفتاده باشد
گام ۱offset_days = 0 لنگر دوره است و «جلسهٔ قبل» ندارد
گام‌های بعدی → offset_days > 0 فاصلهٔ صفر یعنی دو جلسه در یک روز
حداقل یک پرسنل مجاز بدون آن هر پرسنلی پای هر دستگاهی می‌نشیند

GET /api/v1/service-item/{uuid}/treatment-protocol

Permission: IS_AUTHENTICATED_FULLY, محدود به محیط جاری — سرویس محیط دیگر 404 می‌گیرد.

data: null یعنی سوییچ خاموش است، نه اینکه چیزی پیدا نشد.

Response 200

{
    "success": true,
    "data": {
        "uuid": "8de51c47-ddd1-44ea-bae1-83cf6457b182",
        "service_uuid": "cc0b11ec-1c39-45f0-bc1d-5514619bc74a",
        "active": true,
        "total_sessions": 4,
        "supervisor": null,
        "steps": [
            { "step_number": 1, "offset_days": 0 },
            { "step_number": 2, "offset_days": 15 },
            { "step_number": 3, "offset_days": 30 },
            { "step_number": 4, "offset_days": 30 }
        ],
        "staff": [
            { "uuid": "53acc523-48a7-4f4a-89b1-745e8e7a69bd", "name": "پرسنل۱" }
        ]
    }
}

Errors:

Code HTTP توضیح
ERR_NOT_FOUND_001 404 سرویس یافت نشد یا مال محیط دیگری است
ERR_AUTH_001 401 بدون توکن

PUT /api/v1/service-item/{uuid}/treatment-protocol

Replace the whole protocol. Creates it on first call, so this doubles as "turn the switch on".

Everything is validated before anything is written: an invalid step at the end of the list must not wipe the valid steps already stored. Steps and staff are then cleared and rewritten inside one transaction.

Permission: IS_AUTHENTICATED_FULLY, محدود به محیط جاری.

Request Body (application/json)

Field Type Required توضیح
steps array ۲ تا ۶۰ گام
steps[].step_number int پیوسته از ۱؛ نبودنش یعنی ترتیب آرایه
steps[].offset_days int فاصله از جلسهٔ قبلی
staff_uuids string[] حداقل یکی، همه از محیط جاری و فعال؛ تکراری‌ها حذف می‌شوند
supervisor_doctor_uuid string پزشک ناظر؛ باید عضو همین محیط باشد
{
  "staff_uuids": ["53acc523-48a7-4f4a-89b1-745e8e7a69bd"],
  "supervisor_doctor_uuid": null,
  "steps": [
    { "step_number": 1, "offset_days": 0 },
    { "step_number": 2, "offset_days": 15 },
    { "step_number": 3, "offset_days": 30 },
    { "step_number": 4, "offset_days": 30 }
  ]
}

Response 200

Same shape as GET.

Errors:

Code HTTP Field توضیح
ERR_VALIDATION_001 422 steps کمتر از ۲ یا بیشتر از ۶۰ گام
ERR_VALIDATION_002 422 steps فیلد steps نیست یا آرایه نیست
ERR_VALIDATION_002 422 offset_days offset_days یک گام نیست یا عدد نیست
ERR_VALIDATION_001 422 offset_days گام اول صفر نیست، یا گام بعدی صفر/منفی است
ERR_VALIDATION_001 422 step_number شماره‌ها پیوسته از ۱ نیستند
ERR_VALIDATION_002 422 staff_uuids فهرست خالی است یا uuid نامعتبر دارد
ERR_NOT_FOUND_001 404 staff_uuids پرسنل یافت نشد، غیرفعال است، یا مال محیط دیگری است
ERR_NOT_FOUND_001 404 پزشک ناظر عضو این محیط نیست

Real 422 responses:

{"success":false,"data":null,"errors":[{"code":"ERR_VALIDATION_001","message":"دورهٔ درمان حداقل 2 جلسه دارد؛ کمتر از آن یعنی سرویس تک‌جلسه‌ای","field":"steps"}]}
{"success":false,"data":null,"errors":[{"code":"ERR_VALIDATION_002","message":"حداقل یک پرسنل مجاز الزامی است","field":"staff_uuids"}]}
{"success":false,"data":null,"errors":[{"code":"ERR_VALIDATION_001","message":"شمارهٔ گام‌ها باید پیوسته از ۱ باشد؛ گام 2 انتظار می‌رفت","field":"step_number"}]}

DELETE /api/v1/service-item/{uuid}/treatment-protocol

Turn the switch off — the protocol, its steps and its staff list are removed and the service is single-session again. Idempotent: deleting a service that has no protocol still answers 200.

Permission: IS_AUTHENTICATED_FULLY, محدود به محیط جاری.

Response 200

{ "success": true, "data": null }