Verallgemeinerte Erkenntnisse aus einem Ticketdurchlauf einarbeiten

Design-Paritaet 1.5 -> 1.6:
- Site-Set-page.tsconfig erreicht keine Datensaetze in Ordnern neben dem
  Site-Root; solche Konfiguration gehoert in die globale page.tsconfig
  der Extension. Symptom ist, dass eine TCEFORM-Aenderung genau fuer
  einen Datensatztyp wirkungslos bleibt.
- Angebotene und gerenderte Crop-Variante koennen auseinanderlaufen,
  dann beschneidet die Redaktion ins Leere.
- Feste Bildhoehe laesst das Seitenverhaeltnis ueber die Breakpoints
  wandern, sodass kein Zuschnitt mehr ueberall passt; aspect-ratio statt
  fester Hoehe.
- Umbrechende Labels brauchen eine reservierte Zeilenhoehe, sonst
  springt der Rhythmus des Rasters; dabei die Untermarge des Absatzes
  neutralisieren und die schmalste Geraetebreite pruefen, nicht nur 360.
- :has() laesst sich nicht in :has() verschachteln, die Regel wird
  komplett verworfen - ohne jede Fehlermeldung.
- Neuer Abschnitt zu Meldungen, die Rasterartefakte statt Fehler sind:
  gegen die Referenzseite pruefen, ueber mehrere Zoomstufen UND
  Subpixel-Versaetze messen, das Ganze per Canvas in einem Durchgang -
  und rechtzeitig sagen, dass Geometrie es nicht loest.

v11->v14 1.1 -> 1.2:
- Ein "verlorenes" Feld ist oft ein umgebautes Feld; zwei Spalten werden
  gern zu einem Feld plus Schalter. Erst das neue Modell pruefen, bevor
  man eine fremde Extension patcht - dann ist es eine Datenmigration.
  Dazu die abgesicherte UPDATE-Bedingung und der Hinweis, dass Fluid
  keinen !-Operator kennt.
- Vor "Regression" gegen die Referenzseite pruefen: zwei Tickets zum
  selben fehlenden Element koennen Verlust und Neuwunsch sein.

Cutover 1.1 -> 1.2:
- Eingebettete Fremddienste sperren sich per frame-ancestors oft gegen
  Staging. Solche Tests sind dort in keinem Browser moeglich; frueh
  klaeren, den eigenen Anteil trotzdem pruefen.

Redmine 1.3 -> 1.4:
- Textile beendet den Durchstrich am ersten Bindestrich im Text, ein
  Pfeil laesst also die Handlungsaufforderung ungestrichen stehen; HTML
  hilft nicht, Redmine escapt es. Und das Ergebnis nachsehen, die API
  bestaetigt nur die Speicherung.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-07 16:05:42 +02:00
