The invitation flow never created an account for the invitee. accept() only
looked up an existing doctor by mobile, so for a brand-new invitee it marked
the invitation accepted and burned the token while leaving doctor_id NULL —
no login, no clinic link, and every doctor-facing endpoint 404ing afterwards.
- invite/accept now provision the users + doctors pair, claim the profile on
accept, link it to the clinic, and SMS generated credentials when the user
has no password. Existing passwords are never overwritten.
- accept runs in one transaction so an invitation can no longer be marked
accepted without its doctor profile and clinic link.
- changeStatus accepts `pending`, refreshing the token and re-sending the SMS
so reactivating a suspended invitation yields a link that actually works.
Answered invitations are rejected with 409.
- DELETE returns 200 with the standard envelope instead of a bodyless 204,
which made the admin panel show a false error toast; api.ts also stops
calling res.json() on empty responses.
- The clinic-doctors settings page sent the active context uuid as the clinic
uuid, so users holding both a doctor and a clinic context got 404 on every
invitation action. It now always resolves the clinic context.
- Adds app:invitations:repair to fix invitations already left orphaned.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Implemented ClinicInvitationWebController to manage the invitation process via web.
- Added view and respond methods to handle invitation display and responses.
- Created result.html.twig and view.html.twig templates for rendering invitation results and views.
- Integrated CSRF protection for form submissions.
- Established routes for invitation viewing and responding.
~27 ad-hoc error codes (SLOT_TAKEN, USER_NOT_FOUND, VALIDATION, …) were raw
strings, so ErrorCodes::message() returned the "unknown" fallback for them.
Register all 14 distinct codes as constants with their messages and replace the
raw usages across AdminApiController, MyAppointmentsController, CategoryController,
PreRegistrationController and ClinicInvitationController.
Wire values are kept identical (verified no consumer — admin SPA, nobat724_front,
tauri — switches on these strings), so this is backward compatible.
Regression: tests/Shared/ErrorCodesTest (wire values preserved + message resolves).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Implemented InviteDoctorModal component for inviting doctors to clinics.
- Updated ClinicDashboard to include a button for inviting doctors and handle modal state.
- Added createAppointment API endpoint in AdminApiController for scheduling appointments.
- Enhanced ClinicInvitationController to check user access when inviting doctors.
- Updated MyAppointmentsController to ensure unique appointment records.
- Added seed_test_data.php for populating test data including doctors, clinics, and appointments.
- Refactored styles to include new appointment status badges and updated font imports.
- Implemented ClinicInvitationController to handle doctor invitations.
- Created ClinicDoctorInvitation entity and repository for managing invitations.
- Added ClinicInvitationService for business logic related to invitations.
- Introduced endpoints for inviting, listing, resending, changing status, and deleting invitations.
- Updated security configuration to allow public access to invitation endpoints.
- Added migration for clinic_doctor_invitations table.
- Enhanced DoctorRepository with a method to find doctors by mobile number.
- Updated ClinicDetailPage to include invitation management UI.