Commit Graph
15 Commits
Author SHA1 Message Date
hamedandClaude Opus 4.8 e8bf2ce9b1 feat(secretary): grant staff/discounts/sms/appointment_settings/clinic_doctors (phase B)
Extends the secretary permission system to five previously owner-only modules,
so a clinic/doctor can delegate each page to a secretary. All were unreachable
by secretaries before (role-based tenant resolution returned "unknown" → 403).

New permission resources (default-deny, three-place add: entity default,
SecretaryPermissions type, both MySecretariesPage + admin SecretariesPage):
staff, discounts, sms, appointment_settings (view/update only), clinic_doctors
(clinic-only — hidden from independent doctors via `clinicOnly` section filter).

Backend enforcement (SecretaryAccessChecker, three new reusable helpers):
- resolveOwnerEntity(): owner pair from active context — used by StaffController,
  DiscountController, SmsWalletController (now secretary-aware resolveEntity).
- canForDoctor(): per-doctor-scoped check (assigned doctor + toggle) — wired into
  AppointmentSettingsController::denyDoctorAccess.
- canForClinic(): clinic-scoped check — wired into ClinicController::detachDoctor,
  ClinicDoctorPermissionController (view/update), ClinicInvitationController
  (create/view/update/delete). clinic_doctors is clinic-context only.
Guards run ahead of any subscription gate; non-secretary roles pass unchanged.

Frontend:
- RoleRoute: staff, discounts, sms-wallet, appointment-settings (doctor+clinic
  variants), settings/clinic-doctors routes accept secretary + permission gate.
- Sidebar (secretary branch): five new items gated by can(); appointment_settings
  route follows active scope; clinic_doctors only in clinic scope.

Tests: SecretaryResourceEnforcementTest — denied-by-default + allowed-when-granted
for all five (18 total). Sidebar.test — B-resource gating + clinic_doctors scope
rule. docs/api/secretary.md resource list, enforcement map, JSON example updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 17:29:51 +03:30
hamed d780b5cbb6 feat(validation): enforce naming rules for doctors and clinics to prevent placeholders 2026-07-19 08:38:11 +03:30
hamedandClaude Opus 4.8 3a23aa242e fix(clinic-invitation): provision doctor accounts and repair panel actions
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>
2026-07-18 09:14:13 +03:30
hamed a4a17bf8c7 feat: add patient appointment interface and endpoints
- Introduced `PatientAppointment` interface to define appointment structure.
- Implemented `findByUserAndDoctorIds` method in `AppointmentRepository` to retrieve appointments for a user filtered by doctor IDs.
- Added `acceptedDoctorIdsByClinic` method in `ClinicDoctorInvitationRepository` to get accepted doctor IDs for a clinic.
- Created new endpoint in `PatientController` to fetch appointments for a patient, ensuring only relevant doctors' appointments are displayed.
2026-07-13 10:15:44 +03:30
hamed 744a40c0f6 feat: add ClinicInvitationWebController and related templates for handling clinic invitations
- 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.
2026-07-11 09:33:55 +03:30
hamed 9f56f4aa08 feat(migrations): add ownership fields to doctors table for IRIMC import
- Introduced new columns: owner_status, source, source_ref, managed_by, and claimed_at to the doctors table.
- Created indexes for owner_status and source to optimize queries related to unclaimed doctors.

feat(auth): implement SystemOwnerCommand for managing system-owner user

- Added command to create, activate, and deactivate a system-owner user for IRIMC crawler.
- Ensured the user has ROLE_ADMIN to access import endpoints.
- Handled password setting and user status management within the command.
2026-07-11 08:59:36 +03:30
hamed 969dc9651f Refactor SMS sending to use KavehNegar VerifyLookup templates
- Removed SmsTextResolver dependency from multiple services and controllers.
- Introduced dispatchTemplate method in SmsService to handle SMS sending with templates.
- Updated existing SMS sending logic across various services (OtpService, PreRegistrationController, ClinicInvitationService, PaymentManager, SecretaryController, RepresentationActionController) to utilize the new dispatchTemplate method.
- Enhanced SmsMessageTemplate entity to include kavenegar_template and token_map fields.
- Created migration to add new fields to the sms_message_templates table and populate them with existing data.
- Updated SeedSmsMessageTemplatesCommand to handle new template structure.
- Added documentation for the new SMS template structure and usage.
2026-07-05 11:20:53 +03:30
hamedandClaude Opus 4.8 4b80616a17 refactor(errors): centralise legacy string error codes in ErrorCodes (M21)
~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>
2026-06-28 21:12:23 +03:30
hamed 36b87e9817 fix(db): declare onDelete on required FKs that had none
Eight required (nullable:false) FKs had no referential action. Set per the
codebase's existing pattern: CASCADE for owned relations (doctor_insurances,
doctor_secretaries), RESTRICT for owner/reference FKs (Doctor/Clinic.user_id,
invited_by_id, subscription plan/period). Only the two CASCADE FKs need DDL —
RESTRICT is the MySQL default.
2026-06-28 17:04:23 +03:30
hamed fa332f7fa1 feat: Add tagging system for SMS logs and templates
- Introduced a `tag` field in the `SmsLog` entity to categorize SMS messages.
- Updated the `SmsService` to handle the new `tag` parameter during SMS dispatch.
- Implemented a `SmsTextResolver` service to resolve SMS message templates based on tags.
- Created a new `SmsMessageTemplate` entity for editable SMS templates with placeholders.
- Added endpoints for managing SMS message templates in the admin panel.
- Enhanced existing SMS dispatching methods across various controllers to utilize the tagging system.
- Migrated the database to include the new `tag` field and created a seeding command for default SMS templates.
- Updated admin API to filter SMS logs by tag and include tag information in responses.
2026-06-19 20:42:04 +03:30
hamed ec36eefeb8 feat: add OpenAPI tags to various controllers for improved API documentation 2026-06-15 14:54:10 +03:30
hamed aa15addcb9 feat: implement doctor invitation acceptance logic to add doctors to clinic_doctors 2026-06-13 17:53:27 +03:30
hamed d50fb96542 pwa setting 2026-06-13 13:28:39 +03:30
hamed 82e1c264a1 feat: add doctor invitation modal and appointment creation API
- 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.
2026-06-11 13:36:54 +03:30
hamed af0ae51987 feat: add clinic doctor invitation feature
- 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.
2026-06-10 22:13:39 +03:30