Insurance pages redirected to the dashboard: the insurance-pricing/claims
routes never listed `secretary`, so RoleRoute bounced a secretary who had
insurances.view and saw the menu item. Added secretary + permission
['insurances','view'] to both routes; also gated my-financial with
['payments','view'] for consistency.
«خرید اشتراک» was owner-only with no permission toggle, so it could not be
granted. Added a `subscription` secretary resource (view/create) end-to-end:
- entity DEFAULT_PERMISSIONS + SecretaryPermissions type + both secretary forms.
- backend: SubscriptionController::my (view) and trial (create),
PaymentController::initiateSubscription (create). resolveEntity in
SubscriptionController was already secretary-aware.
- frontend: subscription + subscription/success routes accept secretary +
permission; settings navs gate «خرید اشتراک» by ['subscription','view'].
Tests: subscription denied-by-default / allowed-when-granted. docs/api
secretary.md updated (resource list, enforcement map, JSON example).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three reported secretary-access bugs.
1) Settings menu structure. Phase B flat-listed staff/discounts/sms/tags/
appointment_settings/clinic_doctors in the secretary's main sidebar. Mirror
the doctor/clinic layout instead: only inventory + services stay in the main
«مدیریت» nav; the rest live under a single «تنظیمات» entry
(→ /admin/account-settings). Made both settings navs permission-aware for
secretaries: SETTINGS_MENU (menuForRole now takes `can`) and
PurchaseSubscriptionSidebar filter by a per-item `perm`/`alwaysOpen` instead
of role only, so a secretary sees exactly their permitted settings pages and
owner-only items (subscription, secretary-management) stay hidden.
2) Clinic secretary appointment timeline. AppointmentsPage treated a
clinic-scoped secretary as a single-doctor profile: the doctor list was
fetched/shown only for isClinic/isAdmin, so no doctor tabs, timeline, or
booking. Now a clinic-scoped secretary is multi-doctor: fetches the doctor
list, shows tabs, auto-selects the first doctor. The list comes from a new
authenticated endpoint GET /api/v1/my/clinic-doctors returning only the
secretary's ASSIGNED doctors — /clinic/doctor-list is on the public (no-JWT)
firewall and cannot scope by user, so it would have leaked unbookable doctors.
3) Patient record delete. The `patients.delete` toggle was dead: every record
delete (note/medical-record/attachment/call/message) was gated as
`patients.update`. Mapped them to `patients.delete` so the toggle is honored
and delete is controllable separately from edit.
New SecretaryAccessChecker::assignedClinicDoctorIds. Tests: doctor-list scoping,
patients.delete separation (denied/allowed). docs/api secretary.md +
appointment.md updated. Backend 286 + frontend 25 pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
Secretaries could reach neither the services module (EntityContextResolver
does not recognise a secretary as clinic owner, so they resolved to
`unknown` → 403) nor had any toggle to grant it. Add `services` as a
first-class secretary permission resource, enforced end-to-end.
Backend
- DoctorSecretary::DEFAULT_PERMISSIONS: new `services` resource (default-deny).
- SecretaryAccessChecker::resolveOwnerEntity(): reusable owner (clinic/doctor)
resolution from the secretary's active context, for controllers whose data
is fetched by [entityType, entityId] and whose generic resolver is not
secretary-aware.
- ClinicServiceController: resolveEntity() is now secretary-aware; every action
(sections, items, tariffs — 13 total) guards with `services` view/create/
update/delete via denyUnlessGranted, ahead of the subscription gate.
Frontend
- SecretaryPermissions type + MySecretariesPage + SecretariesPage: `services`
section so owners can grant it.
- Sidebar (secretary branch): services / inventory / tags menu items gated by
can(resource, 'view').
- RoleRoute: a secretary now needs the page's `permission` to open it (direct
URL entry included); clinic-services, inventory, tags-settings routes accept
secretary + permission gate.
Tests
- SecretaryResourceEnforcementTest: services denied-by-default, allowed-when-
granted, create-denied-while-view-granted.
- Sidebar.test: secretary menu gating for services/inventory/tags.
Docs: secretary.md + clinic-services.md updated with the `services` resource
and the resolveOwnerEntity note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Added SecretaryAccessChecker to manage resource access for secretaries.
- Integrated permission checks for payments, inventory, and tags in relevant controllers.
- Updated PaymentController and PaymentMethodController to enforce secretary permissions.
- Enhanced TenantTagController to check permissions for tag management actions.
- Introduced tests for secretary resource enforcement, ensuring proper access control.
- Updated DoctorSecretary entity to include inventory and tags permissions.
- Created a comprehensive audit document for secretary permissions coverage and enforcement.
- Fixed potential crashes in SecretaryDashboard when rendering without doctor data.
- 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.
Users typing on a Persian keyboard produced two distinct failures. Fields with
type="number" silently returned an empty string — the browser rejects Persian
digits, so the value was lost and saved as empty or zero. Text fields passed the
Persian characters straight through to the database, where a mobile stored as
۰۹۱۲… never matches 09… again. The secretary form hit the second case with no
validation at all.
Frontend:
- Adds digitsOnly() and the national-code schemas to lib/utils, plus lib/forms
with numericField()/latinDigitsField() wrappers for React Hook Form fields.
- Converts every type="number" input to type="text" inputMode="numeric" with
digit normalization; none remain. Fields that legitimately carry non-digits
(sheba, landline) only get the digits translated, keeping IR and separators.
- Points the patient national-code and mobile schemas at the shared normalizing
schemas, which accept Persian input instead of rejecting it.
- Drops two duplicate local digit converters in favour of the shared helper.
Backend:
- Adds NumericFieldNormalizerSubscriber, translating digits in whitelisted
numeric keys of JSON request bodies under /api/v1/ before controllers run, so
nobat724_front and clinic-pro-tauri are covered too. Translation only — no
characters are stripped, non-string values and other keys are untouched.
Three component tests asserted on role="spinbutton" and numeric input values;
both are properties of type="number", so they were updated to match the new
text inputs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Added functionality to assign a single secretary to multiple doctors within a clinic, allowing for scoped access to appointments.
- Introduced `SecretaryService` to handle the logic for assigning and syncing doctors for a secretary.
- Updated `SecretaryController` to support multi-doctor assignment via new endpoints and modified existing ones.
- Enhanced `DoctorSecretary` entity to include secretary UUID in its serialized output.
- Implemented repository methods to facilitate the retrieval and management of doctor-secretary relationships.
- Adjusted appointment filtering in `MyAppointmentsController` to ensure secretaries only see appointments for assigned doctors.
- Created tests to validate the new multi-doctor assignment functionality and appointment access restrictions.
- Updated frontend components to support multi-select for doctors in the secretary management UI.
- Created new AST JSON file for the doctor service API documentation, detailing endpoints, parameters, and responses.
- Added AST JSON file for the TagController, including methods and their relationships with imported classes.
- Introduced AST JSON file for the SmsLog entity, outlining its methods and dependencies.
- Added seed_realistic_data.php to clean existing data and populate the database with realistic entries for doctors, clinics, and secretaries.
- Created a structured approach to generate 100 doctors per city with diverse specialties and services.
- Implemented database cleanup routines to ensure a fresh start for data seeding.
- Enhanced the DoctorSecretaryRepository with improved comments for clarity.
- Added `owner_type` and `clinic_id` fields to `DoctorSecretary` entity to distinguish between clinic and personal practice relationships.
- Updated repository methods to be scope-aware, allowing for specific queries based on the context of the secretary's relationship (clinic or doctor).
- Modified `SecretaryController` to handle secretary creation with appropriate scope based on the current user's role.
- Enhanced `AuthController` to build contexts that reflect the scope of the secretary's access.
- Updated `DashboardController` and `PatientController` to respect the new scope logic when retrieving data.
- Created migration to update the database schema accordingly, dropping the old unique constraint and adding the new fields and constraints.
- Fix national code handling in staff creation and updates to support Persian digits.
- Update ClinicStaff entity to allow longer national codes (up to 15 characters).
- Implement support for clinic secretaries in SecretaryController, allowing creation without a doctor UUID.
- Add a new endpoint to retrieve doctors associated with a clinic for secretary management.
- Improve appointment management by ensuring doctors are selectable even when no appointments exist.
- Extend PatientController to allow secretaries to create patient records if they have the appropriate permissions.
- Introduce a PriceInput component for better price formatting in forms, supporting Persian digits.
- Add a MockGateway for testing payment processes without real transactions.
- Enhance SMS settings management with an approval flow for post-visit text messages, including new fields for pending text and status.
- Update migrations to reflect changes in database schema for national codes and SMS settings.
- Added StaffController for managing clinic staff, including listing, creating, updating, and toggling staff status.
- Created ClinicStaff entity and repository for staff data handling.
- Developed SubscriptionController to manage subscription plans and periods, including trial subscriptions.
- Introduced SubscriptionPlan, SubscriptionPeriod, and ClinicSubscription entities for subscription management.
- Implemented SubscriptionService for handling subscription logic, including trial activation and subscription creation from payments.
- Added necessary repositories for subscription entities to facilitate data access and manipulation.