Implement Care RBAC role→permission→app matrix.
Deploy Ladill Care / deploy (push) Successful in 57s

Replace broad doctor/nurse specialty access with granular roles and primary
apps, permission inheritance for lab/BB managers, and cannot-rules for
discharge, lab approve, and cashier vs billing officer.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-20 00:24:09 +00:00
co-authored by Cursor
parent 55a1288d30
commit ac870bcf33
21 changed files with 913 additions and 239 deletions
+13 -3
View File
@@ -8,6 +8,7 @@ use App\Models\Branch;
use App\Models\Member;
use App\Models\Practitioner;
use App\Services\Care\AuditLogger;
use App\Services\Care\CarePermissions;
use App\Services\Identity\IdentityTeamClient;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
@@ -31,7 +32,7 @@ class MemberController extends Controller
->get();
$adminRoles = ['super_admin', 'hospital_admin'];
$clinicalRoles = ['doctor', 'nurse', 'lab_technician', 'lab_manager', 'pharmacist', 'blood_bank_manager'];
$clinicalRoles = app(CarePermissions::class)->clinicalPractitionerRoles();
$heroStats = [
'total' => $members->count(),
@@ -71,6 +72,7 @@ class MemberController extends Controller
'organization' => $organization,
'branches' => $branches,
'roles' => config('care.roles'),
'practitionerRoles' => app(CarePermissions::class)->clinicalPractitionerRoles(),
'mailboxOptions' => $mailboxOptions,
'specialties' => Practitioner::specialtyOptions(),
]);
@@ -82,11 +84,16 @@ class MemberController extends Controller
$organization = $this->organization($request);
$owner = $this->ownerRef($request);
$permissions = app(CarePermissions::class);
$needsPractitionerDesk = $permissions->usesPractitionerBranchScope(
new Member(['role' => $request->input('role')])
);
$validated = $request->validate([
'email' => ['required', 'email', 'max:255'],
'role' => ['required', 'string', 'in:'.implode(',', array_keys(config('care.roles')))],
'branch_id' => [
Rule::requiredIf(fn () => $request->input('role') === 'doctor'),
Rule::requiredIf(fn () => $needsPractitionerDesk),
'nullable',
'integer',
'exists:care_branches,id',
@@ -138,7 +145,10 @@ class MemberController extends Controller
AuditLogger::record($owner, 'member.invited', $organization->id, $owner, Member::class, $member->id);
$createPractitioner = $request->boolean('create_practitioner', $validated['role'] === 'doctor');
$createPractitioner = $request->boolean(
'create_practitioner',
app(CarePermissions::class)->usesPractitionerBranchScope(new Member(['role' => $validated['role']])),
);
if ($createPractitioner) {
$name = trim((string) ($validated['practitioner_name'] ?? '')) ?: Str::headline(Str::before($email, '@'));
$practitioner = Practitioner::query()->firstOrCreate(