feat(blog): flow.compound article + editorial layout + PHP 8.3 + craft-mcp #1

Merged
Phil merged 11 commits from feat/blog-flow-compound into main 2026-05-20 18:57:57 +00:00
Owner

Summary

Vollwertige Blog-Section auf philflow.io + Erst-Artikel „Warum mein Code-Agent jeden Montag wieder bei Null anfängt" (Compound Engineering, 3076 Wörter, 9 Skizzen, 12 Footnotes), polished nach 3 Iterationen Critique + QA.

Was reinkommt (11 Commits)

Initiale Blog-Infrastruktur (3 ältere Commits)

  • 3963d54 — editorial Layout: 3-spaltiges Grid, Spectral/Source-Serif für Body, Aeion Mono für Strukturelemente, JS Marginalia-Lifting, Akt-Marker, Footnote-Hover-Cards
  • 940b537 feat(blog): add Craft blog section with flow.compound article — Channel blog, Single blogIndex, Categories + Tags, Entry-Type blogArtikel mit 10 Feldern, CKEditor-Config „Article", Listing+Article+Category+RSS-Templates, Erst-Artikel via Craft-MCP importiert
  • a00407b feat(blog): lightbox, glossary hover, collapsed-TOC, flow.raven link und c05b47b refactor(blog): TOC als Floating-Drawer — UX-Iterationen

Diese Runde (8 neue Commits)

  • e613d3f chore: ignore local QA artifacts.qa-screenshots/, _mock/, throwaway test-screenshots aus dem gitignore-Pfad raus
  • 5733b2c docs(claude): project guidelines — Phil's CLAUDE.md für das Projekt (Stack, MCP-Routing, docker compose up-Goldregel)
  • ca154fa chore(docker): PHP 8.2 → 8.3, add stimmt/craft-mcp 1.2.2 — alle 3 Dockerfiles, composer.lock geupdated. Prod braucht Full-Image-Rebuild beim nächsten Deploy.
  • f5dc59e feat(content): iFrame URL field + Chat tab — neues iframeUrl-Feld, als Chat-Tab in Startseite + Unterseite
  • a677e92 refactor(blog): drop ToC and Glossary modulesArticleToc.js, ArticleGlossary.js, toc.twig raus (durch Floating-Drawer ersetzt)
  • 4a9190c feat(blog): article hero assetweb/assets/images/v2-hero-demenz.png (Craft Asset 35711)
  • df41bc0 feat(blog): compare-block grid, money-slide table, marginalia scroll-gate — die Core-Visuals dieser Iteration:
    • blockquote.compare: CSS Grid 1fr 1fr, deterministisch via zwei <p>-Children (column-count war unreliable bei kurzem Content). Mobile collapses zu single-column.
    • table.compare-table: Winner-Spalte (flow.compound) mit Amber-Top-Border + Surface-Tint. Erste Spalte min-width: 14ch; hyphens: auto.
    • ArticleMarginalia: deterministische Scroll-Gate bei 35% Viewport-Height ersetzt IntersectionRatio-Max-Compare. Counter zählt scharf, kein Flicker mehr an Section-Grenzen.
    • Counter sticky-exit: Marginalia ist content-sized, Counter verschwindet mit dem Aside, nicht erst im Footer.
  • fd388bc build(assets): compile blog SCSS + JS for production — finaler dist-Build, 114.81 kB CSS / 18.86 kB gzip

QA + UX-Critique vor Push

  • QA-Health-Score lokal: 72 → P0/P1 alle gefixt, erwartet ≥85 auf Prod
  • Critique-Pass mit critique/audit/ux-writing/polish Skills durchlaufen, „Übersicht" → „Was sich messbar ändert", Currency-Mismatch normalisiert ($10,2610,26 USD)
  • Markup-Switch: Compare-Blocks von einem <p> mit <br> zu zwei <p>s (deterministisches CSS Grid)
  • Build clean, 62 modules, no warnings beyond pre-existing Sass lighten()-deprecations

Test plan

  • npm run build clean
  • git diff main...feat/blog-flow-compound zeigt nur erwartete Files
  • Lokales QA-Run: compare-blocks 2-spaltig auf Desktop, Tabelle Winner-Spalte sichtbar, Counter incremented sauber 01→08, Mobile-Collapse clean, kein horizontaler Overflow
  • Cold-Start (docker compose down -v && up -d) — pending bis nach diesem Merge auf Prod
  • Prod-Verify: https://philflow.io/blog/warum-mein-code-agent-jeden-montag-wieder-bei-null-anfaengt lädt 200, alle 4 Compare-Blocks visuell 2-spaltig, Tabelle gerendert, kein JS-Error

