PHPackages                             anlqn/appointments - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. anlqn/appointments

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

anlqn/appointments
==================

Reusable appointments module (DDD-lite) for Laravel (no .ics; Google sends invites).

v0.1.1(7mo ago)04MITPHPPHP ^8.0

Since Sep 29Pushed 7mo agoCompare

[ Source](https://github.com/lequangngocan-organization/appoinments)[ Packagist](https://packagist.org/packages/anlqn/appointments)[ RSS](/packages/anlqn-appointments/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (6)Versions (3)Used By (0)

anlqn/appointments — Laravel reusable appointments (DDD-lite, Google Calendar, no .ics)

A drop-in appointments module for Laravel 9–12 that creates/reschedules/cancels Google Calendar events and lets Google send invitations/RSVP emails (no .ics). Includes optional “brand emails”, a Google Meet toggle, and public demo routes (no auth) you can flip on/off via .env.

Features

✅ Laravel 9 / 10 / 11 / 12 compatible (PHP ≥ 8.0)

✅ Domain-driven module (DDD-lite): application/use-cases + ports/gateways

✅ Google Calendar OAuth (user consent) — Google sends invites (sendUpdates)

✅ Public demo routes (no auth) you can enable for quick testing

✅ Google Meet on/off by config

✅ Optional Laravel Mail templates (disabled by default)

✅ Works without .ics; attendees receive official Google invites

TL;DR (quick start)

1) Install
==========

[](#1-install)

composer require anlqn/appointments

2) Publish config (optional but recommended)
============================================

[](#2-publish-config-optional-but-recommended)

php artisan vendor:publish --provider="Anlqn\\Appointments\\AppointmentsServiceProvider" --tag=appointments-config

3) Migrate (creates appointments\_google\_accounts table)
=========================================================

[](#3-migrate-creates-appointments_google_accounts-table)

php artisan migrate

4) Set .env (demo, no auth)
===========================

[](#4-set-env-demo-no-auth)

echo " APP\_URL=APPT\_EXPOSE\_ROUTES=true APPT\_PUBLIC\_ROUTES=true APPT\_EXPOSE\_OAUTH\_ROUTES=true APPT\_OAUTH\_PUBLIC=true

APPT\_GOOGLE\_ENABLED=true APPT\_GOOGLE\_CLIENT\_ID=your\_client\_id.apps.googleusercontent.com APPT\_GOOGLE\_CLIENT\_SECRET=your\_client\_secret APPT\_GOOGLE\_REDIRECT\_URI=APPT\_GOOGLE\_SEND\_UPDATES=all APPT\_GOOGLE\_MEET=true # set false to disable Meet

APPT\_MAIL\_ENABLED=false QUEUE\_CONNECTION=sync APPT\_TZ=Asia/Ho\_Chi\_Minh " &gt;&gt; .env

php artisan config:clear

5) Connect Google (one time)
============================

