# Update Log: HGBI — Laravel 11 → 12 + Ecosystem > **Date:** 2026-02-20 > **Branch:** `updates-to-v12` > **AI Tool:** Claude Code (Opus 4.6) --- ## Starting State | Package | Before | Target | |-------------------|---------|----------------------| | PHP | 8.4.17 | (no change expected) | | laravel/framework | 11.48.0 | ^12.0 | | filament/filament | 3.3.49 | ^5.0 | | livewire/livewire | 3.7.10 | ^4.0 (via Filament) | | tailwindcss | 3.4.19 | ^4.0 | | pestphp/pest | 4.x | (no change expected) | **Baseline tests:** 249 passed (1774 assertions), 3 risky, 20 incomplete **Baseline build:** Success (client + SSR) --- ## Upgrade Phases ### Phase 1: Pre-Flight - [x] Branch created (`updates-to-v12`) - [x] Baseline tests recorded - [x] Baseline build verified - [x] Reference document consulted ### Phase 2: Composer — Remove Blockers - [x] `codezero/laravel-localizer` removed - [x] `codezero/laravel-localized-routes` replaced with `opgginc/codezero-laravel-localized-routes:^5.0` - [x] `codezero/composer-preload-files` set to `false` in allow-plugins - [x] `saloonphp/laravel-http-sender` removed, `config/saloon.php` updated to `GuzzleSender` - [x] `johncarter/filament-focal-point-picker` removed and usage cleaned from 2 files - [x] Bootstrap cache cleared - [x] Tests pass (249), build succeeds ### Phase 3: Composer — Laravel 12 + Direct Dependencies - [x] Laravel framework 12.52.0 installed - [x] All direct dependencies bumped (see Packages Changed table) - [x] `spatie/icalendar-generator` v3 enum syntax fixed (`EventStatus::Confirmed`, `Classification::Private`) - [x] Bootstrap cache cleared - [x] Tests pass (249), build succeeds ### Phase 4: Filament v3 → v5 - [x] `filament/spatie-laravel-translatable-plugin` removed (no v4/v5 exists) - [x] Filament v5.2.2 installed directly (v4 intermediary had no translatable support) - [x] `filament/upgrade:^4.0` installed, `filament-v4` rector run on `app/` - [x] `filament/upgrade:^5.0` installed, `filament-v5` rector run on `app/` - [x] `lara-zeus/spatie-translatable:^2.0` installed (replaces translatable plugin) - [x] `DisplayText::make()` signature fixed (`?string $name = null`) - [x] `TextInput\Mask` replaced in `ShippingRateResource` and `CouponResource` - [x] `FaqsRelationManager` form signature fixed (`Schema $schema`) - [x] Livewire v4.1.4 installed (via Filament) - [x] Tests pass (249), build succeeds ### Phase 5: NPM Major Updates - [x] Major frontend packages upgraded - [x] vite.config.js SSR fix: `@inertiajs/server` → `@inertiajs/vue3` - [x] `@vue/server-renderer` deduplicated (removed from dependencies, kept in devDependencies) - [x] `apexcharts` added as explicit dependency (previously transitive) - [x] Build succeeds (client + SSR) - [x] Tests pass (249) ### Phase 6: ESLint Cleanup - [x] `eslint-plugin-tailwindcss` removed from devDeps and eslint.config.mjs - [x] Tailwind-specific rules/settings cleaned from ESLint config - [x] Linter passes ### Phase 7: Final Verification (Laravel 12 Upgrade) - [x] Tests pass: 249 passed (1774 assertions), 3 risky, 20 incomplete — matches baseline - [x] Build succeeds (client + SSR) - [x] Pint passes (`--dirty --format agent` → `pass`) - [x] `composer outdated --direct` → all up to date - [x] `npm outdated` → only deferred packages (eslint 10, tailwindcss 4, globals 17) - [x] `php artisan about` → Laravel 12.52.0 ### Phase 8: Tailwind CSS v3 → v4 - [x] Automated upgrade tool (`@tailwindcss/upgrade`) run — partially succeeded - Migrated `app.css` directives (`@import 'tailwindcss'`, `@config` reference, border compat layer) - Updated `tailwindcss` package to ^4.2.0 - Failed on: callback-based theme extensions (`negative`), then `tailwindcss/defaultTheme` module removed in v4 - [x] Manual fixes applied: - Callback theme extensions (`inset: (theme, {negative}) => ...`) converted to static `...generateSpacing()` objects - `tailwindcss/defaultTheme` import removed, font stack inlined - `@tailwindcss/postcss` installed, `postcss.config.js` updated (removed `autoprefixer`) - `@layer base` → `@utility` blocks in `utility.css` (13 utilities converted) - Custom-class-in-custom-class patterns expanded (`inner-container`/`container`/`outer-container` no longer `@apply pl-container pr-container`) - Container override: `@source not inline('container')` added to `app.css` (ref #37) - `corePlugins.container = false` removed from JS config (not supported in v4 CSS-first mode) - Old TW v3 plugins removed: `@tailwindcss/forms`, `@tailwindcss/typography`, `@tailwindcss/aspect-ratio`, `autoprefixer` - `require()` plugin calls removed from `tailwind.config.js` (forms/typography now built into v4) - `@formkit/themes/tailwindcss` plugin kept — works in compat mode - [x] Deprecated TW v3 class patterns updated in 4 Vue files: - `bg-gray-500 bg-opacity-75` → `bg-gray-500/75` (3 modal components) - `ring-black ring-opacity-5` → `ring-black/5` (1 component) - [x] Build succeeds (client + SSR) - [x] Tests pass: 249 passed (1774 assertions) — matches baseline - [x] Filament assets republished (`php artisan filament:upgrade --no-interaction`) ### Phase 9: Final Verification - [x] Tests pass: 249 passed (1774 assertions), 3 risky, 20 incomplete — matches baseline - [x] Build succeeds (client + SSR) - [x] `npm outdated` → only deferred packages (eslint 10, globals 17) --- ## Exceptions & Issues ### Issue 1: Saloon HttpSender config broke after removing laravel-http-sender **Symptom:** 17 test failures in Labonovum/Saloon-related tests after removing `saloonphp/laravel-http-sender`. **Root Cause:** `config/saloon.php` referenced `Saloon\HttpSender\HttpSender` which was in the removed package. Then changed to `Saloon\Laravel\HttpSender` which also doesn't exist in v3. **Fix:** Changed to `Saloon\Http\Senders\GuzzleSender` (the default in `saloonphp/laravel-plugin` v3). **Files affected:** `config/saloon.php` ### Issue 2: spatie/icalendar-generator v3 enum method syntax changed **Symptom:** `Call to undefined method Spatie\IcalendarGenerator\Enums\EventStatus::confirmed()` **Root Cause:** v3 switched from method-based enums to PHP 8.1 backed enums (`::Confirmed` instead of `::confirmed()`). **Fix:** `EventStatus::confirmed()` → `EventStatus::Confirmed`, `Classification::private()` → `Classification::Private` **Files affected:** `provider/Models/Appointment.php` ### Issue 3: filament/spatie-laravel-translatable-plugin has no v4 or v5 **Symptom:** No v4/v5 release exists. Plugin only has v3.x which requires `filament/support:self.version` (v3), blocking Filament upgrade. **Root Cause:** The translatable plugin was deprecated by Filament and replaced by a community package. **Fix:** Removed `filament/spatie-laravel-translatable-plugin`, installed `lara-zeus/spatie-translatable:^2.0`. Rector scripts automatically migrated all 40+ imports. **Files affected:** All Filament resource files using translatable traits. ### Issue 4: ariaieboy/filament-currency v3 requires Filament v5 **Symptom:** `ariaieboy/filament-currency:^3` requires `filament/tables ^5.0`, blocking Filament v4 installation. **Root Cause:** v3.0.0 skipped v4 support entirely. **Fix:** Went directly to Filament v5, installed `ariaieboy/filament-currency:^3`. ### Issue 5: DisplayText::make() signature incompatibility **Symptom:** `Declaration of App\Forms\Components\DisplayText::make(string $name = ''): static must be compatible with Filament\Forms\Components\Field::make(?string $name = null): static` **Root Cause:** Filament v4+ changed `Field::make()` from `string $name` to `?string $name = null` (ref #17). **Fix:** Updated to `make(?string $name = null)` and pass `$name ?? ''` to parent. **Files affected:** `app/Forms/Components/DisplayText.php` ### Issue 6: TextInput\Mask removed in Filament v5 **Symptom:** `use Filament\Forms\Components\TextInput\Mask` import fails. **Root Cause:** Mask builder class removed in Filament v5 (ref #15). **Fix:** Replaced mask closures with `->numeric()->step(0.01)->minValue(0)->prefix('€')` approach. **Files affected:** `app/Filament/Resources/ShippingRateResource.php`, `app/Filament/Resources/CouponResource.php` ### Issue 7: Missing apexcharts npm dependency **Symptom:** `Rollup failed to resolve import "apexcharts"` during build. **Root Cause:** `vue3-apexcharts` requires `apexcharts` as peer dep, previously resolved transitively (ref #51). **Fix:** Added `apexcharts` as explicit dependency. **Files affected:** `package.json` ### Issue 8: Tailwind upgrade tool fails on callback-based theme extensions **Symptom:** `Cannot destructure property 'negative' of 'undefined'` **Root Cause:** `tailwind.config.js` used callback functions for theme extensions (e.g., `inset: (theme, {negative}) => ...`). TW v4's upgrade tool cannot evaluate these. **Fix:** Converted all callback-based theme extensions to static objects using `...generateSpacing()`. **Files affected:** `tailwind.config.js` ### Issue 9: `tailwindcss/defaultTheme` module removed in TW v4 **Symptom:** `Cannot find module 'tailwindcss/defaultTheme'` during upgrade tool template migration step. **Root Cause:** TW v4 removed the `defaultTheme` export. The config imported it for `fontFamily.sans` fallback stack. **Fix:** Removed the import, inlined the default sans font stack directly. **Files affected:** `tailwind.config.js` ### Issue 10: Custom `.container` class overridden by TW v4 built-in **Symptom:** Potential layout breakage — TW v4 generates its own `.container` utility that would override the project's custom one. **Root Cause:** `corePlugins.container = false` from JS config is not supported in TW v4 CSS-first mode (ref #37). **Fix:** Added `@source not inline('container')` and `@source not inline('container!')` to `app.css`. **Files affected:** `resources/css/app.css` ### Issue 11: `@layer base` with `@apply` fails in TW v4 **Symptom:** `Cannot apply unknown utility class` when building. **Root Cause:** TW v4 no longer supports `@apply` inside `@layer base` for custom utility classes (ref #35). **Fix:** Converted all `@layer base` custom utilities to `@utility` blocks. Non-`@apply` styles (`.hide-scrollbar`, `.lds-ellipsis`, etc.) moved to plain CSS. **Files affected:** `resources/css/utility.css` --- ## Packages Changed | Package | From | To | Notes | |------------------------------------------------|---------|---------|---------------------------------------| | `laravel/framework` | 11.48.0 | 12.52.0 | Core upgrade | | `filament/filament` | 3.3.49 | 5.2.2 | Skipped v4 (no translatable) | | `livewire/livewire` | 3.7.10 | 4.1.4 | Via Filament | | `barryvdh/laravel-debugbar` | 3.16.5 | 4.0.9 | Clean | | `darkaonline/l5-swagger` | 9.0.1 | 10.1.0 | Clean | | `mollie/laravel-mollie` | 3.1.0 | 4.0.2 | Clean | | `predis/predis` | 2.4.1 | 3.4.0 | Clean | | `spatie/eloquent-sortable` | 4.5.2 | 5.0.0 | Clean | | `spatie/calendar-links` | 1.11.1 | 2.0 | Not used in code | | `spatie/icalendar-generator` | 2.9.2 | 3.2.1 | Enum syntax change | | `laravel-notification-channels/fcm` | 4.5.0 | 6.0.1 | Skipped v5 | | `muhammadhuzaifa/telescope-guzzle-watcher` | 3.2.2 | 4.0.0 | Clean | | `staudenmeir/belongs-to-through` | 2.16.4 | 2.17 | Clean | | `staudenmeir/eloquent-has-many-deep` | 1.20.x | 1.21 | Clean | | `amidesfahani/filament-tinyeditor` | 3.x | 4.x | Clean | | `ariaieboy/filament-currency` | 1.x | 3.0.0 | Clean | | `ralphjsmit/laravel-filament-components` | 2.x | 3.x | Clean | | `filament/spatie-laravel-media-library-plugin` | 3.3.49 | 5.2.2 | Clean | | `filament/spatie-laravel-settings-plugin` | 3.3.49 | 5.2.2 | Clean | | `codezero/laravel-localized-routes` | 4.0.1 | — | Removed | | `codezero/laravel-localizer` | 3.0.0 | — | Removed | | `saloonphp/laravel-http-sender` | 3.1.0 | — | Removed (abandoned) | | `johncarter/filament-focal-point-picker` | 3.1.0 | — | Removed | | `filament/spatie-laravel-translatable-plugin` | 3.3.49 | — | Removed | | `opgginc/codezero-laravel-localized-routes` | — | 5.1.0 | Added (fork) | | `lara-zeus/spatie-translatable` | — | 2.0.0 | Added (replaces translatable plugin) | | `laravel-vite-plugin` | 1.3.0 | 2.1.0 | Requires Vite 7 | | `vite` | 6.4.1 | 7.3.1 | Required by laravel-vite-plugin | | `@vitejs/plugin-vue` | 5.2.4 | 6.0.4 | Required by Vite 7 | | `@vueuse/core` | 13.9.0 | 14.2.1 | Clean | | `@vueuse/integrations` | 13.9.0 | 14.2.1 | Clean | | `vue-i18n` | 9.14.5 | 11.2.8 | Clean | | `uuid` | 11.1.0 | 13.0.0 | Clean | | `vue-number-animation` | 1.1.2 | 2.0.2 | Needs `--legacy-peer-deps` | | `imagetools-core` | 7.1.0 | 9.1.0 | Clean | | `vite-imagetools` | 7.1.1 | 9.0.3 | Clean | | `rollup-plugin-visualizer` | 5.14.0 | 6.0.5 | Clean | | `eslint-plugin-tailwindcss` | 3.18.0 | — | Removed | | `apexcharts` | — | 5.6.0 | Added (was transitive) | | `tailwindcss` | 3.4.19 | 4.2.0 | CSS-first mode with `@config` compat | | `@tailwindcss/postcss` | — | 0.1.3 | Added (replaces `tailwindcss` plugin) | | `@tailwindcss/forms` | 0.5.4 | — | Removed (built into v4) | | `@tailwindcss/typography` | 0.5.9 | — | Removed (built into v4) | | `@tailwindcss/aspect-ratio` | 0.4.2 | — | Removed (built into v4) | | `autoprefixer` | 10.4.14 | — | Removed (built into v4) | --- ## What Worked Without Issues - `darkaonline/l5-swagger` 9 → 10: no code changes - `mollie/laravel-mollie` 3 → 4: no code changes - `spatie/eloquent-sortable` 4 → 5: no code changes - `predis/predis` 2 → 3: no code changes - `barryvdh/laravel-debugbar` 3 → 4: only bootstrap cache clear needed - `staudenmeir/belongs-to-through` and `eloquent-has-many-deep`: patch bumps, clean - All Filament companion plugins (media-library, settings, tinyeditor, currency, components): clean upgrades - `@vueuse/core` and `@vueuse/integrations` 13 → 14: no breaking changes encountered - `vue-i18n` 9 → 11: no import changes needed - `uuid` 11 → 13: no changes needed - Filament rector scripts (v4 + v5): handled most namespace transforms correctly - `lara-zeus/spatie-translatable:^2.0`: drop-in replacement, rector migrated all imports - `@formkit/themes/tailwindcss` plugin: works in TW v4 compat mode via `@config` without changes --- ## Remaining / Unresolved - **ESLint v9 → v10**: Intentionally deferred (+ globals 16 → 17). - **`vue-number-animation` peer dep conflict**: Installed with `--legacy-peer-deps`. The v2 package has an optional peer dep on `@vue/composition-api` which conflicts with Vue 3. Works correctly at runtime. - **npm audit vulnerabilities**: 15 high, 1 moderate — review separately. - **Tailwind v4 visual validation**: Build succeeds but manual visual validation is required. TW v4 changes CSS output in subtle ways that automated tests cannot detect. Open key pages in browser and compare against pre-upgrade state. - **`tailwind.config.js` still uses JS compat mode**: The project uses `@config` in CSS to load the JS config. A future cleanup could migrate everything to pure CSS-first `@theme {}` blocks, but this is not required and the compat mode works correctly. --- ## Miscellaneous - Tailwind CSS v3 → v4 completed in Phase 8. Uses `@config` compat mode (JS config still present). - ESLint v9 → v10 is not in scope. - Filament v4 step was effectively skipped due to translatable plugin incompatibility. Went v3 → v5 directly, but ran both v4 and v5 rector scripts. - The `post-update-cmd` script in `composer.json` runs `filament:upgrade` automatically on every `composer update/require`, which generates large diffs in `public/js/filament/*` and `public/css/filament/*`. - `spatie/calendar-links` upgraded to v2 but is not referenced anywhere in code (might be removable). --- ## Recommendations for Next Session - **Manual visual validation** of key pages (homepage, product pages, Filament admin, provider dashboard, modals). TW v4 changes CSS output subtly — a green build does not guarantee correct layout. - Consider removing `spatie/calendar-links` if truly unused. - Review and address npm audit vulnerabilities. - Consider migrating `tailwind.config.js` to pure CSS-first `@theme {}` blocks (optional, compat mode works fine). - ESLint v10 upgrade when ready.