Snapshot of main at 9f39a6e1e (2026-11-02)
This commit is contained in:
commit
6ccf1792d7
2580 files changed
+1040202
No files matched your search
@@ -0,0 +1,360 @@
|
||||
# Laravel upgrade plan: 11 → 12, then 13 (combined)
|
||||
|
||||
**Combined by Claude Code, 2026-10-15** from four documents in this folder:
|
||||
- Claude's plan: `LARAVEL_UPGRADE_PLAN_CLAUDE.md`
|
||||
- Vibe's plan: `LARAVEL_UPGRADE_PLAN_VIBE.md`
|
||||
- Vibe's hybrid: `LARAVEL_UPGRADE_PLAN_HYBRID.md`
|
||||
- Claude's first hybrid, merged into this file
|
||||
|
||||
**Status: proposal, waiting for the user's decisions** (section 11). Nothing is approved or started.
|
||||
|
||||
Origin of each part: **[C]** Claude, **[V]** Vibe (its plan or its hybrid), **[C+V]** combined. Where a
|
||||
plan assumed something that does not match this codebase, the corrected fact is used (section 2). Section
|
||||
10 lists what was left out and why; section 12 lists how the two hybrids differed.
|
||||
|
||||
---
|
||||
|
||||
## 1. Approach in short
|
||||
|
||||
1. **[C] Laravel 12 first, Laravel 13 as a second project right after it.** Laravel 12 keeps WireChat 0.2;
|
||||
Laravel 13 needs WireChat 0.6, the largest single risk.
|
||||
2. **[C] Prepare on Laravel 11 with small, normal deploys** (Carbon 3, flatpickr into the app, remove unused
|
||||
packages), so the framework upgrade itself stays small.
|
||||
3. **[V] Verify by area of this application**: multi-guard profiles, the two permission layers, white-label
|
||||
platforms, payments, chat, search, themes, background processes. Use a test matrix, a reusable
|
||||
verification command and explicit success criteria.
|
||||
4. **[V] Measure before and after** (page times, search time, queue lag), and **decide on rollback with
|
||||
triggers set in advance**.
|
||||
5. **[C+V] Reuse the proven tooling** (`scripts/upgrade.sh`: backup, snapshot, rollback, maintenance with a
|
||||
bypass) **with a deliberate order**: local rehearsals, then a test server if there is one, then
|
||||
production in a quiet window, then other instances.
|
||||
6. **[V] Tell users in advance**, and keep a checklist for before, during and after.
|
||||
|
||||
---
|
||||
|
||||
## 2. Facts that both plans rest on
|
||||
|
||||
Checked 2026-10-15 against Composer, Packagist and the code of branch `laravel-11`.
|
||||
|
||||
| Topic | Fact | Note |
|
||||
|---|---|---|
|
||||
| Laravel releases | 12.70.0 and 13.36.0 are out | Vibe's plan said "when Laravel 12 is released" |
|
||||
| PHP | Laravel 12 needs PHP 8.2+, Laravel 13 needs **8.3+**; production runs 8.3.35 | Vibe's plan required 8.3 for 12; only 13 needs it |
|
||||
| Support | 11: no security fixes since March 2026 · 12: security fixes until 2027-02-24 | Verify on laravel.com/docs/master/releases |
|
||||
| Livewire | 3.8 has releases for Laravel 12 and 13: **4.0 is not needed** | Vibe's plan had a Livewire 4 migration |
|
||||
| Spatie Permission | we run **6.25**, which supports 12 and 13 | Vibe's plan had a v5 → v6 migration |
|
||||
| Reverb | 1.12 supports 12 and 13; **there is no Reverb 2** | |
|
||||
| Scout | 10.x supports 12; 11 is optional | |
|
||||
| Blockers | **flatpickr** (no release after Laravel 11), **Carbon 3** (28 `diffIn*()` calls), **`psr/simple-cache` pin**, **sluggable/taggable** new majors, unused **Mary** and **laradumps** | Not in Vibe's plan |
|
||||
| Laravel 13 only | **WireChat 0.6** (we have 0.2 with 45 override and view files), tinker 3, debugbar 4 | |
|
||||
| Backup and rollback | `scripts/upgrade.sh` already does verified backups, a vendor/build snapshot, a code and/or database rollback, and maintenance with a bypass; tested in 3 rehearsals and the 2026-10-15 production upgrade | Vibe's plan wrote new backup and rollback scripts: not needed, reuse |
|
||||
|
||||
Package details: `references/plans/LARAVEL_UPGRADE_PLAN_CLAUDE.md`, section 3.
|
||||
|
||||
---
|
||||
|
||||
## 3. Phases
|
||||
|
||||
### Phase 0: Preparation, no code changes [C+V]
|
||||
|
||||
1. **[C]** Finish the Laravel 11 follow-ups: quiet logs, `main` fast-forwarded, snapshot removed.
|
||||
2. **[V]** **Inventory per server**: PHP version, Composer version, free disk, services (workers, Reverb,
|
||||
scheduler) and the platform config name. Use one read-only block per server. Laravel 13 needs PHP 8.3
|
||||
everywhere.
|
||||
3. **[V]** **Baseline measurements on production** (for section 5), taken before anything changes.
|
||||
4. **[C]** **Decision**: 12 then 13 (recommended), or straight to 13.
|
||||
5. **[V]** **Is there a test or staging server?** If not, decide whether to set one up or rely on local
|
||||
rehearsals (which worked for Laravel 11).
|
||||
|
||||
### Phase 1: Preparation on Laravel 11 (normal deploys, one step at a time) [C]
|
||||
|
||||
Each step is a commit on `main`, the full suite passes, and it ships with the normal `deploy.sh`.
|
||||
|
||||
1. **Carbon 3.**
|
||||
- `nesbot/carbon ^3.8`.
|
||||
- Review the 28 `diffIn*()` calls: in Carbon 3 they are signed and fractional, which would give, for
|
||||
example, negative durations in the inactivity mails.
|
||||
- Add tests for durations shown to people.
|
||||
2. **Composer clean-up.**
|
||||
- Drop the `psr/simple-cache ^1.0` pin.
|
||||
- Remove `robsontenorio/mary` (with `config/mary.php`) and `laradumps/laradumps`.
|
||||
3. **Flatpickr into the app.**
|
||||
- The component (already overridden in `app/Overrides/Asdh`), its views and its assets move into the app
|
||||
under the same name, so the 21 `<x-flatpickr>` views stay unchanged.
|
||||
- Remove the package.
|
||||
4. **Updates within the current lines**: Collision 8.6+, the `staudenmeir` packages, Livewire 3.8.x.
|
||||
5. **[V] After each deploy**: the verification command (section 4.2) and a short look at the logs.
|
||||
|
||||
**[V] Commands** (each step is its own commit; run the full suite after each):
|
||||
```bash
|
||||
composer require nesbot/carbon:^3.8 -W # 1, plus the diffIn*() review
|
||||
composer remove robsontenorio/mary laradumps/laradumps # 2, plus deleting config/mary.php
|
||||
composer require psr/simple-cache:^3.0 -W # 2, or remove the pin from composer.json
|
||||
composer remove asdh/laravel-flatpickr # 3, after the component lives in the app
|
||||
composer update nunomaduro/collision "staudenmeir/*" livewire/livewire -W # 4
|
||||
```
|
||||
(`cviebrock/eloquent-sluggable` and `-taggable` cannot move on Laravel 11: their next majors need
|
||||
Laravel 12, so they belong to Phase 2. The flatpickr component goes to `app/View/Components/`, the
|
||||
Laravel convention.)
|
||||
|
||||
**[V] Phase 1 is complete when:**
|
||||
- [ ] Carbon 3, the clean-up and flatpickr are on production through normal deploys
|
||||
- [ ] the full suite and `upgrade:verify` pass
|
||||
- [ ] three days without new error types in the production log
|
||||
|
||||
### Phase 2: Laravel 12 (branch `laravel-12`) [C+V]
|
||||
|
||||
1. **[C] Composer:**
|
||||
- `laravel/framework ^12.0`, `cviebrock/eloquent-sluggable ^12.0`, `cviebrock/eloquent-taggable ^12.0`,
|
||||
then `composer update -W`.
|
||||
- Write down every major version that changed in the lock file.
|
||||
2. **[C] Upgrade guide checked against the code**: Carbon applies. SVG images, the `local` disk root,
|
||||
UUIDv7, `mergeIfMissing`, `Concurrency`, `Schema::getTables()` and the token repository are not used or
|
||||
not affected. Diff the skeleton config 11 → 12.
|
||||
3. **[C] Overrides**: diff the vendor originals old → new for every override and published view (Jetstream
|
||||
`HasProfilePhoto`, Matchish, WireChat views, WireUI) and port the changes.
|
||||
4. **[C+V] Tests:**
|
||||
- full suite
|
||||
- the verification command (4.2)
|
||||
- the manual test matrix (4.3), with all 4 themes
|
||||
5. **[C] Rehearsals with `upgrade.sh`:**
|
||||
- a clone of `main` with a copy of the database (success path, rollback before and after going live)
|
||||
- the fictitious Uuro platform
|
||||
- a routine deploy afterwards
|
||||
6. **[V] Test server** (if decided in Phase 0): a real run there, the matrix, and fixes on `laravel-12`.
|
||||
7. **[C] Docs**: `references/UPGRADE_LARAVEL_11_TO_12.md`, versions in `AGENTS.md`.
|
||||
8. **[C+V] Rollout**: see section 6, per instance with `--target origin/laravel-12`; fast-forward `main`
|
||||
when all are done.
|
||||
|
||||
**[V] Commands:**
|
||||
```bash
|
||||
git switch -c laravel-12 main # only after the user agrees: a whole-tree git command
|
||||
composer require laravel/framework:^12.0 cviebrock/eloquent-sluggable:^12.0 cviebrock/eloquent-taggable:^12.0 -W
|
||||
git diff composer.lock | grep -E '"version"' | head # write down every major that moved
|
||||
```
|
||||
|
||||
**[V] Phase 2 is complete when:**
|
||||
- [ ] Laravel 12 runs on every instance
|
||||
- [ ] `upgrade:verify` and the high-priority matrix rows pass on each
|
||||
- [ ] three days without new error types per instance
|
||||
|
||||
### Phase 3: Laravel 13 (separate project, right after Laravel 12 is live) [C]
|
||||
|
||||
1. PHP 8.3 on every instance (from the Phase 0 inventory).
|
||||
2. **WireChat 0.2 → 0.6**:
|
||||
- read the changelogs
|
||||
- re-port the 45 override and view files, the `_finishUpload` override, private attachments and the
|
||||
listeners across profile switches
|
||||
- extend the chat tests first
|
||||
- can be prepared on Laravel 12 (WireChat 0.6 supports `^11|^12|^13`)
|
||||
3. tinker 3, debugbar 4, sluggable/taggable 13; Symfony 7.4/8, Monolog 3.10.
|
||||
4. The official 12 → 13 upgrade guide, checked against the code item by item.
|
||||
5. Same method as Phase 2. **Finish before 2027-02-24.**
|
||||
|
||||
**[V] Commands:**
|
||||
```bash
|
||||
composer require laravel/framework:^13.0 namu/wirechat:^0.6 laravel/tinker:^3.0 \
|
||||
cviebrock/eloquent-sluggable:^13.0 cviebrock/eloquent-taggable:^13.0 -W
|
||||
composer require --dev barryvdh/laravel-debugbar:^4.0 -W
|
||||
```
|
||||
|
||||
**[V] Phase 3 is complete when:**
|
||||
- [ ] Laravel 13 runs on every instance, PHP 8.3+ everywhere
|
||||
- [ ] chat works as before: messages, images, private attachments, profile switches
|
||||
- [ ] `upgrade:verify`, the full suite and the matrix pass
|
||||
- [ ] three days without new error types per instance
|
||||
|
||||
---
|
||||
|
||||
## 4. Verification
|
||||
|
||||
### 4.1 Automated
|
||||
|
||||
**[C]** The full suite: 656 tests, green on Laravel 11. It runs on every phase step and before every rollout.
|
||||
|
||||
### 4.2 Verification command [V idea, C implementation]
|
||||
|
||||
**[V]** A read-only check per area, runnable locally and on every server after each step. Instead of three
|
||||
tinker scripts, **[C]** one artisan command, `php artisan upgrade:verify`, with correct checks and a
|
||||
non-zero exit code on failure:
|
||||
|
||||
| Area | Check |
|
||||
|---|---|
|
||||
| Framework | Laravel and PHP version, `config:merge --all --dry-run` clean |
|
||||
| Profiles and guards | the 4 guards configured; one User, Organization, Bank and Admin load; the `getActiveProfile()` helpers exist |
|
||||
| Permissions | for every `AdminRole` and `OrganizationRole`: each scoped Spatie role with that suffix has **exactly** the same permission set (sorted arrays compared, not the return value of `sort()`); missing scoped roles listed |
|
||||
| White-label | `config('app.timebank_config')` set and its file exists; `platform_name()` is not empty and not `Example Timebank`; `theme_color('brand')` set; `local_pages` and `android_app` present |
|
||||
| Payments | the app's MySQL user may not UPDATE or DELETE `transactions` (reuse `scripts/test-transaction-immutability.sh`) |
|
||||
| Search | a Scout search returns results for each searchable model |
|
||||
| Background | queue sizes per queue; Reverb answers on its port |
|
||||
|
||||
Written in Phase 1 (on Laravel 11), so the baseline is known before the framework changes.
|
||||
|
||||
Done 2026-10-15 (branch `prep-l12-verify`): `php artisan upgrade:verify [--only=area,...]`. Two checks
|
||||
turned out to need care: `organization_roles` is created by `database:update`, not by a migration (a warning
|
||||
when missing), and roles without a scope prefix are base roles and are skipped.
|
||||
|
||||
### 4.3 Manual test matrix [V, trimmed to this application]
|
||||
|
||||
| Area | Cases | Priority |
|
||||
|---|---|---|
|
||||
| Profiles | register, log in and out, switch User → Organization → Bank → Admin and back, session survives the switch | high |
|
||||
| Permissions | admin pages per role, organization and bank manager rights, edit a role and see it take effect | high |
|
||||
| Payments | a payment, balance and history updated, a call paused at zero credits | high |
|
||||
| Chat | message between profiles, image upload (6 MB), message after a profile switch | high |
|
||||
| Search | results in en and nl, a category browse | high |
|
||||
| White-label | all 4 themes; a platform with its own config (the Uuro rehearsal) | high |
|
||||
| Mail | a mailing preview, a test mail per type (`email:send-test`), inactivity mail texts (Carbon) | medium |
|
||||
| PDF | an account statement, a post PDF | medium |
|
||||
| Dates | every date picker (flatpickr) | medium |
|
||||
| Background | queue workers process jobs, Reverb presence, scheduler tasks | medium |
|
||||
|
||||
---
|
||||
|
||||
## 5. Measurements and success criteria [V, adapted]
|
||||
|
||||
**Baseline (Phase 0) and after each rollout** (simple, production-safe, no load test on production):
|
||||
|
||||
| Metric | How |
|
||||
|---|---|
|
||||
| Response time of the home page, a profile page, search, the payment page | `curl -o /dev/null -s -w '%{time_total}'`, 5 runs each, median |
|
||||
| Search time | timed Scout query in tinker |
|
||||
| Queue lag | `Queue::size()` per queue, and the age of the oldest job |
|
||||
| Errors | `.ERROR` count per day in `laravel-<date>.log` |
|
||||
|
||||
**Done when:**
|
||||
- the full suite and `upgrade:verify` pass;
|
||||
- the manual matrix's high-priority rows pass;
|
||||
- no new error types in the log for 3 days;
|
||||
- response times are within 25% of the baseline.
|
||||
|
||||
---
|
||||
|
||||
## 6. Rollout and rollback [C+V]
|
||||
|
||||
- **Order [V]:** local rehearsals → test server (if any) → production → other instances, one at a time.
|
||||
- **Window [V, adapted]:**
|
||||
- production at a quiet moment the admin is awake for (for example an evening, 20:00–22:00 local time),
|
||||
not 02:00
|
||||
- 5 to 15 minutes of maintenance, by the measure of the Laravel 11 upgrade
|
||||
- **Tool [C]:** `scripts/upgrade.sh` from the target branch, run in tmux, with a dry run first.
|
||||
- **Rollback triggers, decided in advance [V]:**
|
||||
- **before going live**, roll back (the database restore is allowed) when:
|
||||
- `deploy.sh` fails and the cause is not fixed within 30 minutes
|
||||
- any high-priority row of the matrix fails
|
||||
- `upgrade:verify` fails
|
||||
- **after going live**, roll back the code only when:
|
||||
- logging in, payments or chat break and a fix is not available within an hour
|
||||
- errors repeat for many users
|
||||
- **Code-only by default after going live [C]:** a database restore deletes payments and messages written
|
||||
since the backup.
|
||||
|
||||
---
|
||||
|
||||
## 7. Communication [V, sized for this platform]
|
||||
|
||||
- **24 hours before**: a short message to users, a post or a banner: date, time, expected few minutes of
|
||||
downtime.
|
||||
- **During**: the maintenance page; the admin tests through the bypass URL.
|
||||
- **After**: a short "done" note only if something visible changed.
|
||||
- **Between the agents [C]**: `.agents/WORKLOG.md` entries per phase step; one agent per step; the user
|
||||
dispatches.
|
||||
|
||||
---
|
||||
|
||||
## 8. Checklists [V, corrected]
|
||||
|
||||
**Before (per instance):**
|
||||
- [ ] Phase 0 inventory done; PHP and disk sufficient
|
||||
- [ ] `upgrade:verify` passes on the current version
|
||||
- [ ] baseline measured
|
||||
- [ ] users informed
|
||||
- [ ] the MySQL root password at hand (no `DB_DEPLOY_*` in `.env`)
|
||||
|
||||
**During:**
|
||||
- [ ] tmux, dry run, real run
|
||||
- [ ] maintenance on
|
||||
- [ ] config merge `y`/`yes`
|
||||
- [ ] restart Reverb, PHP-FPM and workers
|
||||
- [ ] verification and matrix through the bypass
|
||||
- [ ] go or roll back by the triggers
|
||||
|
||||
**After:**
|
||||
- [ ] `upgrade:verify` and measurements
|
||||
- [ ] workers `active`
|
||||
- [ ] logs for 3 days
|
||||
- [ ] fast-forward `main` when all instances are done
|
||||
- [ ] remove the snapshot
|
||||
- [ ] lessons learned added to the upgrade guide
|
||||
|
||||
---
|
||||
|
||||
## 9. Effort (working time, rough) [C, with Vibe's verification work added]
|
||||
|
||||
| Phase | Effort |
|
||||
|---|---|
|
||||
| 0 | 1 to 2 hours (inventory, baseline, decisions) |
|
||||
| 1 | 2 to 3 days (Carbon review, flatpickr, `upgrade:verify`), 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 |
|
||||
|
||||
---
|
||||
|
||||
## 9a. Timeline [V idea, C dates]
|
||||
|
||||
Vibe's hybrid put Laravel 13 live on 2026-10-26. That is too early: Phase 0 depends on the Laravel 11
|
||||
follow-ups (quiet logs until 2026-10-18), and each production change needs a few quiet days before the
|
||||
next one. A realistic schedule, to be confirmed by the user:
|
||||
|
||||
| Phase | Work | Calendar window | Milestone |
|
||||
|---|---|---|---|
|
||||
| 0 | 1 to 2 hours | from 2026-10-19 | inventory, baseline, decisions |
|
||||
| 1 | 2 to 3 days | late October to early November | Carbon 3, flatpickr, clean-up on production |
|
||||
| 2 | 2 to 3 days | November | Laravel 12 on every instance |
|
||||
| 3 | 3 to 5 days | December to January | Laravel 13 on every instance |
|
||||
| deadline | | **before 2027-02-24** | end of Laravel 12 security fixes |
|
||||
|
||||
---
|
||||
|
||||
## 10. What was left out, and why
|
||||
|
||||
| From | Left out | Why |
|
||||
|---|---|---|
|
||||
| Vibe | Livewire 4, Spatie v5 → v6, Reverb 2, Scout 11 migrations | not needed (section 2) |
|
||||
| Vibe | new backup and rollback scripts | `upgrade.sh` already does it, tested |
|
||||
| Vibe | `composer.json` PHP requirement to `^8.3` for Laravel 12 | only Laravel 13 needs it; do it in Phase 3 |
|
||||
| Vibe | load test with 100 concurrent users on production | puts load on the live site; response-time samples are enough here |
|
||||
| Vibe | a 02:00 production window and a status page | the admin must be awake to test and decide; the platform is small |
|
||||
| Vibe's hybrid | running Vibe's three original verification scripts | they read a non-existent config key (`platform_name`) and compare `sort()` return values, so permissions always look in sync; replaced by `upgrade:verify` (4.2) |
|
||||
| Vibe's hybrid | decisions marked as made, "Approved Strategy" | the user has not decided yet (section 11) |
|
||||
| Vibe's hybrid | production at 02:00–04:00, Laravel 13 by 2026-10-26 | see section 6 and the timeline in 9a |
|
||||
| Claude | — | everything kept |
|
||||
|
||||
---
|
||||
|
||||
## 11. Open questions for the user
|
||||
|
||||
1. Which instances exist besides timebank.cc, and on which PHP version?
|
||||
2. Is there a test or staging server, or should one be set up?
|
||||
3. 12 then 13 (recommended), or straight to 13?
|
||||
4. A preferred rollout window for production?
|
||||
5. Should `upgrade:verify` become a permanent command, also useful after normal deploys?
|
||||
|
||||
---
|
||||
|
||||
## 12. How the two hybrid plans differed
|
||||
|
||||
Both hybrids, written at the same time without seeing each other, chose the same structure: Claude's
|
||||
phases (preparation on 11, then 12, then 13) with Vibe's verification and test matrix. The differences,
|
||||
and what this plan uses:
|
||||
|
||||
| Topic | Vibe's hybrid | Claude's hybrid | This plan |
|
||||
|---|---|---|---|
|
||||
| Verification | Vibe's 3 tinker scripts | one `upgrade:verify` command | `upgrade:verify` (correct checks) |
|
||||
| Measurements, rollback triggers, communication | not included | included (from Vibe's own plan) | included |
|
||||
| Completion criteria per phase | yes | overall only | per phase (from Vibe's hybrid) |
|
||||
| Commands per phase | yes | no | yes, corrected |
|
||||
| Timeline | calendar dates, Laravel 13 by 2026-10-26 | effort only | effort plus realistic windows |
|
||||
| Decisions | marked as decided | open | open |
|
||||
| Production window | 02:00–04:00 | an evening the admin is awake | an evening |
|
||||
|
||||
Reference in new issue
Block a user