novosga/scheduling-bundle
Scheduling bundle for Novo SGA that adds appointment booking, service and time-slot management, and queue-friendly workflows to PHP applications. Helps organize availability and connect scheduling with existing Novo SGA operations.
Before writing any code, verify the package actually installs into your app:
composer require novosga/scheduling-bundle:^2.3
composer why-not novosga/scheduling-bundle 2.3.0
The second command matters most. v2.3.0 moves the package to Symfony 7.4 LTS, so anything in your dependency tree still holding symfony/* at 7.1–7.3 (or a Laravel version that caps below 7.4) will block the install with a confusing conflict message.
Then read vendor/novosga/scheduling-bundle/ in this order:
Resources/config/ — the container wiring lives here. There is no Laravel service provider, no config/scheduling.php, no facade.Scheduling, Schedule, Service, Place/Unit, User. These are Doctrine-mapped, not Eloquent.First use case: create a scheduling (appointment) for a service at a unit. This is the right place to start because v2.3.0 touched both ends of that flow — command input is now UTC, and confirmation display now uses the unit's timezone. Get that round-trip correct before anything else.
Decide on the integration boundary first. This is a Symfony bundle with Doctrine entities. Three realistic options, in order of decreasing pain:
Treat UTC as the storage contract. After the v2.3.0 fix, commands expect and emit UTC datetimes. Persist everything UTC, and convert only at the display edge:
// input boundary — normalise before handing to the scheduler
$startsAt = Carbon::parse($request->input('starts_at'), $unit->timezone)
->utc();
// output boundary — confirmation display follows the unit, not the app
$confirmation = $scheduling->startsAt
->copy()
->setTimezone($unit->timezone)
->translatedFormat('D, d M Y H:i');
The asymmetry is deliberate: the app config timezone is not the reference point. The unit's timezone is. Make sure the timezone column on your unit/place record is populated — a null there is the most likely source of "the confirmation says the wrong time" reports.
Wrap creation in a transaction with an explicit conflict check. The bundle validates schedules, but concurrency is your problem. Run the create inside DB::transaction() (or the Doctrine equivalent) and re-check overlap after acquiring the row.
The new sync button (PR #8) is a UI affordance that triggers a synchronization run. Treat it as an admin action, not a request-path action:
withoutOverlapping on the job);Hook notifications off domain events, not controller code. If the bundle dispatches events on scheduling lifecycle, subscribe to them and dispatch your own Laravel jobs from the listener — that keeps the bridge thin.
Illuminate\Support\ServiceProvider, no publishable config. app(SchedulingManager::class) will not resolve it. Budget for adapters.composer why-not output before assuming a version bump is safe; the upgrade from 7.1 is LTS-aligned but will surface in any package still pinning older components.America/Sao_Paulo) and asserts both the stored value and the rendered confirmation.phpcs.xml.storage/logs/laravel.log and stderr after upgrading; deprecation notices from the bundle surfacing in your app usually mean a version mismatch in a transitive Symfony component.How can I help you explore Laravel packages today?