Files
hamed b05aeaf58b Refactor doctor name handling across the application
- Removed the "دکتر" prefix from doctor names in various components and API responses to ensure consistency and clarity.
- Updated the AppointmentDetailPage, CommentsPage, DashboardPage, RatingsPage, SecretariesPage, and other relevant files to reflect the changes in doctor name formatting.
- Adjusted API documentation to align with the new naming conventions.
- Implemented validation to prevent the creation of clinics without a name and restricted users to a single clinic.
- Added tests to verify that doctor names are stored without titles and that clinic creation adheres to the new validation rules.
2026-07-19 16:09:55 +03:30

11 KiB
Raw Permalink Blame History

Rating & Comments API

Prefix: /api/v1/rate, /api/v1/comment, /api/v1/like


POST /api/v1/rate

Submit a multi-dimensional rating for a doctor. Upsert — re-submitting overwrites the user's previous rating.

Permission: AUTH

Eligibility rule: The user must have had a confirmed appointment (status = confirmed) with this doctor whose slot_start falls within the last 30 days. Otherwise the request is rejected with 403 ERR_RATING_NOT_ELIGIBLE. Use GET /api/v1/rate/{doctorUuid}/eligibility to check before showing the rating UI.

Request Body (application/json)

Five dimensions, each an integer percentage 0100:

{
  "doctor_uuid": "550e8400-...",
  "waiting_time_at_clinic": 80,
  "accuracy_of_diagnosis": 100,
  "doctor_behavior": 100,
  "clinic_cleanliness": 60,
  "doctor_expertise": 100
}
Field Type Required Validation
doctor_uuid string (UUID) Must exist
waiting_time_at_clinic integer 0100
accuracy_of_diagnosis integer 0100
doctor_behavior integer 0100
clinic_cleanliness integer 0100
doctor_expertise integer 0100

Response 201 / 200

Returns the updated aggregate for the doctor (same shape as GET /api/v1/rate/{doctorUuid}):

{
  "success": true,
  "data": {
    "data": {
      "point": 4.4,
      "satisfaction": 88,
      "averages": [
        { "name": "waiting_time_at_clinic", "label": "زمان انتظار در مطب", "progress": 80 },
        { "name": "accuracy_of_diagnosis",  "label": "تشخیص درست",        "progress": 100 },
        { "name": "doctor_behavior",        "label": "برخورد مناسب پزشک",  "progress": 100 },
        { "name": "clinic_cleanliness",     "label": "نظافت مطب",         "progress": 60 },
        { "name": "doctor_expertise",       "label": "مهارت پزشک",        "progress": 100 }
      ]
    }
  }
}

Note: response is double-nested (data.data) — success(['data' => $aggregate]).

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_RATING_NOT_ELIGIBLE 403 No confirmed appointment with this doctor in the last 30 days
ERR_NOT_FOUND_001 404 Doctor not found
ERR_VALIDATION_001 422 A dimension is out of the 0100 range

GET /api/v1/rate/{doctorUuid}

Get the aggregate (multi-dimensional) rating for a doctor: overall star point, satisfaction percent, and per-dimension averages.

Permission: PUBLIC

Path Parameters

Param Type Description
doctorUuid string (UUID) Doctor UUID

Response 200

{
  "success": true,
  "data": {
    "data": {
      "point": 4.4,
      "satisfaction": 88,
      "averages": [
        { "name": "waiting_time_at_clinic", "label": "زمان انتظار در مطب", "progress": 80 },
        { "name": "accuracy_of_diagnosis",  "label": "تشخیص درست",        "progress": 100 },
        { "name": "doctor_behavior",        "label": "برخورد مناسب پزشک",  "progress": 100 },
        { "name": "clinic_cleanliness",     "label": "نظافت مطب",         "progress": 60 },
        { "name": "doctor_expertise",       "label": "مهارت پزشک",        "progress": 100 }
      ]
    }
  }
}
  • point: overall rating on a 05 scale (satisfaction / 20).
  • satisfaction: mean of all dimensions, percent 0100.
  • averages[].progress: per-dimension mean, percent 0100.
  • If the doctor has no ratings: point=0, satisfaction=0, every progress=0.
  • Response is double-nested (data.data).

Errors

Code HTTP Description
ERR_NOT_FOUND_001 404 Doctor not found

GET /api/v1/rate/{doctorUuid}/eligibility

Whether the current authenticated user is allowed to rate/comment on this doctor — i.e. had a confirmed appointment with them in the last 30 days. Intended for the public site to conditionally show the "submit review" UI.

Permission: AUTH (IS_AUTHENTICATED_FULLY)

Path Parameters

Param Type Description
doctorUuid string (UUID) Doctor UUID

Response 200

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

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_NOT_FOUND_001 404 Doctor not found

POST /api/v1/comment

Submit a comment/review for a doctor.

Permission: AUTH

Comments require admin approval before appearing publicly.

