Initial commit: TYPO3 v11→v14 upgrade / design-parity / konsoleH-deploy skills

Three reusable, placeholder-based Claude Code skills distilled from the IVV
Aachen TYPO3 v11→v14 project:
- typo3-v11-to-v14-ddev-upgrade
- typo3-t3bootstrap-live-design-parity (v1.1)
- typo3-konsoleh-staging-deploy

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-20 12:01:06 +02:00
commit 4e4af79e4f
4 changed files with 574 additions and 0 deletions
+133
View File
@@ -0,0 +1,133 @@
---
name: typo3-v11-to-v14-ddev-upgrade
description: "Bring an existing TYPO3 v11 site up and booting on TYPO3 v14 LTS (v14.3) locally under DDEV, starting from a v11 SQL dump + the old sitepackage. Use when upgrading/migrating a TYPO3 v11 (or v12/13) project to v14 for local dev, when a v11 database dump must be made to boot on v14, or when a t3bootstrap-based v11 site needs its composer/config/schema/upgrade-wizards/site-sets brought to v14. Covers: composer.json rework to ^14 + private git repos & composer registry auth, config/system/settings.php, the v14 .htaccess, database:updateschema, backend admin, upgrade wizards (incl. confirmable + one-way ones), language packs, wiring t3bootstrap TypoScript via site sets, and the recurring v11->v14 traps. NOT for fresh installs and NOT for server deployment (see the konsoleH staging-deploy skill for that)."
metadata:
author: Wappler
version: "1.0"
---
# TYPO3 v11 → v14 upgrade (local, DDEV)
Get an existing **TYPO3 v11 site** installable and **booting on v14 LTS (14.3.x)** under **DDEV**,
from a **v11 SQL dump** + the old sitepackage. This is the "make it run" phase — a later phase
matches the frontend design (see the *t3bootstrap live-design parity* skill) and another deploys to
staging (see the *konsoleH staging-deploy* skill).
Work **one step at a time and verify each** before moving on. **`ddev snapshot` before anything
destructive** (especially upgrade wizards — several are one-way). Never let a live secret appear in a
command. Many errors here look like config bugs but are data/schema/host issues — always confirm the
*actual* error before "fixing".
## Placeholders to resolve first
- `<PROJECT_DIR>` — the DDEV project root (docroot `public/`).
- `<SITE_ID>` — the site identifier folder under `config/sites/<SITE_ID>/`.
- `<SITE_BASE_HOST>` — the site's base host from `config/sites/<SITE_ID>/config.yaml` (e.g. the
`*.ddev.site` host). The FE only answers on this host, NOT `localhost`.
- `<REGISTRY_URL>` — the private Composer registry for the theme/vendor packages, if any (e.g. a
Gitea `.../api/packages/<vendor>/composer` URL). `<GIT_REPOS>` — any `gitea@`/GitHub SSH git repos
in `composer.json` `repositories`.
- `<TEMPLATE_PACKAGE>` — the sitepackage's composer `name` (⚠ often ≠ repo name — read the repo's
own `composer.json`). `<TEMPLATE_EXTKEY>` — its extension key (keep it stable across the rename).
---
## Step 0 — DDEV up + import the dump (read-only baseline)
`ddev start`; import the v11 dump into the `db` database (`ddev import-db --file=dump-*.sql` or
`ddev mysql < dump.sql`). Confirm PHP/DB versions match the target (v14.3 wants PHP 8.28.5). Snapshot:
`ddev snapshot --name pre-upgrade`.
## Step 1 — Rework `composer.json` for v14
- Bump every `typo3/cms-*` to `^14`. Bump third-party exts (news, address, t3bootstrap/*, …) to their
^14 releases. Drop anything with no v14 release (e.g. **flux/vhs are gone in v14 t3bootstrap**
`t3bootstrap/flux-*` do not exist; do not re-add them).
- **Custom-repo package name ≠ repo name.** A git repo `…/<name>.git` may publish itself as a
*different* composer package name — read the repo's `composer.json` `name` and require THAT.
- **Contradictory constraints fail:** `"^14 dev-release/v14"` (tag AND branch) → composer "cannot
possibly match". Use plain `"^14"` for a tagged package, or `"dev-<branch>"` for an untagged one.
- **Repository order controls the source.** If the same package name is served by both a git repo and
the registry, composer takes the **first** repo listed as canonical → list the project's git repo
**before** the composer registry in `repositories` to make it win.
## Step 2 — Composer auth
- SSH git repos: `ddev auth ssh` (loads your keys into the DDEV agent; covers `gitea@…`/GitHub).
- Private registry: `ddev composer config http-basic.<registry-host> <user> <token>` (writes the
project `auth.json`). Get the token from the user — never invent/guess it.
## Step 3 — Install
`ddev composer update -W` (resolve + install with dependencies). Fix constraint conflicts per Step 1.
## Step 4 — Create `config/system/settings.php`
v14 does **not** auto-write `settings.php`; `ConfigurationManager` reads it if present, else falls
back to the old `typo3conf/LocalConfiguration.php` in place — so a v11→v14 jump with **production DB
creds** in the old file fails to boot first. Create `settings.php` from the old
`LocalConfiguration.php`, but with **DDEV DB creds** (host `db`, name `db`, user `db`, pass `db`, port
3306, `utf8mb4`). Preserve `SYS/encryptionKey`, install-tool password, sitename, systemMaintainers,
mail sender, and per-extension `EXTENSIONS` config. Drop obsolete v11 feature flags.
## Step 5 — Replace `public/.htaccess`
Swap in the v14 template:
`cp vendor/typo3/cms-install/Resources/Private/FolderStructureTemplateFiles/root-htaccess public/.htaccess`.
Symptom of the stale v11 `.htaccess`: Apache **500 "Request exceeded the limit of 10 internal
redirects"** (looks like a config error; it's the htaccess).
## Step 6 — Update the DB schema
`ddev exec vendor/bin/typo3 database:updateschema "*.add,*.change"` — adds the ~20 tables v12v14 need
(e.g. `sys_csp_resolution`). Non-destructive (add/change only). Symptom if skipped:
`Table 'db.sys_csp_resolution' doesn't exist` on any backend request.
## Step 7 — Backend admin
`ddev exec vendor/bin/typo3 backend:createadmin <user> <pass>` (or `backend:resetpassword` if an admin
already exists in the dump). Do NOT create admin users the user didn't ask for on shared/live systems;
local DDEV is fine.
## Step 8 — Upgrade wizards (⚠ snapshot first)
`ddev snapshot --name pre-upgradewizards`. Then `vendor/bin/typo3 upgrade:list` and run wizards:
- **`upgrade:run` gates on a "Database Up-to-Date" prerequisite** → clear data blockers, re-run
`database:updateschema`, then `upgrade:run`. Blockers commonly seen:
- `tx_news_domain_model_news.related_links` NULL/non-int → `UPDATE … SET related_links=0 WHERE
related_links IS NULL OR NOT related_links REGEXP '^[0-9]+$'`.
- `sys_category_record_mm` duplicate PK tuples (table has no `uid`) → add a temp AUTO_INCREMENT PK,
`DELETE` via self-join keeping the lowest, drop the temp column.
- **Confirmable wizards** (e.g. `convertHeadersize`, `rewriteIconPaths`) error *"You have to
acknowledge this wizard"* under `--no-interaction`. There is **no `--confirm` flag** (`--confirm all`
throws). Run interactively with piped input: `printf 'yes\n' | ddev exec vendor/bin/typo3
upgrade:run <id>` (omit `--no-interaction`).
- **One-way wizards** (e.g. container migration, address→contacts) — the snapshot is your only undo.
- **news 14.0.x vs `FlexFormTools::cleanFlexFormXML()`**: older news calls it with 3 args, v14.3 wants
4 → blocks `txNewsPluginUpdater`. Fix: update news to a patched 14.x, or one-time-patch the vendor
`PluginUpdater` (the wizard marks itself done; the patch is then harmless if reverted).
## Step 8b — Language packs
`ddev exec vendor/bin/typo3 language:update`. Composer mode ships **no** language packs → labels fall
back to English (e.g. news "more-link"). Run this whenever the site language isn't English.
## Step 9 — Wire TypoScript via site sets
v14 t3bootstrap delivers TypoScript (incl. the `PAGE` object) through **site sets**, not `sys_template`.
The site config must declare them under `dependencies:` in `config/sites/<SITE_ID>/config.yaml`, or the
FE dies with **"No page configured for type=0"**. Add the set identifiers (the `name:` in each ext's
`Configuration/Sets/*/config.yaml` — independent of package name/extkey), e.g. the theme set +
container-bs5-templates + news/form/address/blog/slider as used. See the design skill for details.
## Step 10 — Flush + verify
`ddev exec vendor/bin/typo3 cache:flush`. Verify over HTTP with the **correct host**: `/typo3/` → 200,
FE with `curl -H "Host: <SITE_BASE_HOST>" …` (or the real DDEV URL) → 200. **"No site configuration
found" is usually a false alarm from curling `localhost`** instead of `<SITE_BASE_HOST>`.
---
## Other recurring traps
- **Leftover custom content element with no v14 provider → FE fatal** empty-`templateName`
`InvalidTemplateResourceException`. Don't assume it's flux — check the old sitepackage; a plain
custom FSC CType must be re-registered for v14 (see the design skill's iconmenu example).
- **Relocating a git-repo package's vendor path:** change the `name` in *that repo's own*
`composer.json` (composer installs by declared name, not repo URL). Keep the `extension-key`
unchanged so `EXT:<key>/…` refs + set names keep working. Untagged repo → require `dev-<branch>`.
- **v14 FlexForm relational fields:** `FlexFormFieldValues::get()` returns a `LazyRecordCollection` /
`RecordInterface` for relation fields (NOT a CSV of uids), which breaks `intExplode()`/`(int)` casts
in migrated/old ext code → `TypeError`. Normalize to `(string)`/`(string)$record->getUid()` before
parsing. Reproduce/verify from CLI with a small bootstrap script (SystemEnvironmentBuilder::run +
Bootstrap::init + the record API).
- **TYPO3 Console** (`helhum/typo3-console` ^8.3) works with v14 — `vendor/bin/typo3` is the console
binary.
Each step verified + a snapshot before wizards = a reversible, debuggable upgrade.