GET/PATCH /api/v1/user-profile/{uuid} treated {uuid} as the profile's own
uuid, but clients pass the user's uuid — and a freshly OTP-registered user
has no profile row, so the call always 404'd. Add resolveProfile(): try
profile uuid, then user uuid → that user's profile, and (for the current
user or an admin) lazy-create an empty profile so the client always gets
an editable one. Foreign/unknown uuids still 404 with no leak.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add config/packages/dev/rate_limiter.yaml raising send_code and login
limits to 1000 in the dev environment only, so repeated OTP testing
isn't blocked by 'درخواستهای زیاد'. Production limits in
config/packages/rate_limiter.yaml (5/hour, 10/min) are untouched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
appointment.md: for_self + patient_* request fields, expires_at and
patient_* response fields, the 15-minute lock/expiry behavior, and the
atomic-conflict 409. payment.md: successful appointment payment confirms
the booking and SMSes the patient.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The payment callback handled subscription and sms-wallet types but left
appointment payments pending. Add a TYPE_APPOINTMENT branch that
transitions the booking pending → confirmed (guarded by canTransitionTo,
so an already-expired booking is skipped) and dispatches a confirmation
SMS to the patient's mobile.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add findPaymentExpired (pending with expires_at < now) and have the
cancel-expired command flip both payment-expired and slot-time-passed
pendings to expired (deduped). Run it on a schedule (e.g. every minute:
* * * * * php bin/console app:cancel-expired-appointments) to free locks
held by unpaid bookings.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
book() now accepts for_self plus patient_* fields: for_self fills the
patient from the paying user's profile, otherwise patient_name/mobile are
required (422 if missing) and the rest are stored. Every booking starts
pending with a 15-minute expires_at. Persisting goes through
bookAtomically (re-check inside a transaction) so two concurrent requests
for the same slot can't both win — the loser gets 409.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A slot is taken only if confirmed, or pending with a still-valid lock
(expires_at null or in the future). An expired pending booking no longer
blocks the slot even before the cron flips it to expired.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a 15-minute payment TTL (expires_at) plus patient_name/mobile/
national_code/gender/reason columns so a booking can hold a slot
temporarily and record a patient distinct from the paying user. New
markPendingWithTtl() sets the lock; transitioning out of pending clears
expires_at. All columns nullable (migration added).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
is_available only checked whether a slot was booked, so on today's date
slots whose start time had already passed (e.g. 10:00 when it is 12:00)
still showed as bookable until the POST /appointment 422. Treat a slot
with start < now as unavailable in getAllSlotsWithAvailability, and drop
past slots in filterBookedSlots so getAvailableSlots agrees. Future days
are unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- appointment-settings.md: weekly-schedule meta (online_booking_enabled,
booking_window value/unit), defaults, and the slot-gating behavior.
- appointment.md: new public month-availability endpoint (Gregorian
year/month, disabled/enabled dates) and the empty-slots conditions for
appointment-slots.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a نوبتدهی آنلاین card to the weekly-schedule tab: a toggle for
online_booking_enabled and a value+unit (هفته/ماه) booking window.
Hydrated from the schedule meta and sent in the weekly-schedule
POST/PATCH payload. Uses existing .input/.btn classes, RTL.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add GET /api/v1/appointment-settings/month-availability/{doctorUuid}
?year=&month= (Gregorian) returning disabled_dates / enabled_dates for
the month plus the doctor's online_booking flag and window. Lives in
AppointmentController (per-method guards) so it is genuinely public —
the class-level IsGranted on AppointmentSettingsController would have
forced auth. Whitelisted in security.yaml (firewall + access_control).
Uses SlotCalculator::hasAnyAvailability per day, so holidays, closed
overrides, non-working days and out-of-window dates all come back
disabled.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
buildAllSessions now rejects dates that are in the past, beyond the
doctor's booking window (today + value week|month), or when online
booking is disabled — gating overrides and weekly schedule alike. Add a
public hasAnyAvailability() for the month-availability endpoint. Window
config is read from the schedule meta, falling back to defaults.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a reserved meta key inside WeeklySchedule.setting (no migration) holding
online_booking_enabled and a booking_window value+unit (week|month), with
sane defaults. Expose meta separately in toArray() and keep it out of the
day schedule map. setSetting now preserves meta when the day schedule is
replaced; the weekly-schedule POST/PATCH endpoints accept an optional meta.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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.
- Active subscription card: colored gradient bg, icon, progress bar, expiry warning badge
- Trial banner: shown when no subscription and trial not used yet
- Plan cards: icon header, feature checklist (✓/✗), per-period buy buttons inline
- Free plan card shows "شما اکنون در این پنل هستید" when current
- Payment modal: order summary card + gateway selector with styled radio buttons
- Loading skeleton for plan cards
- Footer with trust signals
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MySecretariesPage: doctor/clinic can manage their own secretaries
with add/permissions-matrix/deactivate; uses GET /api/v1/secretaries/{doctorUuid}
- AdminSubscriptionPage: admin can create/edit plans and periods,
view subscription sales report; tabs: پنلها / گزارش فروش
- Sidebar: add منشیان link for doctor+clinic roles, add اشتراکها link for admin
- App.tsx: add /my-secretaries and /admin-subscription routes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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.