[](#5-connect-google-one-time)

open in browser:
================

[](#open-in-browser)

============================================

[](#http1270018000authgoogleredirect)

6) Create an appointment (Google sends the invite)
==================================================

[](#6-create-an-appointment-google-sends-the-invite)

curl --location ''
\--header 'Content-Type: application/json'
\--data '{ "title": "Demo meeting", "description": "Trao đổi 30 phút", "sender\_email": "[THE\_GMAIL\_YOU\_CONNECTED@example.com](mailto:THE_GMAIL_YOU_CONNECTED@example.com)", "receiver\_email": "", "start\_at": "2025-10-02 09:00:00", "end\_at": "2025-10-02 09:30:00", "timezone": "Asia/Ho\_Chi\_Minh" }'

Installation A) From Packagist (standard) composer require anlqn/appointments

B) Local monorepo (path)

In your app’s composer.json:

{ "repositories": \[ { "type": "path", "url": "packages/anlqn/appointments" } \] }

Then:

composer require anlqn/appointments:\* --prefer-source

The service provider auto-registers via extra.laravel.providers.

Configuration

Publish the config (optional):

php artisan vendor:publish --provider="Anlqn\\Appointments\\AppointmentsServiceProvider" --tag=appointments-config

You can also rely on .env only (the package reads from env).

Key .env options

Routes
======

[](#routes)

APPT\_EXPOSE\_ROUTES=true # expose REST API (/api/appointments) APPT\_PUBLIC\_ROUTES=true # true = demo (no auth); false = secure mode (you add your guard) APPT\_ROUTES\_PREFIX=api

OAuth routes
============

[](#oauth-routes)

APPT\_EXPOSE\_OAUTH\_ROUTES=true # expose /auth/google/redirect|callback APPT\_OAUTH\_PUBLIC=true # true = public; false = behind web/auth APPT\_OAUTH\_PREFIX=auth

Google OAuth / Calendar
=======================

[](#google-oauth--calendar)

APPT\_GOOGLE\_ENABLED=true APPT\_GOOGLE\_CLIENT\_ID=... APPT\_GOOGLE\_CLIENT\_SECRET=... APPT\_GOOGLE\_REDIRECT\_URI=APPT\_GOOGLE\_SEND\_UPDATES=all # all | externalOnly | none APPT\_GOOGLE\_MEET=true # true=create Meet link, false=none APPT\_ORGANIZER\_EMAIL= # optional fixed organizer; else use sender\_email from request

Mail (package internal templates; OFF when using Google’s invites only)
=======================================================================

[](#mail-package-internal-templates-off-when-using-googles-invites-only)

APPT\_MAIL\_ENABLED=false

Timezone &amp; Queue
====================

[](#timezone--queue)

APPT\_TZ=Asia/Ho\_Chi\_Minh QUEUE\_CONNECTION=sync # switch to redis/db + run queue:work in prod

Database

The package ships a migration for appointments\_google\_accounts (stores OAuth tokens). Run:

php artisan migrate

Google Cloud (OAuth) setup

Enable: Google Calendar API

OAuth consent screen:

Testing (recommended for dev), External audience if using Gmail personal

Add Test users (your email)

Scopes (Data Access → Add scopes):

openid, ,

Create OAuth Client (Web)

Authorized redirect URI:  (or your APP\_URL)

Fill .env with client id/secret and redirect URI.

Open  and approve.

In Testing mode you must login using an email added to Test users.

Exposed Endpoints OAuth (public if APPT\_OAUTH\_PUBLIC=true)

GET /auth/google/redirect → redirects to Google

GET /auth/google/callback → saves token into appointments\_google\_accounts

Appointments API (public if APPT\_PUBLIC\_ROUTES=true)

POST /api/appointments — create (Google sends invite)

PUT /api/appointments/{id} — reschedule

DELETE /api/appointments/{id} — cancel (Google sends cancel email)

Request/validation format

start\_at, end\_at: Y-m-d H:i:s

timezone: any valid PHP/ICU tz (e.g. Asia/Ho\_Chi\_Minh)

sender\_email: organizer’s email (should match a connected Google account, unless you set APPT\_ORGANIZER\_EMAIL)

receiver\_email: attendee email

cURL examples (ready to paste)

Create

curl --location ''
\--header 'Content-Type: application/json'
\--data '{ "title": "Demo meeting", "description": "Trao đổi 30 phút", "sender\_email": "[YOUR\_CONNECTED\_GMAIL@example.com](mailto:YOUR_CONNECTED_GMAIL@example.com)", "receiver\_email": "", "start\_at": "2025-10-02 09:00:00", "end\_at": "2025-10-02 09:30:00", "timezone": "Asia/Ho\_Chi\_Minh" }'

Update (reschedule) Replace &lt;APPT\_ID&gt; with the id from the create response.

curl --location --request PUT '&lt;APPT\_ID&gt;'
\--header 'Content-Type: application/json'
\--data '{ "start\_at": "2025-10-02 10:00:00", "end\_at": "2025-10-02 10:30:00", "timezone": "Asia/Ho\_Chi\_Minh" }'

Delete (cancel)

curl --location --request DELETE '&lt;APPT\_ID&gt;'

Google Meet toggle

Enable Meet links in events:

APPT\_GOOGLE\_MEET=true

Disable Meet:

APPT\_GOOGLE\_MEET=false

Clear config after change:

php artisan config:clear

(Internally, the gateway sets/removes conferenceData and conferenceDataVersion accordingly.)

Production notes

Switch queue to redis/database and run a worker:

QUEUE\_CONNECTION=redis php artisan queue:work

Keep using sendUpdates='all' to let Google send official emails.

Optional: enable package mail (APPT\_MAIL\_ENABLED=true) if you want branded copies in addition to Google’s invites.

For secure mode, set:

APPT\_PUBLIC\_ROUTES=false

…and add your auth middleware to the app routes if you expose secure endpoints.

Troubleshooting

“Redirect URI must be absolute” Set an absolute APPT\_GOOGLE\_REDIRECT\_URI (with http:///https://), matching the OAuth client. Ensure APP\_URL is correct; run php artisan config:clear.

“Access blocked: app has not completed verification” Use Testing mode and add your email to Test users. Scopes used are sensitive (OK in Testing), not restricted.

“Google organizer not connected” No token found for organizer:

Use sender\_email that matches the connected Google account or

Set APPT\_ORGANIZER\_EMAIL to the connected email or

(Package default) falls back to the first stored account. Also make sure you opened /auth/google/redirect and a row exists in appointments\_google\_accounts.

“Call to undefined method PendingChain::dispatchAfterResponse()” Use job dispatching like:

CreateCalendarEventJob::withChain(\[ new SendInvitationEmailsJob($id), \])-&gt;dispatch($id)-&gt;afterCommit(); // (optional) -&gt;afterResponse()

“Event::setStart(): array given” Google client requires EventDateTime:

$dt = new \\Google\\Service\\Calendar\\EventDateTime(); $dt-&gt;setDateTime($iso); $dt-&gt;setTimeZone($tz); $event-&gt;setStart($dt);

Uninstall composer remove anlqn/appointments

Optionally drop the table:

php artisan tinker

> > > Schema::dropIfExists('appointments\_google\_accounts');

License

MIT

###  Health Score

27

—

LowBetter than 49% of packages

Maintenance64

Regular maintenance activity

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity31

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~3 days

Total

2

Last Release

221d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/d053a005ea341acb2d98265ba8491f1b6860ae135f5d0558c9f58b1c410a1fe2?d=identicon)[lequangngocan](/maintainers/lequangngocan)

---

Top Contributors

[![lequangngocan](https://avatars.githubusercontent.com/u/60908718?v=4)](https://github.com/lequangngocan "lequangngocan (2 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/anlqn-appointments/health.svg)

```
[![Health](https://phpackages.com/badges/anlqn-appointments/health.svg)](https://phpackages.com/packages/anlqn-appointments)
```

###  Alternatives

[barryvdh/laravel-ide-helper

Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.

14.9k123.0M687](/packages/barryvdh-laravel-ide-helper)[orchestra/canvas

Code Generators for Laravel Applications and Packages

21017.2M158](/packages/orchestra-canvas)[flarum/core

Delightfully simple forum software.

211.3M1.9k](/packages/flarum-core)[kirschbaum-development/commentions

A package to allow you to create comments, tag users and more

12369.2k](/packages/kirschbaum-development-commentions)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

255.2k](/packages/aedart-athenaeum)[glhd/special

1929.4k](/packages/glhd-special)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