Eligibility rule: Same as POST /api/v1/rate — the user must have had a confirmed appointment with this doctor within the last 30 days, otherwise 403 ERR_RATING_NOT_ELIGIBLE.

Request Body (application/json)

{
  "doctor_uuid": "550e8400-...",
  "comment": "پزشک بسیار مؤدب و متخصص بودند",
  "parent": null
}
Field Type Required Validation
doctor_uuid string (UUID) Must exist
comment string Non-empty
parent string (UUID) | null If set, this comment is a reply to the parent comment

Response 201

Returns the created comment in the rich shape (see GET /comments below). New comments are pending until an admin approves them, so they will not appear in the public list yet.

Comment Status Values: pending (awaiting review) · approved (public) · rejected.

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_RATING_NOT_ELIGIBLE 403 No confirmed appointment with this doctor in the last 30 days
ERR_NOT_FOUND_001 404 Doctor (or parent comment) not found
ERR_VALIDATION_002 422 Comment text empty

GET /api/v1/comments/{doctorUuid}

Get approved root comments for a doctor (replies are nested under each root via replies).

Permission: PUBLIC

صفحه‌بندی: ?page و ?limit (پیش‌فرض ۵۰، حداکثر ۱۰۰)؛ پاسخ شامل data.meta (totalRecords/totalPages/currentPage) است. آرایه‌ی نظرات همچنان در data.data است. همین صفحه‌بندی روی GET /api/v1/admin/comments/pending هم اعمال می‌شود.

Path Parameters

Param Type Description
doctorUuid string (UUID) Doctor UUID

Response 200

Response is double-nested (data.data). Each item:

{
  "success": true,
  "data": {
    "data": [
      {
        "uuid": "...",
        "comment": "پزشک بسیار مؤدب...",
        "created": 1717000000,
        "parent": null,
        "author": { "real_name": "میثم امیری", "picture": [] },
        "like_status": {
          "like_count": 6,
          "dislike_count": 1,
          "current_user_like": { "like": false, "dislike": false }
        },
        "replies": [
          {
            "uuid": "...",
            "comment": "پاسخ ...",
            "created": 1717000500,
            "parent": "<root-uuid>",
            "author": { "real_name": "امیر حبیبی", "picture": [] },
            "like_status": { "like_count": 0, "dislike_count": 0, "current_user_like": { "like": false, "dislike": false } },
            "replies": []
          }
        ]
      }
    ]
  }
}
  • comment (not body); created (not created_at); both Unix seconds.
  • author.real_name from the user (falls back to «کاربر نوبت‌۷۲۴» if unset). author.picture is always [] (no user avatar field) — frontend uses a default image.
  • current_user_like is always {false,false} on this public endpoint (no token is processed); the real per-user state comes from the POST /like response — keep the UI optimistic.
  • Only approved comments/replies are returned.

Errors

Code HTTP Description
ERR_NOT_FOUND_001 404 Doctor not found

DELETE /api/v1/comment/{uuid}

Delete a comment.

Permission: AUTH — must be the comment author or ROLE_ADMIN

Response 200

{ "success": true, "data": { "message": "نظر حذف شد" } }

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_FORBIDDEN_001 403 Not the author
ERR_NOT_FOUND_001 404 Comment not found

GET /api/v1/admin/comments/pending

Get all pending comments waiting for review.

Permission: ROLE_ADMIN

Response 200

{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "body": "...",
      "doctor": { "uuid": "...", "title": "علی احمدی" },
      "user": { "uuid": "...", "real_name": "..." },
      "status": "pending",
      "created_at": 1717000000
    }
  ]
}

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_AUTH_006 403 Not admin

POST /api/v1/admin/comment/{uuid}/approve

Approve a pending comment (makes it public).

Permission: ROLE_ADMIN

Response 200

Updated comment object with status: "approved".

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_AUTH_006 403 Not admin
ERR_NOT_FOUND_001 404 Comment not found

POST /api/v1/admin/comment/{uuid}/reject

Reject a pending comment.

Permission: ROLE_ADMIN

Response 200

Updated comment object with status: "rejected".

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_AUTH_006 403 Not admin
ERR_NOT_FOUND_001 404 Comment not found

POST /api/v1/like/{commentUuid}

Cast a like or dislike on a comment. Toggling logic:

  • Same vote sent again → vote is removed.
  • Opposite vote sent → vote is replaced (e.g. like → dislike).
  • No existing vote → vote is added.

Permission: AUTH

Path Parameters

Param Type Description
commentUuid string (UUID) Comment UUID

Request Body (application/json)

{ "value": 1 }
Field Type Required Description
value integer (default 1) 1 = like, -1 = dislike

Response 200

{
  "success": true,
  "data": {
    "like_count": 6,
    "dislike_count": 1,
    "current_user_like": { "like": true, "dislike": false }
  }
}

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_NOT_FOUND_001 404 Comment not found