co-authored by Claude Opus 5
parent d91dd97795
commit c1e3a059d3
4 changed files with 101 additions and 4 deletions
+9 -1
View File
@@ -3,7 +3,7 @@ name: redmine-issue-workflow
description: "Read and update issues on a self-hosted Redmine via its REST API from the CLI — list/read tickets, add notes, change status, edit an existing journal note in place, and download attachments. Use when a project tracks its work/bugs in Redmine and you need to look up 'the next fixes', check a ticket's details, mark work done, or maintain a collection ('Sammelticket') ticket. Covers: API-key auth via header (never inline the secret), the issues/journals/attachments endpoints, Textile (NOT Markdown) formatting, localized statuses, and the posting-style rules (keep customer-visible notes minimal — strike through or 'erledigt', don't write the bug's cause; don't post unless asked)." description: "Read and update issues on a self-hosted Redmine via its REST API from the CLI — list/read tickets, add notes, change status, edit an existing journal note in place, and download attachments. Use when a project tracks its work/bugs in Redmine and you need to look up 'the next fixes', check a ticket's details, mark work done, or maintain a collection ('Sammelticket') ticket. Covers: API-key auth via header (never inline the secret), the issues/journals/attachments endpoints, Textile (NOT Markdown) formatting, localized statuses, and the posting-style rules (keep customer-visible notes minimal — strike through or 'erledigt', don't write the bug's cause; don't post unless asked)."
metadata: metadata:
author: Wappler author: Wappler
version: "1.3" version: "1.4"
--- ---
# Redmine issue workflow (REST API, CLI) # Redmine issue workflow (REST API, CLI)
@@ -52,6 +52,14 @@ Redmine renders **Textile** by default. Consequences:
- Strike-through = `-text-` (Markdown `~~…~~` does nothing). - Strike-through = `-text-` (Markdown `~~…~~` does nothing).
- A leading `#` is an **ordered-list** item, not a heading (Markdown `#` headings render as `<ol><li>`). - A leading `#` is an **ordered-list** item, not a heading (Markdown `#` headings render as `<ol><li>`).
- Bold `*text*`, italic `_text_`, inline code `@code@`. - Bold `*text*`, italic `_text_`, inline code `@code@`.
- **⚠ A strike-through ENDS at the first `-` inside the text.** Wrapping a whole sentence that contains
an arrow (`->`) closes the `<del>` right there, leaving the tail — often the action item, "-> please
clarify" — un-struck, i.e. still looking open. Inserting a single space (`. ->`) makes that dash read
as an opener instead and the strike-through runs to the end. **HTML is no way out: Redmine escapes
`<del>` in journal notes and the raw tag shows.**
- **Verify what you wrote actually RENDERED.** The API only tells you the source was stored. Fetch the
issue page with the same API-key header and grep for `<del>` — it renders the Textile server-side, so
you see exactly what the customer sees. Worth it whenever you strike text through in place.
## Posting style (team rules — important) ## Posting style (team rules — important)
- **Don't post unless asked.** The user often does the Redmine updates themselves; offer/confirm first. - **Don't post unless asked.** The user often does the Redmine updates themselves; offer/confirm first.
+12 -1
View File
@@ -3,7 +3,7 @@ name: typo3-staging-to-live-cutover
description: "Promote an approved TYPO3 staging site to production — the go-live step AFTER a staging environment exists. Use when a TYPO3 site is about to go live, when a staging/preview site must become the public site, when asked to clean up a staging server before launch, or when preparing a launch checklist for a shared/managed host. Covers: what must NOT travel to live (DB dumps, one-off SQL/PHP scripts, .bak files, error logs), the environment-specific config that must change (trustedHostsPattern, displayErrors, site base, DB credentials, mail), removing basic-auth/staging locks, indexing and redirects, scheduler and SSL, plus verification and rollback. Assumes the build already runs on staging (see the staging-deploy skill for that)." description: "Promote an approved TYPO3 staging site to production — the go-live step AFTER a staging environment exists. Use when a TYPO3 site is about to go live, when a staging/preview site must become the public site, when asked to clean up a staging server before launch, or when preparing a launch checklist for a shared/managed host. Covers: what must NOT travel to live (DB dumps, one-off SQL/PHP scripts, .bak files, error logs), the environment-specific config that must change (trustedHostsPattern, displayErrors, site base, DB credentials, mail), removing basic-auth/staging locks, indexing and redirects, scheduler and SSL, plus verification and rollback. Assumes the build already runs on staging (see the staging-deploy skill for that)."
metadata: metadata:
author: Wappler author: Wappler
version: "1.1" version: "1.2"
--- ---
# TYPO3 — staging → live cutover # TYPO3 — staging → live cutover
@@ -135,6 +135,17 @@ Every one of these is pinned to staging and silently wrong on live.
--- ---
## Phase 5 — Verify, then keep a way back ## Phase 5 — Verify, then keep a way back
- **⚠ Some things CANNOT be tested before the cutover — find out which, early.** Third-party services
embedded in the site (portals, booking or download systems, maps, payment widgets) commonly restrict
who may frame them via `content-security-policy: frame-ancestors …`, listing only the LIVE domain.
On staging the browser then blocks the embed in **every** browser — it is the provider's
server-side policy, not a browser quirk, so "please test it in Chrome and Edge" is impossible to
fulfil there. Check with `curl -sI <embedded-url> | grep -i content-security-policy`, and confirm in
the console (*"Framing … violates … The request has been blocked"*). Then either ask the provider to
add the staging host, or schedule that test for right after go-live and say so in the ticket rather
than leaving it looking unfinished. **You can still test your own half meanwhile** — that the page
passes the right parameters through, rejects foreign hosts, and survives the extra query parameter
without a cHash error.
- **Rollback plan before the switch**: a final DB dump plus the previous DNS values, written down. - **Rollback plan before the switch**: a final DB dump plus the previous DNS values, written down.
Store the dump outside the docroot and **delete it once the launch is accepted** — otherwise it Store the dump outside the docroot and **delete it once the launch is accepted** — otherwise it
becomes exactly the Phase 1 problem on the live server. becomes exactly the Phase 1 problem on the live server.
+60 -1
View File
@@ -3,7 +3,7 @@ name: typo3-t3bootstrap-live-design-parity
description: "Match a TYPO3 v14 t3bootstrap-based build (local DDEV) to a reference LIVE site page by page — the frontend/design phase after a v11->v14 upgrade. Use when making an upgraded TYPO3 site look like its old/live counterpart, when doing per-page visual parity against a reference URL, when content that exists in the DB isn't rendering after a v11->v14 migration, or when customizing a t3bootstrap sitepackage's templates/SCSS/settings. Covers: the Playwright compare loop (computed style + CSS rule), the settings-vs-SCSS decision, the t3b_core spacing system (spacing.yaml / tx_t3b_spacing) and why spacing must never be fixed in SCSS, recurring structural fixes (stranded colPos, missing templateLayout partials, template partialRootPaths precedence/shadowing, on-demand component CSS, unregistered CTypes), a full visual-parity checklist (layout/width, typography, colors, links/buttons, equal-sizing, icons, borders, footer, header/nav, hero carousel incl. why Bootstrap autoplay cannot be switched off via the interval), diagnosing regressions caused by an editor's SAVE (CKEditor dropping undeclared classes, FlexForm selects with no empty item flipping to "yes"), and cache-safe techniques (full-bleed bands, image-border restyle, responsive crop variants, client-side randomisation, FAL-via-DataHandler). Assumes the site already boots on v14 (see the v11->v14 upgrade skill)." description: "Match a TYPO3 v14 t3bootstrap-based build (local DDEV) to a reference LIVE site page by page — the frontend/design phase after a v11->v14 upgrade. Use when making an upgraded TYPO3 site look like its old/live counterpart, when doing per-page visual parity against a reference URL, when content that exists in the DB isn't rendering after a v11->v14 migration, or when customizing a t3bootstrap sitepackage's templates/SCSS/settings. Covers: the Playwright compare loop (computed style + CSS rule), the settings-vs-SCSS decision, the t3b_core spacing system (spacing.yaml / tx_t3b_spacing) and why spacing must never be fixed in SCSS, recurring structural fixes (stranded colPos, missing templateLayout partials, template partialRootPaths precedence/shadowing, on-demand component CSS, unregistered CTypes), a full visual-parity checklist (layout/width, typography, colors, links/buttons, equal-sizing, icons, borders, footer, header/nav, hero carousel incl. why Bootstrap autoplay cannot be switched off via the interval), diagnosing regressions caused by an editor's SAVE (CKEditor dropping undeclared classes, FlexForm selects with no empty item flipping to "yes"), and cache-safe techniques (full-bleed bands, image-border restyle, responsive crop variants, client-side randomisation, FAL-via-DataHandler). Assumes the site already boots on v14 (see the v11->v14 upgrade skill)."
metadata: metadata:
author: Wappler author: Wappler
version: "1.5" version: "1.6"
--- ---
# TYPO3 v14 t3bootstrap — live-design parity # TYPO3 v14 t3bootstrap — live-design parity
@@ -66,6 +66,30 @@ placeholders below from the site you're matching; keep a per-project log of what
(getComputedStyle + walk `document.styleSheets` for the selector). Don't assume inheritance. (getComputedStyle + walk `document.styleSheets` for the selector). Don't assume inheritance.
3. Diff vs DDEV → decide **setting vs SCSS** (below) → apply → flush → re-screenshot → verify. 3. Diff vs DDEV → decide **setting vs SCSS** (below) → apply → flush → re-screenshot → verify.
## When the report is a rendering artefact, not a defect
Some "it looks broken" reports are sub-pixel rasterisation: a hairline that washes out, a circle whose
cap renders as a straight edge, an outline that vanishes. They are **display-dependent**, which is why
one person sees them and another does not, and why they come and go with the zoom level.
- **First ask whether the reference site does the same.** If live emits the identical asset at the
identical size, it is not a regression — say so before spending a day on it.
- **A single zoom level proves nothing.** An element's box lands on a fractional device-pixel position
that depends on zoom AND on where it sits in the page. A change that looks like a fix at 100 % can
be measurably worse at 120 %. Always sweep several zoom levels **and** several sub-pixel offsets.
- **Measure the whole sweep in ONE call instead of a screenshot per variant.** Build each variant as an
SVG data-URL, `drawImage` it into a canvas at the exact device size and offset, and read the edge
rows with `getImageData`. Same rasteriser as the page, no screenshot round-trips:
```js
ctx.drawImage(img, 0, offset, size, size); // size = base * zoom, offset = 0 … 0.8
const d = ctx.getImageData(0, 0, n, n).data; // then count alpha>128 per row
```
Compare the top and bottom edge rows; a large difference is the asymmetry the user is seeing.
- **Know when to stop and say so.** Geometry often cannot fix it: shrinking a radius just moves the
bad zoom levels, thickening an inner ring changes nothing because the OUTER edge does the
rasterising, and making the icon bigger scales the artefact with it. Report the measurements and let
the customer decide between living with it and redrawing the asset — that is a design decision, not
a bug fix. Do not ship a change that your own numbers say is not an improvement.
## Settings vs SCSS decision ## Settings vs SCSS decision
- **Setting** (`config/sites/<SITE_ID>/settings.yaml`) for anything mapped in the theme's - **Setting** (`config/sites/<SITE_ID>/settings.yaml`) for anything mapped in the theme's
`Configuration/TypoScript/Plugin/Setup/tx_wsscss.typoscript`: `design.color.{primary,secondary, `Configuration/TypoScript/Plugin/Setup/tx_wsscss.typoscript`: `design.color.{primary,secondary,
@@ -184,6 +208,23 @@ rewrite parts of it, and whatever was never expressible in the backend gets norm
## Layer 1 — Structural fixes (content that won't render). Do these FIRST. ## Layer 1 — Structural fixes (content that won't render). Do these FIRST.
These are v11→v14 migration artifacts, not design; they recur across many pages. These are v11→v14 migration artifacts, not design; they recur across many pages.
- **⚠ Site-set page TSconfig does NOT reach records in storage folders beside the site root.** A site
set's `Configuration/Sets/<Set>/page.tsconfig` only applies to pages in that site's ROOTLINE.
Storage folders for news, addresses, jobs are frequently SIBLINGS of the site root under a common
parent, not descendants — so TCEFORM you put in the set never reaches the editing form of those
records, while it visibly works on normal pages. Symptom: your TCA/TCEFORM change "does nothing"
for exactly one record type. **Check the storage folder's pid, not a content page:**
`BackendUtility::getPagesTSconfig(<storagePid>)` in a CLI bootstrap, and compare with a site page.
**Fix:** move it to the extension's **global** `Configuration/page.tsconfig`, which TYPO3 loads for
every page. Load order then decides who wins — your sitepackage must load AFTER the extension you
are overriding (`vendor/bin/typo3 extension:list` to confirm), which it normally does.
- **The crop variant OFFERED to the editor may not be the one RENDERED.** Extensions ship global
page TSconfig that **replaces** the crop variants of a field with the single ratio their own layout
wants. If your templates request a different variant, an editor can crop all day with no effect and
the image is emitted uncropped. Trace BOTH ends before touching anything: which variant the template
asks for (often a setting such as `settings.imageFormat`, with a fallback for the literal value
`default`), and which variants the form offers at that record's pid. They must be the same name.
- **Stranded `colPos=1` (the #1 recurring bug).** v11 content sitting at `colPos 1` (or 2/3) is not - **Stranded `colPos=1` (the #1 recurring bug).** v11 content sitting at `colPos 1` (or 2/3) is not
rendered by the v14 backend layout → the page looks half-empty though the content is in the DB. rendered by the v14 backend layout → the page looks half-empty though the content is in the DB.
Find it site-wide: Find it site-wide:
@@ -239,6 +280,24 @@ These are v11→v14 migration artifacts, not design; they recur across many page
- **Repeated items (cards/teasers/logos/icon tiles):** live usually forces **equal height AND width** - **Repeated items (cards/teasers/logos/icon tiles):** live usually forces **equal height AND width**
across the row (`height:100%` in an equal-height row; images `object-fit:cover` + fixed height; across the row (`height:100%` in an equal-height row; images `object-fit:cover` + fixed height;
logo boxes equal size). DDEV often renders ragged — measure siblings, don't assume. logo boxes equal size). DDEV often renders ragged — measure siblings, don't assume.
- **⚠ A FIXED HEIGHT on a cropped image box drifts in aspect ratio across breakpoints.** The height
stays put while the column width grows, so the same box is e.g. 1.58 on desktop and 1.82 on a
phone — and then **no single crop variant can fit both**, which reads as "the crop is off" on one
device. Use `aspect-ratio: <w> / <h>; height: auto` instead so the box keeps ONE ratio everywhere,
then one crop variant is enough. Measure live's box before choosing the ratio; it usually already
holds a constant one.
- **⚠ Wrapped labels under tiles: reserve the line box, or the grid rhythm breaks.** In a wrapping
Bootstrap row each flex line sizes itself from its tallest item, so one two-line label makes that
whole row taller and the icon-to-icon pitch varies. Give the label `min-height: <maxLines> ×
line-height` **and zero the label `<p>`'s bottom margin** — otherwise that margin is added on
exactly the tiles that actually reach the maximum, which are the ones you were trying to level.
Derive `maxLines` per breakpoint by measuring, and **check the narrowest device (320px), not just
360** — the extra column narrowness there routinely needs one line more.
- **⚠ `:has()` cannot be nested inside `:has()` — the whole rule is silently discarded.** A selector
like `.a:has(.x):has(+ .a:has(.x))` is invalid CSS, so the browser drops it entirely and you get
no error anywhere. Very easy to write when chaining "frame that is followed by another frame"
rules. If a rule seems to have no effect, check the computed value on the element first; a
property that never appears at all points at an invalid selector, not at specificity.
- **background-media hero image** (textmedia with `asBackground`, usually empty text — e.g. section - **background-media hero image** (textmedia with `asBackground`, usually empty text — e.g. section
landing/"Auftraggeber" pages): the image is a CSS background on a grid column sitting on a grey band. landing/"Auftraggeber" pages): the image is a CSS background on a grid column sitting on a grey band.
Live renders it **flush + container-width**; DDEV insets it (frame `t3b-pt-l/pb-l` padding + a Live renders it **flush + container-width**; DDEV insets it (frame `t3b-pt-l/pb-l` padding + a
+20 -1
View File
@@ -3,7 +3,7 @@ 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, when a t3bootstrap-based v11 site needs its composer/config/schema/upgrade-wizards/site-sets brought to v14, or when after such an upgrade a non-admin editor can't edit content (no edit icons / missing Media tab). 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, fixing non-admin editor permissions (be_groups explicit_allowdeny :ALLOW-format conversion, v14 CType allow-list, non_exclude_fields), and the recurring v11->v14 traps. NOT for fresh installs and NOT for server deployment (see the konsoleH staging-deploy skill for that)." 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, when a t3bootstrap-based v11 site needs its composer/config/schema/upgrade-wizards/site-sets brought to v14, or when after such an upgrade a non-admin editor can't edit content (no edit icons / missing Media tab). 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, fixing non-admin editor permissions (be_groups explicit_allowdeny :ALLOW-format conversion, v14 CType allow-list, non_exclude_fields), and the recurring v11->v14 traps. NOT for fresh installs and NOT for server deployment (see the konsoleH staging-deploy skill for that)."
metadata: metadata:
author: Wappler author: Wappler
version: "1.1" version: "1.2"
--- ---
# TYPO3 v11 → v14 upgrade (local, DDEV) # TYPO3 v11 → v14 upgrade (local, DDEV)
@@ -174,5 +174,24 @@ found" is usually a false alarm from curling `localhost`** instead of `<SITE_BAS
Bootstrap::init + the record API). Bootstrap::init + the record API).
- **TYPO3 Console** (`helhum/typo3-console` ^8.3) works with v14 — `vendor/bin/typo3` is the console - **TYPO3 Console** (`helhum/typo3-console` ^8.3) works with v14 — `vendor/bin/typo3` is the console
binary. binary.
- **⚠ A "lost" field is often a REMODELLED field — check the new data model before patching anything.**
Editors report that something they used to maintain has disappeared, you find the old column still
sitting in the DB with data and no v14 code referencing it, and the obvious conclusion is that the
extension dropped the feature and needs an upstream fix. Look for the v14 equivalent first: two v11
columns are frequently folded into **one field plus a switch** (real case: separate columns for a
pre- and post-nominal academic title became one title field plus an "append" boolean). Then it is a
data migration, not a code change — and no release of a shared extension is needed.
- Guard the migration so it cannot destroy the other use of the surviving field:
`SET <new> = <old>, <flag> = 1 WHERE <old> <> '' AND (<new> = '' OR <new> IS NULL)`, and verify
afterwards that no row was touched which should not have been.
- **Then check whether anything RENDERS the switch.** A flag that no template evaluates — not even
the owning extension's own templates — is exactly why the data looked lost. Grep the templates for
the property before assuming the display side works.
- Fluid has **no `!` operator**: write `{x} && {flag} == 0` / `== 1`, not `!{flag}`.
- **⚠ Verify against the reference site before calling something a regression.** Two tickets can
describe the same missing element and be different things: on one page the old site really did show
it (a migration loss), on another it never did (a new wish). Fetch the live page and count the
occurrences. It changes what you promise, and it saves the "why does it look different from before"
conversation later.
Each step verified + a snapshot before wizards = a reversible, debuggable upgrade. Each step verified + a snapshot before wizards = a reversible, debuggable upgrade.