NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages

The published config/appointments.php in full:

use RoundlyConsulting\Appointments\Models\Appointment;
use RoundlyConsulting\Appointments\Models\Participant;
use RoundlyConsulting\Appointments\Reviews\DatabaseVerifiedAttendanceResolver;

return [
    'model' => Appointment::class,
    'participant' => Participant::class,

    // bigint | uuid | ulid — the key type of the polymorphic participant column
    'key_type' => env('APPOINTMENTS_KEY_TYPE', 'bigint'),

    'table_names' => [
        'appointments' => 'appointments',
        'participants' => 'appointment_participants',
    ],

    'timezone' => null,
    'default_duration_minutes' => 60,
    'prevent_conflicts' => false,

    'recurrence' => [
        'max_occurrences' => 365,
    ],

    'reviews' => [
        'verified_attendance_resolver' => DatabaseVerifiedAttendanceResolver::class,
        'require_verified_attendance' => false,
    ],

    'approvals' => [
        'enforce_transitions' => false,
    ],
];

Every key

KeyDefaultPurpose
modelAppointment::classAppointment model. Point it at a subclass of the packaged model to customise behaviour; any other class throws InvalidConfigurationException.
participantParticipant::classParticipant model; same rules as model.
key_typebigintKey type of the polymorphic participant_id column — bigint, uuid or ulid (env APPOINTMENTS_KEY_TYPE). Set before you migrate; any other value throws InvalidConfigurationException when the migrations run.
table_names.appointmentsappointmentsTable the migrations create and the Appointment model reads and writes. Set it before you migrate. Blank = not set (appointments); any other value must be a string.
table_names.participantsappointment_participantsTable the migrations create and the Participant model reads and writes. Set it before you migrate. Blank = not set (appointment_participants); any other value must be a string.
timezonenullZone stored on a new appointment when none is given, and the zone a wall-clock string without an offset is read in; not set (null or blank) uses config('app.timezone'), anything else must be a timezone PHP knows (Europe/Bratislava). Each appointment keeps the zone it was booked in, so changing this later doesn’t re-time existing ones.
default_duration_minutes60Duration applied when neither a duration nor an end time is given; ends_at is derived from it. 1–525600.
prevent_conflictsfalseWhen true, creating, rescheduling or adding a participant throws on an overlapping booking for a participant. Can also be enabled per call.
recurrence.max_occurrences365Hard cap on the number of occurrences one recurring series may expand to, 1–100000.
reviews.verified_attendance_resolverDatabaseVerifiedAttendanceResolver::classDecides whether a review is verified (default: the author is a participant of a completed appointment). Must implement VerifiedAttendanceResolver. Not set (left out, null or blank) still binds DatabaseVerifiedAttendanceResolver; to never verify, name NullVerifiedAttendanceResolver::class explicitly.
reviews.require_verified_attendancefalseWhen true, review() throws for an unverified author instead of storing an unverified review.
approvals.enforce_transitionsfalseWhen true, the approval status-sync listener respects the transition matrix — a mapped but illegal move is skipped.

The bool keys also take env-style strings — true/1/on/yes and false/0/off/no — and the int keys take integer strings ('45'). A key that is not set (absent, null, or blank: '' or whitespace) takes its default. Anything else — a mistyped switch ('disabled'), a duration or cap that isn’t a whole number in range ('an hour', 0), a non-string table name, an unknown timezone, a resolver that isn’t a VerifiedAttendanceResolver — throws InvalidConfigurationException naming the key instead of quietly reading as a default.

Environment

Only the participant key type is env-backed. It types a database column, so set it before you publish and run the migrations:

# bigint | uuid | ulid — set before you publish and run the migrations
APPOINTMENTS_KEY_TYPE=bigint

The about command

php artisan about --only=appointments reports the effective setup:

  • Model and Participant model — the short class names of the resolved models.
  • Appointments table and Participants table — the configured table names.
  • Default timezone — SET or APP DEFAULT. Only presence is reported, never the value.
  • Default duration — e.g. 60 min — and Max occurrences, the recurrence cap.
  • Prevent conflicts, Require verified attendance and Approval transitions — ON or OFF.
  • Attendance resolver — the class name of the bound review resolver.

A malformed table name, timezone, default duration, occurrence cap or resolver shows as INVALID, so about still renders on a misconfigured host while the real read path throws.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.