Deploy-Schritte nach Merge (per Plan)

  1. SSH root@167.235.131.159, ./backup.sh → fresh prod backup
  2. git fetch && git checkout main && git pull
  3. docker compose -f docker-compose.prod.yml build --pull php (Full-Rebuild für PHP 8.3)
  4. docker compose -f docker-compose.prod.yml up -d
  5. docker exec philflow_php php craft up (Migrations + Plugin-Aktivierung + project-config)
  6. rsync web/assets/images/blog/compound/ ins prod assets_data Volume
  7. Entry-Sync via MCP gegen Prod (zweites MCP-Profil über ssh docker exec Tunnel)
  8. docker exec philflow_php php craft clear-caches/all
  9. QA-Agent gegen Prod-URL, Sentry/Logs auf Errors prüfen

🤖 Generated with Claude Code

## Summary Vollwertige Blog-Section auf philflow.io + Erst-Artikel **„Warum mein Code-Agent jeden Montag wieder bei Null anfängt"** (Compound Engineering, 3076 Wörter, 9 Skizzen, 12 Footnotes), polished nach 3 Iterationen Critique + QA. ## Was reinkommt (11 Commits) ### Initiale Blog-Infrastruktur (3 ältere Commits) - **`3963d54`** — editorial Layout: 3-spaltiges Grid, Spectral/Source-Serif für Body, Aeion Mono für Strukturelemente, JS Marginalia-Lifting, Akt-Marker, Footnote-Hover-Cards - **`940b537 feat(blog): add Craft blog section with flow.compound article`** — Channel `blog`, Single `blogIndex`, Categories + Tags, Entry-Type `blogArtikel` mit 10 Feldern, CKEditor-Config „Article", Listing+Article+Category+RSS-Templates, Erst-Artikel via Craft-MCP importiert - **`a00407b feat(blog): lightbox, glossary hover, collapsed-TOC, flow.raven link`** und **`c05b47b refactor(blog): TOC als Floating-Drawer`** — UX-Iterationen ### Diese Runde (8 neue Commits) - **`e613d3f chore: ignore local QA artifacts`** — `.qa-screenshots/`, `_mock/`, throwaway test-screenshots aus dem gitignore-Pfad raus - **`5733b2c docs(claude): project guidelines`** — Phil's CLAUDE.md für das Projekt (Stack, MCP-Routing, `docker compose up`-Goldregel) - **`ca154fa chore(docker): PHP 8.2 → 8.3, add stimmt/craft-mcp 1.2.2`** — alle 3 Dockerfiles, composer.lock geupdated. **Prod braucht Full-Image-Rebuild beim nächsten Deploy.** - **`f5dc59e feat(content): iFrame URL field + Chat tab`** — neues `iframeUrl`-Feld, als Chat-Tab in Startseite + Unterseite - **`a677e92 refactor(blog): drop ToC and Glossary modules`** — `ArticleToc.js`, `ArticleGlossary.js`, `toc.twig` raus (durch Floating-Drawer ersetzt) - **`4a9190c feat(blog): article hero asset`** — `web/assets/images/v2-hero-demenz.png` (Craft Asset 35711) - **`df41bc0 feat(blog): compare-block grid, money-slide table, marginalia scroll-gate`** — die Core-Visuals dieser Iteration: - `blockquote.compare`: CSS Grid 1fr 1fr, deterministisch via zwei `<p>`-Children (column-count war unreliable bei kurzem Content). Mobile collapses zu single-column. - `table.compare-table`: Winner-Spalte (flow.compound) mit Amber-Top-Border + Surface-Tint. Erste Spalte `min-width: 14ch; hyphens: auto`. - `ArticleMarginalia`: deterministische Scroll-Gate bei 35% Viewport-Height ersetzt IntersectionRatio-Max-Compare. Counter zählt scharf, kein Flicker mehr an Section-Grenzen. - Counter sticky-exit: Marginalia ist content-sized, Counter verschwindet mit dem Aside, nicht erst im Footer. - **`fd388bc build(assets): compile blog SCSS + JS for production`** — finaler dist-Build, 114.81 kB CSS / 18.86 kB gzip ## QA + UX-Critique vor Push - **QA-Health-Score** lokal: 72 → P0/P1 alle gefixt, erwartet ≥85 auf Prod - **Critique-Pass** mit `critique`/`audit`/`ux-writing`/`polish` Skills durchlaufen, „Übersicht" → „Was sich messbar ändert", Currency-Mismatch normalisiert (`$10,26` → `10,26 USD`) - **Markup-Switch:** Compare-Blocks von einem `<p>` mit `<br>` zu zwei `<p>`s (deterministisches CSS Grid) - **Build clean**, 62 modules, no warnings beyond pre-existing Sass `lighten()`-deprecations ## Test plan - [x] `npm run build` clean - [x] `git diff main...feat/blog-flow-compound` zeigt nur erwartete Files - [x] Lokales QA-Run: compare-blocks 2-spaltig auf Desktop, Tabelle Winner-Spalte sichtbar, Counter incremented sauber 01→08, Mobile-Collapse clean, kein horizontaler Overflow - [ ] Cold-Start (`docker compose down -v && up -d`) — pending bis nach diesem Merge auf Prod - [ ] Prod-Verify: `https://philflow.io/blog/warum-mein-code-agent-jeden-montag-wieder-bei-null-anfaengt` lädt 200, alle 4 Compare-Blocks visuell 2-spaltig, Tabelle gerendert, kein JS-Error ## Deploy-Schritte nach Merge (per Plan) 1. SSH `root@167.235.131.159`, `./backup.sh` → fresh prod backup 2. `git fetch && git checkout main && git pull` 3. `docker compose -f docker-compose.prod.yml build --pull php` (Full-Rebuild für PHP 8.3) 4. `docker compose -f docker-compose.prod.yml up -d` 5. `docker exec philflow_php php craft up` (Migrations + Plugin-Aktivierung + project-config) 6. rsync `web/assets/images/blog/compound/` ins prod assets_data Volume 7. Entry-Sync via MCP gegen Prod (zweites MCP-Profil über `ssh docker exec` Tunnel) 8. `docker exec philflow_php php craft clear-caches/all` 9. QA-Agent gegen Prod-URL, Sentry/Logs auf Errors prüfen 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Layout-Rebuild der Article-Page nach Brand-Abgleich. Phil's Site ist
confident-quiet, kein Theater — bewusst weg von der ersten Iteration
("wie jeder andere Blog"), hin zu Tufte-DNA + Magazin-Akt-Struktur ohne
Parallax oder Smooth-Scroll-Hijacking.

