- Astro 6 + React + Tailwind v4 Projekt-Skelett mit allen Marketing-Seiten (Home, Module, Tester, Souveränität, Roadmap, Kontakt, Impressum, Datenschutz) - Self-hosted Outfit + JetBrains Mono Fonts (DSGVO) - Marketing-Komponenten gemäss CLAUDE.md §5.6 (NumberedItem, ModuleCard, StatusDot, TechStrip, SovereigntyBlock, RoadmapTimeline, etc.) - Module-Daten in src/content/module.ts als Single Source of Truth - E2E Smoke-Tests via Playwright - OG-Image-Generator - Forgejo Workflow .forgejo/workflows/deploy.yml für Tier-2 Static Deploy - Infra-as-Code Snapshot in infra/marketing-vps/ - Brand-System Submodule auf Forgejo umgezogen (war GitHub) - Deployment- und Handoff-Dokumentation - .DS_Store aus Tracking entfernt, .gitignore um Test-Artefakte ergaenzt
25 KiB
Phase 0 — Handoff
Stand: 2026-05-04
Was funktioniert
- Astro 6.2.2 mit Static-Output,
@astrojs/react,@astrojs/sitemap,@astrojs/mdx - Tailwind v4 via
@tailwindcss/vite— alle Design-Tokens im@theme inline-Block insrc/styles/global.css - Self-hosted Fonts in
public/fonts/: Source Serif 4 Variable, Inter Variable, JetBrains Mono Variable (latin + latin-ext). Kein Google Fonts CDN. - Design-Tokens aus
digiformer-brand-system.mdkorrekt umgesetzt: Electric Persimmonoklch(0.71 0.22 38), Text-on-Accent#2A0F02, alle Surface-/Text-/Border-Token - shadcn/ui-Primitives: Button (3 Varianten: default/secondary/ghost), Input, Textarea, Label, Dialog — alle mit Brand-Token statt hardcodierten Farben
- BaseLayout mit korrektem
<head>(OG-Tags, hreflang, canonical, font-preload), NavBar, Footer - NavBar: sticky, Mono-Wortmarke, 4 Nav-Links, DE/EN-Switcher (EN ausgegraut), CTA-Button, Hamburger-Icon mobil, Border-on-scroll
- Footer: 4-Spalten (Marke, Produkt, Stack, Kontakt), Bottom-Bar mit Copyright + Impressum/Datenschutz
- Home (
index.astro): Hero-Sektion mit Eyebrow, H1 (Persimmon-Akzent auf "Grenzenlos"), Lead-Text, zwei CTAs pnpm devläuft auflocalhost:4321, Typografie und Farben visuell verifiziert- Astro-Telemetrie deaktiviert
Verzeichnisstruktur
src/
├── components/
│ ├── primitives/ ← Button, Input, Textarea, Label, Dialog (React)
│ ├── marketing/ ← NavBar.astro, Footer.astro
│ └── islands/ ← (leer, für Phase 3: TesterForm, ContactForm)
├── content/ ← (leer, für Phase 1: module.ts)
├── layouts/ ← BaseLayout.astro
├── pages/ ← index.astro
└── styles/ ← global.css
Was als Nächstes (Phase 1 — Komponenten-Bibliothek)
Laut CLAUDE.md §9, Phase 1:
Eyebrow,SectionHeading,NumberedItem— primitive Layout-BausteineStatusDot,ModuleCard,ModuleGrid— Modul-VisualisierungTechStrip,SovereigntyBlock,RoadmapTimeline— Sektions-KomponentenObjectionAnswer,CTABlock— Argumentations- und Abschluss-Komponenten- Dev-Seite:
/dev/components.astro— alle Bausteine in allen Varianten
Update 2026-05-04 — Hero Dark-Variante (verbindlich)
CLAUDE.md §7.1 wurde mit verbindlicher Spec für dunkle Hero-Variante erweitert. Umsetzung:
src/pages/index.astro— Hero-Sektion komplett umgebaut:#0E0F14-Hintergrund, Off-White-Text#F5F5F0, Persimmon-Eyebrow mit▸-Prefix in#FF6B2C. Wort „Grenzenlos" als Background-Highlight (#FF6B2Cbg,#2A0F02fg, padding0 12px,box-decoration-break: clone, kein border-radius). Tech-Strip läuft im selben dunklen Hintergrund weiter (border 0.5px solid rgba(245,245,240,0.08), STACK-Label bei0.85-Opacity, Items bei0.55). Sentinel<div data-hero-end>markiert das Ende der dunklen Zone für die NavBar.src/components/marketing/NavBar.astro— Dual-Mode-Implementierung. CSS-Klassen.nav-bar--darkund.nav-bar--lightdefinieren je eigene Farb-Sätze (Logo, Links, Lang-Switch, CTA). Toggle per Scroll-Listener:getBoundingClientRect()desdata-hero-end-Sentinels gegen NavBar-Höhe. Auf Nicht-Home-Seiten (Sentinel fehlt) immer Light-Mode. Transition 200ms.
Visuell verifiziert via preview_inspect: bg = rgb(14,15,20), Highlight-Farben korrekt, box-decoration-break: clone aktiv (mit -webkit-Prefix), NavBar-Dark-Mode bei scrollY=0, Light-Mode-Switch beim Sentinel-Crossing nachgewiesen.
Phase 1 abgeschlossen — Komponenten-Bibliothek
Alle 11 Marketing-Komponenten plus Daten-Foundation und Showcase-Seite stehen.
Neue Dateien:
src/content/module.ts— Modul-Typen, 19 Module aus Appendix A,statusLabel/pillarTitles-Mapssrc/components/marketing/Eyebrow.astro— Mono-Caption mit Tone-Varianten (tertiary/accent/inverse), optionalemprefix(z.B.▸) und Status-Pillesrc/components/marketing/StatusDot.astro— vier Status-Glyphen rein per CSS (gefüllt / halbgefüllt / outline / dashed), monochrom, mitinverse-Variante für dunkle Hintergründesrc/components/marketing/SectionHeading.astro—h2mit optionalem Eyebrow + Subtitle,display-Variante für „große Versprechen"-Sektionen, inverse-Modussrc/components/marketing/NumberedItem.astro— Mono-Nummer + Serif-Title + Body-Slotsrc/components/marketing/ModuleCard.astro/ModuleGrid.astro— eine Säulen-Karte und das 4-Spalten-Grid mit optionaler Status-Legendesrc/components/marketing/TechStrip.astro— extrahiert ausindex.astro, hatdark/light-Variantensrc/components/marketing/SovereigntyBlock.astro— 2-Spalten-Layout mit Display-Headline links und 2×2-Border-Left-Items rechtssrc/components/marketing/RoadmapTimeline.astro— vertikale Linie mit Phase-Markern, current-Pillesrc/components/marketing/ObjectionAnswer.astro— Serif-Frage als Quote, Body-Slotsrc/components/marketing/CTABlock.astro— Eyebrow + Headline + Body + bis zu 3 CTAs (primary/secondary/ghost),inverse-Modussrc/pages/dev/components.astro— interne Showcase-Seite mit jeder Komponente in jeder Variante (nicht im Sitemap)public/og-default.png— 1200×630 Platzhalter, gespiegeltes Hero-Layout, generiert vianode scripts/generate-og.mjsscripts/generate-og.mjs— Skript zur Regenerationsharpzur Dev-Dependency-Liste ergänzt (für OG-Generierung; war ohnehin transitiv via Astro vorhanden)
Geänderte Dateien:
src/pages/index.astro— Tech-Strip-Inline-Code durch<TechStrip variant="dark" />ersetzt, identisches visuelles ErgebnisCLAUDE.md§0 + §4.1 — „Astro 5" → „Astro 6" (stillschweigender Versions-Update wie abgesprochen)
Visuell verifiziert: Komplettes Durchscrollen von /dev/components und Re-Check von /. Status-Glyphen monochrom korrekt, Persimmon-Akzent sparsam (nur Hero-Highlight, current-Pille, primary CTAs, Eyebrow-accent-Variante, Border-Left auf SovereigntyBlock-Items), keine Drop-Shadows oder Gradients.
Phase 2 abgeschlossen — Home
Alle 9 Sektionen aus CLAUDE.md §7.1 sind in src/pages/index.astro komponiert:
- Hero (dark) — unverändert aus Phase 0/1
- Tech-Strip (dark) — unverändert
- Modul-Landschaft —
<ModuleGrid />mit Legende, Eyebrow nutztmodules.length(aktuell 19), Footer-Link auf/module - Was uns trennt — 3
<NumberedItem>01/02/03, Surface-White-Hintergrund - Souveränität —
<SovereigntyBlock>mit dreizeiliger Display-Headline, vier Border-Left-Items - Roadmap-Snapshot —
<RoadmapTimeline>mit 4 Phasen, „Heute" mit Aktuell-Pille (Persimmon) - Schnell-Argumentarium — 5
<ObjectionAnswer>im 2-Spalten-Grid, fünfter wraps unten allein (per Spec) - Tester-Programm-Teaser —
<CTABlock>mit Primary + Ghost-Mail-Link - Final-CTA —
<CTABlock inverse>mit Primary + Secondary, dunkler Hintergrund symmetrisch zum Hero
Visueller Rhythmus: Dunkel (Hero+Strip+Sentinel) → hell → surface-white → hell → surface-white → hell → surface-white → dunkel (Final-CTA). Wechselnde Bg-Töne strukturieren ohne Bordüren.
NavBar Dual-Mode verifiziert: bei scrollY=0 über Hero nav-bar--dark aktiv, beim Body-Scroll wechselt korrekt zu nav-bar--light. Beim Final-CTA bleibt sie hell (Sentinel ist nach Sektion 2 platziert).
Verifiziert per DOM-Inspection: Alle Sektionen rendern mit korrekter Bg, Eyebrow, Headline. Auto-Count im Modul-Eyebrow funktioniert (VIER SÄULEN · 19 MODULE).
Inhaltliche Hinweise an Pascal:
- CLAUDE.md erwähnt mehrfach „16 Module", in
module.ts(Appendix A) sind aber 19 hinterlegt. Der Eyebrow rendert dynamisch aus den Daten —19 MODULE. Wenn 16 die richtige Marketing-Aussage ist, kürze ich die Modul-Liste; wenn 19 stimmt, aktualisiere ich CLAUDE.md §0/§1. - Die
Aktuell-Pille auf der Roadmap nutzt Persimmon-Bg + dunklen Text — passt zum Brand-System §3.5 („Status-Pille aktuelle Phase"). - Final-CTA-Headline ist bewusst eine zusammengefasste Version der zwei Sätze aus §7.1 §9 („30 Minuten, kostenlos, unverbindlich..." + „Sie schildern, wo Sie stehen..."). Wenn du beide Sätze willst, splitte ich es in body + headline.
Update — EN-Variante + Sprachumschaltung (vorgezogen aus Phase-2-Backlog)
EN war ursprünglich Phase 2 (CLAUDE.md §9 Phase 6: „EN-Variante mit astro-i18n oder Manual-Routing"). Auf Pascal-Wunsch jetzt vorgezogen.
Routing: Astro built-in i18n in astro.config.mjs, defaultLocale: 'de', prefixDefaultLocale: false. → / bleibt DE, /en/ ist EN.
Neue/Geänderte Dateien:
astro.config.mjs— i18n-Block, sitemap mit Locale-Mapsrc/content/module.ts—nameEn,pillarTitleEn,descriptionEnpro Modul;statusLabelEn/pillarTitlesEn-Maps; HelpergetModuleName/getStatusLabel/getPillarTitle(item, lang)src/i18n/strings.ts— zentrale UI-Strings DE/EN für NavBar, Footer, Roadmap-Pille;getLangFromPath()undgetLocalizedPath()src/layouts/BaseLayout.astro— auto-detect Lang aus Pfad,<html lang>, hreflang DE/EN/x-default, og:locale, lokalisierte Default-Descriptionsrc/components/marketing/NavBar.astro— Sprachumschalter mit aktiv/inaktiv-States in beiden Modi (dark/light), Links viagetLocalizedPath(), lang-spezifische Nav-Pfade (/modulevs/en/moduleetc.)src/components/marketing/Footer.astro— alle Strings aus i18n-Dictsrc/components/marketing/StatusDot.astro/ModuleCard.astro/ModuleGrid.astro/RoadmapTimeline.astro—lang-Prop (Default'de')src/pages/en/index.astro— komplette englische Home, gleiche 9 Sektionen mit übersetzten Inhalten
Verifiziert:
/→<html lang="de">, deutsche Inhalte, DE aktiv im Switcher/en/→<html lang="en">, englische Inhalte, EN aktiv im Switcher- Switcher-Links: DE-Button auf
/en/führt zu/, EN-Button auf/führt zu/en/ - hreflang reziprok auf beiden Seiten,
x-defaultzeigt auf DE - Modul-Namen: „Aufgaben" (DE) / „Tasks" (EN), „Belege" / „Documents", etc. Status-Labels und Säulen-Titel ebenfalls übersetzt
- NavBar-Dual-Mode funktioniert auf EN-Seite identisch (dark über Hero, light beim Body-Scroll)
/dev/componentsrendert weiterhin fehlerfrei (alle Komponenten habenlang-Default'de')
Nicht-übersetzte Pfade (Hinweis): EN-NavBar verlinkt auf /en/module, /en/sovereignty, /en/roadmap, /en/tester — diese Seiten existieren noch nicht (auch nicht in DE), 404 bis Phase 3+4 sie liefern. Footer-Links analog. Sprachumschalter geht von /en/foo zurück nach /foo (oder umgekehrt) — wenn die DE-Variante nicht existiert, landet der User auf der DE-404 mit deutscher Sprache.
Inhaltliche Hinweise an Pascal:
- Module-Eigennamen bleiben in beiden Sprachen identisch wo sinnvoll (CRM, Helpdesk, WhatsApp), übersetzte Konzepte sonst (Belege → Documents, Versand → Shipping, BuHa-Export → Accounting export, Personal → HR, Zeiterfassung → Time tracking)
- „Tester" im EN als „Testers" für die Nav, „Become a tester" als CTA. Wenn du „Beta tester" oder „Pilot user" stärker findest, ändere ich
- Hero-Headline EN: „Start lean. Grow without limits." mit Highlight nur auf „Grow" (statt „Grenzenlos"). Andere Variante denkbar: „Grow boundless." oder „Scale without limits." — sag wenn du eine bestimmte willst
- Tech-Strip EN: DSGVO → GDPR (selbe Sache, andere Schreibung), Rest unverändert
- Sektion 5 Souveränität: „Your data. Your country. Your control." spiegelt das DE 1:1
- Imprint/Privacy: Deutsche Pflichtseiten haben deutsche URLs (
/impressum,/datenschutz); EN-Footer linkt auf/en/imprintund/en/privacy. Diese müssen in Phase 4 angelegt werden — englische Pflichtseiten sind rechtlich zwar nicht erforderlich, aber Usability-relevant
Phase 3 abgeschlossen — Module + Tester (Scope C, ohne Form)
Pascal-Entscheidung: Form-Anbindung auf Phase 3.5 verschieben, weil app.slimcore.io produktiv noch nicht live ist (nur app.staging.slimcore.io). Marketing-Site geht ohne Form-Submission live, Tester-Anmeldung läuft über Mail + Calendly bis Production-App + Form fertig sind.
Neue Dateien:
src/pages/module.astro— DE Modul-Seite, Hero-light + ModuleFilter-Island +<noscript>-Fallback mit allen 19 Modulen statischsrc/pages/en/module.astro— EN-Variantesrc/pages/tester.astro— DE Info-Seite mit 4 Sektionen (Wer/Was bekommen/Was geben/Worauf einstellen) + Pascal-Pull-Quote + CTA-Block (Mail + Calendly)src/pages/en/tester.astro— EN-Variantesrc/components/islands/ModuleFilter.tsx— React-Island mit Status- (5 Optionen) + Säulen-Filter (5 Optionen), Live-Counter, gerenderte Modul-Karten
Geänderte Dateien:
src/i18n/strings.ts—filter-Sektion mit Labels („Status", „Säule", „Alle", Singular/Plural), reziproke EN-Stringssrc/styles/global.css—.dot-Klassen (synchron mit StatusDot.astro) für die React-Island
Hydration-Issue gelöst: Erste Implementierung mit client:visible (laut CLAUDE.md §4.3 Empfehlung) hydratierte nicht — weder im Dev-Mode noch im Production-Build. Nach Bisect: client:load funktioniert sauber. Die exakte Ursache (vermutlich ein Bug in Astro 6 / React 19 mit client:visible + display: contents-Wrapper + IntersectionObserver auf 0×0-Element) habe ich nicht final isoliert, weil client:load für diese Seite ohnehin die richtige Wahl ist: Auf /module ist der Filter das Hauptinteraktionselement, sofortige Hydration kostet ~30 KB JS aber gibt unmittelbare Reaktivität ohne Layout-Shift. SSR-HTML enthält die volle Filter-UI + 19 Modul-Karten, also auch SEO sauber.
Verifiziert:
/module: H1 „Module", Eyebrow „MODULE · 19 GESAMT", Filter funktioniert (Verfügbar = 6 Module, Verfügbar + Pillar 01 = 1 Modul (CRM)), Counter aktualisiert sich live/en/module: H1 „Modules", „Available" + „All" = 6 modules, Filter-Logik identisch/tester: 5 Sektions-H2 inkl. „Anmeldung läuft aktuell per Mail oder Termin." (statt Form), Pascal-Pull-Quote im Serif-Style mit Border-Left-Akzent/en/tester: spiegelnd mit „Sign-up currently runs by email or call."
Inhaltliche Hinweise an Pascal:
- Tester-Seiten: Anmelde-Sektion ist als Übergangs-CTA gestaltet — Mail an
hallo@slimcore.io?subject=Tester-Programm%20Phase%201mit vorausgefülltem Subject, plus Calendly-Termin-Link. Sobaldapp.slimcore.io/api/public/leadsproduktiv steht, ersetzt der echte Form-Island diese Sektion. - Modul-Seite zeigt 19 Module aus
module.tsals Single Source of Truth. Wenn du beim CLAUDE.md-Hinweis 16 → 19 noch eine Entscheidung treffen willst, gib Bescheid.
Phase 3.5 (verschoben) — Form-Anbindung
Aktivieren, sobald app.slimcore.io/api/public/leads produktiv ist:
- Form-Island als React
client:load(oberhalb der Falte) auf/testerund/en/tester - Felder gemäß CLAUDE.md §7.4: Firma, Name, E-Mail, Telefon (opt), Branche (Free-Text), Team-Größe (Slider 1–50), „Was nutzen Sie heute?", „Was wäre die größte Lücke?"
- Altcha-Integration (Self-hosted Proof-of-Work) + Honeypot-Feld
- POST an
PUBLIC_LEADS_API_URL(env-var), Default Staging während Übergang - Doppel-Opt-in über Brevo SMTP (Mail-Render in App, Versand Brevo)
/dankeund/en/thank-youBestätigungsseiten- API-Spec:
slimcore-go-to-market.md§3 (liegt im App-Repo) — vor Implementierung lesen
Update — Dunkles Design auf allen Hero-Sektionen
Pascal-Wunsch: alle Seiten dunkler Hero, nicht nur Home. Umgesetzt für /module, /en/module, /tester, /en/tester und alle Phase-4-Seiten unten. NavBar wechselt überall sauber zwischen dark (über Hero) und light (Body) per [data-hero-end]-Sentinel.
Kleine Komponenten-Erweiterung: SectionHeading.astro bekam eyebrowPrefix (z.B. „▸") und eyebrowTone (default: accent bei inverse=true, sonst tertiary).
Phase 3.5 (verschoben) — Form-Anbindung
Aktivieren, sobald app.slimcore.io/api/public/leads produktiv ist:
- Form-Island als React
client:load(oberhalb der Falte) auf/testerund/en/tester - Felder gemäß CLAUDE.md §7.4
- Altcha-Integration + Honeypot
- POST an
PUBLIC_LEADS_API_URL(env-var) - Brevo SMTP für DOI
/dankeund/en/thank-youBestätigungsseiten- API-Spec:
slimcore-go-to-market.md§3 (App-Repo) — vor Implementierung lesen
Phase 4 abgeschlossen — Restliche Seiten
10 neue Seiten (5 DE + 5 EN), alle mit dunklem Hero und Sentinel-NavBar-Toggle.
Neue Dateien:
src/pages/souveraenitaet.astro/src/pages/en/sovereignty.astro— 6 nummerierte Long-form-Sektionen (Warum jetzt → Hosting → OSS-Stack mit Tabelle → Keine US-Abhängigkeiten → Kein Lock-in → Optionaler Compliance-Layer)src/pages/roadmap.astro/src/pages/en/roadmap.astro— 4 Phasen, dynamisch ausmodule.ts(alle Module mit Status, Säule, Beschreibung pro Phase)src/pages/kontakt.astro/src/pages/en/contact.astro— 3 Kontaktwege (Mail, Calendly extern, Post). Calendly ist nur ein externer Link, kein Embed — vermeidet Cookie-Pflichtsrc/pages/impressum.astro/src/pages/en/imprint.astro— TMG-Template mit[Platzhaltern]für Adresse/Geschäftsführer/HRB/USt-IDsrc/pages/datenschutz.astro/src/pages/en/privacy.astro— DSGVO-Template, nennt Hetzner (DE), Brevo (FR), Calendly (US-Übergangs-Realität) als Auftragsverarbeiter. Bestätigt: keine Cookies, keine Analytics, self-hosted Fonts
Geänderte Dateien:
src/components/marketing/SectionHeading.astro—eyebrowPrefix-Prop,eyebrowTone-Override; default Eyebrow-Tone wechselt smartly mitinversesrc/pages/{module,tester}.astround EN-Pendants — dunkler Hero + Sentinelsrc/pages/index.astround EN-Pendant — Tech-Strip-Refactor (Phase 1)
Verifiziert: pnpm build erzeugt 17 Pages in 1.21s, alle 10 neuen Routen liefern HTTP 200, Hero-Bg = rgb(14,15,20), NavBar = dark bei scrollY=0, Tabellen rendern (Souveränität: 7 Reihen Stack-Tabelle), Footer-Links auf Impressum/Datenschutz funktionieren.
Inhaltliche Hinweise an Pascal — vor Production-Launch nötig:
- Impressum:
[Straße + Hausnummer],[PLZ Ort],[Rufnummer],[Amtsgericht],HRB [Nummer],DE [Nummer]— alle Platzhalter durch echte digiFORMER-Daten ersetzen. - Datenschutz: Template bildet Phase-1-Realität ab (keine Cookies, keine Analytics). Sobald Phase-3.5-Form aktiviert wird, muss Sektion „Tester-Anmeldung" mit Form-Daten, DOI, Altcha-PoW ergänzt werden. Empfehlung: vor Production-Launch durch Datenschutzberatung freigeben lassen.
- Souveränität: Long-form ist als Astro-Markup geschrieben, nicht MDX. Falls du den Text öfter editierst, kann ich auf
.mdxumbauen — aber für statische Marketing-Seite ist Astro-Markup näher dran. - Roadmap: Phasen-Beschreibungen und „Aktuell"-Pille für „Heute" gesetzt. Inhalte (welche Module welche Phase) kommen automatisch aus
module.tsStatus-Feld — wenn du die Liste pflegst, aktualisiert sich die Roadmap. - Kontakt: Adress-Block hat Platzhalter wie das Impressum. Zusätzlich erwähnt der Calendly-Block, dass es Übergangs-Realität ist und ein eigenes Termin-Modul folgt.
Update — Schriftarten auf Outfit umgestellt (Brand-System-Override)
Pascal-Entscheidung: SlimCore wechselt von Source Serif 4 + Inter (Brand-System §4.1 Default) auf Outfit für Headlines und Body. JetBrains Mono bleibt als Familien-Anker für Eyebrows, Stack-Strip und Wortmarke.
Begründungen:
- Mobile-Performance: 833 KB Fonts → 102 KB (88 % Ersparnis)
- Lighthouse Mobile: Performance 81 → 100/100, LCP 5.3s → 1.4s
- Differenzierung zur Mutter-Marke digiFORMER (Editorial-Serif) — SlimCore positioniert sich klar als „Werkzeug-Marke" mit geometric-modern Sans
- Tonalität §11 („pragmatisch, nicht idealistisch"): Outfit liest sich präziser-bestimmter als Inter
Brand-System-Implikation (für Pascal): Brand-System §4.1 nennt Source Serif 4 + Inter als Familien-Anker. Mit dem SlimCore-Switch auf Outfit wird einer der drei Familien-Anker gebrochen. Zwei Pfade vorwärts:
- SlimCore-spezifischer Override dokumentieren — andere Marken (digiFORMER, trendscout, SlimSafe) bleiben bei Source Serif 4 + Inter. Aktuell die De-facto-Realität, weil nur SlimCore live ist.
- Familien-System anpassen — Brand-System §4.1 darum erweitern, dass jede Marke eigene Sans wählen darf, solange JetBrains Mono als Familien-Anker bleibt. Die nummerierten Sektionen + Status-Glyphen + Mono-Eyebrows tragen dann die Familien-Konsistenz.
Empfehlung Variante 2 — JetBrains Mono ist eh der „technische Familien-Marker", und Editorial-Serif vs Geometric-Sans als Marken-Differenzierung ist eine starkere Architektur als „alle drei Schriften überall identisch".
Geänderte/Entfernte Dateien:
src/styles/global.css—@font-facefür Outfit (Latin + Latin-Ext via unicode-range),--font-sans/--font-serifzeigen beide auf Outfit (Alias bleibt für Tailwind-Kompatibilität),h1/h2/h3mitletter-spacing: -0.01emfür Geometric-Sans-Headlinessrc/layouts/BaseLayout.astro— Preload-Tags auf Outfit + JetBrains Monopublic/fonts/outfit-variable.woff2(32 KB) +outfit-variable-latin-ext.woff2(15 KB) hinzugefügtpublic/fonts/source-serif-4-variable.woff2undinter-variable.woff2entfernt (~778 KB gespart)src/pages/dev/fonts.astroundpublic/fonts/comparison/entfernt — Vergleichsseite hat ihren Zweck erfüllt- 11 temporäre fontsource-Packages aus devDependencies entfernt; nur
@fontsource-variable/outfitbleibt
Verifiziert: Lighthouse Mobile 100/100/100/100, Desktop 100/100, alle 24 Playwright-Smoke-Tests grün.
Phase 5 — Polish & Deploy (im Gang)
5.1 ✓ robots.txt + Sitemap (sitemap-index.xml mit hreflang-Pairs, /dev/-Routen ausgefiltert)
5.2 ✓ Playwright-Smoke-Tests (24 Tests, alle Routen + Filter-Island + Sprachumschalter + Footer-Links)
5.3 ✓ Build-Artefakt-Analyse + Lighthouse-Audit (Performance/A11y/Best-Practices/SEO alle 100/100 Mobile + Desktop nach Outfit-Switch)
5.4 ✓ Deployment-Konzept als Tier-2 Standard dokumentiert: docs/deployment.md (Forgejo-First, kein Coolify, kein GitHub-Übergang)
Familienweiter Deployment-Standard (statt Coolify):
- Tier 1 — Production SaaS mit Docker (SlimCore-Pattern): raw
docker-compose.*.yml+ Forgejo Actions SSH-Deploy + Branch-Protection. Fürapp.slimcore.io,app.fonboard.io, ggf. späterapp.slimsafe.io. Detaillierte Spec liegt im cockpit-Repo (docs/superpowers/specs/2026-04-30-production-infra-phase1-design.md). - Tier 2 — Static Marketing-Sites: Caddy + rsync (kein Docker pro Site nötig). Eine geteilte Caddy-Instanz auf einem Marketing-VPS hostet
slimcore.io,digiformer.eu,slimsafe.io,fonboard.io. Forgejo Actions baut + rsync't pro Repo. Spec:docs/deployment.mdin diesem Repo.
Warum kein Coolify: Single Point of Failure für alle Deployments, Drift zwischen UI-State und Repo-State, schwierig für HA-State-Cluster (Patroni + etcd + Redis Sentinel im SlimCore-App). Beim Tier-2-Pattern ist Docker nicht mal nötig — die Marketing-Site ist statisch, Caddy + rsync reicht.
Warum kein GitHub: Brand-System §7.5 sieht Forgejo als Migrationsziel vor. Für eine neu gebaute Marketing-Site lohnt sich der GitHub-Umweg nicht — wir starten direkt auf Forgejo. Cockpit (SlimCore-App) wird später migriert; Marketing-Site dient als niedrig-risikoreicher Forgejo-Pilot.
Neue Dateien (in diesem Repo):
docs/deployment.md— kompletter Deployment-Guide (Phase A: Forgejo-Server-Setup, Phase B: Marketing-VPS-Setup, Phase C: dieses Repo deployen, Phase D: weitere Marken nachziehen, Phase E: cockpit später migrieren).forgejo/workflows/deploy.yml— funktionsbereiter Workflow (Test → Build → Rsync → Verifikation → Mail-Notification via Brevo)infra/marketing-vps/Caddyfile— Caddy-Config-Template mit Blöcken für alle 4 Marken-Sites + Status-Pageinfra/marketing-vps/docker-compose.yml— Caddy + Uptime-Kuma-Stackinfra/marketing-vps/README.md— VPS-Setup-Anleitung inkl. rsync-deploy-User mitrrsync-Restriktion
Kostenbild Tier 2 (alle Marketing-Sites zusammen): ~€20/mo (Forgejo-VPS €5 + Marketing-VPS €5 + Storage-Box €10 geteilt mit anderen Backups).
Was Pascal jetzt tun muss
5.5 — Forgejo-VPS bestellen und Phase A durcharbeiten (~1 h)
5.6 — Marketing-VPS bestellen und Phase B durcharbeiten (~30 min)
5.7 — DNS-Records bei Registrar setzen (forge.digiformer.eu, slimcore.io, etc.)
5.8 — slimcore-website-Repo auf Forgejo spiegeln, Workflow läuft auto bei git push
5.9 — Smoke-Test gegen https://slimcore.io/, dann Launch
5.10 — Spätere Marketing-Sites einzeln nach Phase D nachziehen
5.11 — Cockpit-Migration als separater Plan in cockpit/docs/infrastructure/forgejo-migration.md
Offene Fragen vor Phase 2
- Mobile Hamburger-Drawer noch nicht implementiert — entschieden: Astro-Script + CSS-Transition. Wird in Phase 2 mit dem Home-Ausbau erledigt, da der Drawer nur sinnvoll testbar ist, wenn die Nav-Ziele auch existieren.
OG-Image— erledigt, Platzhalter generiert. Replacement nur bei Bedarf, sonst Phase 5 (dynamisch).Astro-Version— erledigt, v6 behalten und in CLAUDE.md angepasst.