Tasks 04 and 05 shipped working engines that a clinic could only reach through
the API. Both now have the panel that makes them usable.
Groups tab
- Inline min/max per group, saved on blur, with the meaning of an empty maximum
spelled out next to the field rather than left as folklore
- Incompatible / prerequisite rows; the prerequisite-cycle 422 surfaces the
server's own message, which is more precise than anything generic
- A live preview that calls the same service-selection/validate the public site
calls, debounced 400ms. Two separate calculations would eventually show the
operator and the patient different numbers
- The breakdown table shows which item was counted as the anchor and which as
additional, so a surprising total explains itself
Segments tab
- Sequence, duration source, patient-present and mergeable per segment, plus
resource requirements with an explanation attached to each occupancy mode
- A timeline bar whose widths are proportional to duration, with segments the
patient is absent for drawn faded. That contrast is the whole point of task
05: the waiting segment holds the room but frees the operator
- "No eligible resource" renders with a link to add one — an error with no
route forward is a dead end
Task 05's checklist had been left on "not started" this whole time even though
its code shipped with the task; it is now filled in against reality.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Added BackButton component to standardize back navigation across pages.
- Integrated BackButton into various pages, replacing custom back buttons for consistency.
- Updated PageHeader to accept backTo prop for displaying BackButton when navigating from subpages.
- Created useGoBack hook to handle navigation logic, determining whether to go back in history or redirect to a fallback page.
- Added tests for BackButton and its integration with PageHeader to ensure expected behavior.
- Changed franchise_rials to franchise_percent in tenant_insurances and tenant_service_coverage tables.
- Reset old rial values to 0/NULL as they are not convertible to percentage.
feat(command): add SeedInsuranceScenarioCommand for seeding insurance data
- Implemented a command to seed supplementary insurance contracts, patients, and claims for a specified doctor.
- Includes functionality for purging existing scenario data and generating new entries with predefined contracts and patient scenarios.
Backend already returned 403 for ungranted secretary actions, but the UI still
showed the add/edit/delete buttons (e.g. clinic-services showed «بخش جدید» to a
secretary without services.create). Sweep every secretary-reachable page so each
create/edit/delete/manage control renders only when the matching
usePermissions().can(resource, action) is true. Owner/doctor/clinic are
unaffected — can() returns true when there is no permission context — so this
restricts only secretaries and mirrors the server checks.
Pages/components gated (resource):
- services: ClinicServicesPage, ServiceDetailPage (+ its tabs)
- inventory: InventoryPage, InventoryItemsTable, InventoryActionsMenu, PackagesView
- tags: TagsSettingsPage · staff: StaffPage · discounts: DiscountTab
- sms: SmsWalletPage · insurances: TenantInsuranceContracts
- clinic_doctors: ClinicDoctorsPage + ClinicDoctorsManager (props, default true)
- patients: PatientsListPage, MyPatientsPage, PatientDetailPage (records/notes/
sessions/attachments/calls/wallet — create/update/delete split)
- appointments: AppointmentsPage (add + empty-slot booking gated by create),
TurnsTable (status dropdown → read-only badge without update_status; actions
menu hidden without manage/cancel)
- appointment_settings: AppointmentSettingsPage + ClinicAppointmentSettingsPage
pass readOnly to ScheduleSection + FreeVisitPrice (new readOnly prop)
Not gated: view/read, search, filter, tabs, navigation, export, and modal
submit buttons reachable only via an already-gated trigger.
tsc clean; full frontend suite 501/501 passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Introduced `consumables` field in `ServiceItem` to allow multiple individual items alongside inventory packages.
- Created `ServiceItemConsumable` entity to manage individual consumable items linked to a service.
- Updated `ServiceItemController` to handle CRUD operations for consumables.
- Enhanced `ServiceDetailPage` and `ServiceItemFormModal` to display and manage consumables.
- Added tests to ensure functionality for adding, updating, and validating consumables.
- Updated API documentation to reflect changes in service item structure and consumables.
- Added `inventory_package_uuid` and `inventory_package_title` fields to the `ServiceItem` interface.
- Updated API documentation to reflect new fields in service item responses.
- Implemented methods in `ClinicServiceController` to handle inventory package associations.
- Created `ServiceItemAuditLog` entity and repository for tracking changes to service items.
- Added functionality to log changes to service items, including inventory package associations.
- Implemented tests for attaching/detaching inventory packages and auditing changes.
- Created database migrations for new fields and audit log table.
- Implement PriceInput component tests to validate Persian and Arabic numeral handling, input formatting, and controlled behavior.
- Create ServiceDetailPage component with detailed service information, including pricing, insurance coverage, and editing capabilities.
- Add API tests for service item detail retrieval and coverage synchronization with insurance contracts.
- Ensure proper error handling and user feedback for service item retrieval and coverage management.