saade/filament-fullcalendar
Filament FullCalendar is a highly customizable calendar widget for Filament, powered by FullCalendar. It supports viewing, creating, editing, and deleting events through Filament Actions, with a native Filament theme.
Architecture fit. The prior assessment's core premise — "thin presentation adapter, not a scheduling engine" — no longer holds for the v5 line, and that is the single most important change in this release. v4 was a render adapter: you supplied DTOs, you persisted mutations. v5 pulls three responsibilities into the package:
The Filament-native redesign (toolbar composition, Filament buttons/badges/colors, heading/description/header actions, filters and tabs as first-class features with remembered state, Filament actions for create/view/edit/delete with automatic refresh) is genuinely good architecture for the admin-panel use case — it removes duplication between resources and the calendar, and it reuses policies and schemas rather than inventing parallel machinery. But it also means the integration surface is now considerably larger and the package sits closer to your domain layer than before.
Two architectural consequences deserve explicit sign-off:
Still absent or unstated after this release: any recurrence engine, and any explicit timezone resolution contract. Do not assume v5 solves either. The verdict shape is unchanged — good fit for internal operations calendars inside a Filament panel; poor fit for API-first, headless, or Inertia/Vue surfaces — but the "thin adapter" mitigation that previously made fork-and-vendor cheap is now materially more expensive.
Integration feasibility. v5 is no longer a composer-only upgrade, and the release notes are unusually candid about it. The migration path is a Rector-based codemod (vendor/bin/filament-fullcalendar-v5) that rewrites v4 widgets and their tests without booting the application, handling handler signatures, record APIs, deprecated actions, getFormSchema(), test call sites, and an optional preservation of v4 create-button behaviour. It supports --dry-run and prints a residual manual checklist.
That is a real accelerator and a genuine maturity signal — an upgrade assistant is what you build when you expect a large installed base to move. It is also a governance item: a tool that mechanically edits your source tree is a change you review, not a change you trust. Budget for reading the diff.
Feasibility by scope:
The maintainer states GA is expected roughly a week after beta1 and that no further breaking changes are planned. If that timeline holds, waiting for GA costs almost nothing and removes beta risk from the critical path — which matters because the beta3 regression (click/drag/resize on calendars without resource views) demonstrated that the interaction path is exactly where breakage lands.
Technical risk. The dominant risk is still dual upstream coupling (package major and FullCalendar major now version independently; v5 targets FullCalendar 7), and this release adds several new risk classes on top:
schedulerLicenseKey() handling for FullCalendar 7 before anyone builds a resource calendar in a sprint.composer update plus php artisan filament:assets remains mandatory; any pipeline caching panel assets will silently serve stale JS otherwise.Key questions for the maintainer / due diligence:
schedulerLicenseKey() handling for FullCalendar 7, and does the resources API require a licensed view?Verdict (revised): the earlier "adopt v4.x stable, don't run v5 beta in production" holds, but the reasoning behind it has changed from "the beta is immature" to "the beta is immature and the surface it adds is much larger than a theming change." Hold production on v4.x stable, start the v5 spike now using the codemod in --dry-run against a branch, and plan the upgrade for shortly after GA rather than during the beta. The multi-model event contract and the external-feed components are the two areas needing an explicit architectural decision and a named owner before adoption, not after.
Stack fit. v4.x remains PHP 8.1+, Laravel 10/11, Filament 3.x, Livewire 3, with events rendered through Filament Actions so authorization and validation reuse existing machinery. That is still the recommended production line. For v5, the shape of the fit is now better — Filament-native toolbar, filters, tabs, headings, actions and schemas mean a calendar surface behaves like a resource list, which is a real reduction in bespoke code — but the exact floors are unverified and plausibly higher (Filament major, FullCalendar 7). Read composer.json at the target tag before estimating anything. Theming remains panel-plugin scoped and does not change the admin-only positioning.
Migration path. Sequence matters more than it did before, because the codemod is a one-shot rewrite and the new features are optional:
vendor/bin/filament-fullcalendar-v5 --dry-run, and read the full diff. This is the cheapest possible signal about how much of your widget code the script touches and where it leaves manual work.--no-scripts). Run the printed manual checklist. Build assets, run php artisan filament:assets, and execute the interaction smoke script: render read-only, click-open, edit, drag, resize — on a calendar without resource views, which is the configuration the beta3 defect hit.Guardrail change. The old rule was "Eloquent is the single source of truth and EventData is the anti-corruption boundary." That boundary is now optional, and adopting the package's model contract is the whole point of moving to v5. The updated guardrail: adopt the model contract where it removes duplication, but keep one seam you own — a trait, base class or small adapter — so that if the package's contract changes at v5.1 or v6, the change is contained to that seam rather than smeared across every model. Keep an escape hatch to DTOs, and do not let the package's attribute-mapping configuration become the only place your scheduling invariants are expressed.
Compatibility. Pin the package to an exact minor and record the FullCalendar major separately (package and JS versions no longer correspond). Ensure php artisan filament:assets runs in every deploy that updates the package, and treat asset/package version mismatch as a deploy failure. If themes or external calendars are adopted, fail the Vite build when the theme manifest entry is absent, and fail the deploy when outbound-fetch configuration is missing.
Sequencing summary (v5 evaluation and upgrade, ~3–4 days to parity, 2–5 further days for optional capabilities):
composer.json — 0.25 day. If it forces a Filament major, scope that as a panel upgrade program, not a calendar ticket.Maintenance. You now own more than a widget subclass. The maintenance ledger reads: package minor line, FullCalendar major, panel asset build, the upgrade codemod's diff output, an event-model contract, and — if adopted — theme modules, external-feed credentials and outbound fetch policy. That is a meaningful step up from "one adapter class." The upside is real: less bespoke glue, Filament-native behaviour, filters/tabs you no longer hand-build. The trade is that the calendar is now a subsystem with dependencies on your domain models and your network egress. Assign an owner for each adopted capability before adopting it; an unowned model contract becomes an upgrade blocker and an unowned Google OAuth token becomes an incident.
Support. MIT, community-supported, no SLA, no escalation path. The release notes are a strong positive signal — an automated upgrade script, a clear GA timeline, a candid acknowledgement of past maintenance, and an open invitation for PRs against 5.x. That is better hygiene than the prior assessment assumed. It is still not a support commitment, and a single-maintainer project mid-major is churn by definition. Keep the integration surface thin enough that fork-and-vendor remains a weekend, not a quarter; the addition of model contracts and feed handling lengthens that weekend, which is the argument for the owned seam described above.
Scaling. Unchanged at the rendering layer — FullCalendar renders client-side, so the ceiling is events-per-view and Livewire payload size, not RPS. Keep the existing guardrails: filter by the supplied date window in the event source, index start/end columns, cap events per window with an aggregate fallback, cache windowed payloads for shared ranges. New scaling considerations from this release:
Failure modes and mitigations:
| Failure mode | Symptom | Mitigation |
|---|---|---|
| v5 beta in production | Click/drag/resize regressions (as in beta3) reaching users | Production on v4.x; beta only on a spike branch; GA is days away — wait |
| Codemod rewrites code incorrectly | Compiles and tests pass, semantics drift | Dry-run, read the full diff, run the manual checklist, parity-freeze before feature adoption |
| Filament or FullCalendar major bump | Widget fails to register; options silently no-op | Pin package minor and FullCalendar major separately; stage the panel major separately |
| Stale panel assets after upgrade | Old JS served, errors or missing features | Always run php artisan filament:assets; assert asset/package version alignment in deploy |
| Auto-persist on drag/drop bypasses rules | Unauthorized or invalid writes from a UI gesture | Re-validate server-side on every mutation; policies plus domain validation; confirmation mode for high-stakes calendars |
| Mixed-model calendar leaks records | User sees or edits a record their policy denies | Per-model policy audit; test each model in the calendar; keep multi-model usage to a reviewed allowlist |
| iCal URL used as SSRF vector | Application fetches internal endpoints | Allowlist schemes/hosts, block redirects to private ranges, enforce timeouts and response size caps |
| External feed slow or down | Calendar hangs or renders partially | Server-side cache with TTL, hard timeout, circuit breaker, degrade to app-only events |
| Google token expiry or revocation | Feed silently disappears | Expiry monitoring, refresh handling, user-visible feed health state |
| Resource views without entitlement | Legal exposure or watermarked UI | Confirm FullCalendar 7 premium licensing and schedulerLicenseKey() policy before building resources |
| Theme module missing from build | Panel boot error or unstyled calendar | Fail the build on absent manifest entry; keep the default theme as fallback |
| Filter/tab query modification unindexed | Slow calendar on large datasets | Index filter columns; cap result sets; monitor query time per calendar |
| Timezone mismatch | Events on the wrong day or shifting on DST | Store UTC; resolve display timezone explicitly — v5 does not solve this for you |
| Upstream abandonment | No fix for a breaking dependency | Thin owned seam, fork-and-vendor contingency; active beta series lowers near-term risk |
Ramp-up. Higher than v4, and it scales with how much of the new surface you adopt. Baseline for a Filament-fluent developer: ~1 day to a working calendar. Add ~1–2 days for v5 concepts (Filament actions, schemas, model event contracts) and ~0.5 day to run and review the codemod. Per-capability: filters/tabs ~0.5–1 day; drag/drop auto-persist ~1 day including validation review; resource calendars ~1–2 days; external calendars ~1–3 days, mostly security and credential work rather than calendar work; theme authoring ~0.5–1 day if used. A Laravel developer new to Filament should add 1–2 days on top of the baseline. The genuinely non-obvious work is still the domain layer the package does not solve — recurrence semantics, timezone conventions, and the business rules behind drag/drop — and v5's tighter model coupling makes those rules more visible in your codebase, not less necessary.
How can I help you explore Laravel packages today?