Project

General

Profile

Actions

Feature #4213

open
BA

[drcarrot-backend-appointment-role-scopes] orchestration run

Feature #4213: [drcarrot-backend-appointment-role-scopes] orchestration run

Added by Bot AI 6 days ago. Updated 5 days ago.

Status:
New
Priority:
Normal
Assignee:
-
Target version:
-
Start date:
10/24/2026
Due date:
% Done:

0%

Estimated time:
Source:

Description

Orchestration run tracking ticket. Not the real implementation ticket — this exists only so the live timing table has somewhere to post from step 1 onward. The real backend/mobile/web ticket(s) are created and cross-linked here once the run reaches that step.

Requirement:
"Prompt: Extract role-based WHERE conditions into dedicated Appointment scopes
File: Modules/Outpatients/app/Models/Appointment.php
Caller (must keep working): Modules/Outpatients/app/Repositories/AppointmentRepository.php:131 (->visibleTo($user))

Context
Appointment::scopeVisibleTo(Builder $query, User $user) currently resolves the viewer's roles and embeds the doctor and patient WHERE conditions inline:

Doctor ($isDoctor): appointments.doctor_id = user.id OR whereHas('appointmentReferrals', referral_doctor_id = user.id).
Patient-only ($isPatientOnly — has the patient role and no other role): appointments.user_id = user.id.
Any other role (e.g. admin): no restriction.
The two restricting roles are mutually exclusive.
Task
Move the inline doctor and patient WHERE conditions into their own dedicated query scopes, and have scopeVisibleTo compose them. Do not change behaviour or the resulting SQL.

Add scopeForDoctor(Builder $query, User $user): Builder containing the doctor WHERE block (the doctor_id = user.id OR whereHas appointmentReferrals group).
Add scopeForPatient(Builder $query, User $user): Builder containing the patient WHERE block (appointments.user_id = user.id).
Rewrite scopeVisibleTo to keep the role resolution (getRoleNames(), $isDoctor, $isPatientOnly) and the "no restriction for other roles" behaviour, but delegate the actual conditions to ->forDoctor($user) / ->forPatient($user) instead of inlining them.
The new scopes must be independently usable, e.g. Appointment::forDoctor($user)->get().
Constraints (project rules — follow exactly)
declare(strict_types=1); stays; PSR-12 / Laravel Pint clean.
Keep the exact column qualifiers (appointments.doctor_id, appointments.user_id) so joins don't become ambiguous.
Preserve the nested closure grouping on the doctor branch — the OR must stay wrapped in its own where(function…) so it can't leak into other WHEREs.
Type hints: Builder $query, User $user, return Builder.
No env(), no SELECT *, no JSON SQL functions.
Do not change AppointmentRepository; ->visibleTo($user) must behave identically.
Update the existing docblock so it reflects the delegation.
Verify before reporting done
php artisan pint --test Modules/Outpatients/app/Models/Appointment.php
Run the appointment visibility feature tests: php artisan test --filter=Appointment (report pass/fail with output).
Confirm the generated SQL for a doctor viewer, a patient-only viewer, and an admin viewer is unchanged (e.g. via ->toSql() on each scope).
Show the diff and wait for approval — do not commit."

Actions

Also available in: PDF Atom