Snapshot of main at 9f39a6e1e (2026-11-02)

This commit is contained in:
Ronald Huynen committed 2026-11-02 10:41:47 +01:00
commit 6ccf1792d7
2580 files changed
+1040202

No files matched your search

@@ -0,0 +1,244 @@
# Claude's plan: the next Laravel upgrade (11 → 12, then 13)
**Author: Claude Code** · Written 2026-10-15 · Status: proposal, not started
Written to compare with Mistral Vibe's plan (`LARAVEL_UPGRADE_PLAN_VIBE.md`). Every fact about this codebase
below was checked on 2026-10-15 against branch `laravel-11` (8e01ebc4) and Packagist. How: see
[Appendix](#appendix-how-the-facts-were-checked).
---
## 1. Recommendation in short
1. **Go to Laravel 12 first, and plan Laravel 13 as a second project right after it.** Laravel 12 can keep
our heavily customised WireChat 0.2. Laravel 13 needs WireChat 0.6, the largest single risk in either
upgrade. Doing them separately keeps each step small and each rollback simple.
2. **Do the risky preparation on Laravel 11 first**, as normal small deploys: Carbon 3, removing two unused
packages, and taking the abandoned flatpickr package into our own code. The Laravel 12 upgrade itself is
then a small change.
3. **Reuse what worked for Laravel 11**: `scripts/upgrade.sh`, a local rehearsal on a copy of the database, a
rehearsal on a fictitious second platform, and a staged rollout from a separate branch.
4. **Timing matters.** Laravel 11 has had no security fixes since March 2026. Laravel 12 gets security fixes
only until 2027-02-24, so Laravel 13 has to follow soon after.
---
## 2. Where we stand
| | |
|---|---|
| Production | Laravel 11.57.0 since 2026-10-15, PHP 8.3.35, Livewire 3.8 |
| Other instances | to be listed (PHP version per server matters for Laravel 13) |
| Newest Laravel 12 | 12.70.0, needs PHP 8.2+, Carbon 3 |
| Newest Laravel 13 | 13.36.0, needs **PHP 8.3+**, Carbon 3, Symfony 7.4/8 |
| Support (verify on laravel.com/docs/master/releases) | 11: security fixes ended March 2026 · 12: security fixes until 2027-02-24 · 13: about a year longer than 12 |
---
## 3. What blocks the upgrade, in this codebase
### 3.1 Packages
Most packages already have a release for Laravel 12 and 13 **in the major version we use now** (Livewire 3,
Jetstream 5, Fortify, Sanctum, Scout 10, spatie permission 6, medialibrary 11, Reverb, WireUI 2,
laravel-localization 2, dompdf, excel 3, and others). The exceptions:
| Package | Use here | Laravel 12 | Laravel 13 | What to do |
|---|---|---|---|---|
| `asdh/laravel-flatpickr` | `<x-flatpickr>` in 21 views; we already override its component class | **no release** (stops at Laravel 11) | **no release** | Move it into the app (one class, 2 views, CSS/JS), drop the package |
| `nesbot/carbon` | pinned at `^2.72` | needs **Carbon 3** | Carbon 3 | Upgrade on Laravel 11 first (Laravel 11 supports Carbon 3) |
| `psr/simple-cache` | pinned at `^1.0` in our composer.json (left over from the skeleton) | Laravel 12.29+ needs `^3.0` | `^3.0` | Remove the pin or set `^3.0` |
| `robsontenorio/mary` | **not used** (only `config/mary.php`) | needs 2.x | needs 2.x | Remove the package and its config |
| `laradumps/laradumps` (dev) | **no `ds()` calls** | needs 5.x | needs 5.x | Remove |
| `cviebrock/eloquent-sluggable`, `-taggable` | 24 files | 12.x | 13.x | Version bump (these majors only follow Laravel) |
| `nunomaduro/collision` (dev) | test runner | 8.6+ (we have 8.5) | 8.x | Update within 8.x |
| `staudenmeir/*` (3 packages) | relations | newer minor | newer minor | Update within the current line |
| `namu/wirechat` | chat; **45 override and published view files** | 0.2.11 works | **0.6 required** | Laravel 13 only: a project of its own |
| `laravel/tinker`, `barryvdh/laravel-debugbar` (dev) | | current line works | new major | Laravel 13 only |
### 3.2 Carbon 3: the main code risk
Carbon 3 changed `diffIn*()`: the results are now **signed** (negative when the argument is in the past) and
**floats**. Laravel 11 accepts Carbon 3, so this can be fixed and deployed before Laravel 12.
- 28 `diffIn*()` calls in 20 files need review.
- Example that would break: `now()->diffInSeconds(Carbon::parse($lastLoginAt))` in
`InactiveProfileWarning2Mail` and `InactiveProfileWarningFinalMail` becomes negative.
- Calls that already pass `false` (signed) or cast to `(int)` need a check for the float, not the sign.
- 172 `Carbon::parse` and 45 `Carbon::now` calls: mostly unaffected, but run the full suite and look at
date displays (transaction lists, statements, inactivity mails, call expiry).
### 3.3 Laravel 12 upgrade-guide items checked against the code
| Change in Laravel 12 | Here |
|---|---|
| Carbon 3 required | yes, see 3.2 |
| `image` validation rule excludes SVG | not affected: the one upload rule uses `mimes:jpg,jpeg,png,svg` |
| `local` disk default root moves to `storage/app/private` | not affected: `config/filesystems.php` sets `root => storage_path('app')` |
| `HasUuids` generates UUIDv7 | not used |
| `mergeIfMissing` with nested arrays | not used |
| `Concurrency` result keys | not used |
| `Schema::getTables()` and similar, multi-schema | not used |
| `DatabaseTokenRepository` expiry in seconds | no custom repository |
| Route precedence for duplicate names, container default values, `Str::is` with newlines | low; covered by the test suite and smoke tests |
To do in Phase 2: read the full official guide once more, and diff the `laravel/laravel` skeleton 11 → 12
(config files) against ours.
### 3.4 Tests
- 466 test methods, 656 tests including data sets, green on Laravel 11.
- PHPUnit 10.5 can stay for Laravel 12.
- 20 test files still use `@test` docblock annotations. They work on PHPUnit 10 and 11, but PHPUnit 12
ignores them, so converting them to `#[Test]` attributes is preparation for later.
---
## 4. Phases
### Phase 0: Before starting (no code changes)
1. Finish the Laravel 11 follow-ups: a quiet prod log, `main` fast-forwarded to `laravel-11`, snapshot removed
(see the post-upgrade reminder in shared memory).
2. List every instance and its PHP version. Laravel 13 needs PHP 8.3 everywhere.
3. Decide: Laravel 12 then 13 (recommended), or straight to 13 (see [section 6](#6-alternatives-considered)).
### Phase 1: Preparation on Laravel 11 (small changes, normal deploys)
Each step is its own commit on `main`, tested with the full suite, and deployed with the normal
`deploy.sh`, so production gets smaller changes one at a time instead of one big jump.
1. **Carbon 3.**
- `nesbot/carbon` to `^3.8`.
- Review all 28 `diffIn*()` calls: keep the meaning ("how long ago" stays positive, whole numbers where
shown to people), with `abs()` and `(int)` or `floor()` where needed.
- Add tests for the inactivity mails and call expiry, which compute durations.
2. **Composer clean-up.**
- Remove the `psr/simple-cache` pin.
- Remove `robsontenorio/mary` (and `config/mary.php`) and `laradumps/laradumps`.
3. **Flatpickr into the app.**
- Move the component (our override in `app/Overrides/Asdh`), its two views and its CSS/JS into the app.
- Register it under the same name `flatpickr`, so the 21 views keep `<x-flatpickr>` unchanged.
- Remove the package, the override and its classmap entry.
- Test every date picker: transactions table, select period, profile form, posts, calls.
4. **Updates within the current lines.**
- Collision to 8.6+, the `staudenmeir` packages, and the newest Livewire 3.8.x.
- `composer update` within the constraints, then the full suite.
### Phase 2: Laravel 12 (branch `laravel-12`, staged rollout)
1. **Branch** `laravel-12` from `main` once Phase 1 is on `main`.
2. **Composer:**
- `laravel/framework ^12.0`, `cviebrock/eloquent-sluggable ^12.0`, `cviebrock/eloquent-taggable ^12.0`.
- `composer update -W`. Write down every major version that changed in the lock file.
3. **Upgrade guide and skeleton:** apply section 3.3, and diff the Laravel 11 and 12 skeleton config files
against ours.
4. **Our overrides.** For every package with an override or published views (Jetstream `HasProfilePhoto`,
Matchish, WireChat views, WireUI), diff the vendor original between the old and new version and port the
changes, as was done for WireChat 0.2.11.
5. **Tests:**
- Full suite green.
- Render the main Livewire pages.
- Smoke test by hand: log in, switch profile, payment, chat with an image, poll, search, mailing preview,
PDF statement, date pickers.
- All 4 themes.
6. **Rehearsals with `scripts/upgrade.sh`:**
- a clone of `main` with a copy of the database (success path, rollback before and after going live)
- the fictitious Uuro platform (`TIMEBANK_CONFIG=uuro`, own config, own theme)
- a routine deploy afterwards
The script is version-neutral. It reads the PHP requirement from the target lock file, but check its
texts ("Laravel 10 -> 11") and the version check in step 6.
7. **Docs:**
- `references/UPGRADE_LARAVEL_11_TO_12.md` (the 10 → 11 guide with the changes)
- versions in `AGENTS.md`
- the post-upgrade checklist
8. **Rollout:**
- the development server first, then production, then other instances: `--target origin/laravel-12`
- fast-forward `main` once all instances are upgraded or ready
### Phase 3: Laravel 13 (separate project, start right after Laravel 12 is live)
1. **PHP 8.3 on every instance** (production already has 8.3.35).
2. **WireChat 0.2 → 0.6**, the biggest item:
- Read the changelogs of 0.3 to 0.6.
- Re-port our 45 override and view files.
- Check our `_finishUpload` override (Livewire 3.8 signed uploads), private attachments and the listeners
that work across profile switches.
- Extend the chat tests first, so regressions show.
- This can be prepared on Laravel 12 if WireChat 0.6 also supports 12 (it does: `^11|^12|^13`).
3. **Package majors:** tinker 3, debugbar 4 (dev), sluggable and taggable 13; check Symfony 7.4/8,
Monolog 3.10 and Guzzle.
4. **Read the official 12 → 13 upgrade guide.** I do not list its items from memory here; they have to be
checked against the code, as in 3.3.
5. **Same method** as Phase 2: branch `laravel-13`, rehearsals, staged rollout.
6. **Finish before 2027-02-24**, when Laravel 12 gets its last security fixes.
---
## 5. Risks and how to limit them
| Risk | Impact | Limit it by |
|---|---|---|
| Carbon 3 changes durations silently (negative or fractional) | Wrong texts in mails ("-3 days ago"), wrong expiry decisions | Phase 1 on Laravel 11 with tests per `diffIn*()` call; check mails per theme |
| Flatpickr removal breaks date pickers | Forms where a date cannot be entered | Same tag name; test every page with a picker |
| A package's new major changes behaviour (sluggable, taggable) | Wrong slugs or tags | Read their changelogs; tests on posts, tags, calls |
| Override drift (vendor views and classes) | Chat or profile photo regressions | Diff vendor originals old to new, as for WireChat 0.2.11 |
| WireChat 0.6 (Laravel 13) | Chat broken | Separate phase, tests first, prepare on Laravel 12 |
| A server with older PHP | Laravel 13 cannot run there | List PHP versions in Phase 0; `upgrade.sh` refuses too old PHP |
| A long-running branch drifts from `main` | Rebase conflicts during the rollout | Short phases; do not rebase after a server upgraded from the branch |
| Two AI agents in one folder | Conflicting edits during the upgrade | Worklog entries; one agent per phase step; the user dispatches |
---
## 6. Alternatives considered
- **Straight to Laravel 13 in one project.** One rollout instead of two, and the longest support. But it
combines Carbon 3, all package majors, the Laravel 12 and 13 framework changes and WireChat 0.6 in one
step, so a failure is harder to pin down and a rollback undoes more. Reasonable only if Phase 1 is done
and WireChat 0.6 has been tried separately first, so in practice it is the same work in a different order.
- **Laravel 12 only, and stay there.** Its security support ends 2027-02-24. Not an end state.
- **Doing Phase 1 inside the Laravel 12 branch.** Possible, but then production gets Carbon 3, flatpickr
and the framework at once. Phase 1 on Laravel 11 gives smaller, easier-to-check production changes.
---
## 7. Effort (working time, rough)
| Phase | Effort |
|---|---|
| 0 | an hour (an inventory and a decision) |
| 1 | 1 to 2 days (Carbon review is most of it), plus normal deploys |
| 2 | 2 to 3 days, including rehearsals, plus a rollout evening per instance |
| 3 | 3 to 5 days, mainly WireChat 0.6, plus rehearsals and rollout |
---
## 8. Open questions for the user
1. Which instances exist besides timebank.cc, and on which PHP version?
2. Is there still a development server to upgrade first?
3. Agree with Laravel 12 first and 13 straight after, or prefer straight to 13?
4. Is Mary perhaps planned for future UI work? (It is not used now.)
---
## Appendix: how the facts were checked
- **Package support:**
- The Packagist metadata of every package in `composer.json` was read with
`.agents/archive/laravel-compat-check.py` (output: `.agents/archive/laravel-compat-2026-10-15.txt`).
- For each package it checks the newest version supporting Laravel 12 and 13, overall and within the
major version in use.
- **Dependency solving:** `composer update --dry-run -W` in a copy of `composer.json`/`composer.lock` with
`laravel/framework ^12.0` and `nesbot/carbon ^3.8`. It stopped at `cviebrock/eloquent-sluggable` (needs
12.x) and `psr/simple-cache` (`^1.0` pin versus Laravel 12.29+).
- **Code impact:** `grep` counts in `app/`, `resources/views/`, `routes/`, `database/` and `tests/`:
- `<x-flatpickr>`: 21 files
- `diffIn*()`: 28 calls in 20 files
- `Mary`: no use
- `ds()`: none
- WireChat overrides: 45 files
- `@test` annotations: 20 files
- **Not verified here:** Laravel 13's exact upgrade-guide items and support end date (to be read from the
official documentation in Phase 3).