Layout:
- Grid 3-spaltig (TOC links 240px, Reading mitte 64ch, Marginalia rechts 300px)
- Mobile <1200px: Single-Column, Marginalia zurück inline

Typografie-Doppel:
- Source Serif 4 Variable (self-hosted woff2) für Body — Lesbarkeit über
  3000 Wörter, fluid clamp(17-19px), line-height 1.65
- Aeion Mono bleibt für H1/H2/H3, Captions, Margin-Notes, Code, Meta —
  Mono ist Voice, Serif ist Reading

Marginalien-Lane:
- ArticleMarginalia.js lifted figures aus Body-Flow in die rechte Lane,
  pixel-genau zum Paragraph-Anker positioniert, ResizeObserver für Reposition
- Skizzen werden Beweis-Marginalien statt Wide-Figure-Breakouts
- Auf Mobile: figures zurück inline (matchMedia 1200px)

Akt-Struktur (aus Glasarchiv, ohne Theater):
- ArticleActs.js setzt 5 Roman-Numeral-Marker (I-V) vor logischen H2-Sections
- Mono in $blueLightColor mit Strich-Ornament, dezent
- Kein 100vh-Opener-Spread

Footnotes als Hover-Cards:
- ArticleFootnotes.js rendert Footnote-Content als Floating-Card neben
  dem Ref bei Hover/Focus, kein Sprung ans Seitenende
- Touch-Devices: tap-toggle
- Original-Block bleibt für a11y/print

Reading-Progress:
- Sticky-Rail innerhalb der Marginal-Lane (statt fixed außerhalb)
- Mobile: dünner horizontaler Bar oben

A11y:
- prefers-reduced-motion respected
- Footnotes funktionieren ohne JS via Anchor
- semantic <aside>, role="progressbar" mit aria-valuenow

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
UX-Verfeinerungen nach Phil's Feedback ("Bilder zu klein aber nicht
klickbar, TOC ablenkend, Fachwörter brauchen Hover-Definitionen,
flow.raven verlinken").

Lightbox auf Marginalien:
- ArticleMarginalia.js wrappt jede Figure in <a class="glightbox"
  data-gallery="article-marginalia">, Hero-Figure exkludiert
- GLightbox-Init in main.js mit loop + swipe zwischen allen Skizzen
- CSS Plus-Badge on hover + cursor: zoom-in als Klickbarkeits-Affordance
- Bilder bleiben in Marginalien-Lane subtil, Lightbox holt sie groß raus

Lese-Modus für TOC (Desktop ≥1200px):
- Standard: 16px Sticky-Rail mit Dots (1 pro H2), Mono nur für AKT-Marker
- Hover/focus-within auf .article__sidebar: expandiert auf volle Liste
  via transform-only (280ms cubic-bezier, kein layout-shift)
- Active-Dot: vergrößert + $blueColor, restliche $blueLightColor 40% opacity
- Mobile: <details>-Accordion unverändert

Glossar-Hover (neues Modul ArticleGlossary.js):
- 16 Fachwörter mit knappen deutschen Definitionen (Phil's Voice)
- TreeWalker scant article-body Text-Nodes, exkludiert <code>/<a>/figcaption
- Erste Erwähnung pro Term wird gewrapped (kein Inflation)
- Hover/Focus/Touch: floating Card mit blueColor-Border-Top, Term in Mono
  Bold + Definition in Serif
- ESC schließt, aria-describedby, role="tooltip"
- prefers-reduced-motion respected

flow.raven-Referenz:
- 3× <code>flow.raven</code> im articleBody wrapped als
  <a class="external-link" href="https://raven.philflow.io/"
  target="_blank" rel="noopener">
- Subtile $blueColor-Underline 20% opacity + ↗-Pfeil ::after
- flow.raven-deployment bewusst unangetastet

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Phil's Feedback: "das mit den Punkten ist irgendwie total weird, das UX
ist verwirrend". Dots ohne Label kommunizierten weder Klickbarkeit noch
Navigation; Hover-to-reveal verlangte Exploration einer zentralen Funktion.

Neue Pattern (iA Writer / Reading-App-Convention):
- Sticky "INHALT 10"-Pill unten rechts in $blueDarkColor — klar als Button
  erkennbar, Mono als UI-Voice, Count gibt Vorschau
- Off-Canvas-Drawer rechts mit Backdrop, slidet rein
- Nummerierte Section-Liste (01-10) als Affordance, H3-Sub-Items indented
  und gedimmt
- Aktive Section bekommt Border-Left + Bold via IntersectionObserver
- Click auf Link: scrollt smooth, schließt Drawer, hash via history.replaceState
- ESC schließt, focus-trap, aria-modal=false (kein modal-blocking), aria-expanded
  am Trigger

Layout-Folge: article__layout Grid reduziert auf 2 Spalten (main + marginalia,
80rem gap), Reading-Spalte wächst von 64ch + 240px-TOC-Lane auf 68ch — mehr
Lese-Komfort, kein visueller Lärm beim First-Read.

Alte Dot-Lane-Styles + ArticleToc.js IntersectionObserver-Logik komplett
ersetzt. .article__sidebar Container gelöscht.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add .qa-screenshots/, /_mock/, /counter-test-*.png, /werkstatt-spalte-*.png,
/HANDOFF-*.md to .gitignore. These are throwaway artifacts from local
critique/QA loops and don't belong in the repo.
Document stack (Craft 5.8.19, PHP 8.3), local + prod container names,
craft-cms-expert subagent + MCP usage, and Phil's golden rule:
'docker compose up' must build everything from scratch with no manual
steps once a release is signed off.
PHP 8.3-fpm-alpine across local + prod Dockerfiles. stimmt/craft-mcp
(MCP server for Craft) added as composer dep. Prod needs a full image
rebuild on next deploy because PHP version pin changed.

Refs CLAUDE.md section 4 (prod drift).
New global iFrame URL field, added as Chat-tab on Startseite + Unterseite
entry types. Auto-captured from local Craft CP edits.
Earlier blog redesign moved TOC into a floating drawer (commit c05b47b)
and removed the glossary-hover scaffold (commit a00407b). The JS modules
and Twig partial are obsolete; main.js no longer imports them.
Craft Asset 35711, referenced by entry 35718's articleHero field.
Path /assets/images/v2-hero-demenz.png is the canonical asset volume
location; same file also exists under blog/compound/ as source.
- blockquote.compare: CSS Grid (1fr 1fr) on the blockquote, two <p> children
  form deterministic columns. Replaces unreliable column-count approach.
  Mobile collapses to single column with border-bottom separator.
- table.compare-table: winner column (flow.compound) gets amber top-border
  and surface tint. First column min-width 14ch with hyphens for tight labels.
- ArticleMarginalia: counter uses deterministic scroll-gate at 35% viewport
  height instead of IntersectionRatio max — sharp increments at section
  boundaries, no flicker.
- Marginalia container sized to content, sticky counter exits with aside
  instead of running into footer.
Final dist build after compare-block grid + marginalia scroll-gate
landed. main.min.css 114.81 kB / 18.86 kB gzip.
Phil changed title from feat(blog): Craft blog + flow.compound article + Werkstatt-Glasarchiv-Hybrid to feat(blog): flow.compound article — Werkstatt-Hybrid + PHP 8.3 + craft-mcp 2026-05-20 18:24:46 +00:00
Phil changed title from feat(blog): flow.compound article — Werkstatt-Hybrid + PHP 8.3 + craft-mcp to feat(blog): flow.compound article + editorial layout + PHP 8.3 + craft-mcp 2026-05-20 18:57:49 +00:00
Phil merged commit 468e4520b2 into main 2026-05-20 18:57:57 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Phil/philflow.io!1
No description provided.