slimcore-website/docs/handoff.md
Pascal Oelmann 3c79b63db5
Some checks failed
Deploy Marketing-Site / Lint + Smoke-Tests (push) Failing after 1m9s
Deploy Marketing-Site / Deploy auf Marketing-VPS (push) Failing after 0s
Deploy Marketing-Site / Deploy-Notification (push) Successful in 9s
Initial Astro-Build, Deployment-Setup und Forgejo-Workflow
- 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
2026-05-05 01:59:35 +02:00

285 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 in `src/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.md` korrekt umgesetzt: Electric Persimmon `oklch(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 dev`** läuft auf `localhost: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:
1. `Eyebrow`, `SectionHeading`, `NumberedItem` — primitive Layout-Bausteine
2. `StatusDot`, `ModuleCard`, `ModuleGrid` — Modul-Visualisierung
3. `TechStrip`, `SovereigntyBlock`, `RoadmapTimeline` — Sektions-Komponenten
4. `ObjectionAnswer`, `CTABlock` — Argumentations- und Abschluss-Komponenten
5. 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 (`#FF6B2C` bg, `#2A0F02` fg, padding `0 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 bei `0.85`-Opacity, Items bei `0.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--dark` und `.nav-bar--light` definieren je eigene Farb-Sätze (Logo, Links, Lang-Switch, CTA). Toggle per Scroll-Listener: `getBoundingClientRect()` des `data-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`-Maps
- `src/components/marketing/Eyebrow.astro` — Mono-Caption mit Tone-Varianten (`tertiary` / `accent` / `inverse`), optionalem `prefix` (z.B. `▸`) und Status-Pille
- `src/components/marketing/StatusDot.astro` — vier Status-Glyphen rein per CSS (gefüllt / halbgefüllt / outline / dashed), monochrom, mit `inverse`-Variante für dunkle Hintergründe
- `src/components/marketing/SectionHeading.astro``h2` mit optionalem Eyebrow + Subtitle, `display`-Variante für „große Versprechen"-Sektionen, inverse-Modus
- `src/components/marketing/NumberedItem.astro` — Mono-Nummer + Serif-Title + Body-Slot
- `src/components/marketing/ModuleCard.astro` / `ModuleGrid.astro` — eine Säulen-Karte und das 4-Spalten-Grid mit optionaler Status-Legende
- `src/components/marketing/TechStrip.astro` — extrahiert aus `index.astro`, hat `dark`/`light`-Varianten
- `src/components/marketing/SovereigntyBlock.astro` — 2-Spalten-Layout mit Display-Headline links und 2×2-Border-Left-Items rechts
- `src/components/marketing/RoadmapTimeline.astro` — vertikale Linie mit Phase-Markern, current-Pille
- `src/components/marketing/ObjectionAnswer.astro` — Serif-Frage als Quote, Body-Slot
- `src/components/marketing/CTABlock.astro` — Eyebrow + Headline + Body + bis zu 3 CTAs (`primary`/`secondary`/`ghost`), `inverse`-Modus
- `src/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 via `node scripts/generate-og.mjs`
- `scripts/generate-og.mjs` — Skript zur Regeneration
- `sharp` zur 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 Ergebnis
- `CLAUDE.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:
1. Hero (dark) — unverändert aus Phase 0/1
2. Tech-Strip (dark) — unverändert
3. Modul-Landschaft — `<ModuleGrid />` mit Legende, Eyebrow nutzt `modules.length` (aktuell 19), Footer-Link auf `/module`
4. Was uns trennt — 3 `<NumberedItem>` 01/02/03, Surface-White-Hintergrund
5. Souveränität — `<SovereigntyBlock>` mit dreizeiliger Display-Headline, vier Border-Left-Items
6. Roadmap-Snapshot — `<RoadmapTimeline>` mit 4 Phasen, „Heute" mit Aktuell-Pille (Persimmon)
7. Schnell-Argumentarium — 5 `<ObjectionAnswer>` im 2-Spalten-Grid, fünfter wraps unten allein (per Spec)
8. Tester-Programm-Teaser — `<CTABlock>` mit Primary + Ghost-Mail-Link
9. 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-Map
- `src/content/module.ts``nameEn`, `pillarTitleEn`, `descriptionEn` pro Modul; `statusLabelEn`/`pillarTitlesEn`-Maps; Helper `getModuleName/getStatusLabel/getPillarTitle(item, lang)`
- `src/i18n/strings.ts` — zentrale UI-Strings DE/EN für NavBar, Footer, Roadmap-Pille; `getLangFromPath()` und `getLocalizedPath()`
- `src/layouts/BaseLayout.astro` — auto-detect Lang aus Pfad, `<html lang>`, hreflang DE/EN/x-default, og:locale, lokalisierte Default-Description
- `src/components/marketing/NavBar.astro` — Sprachumschalter mit aktiv/inaktiv-States in beiden Modi (dark/light), Links via `getLocalizedPath()`, lang-spezifische Nav-Pfade (`/module` vs `/en/module` etc.)
- `src/components/marketing/Footer.astro` — alle Strings aus i18n-Dict
- `src/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-default` zeigt 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/components` rendert weiterhin fehlerfrei (alle Komponenten haben `lang`-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/imprint` und `/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 statisch
- `src/pages/en/module.astro` — EN-Variante
- `src/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-Variante
- `src/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-Strings
- `src/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%201` mit vorausgefülltem Subject, plus Calendly-Termin-Link. Sobald `app.slimcore.io/api/public/leads` produktiv steht, ersetzt der echte Form-Island diese Sektion.
- Modul-Seite zeigt 19 Module aus `module.ts` als 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:
1. Form-Island als React `client:load` (oberhalb der Falte) auf `/tester` und `/en/tester`
2. Felder gemäß CLAUDE.md §7.4: Firma, Name, E-Mail, Telefon (opt), Branche (Free-Text), Team-Größe (Slider 150), „Was nutzen Sie heute?", „Was wäre die größte Lücke?"
3. Altcha-Integration (Self-hosted Proof-of-Work) + Honeypot-Feld
4. POST an `PUBLIC_LEADS_API_URL` (env-var), Default Staging während Übergang
5. Doppel-Opt-in über Brevo SMTP (Mail-Render in App, Versand Brevo)
6. `/danke` und `/en/thank-you` Bestätigungsseiten
7. **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:
1. Form-Island als React `client:load` (oberhalb der Falte) auf `/tester` und `/en/tester`
2. Felder gemäß CLAUDE.md §7.4
3. Altcha-Integration + Honeypot
4. POST an `PUBLIC_LEADS_API_URL` (env-var)
5. Brevo SMTP für DOI
6. `/danke` und `/en/thank-you` Bestätigungsseiten
7. **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 aus `module.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-Pflicht
- `src/pages/impressum.astro` / `src/pages/en/imprint.astro` — TMG-Template mit `[Platzhaltern]` für Adresse/Geschäftsführer/HRB/USt-ID
- `src/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 mit `inverse`
- `src/pages/{module,tester}.astro` und EN-Pendants — dunkler Hero + Sentinel
- `src/pages/index.astro` und 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 `.mdx` umbauen — 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.ts` Status-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:
1. **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.
2. **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-face` für Outfit (Latin + Latin-Ext via unicode-range), `--font-sans`/`--font-serif` zeigen beide auf Outfit (Alias bleibt für Tailwind-Kompatibilität), `h1/h2/h3` mit `letter-spacing: -0.01em` für Geometric-Sans-Headlines
- `src/layouts/BaseLayout.astro` — Preload-Tags auf Outfit + JetBrains Mono
- `public/fonts/outfit-variable.woff2` (32 KB) + `outfit-variable-latin-ext.woff2` (15 KB) hinzugefügt
- `public/fonts/source-serif-4-variable.woff2` und `inter-variable.woff2` **entfernt** (~778 KB gespart)
- `src/pages/dev/fonts.astro` und `public/fonts/comparison/` **entfernt** — Vergleichsseite hat ihren Zweck erfüllt
- 11 temporäre fontsource-Packages aus devDependencies entfernt; nur `@fontsource-variable/outfit` bleibt
**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ür `app.slimcore.io`, `app.fonboard.io`, ggf. später `app.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.md` in 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-Page
- `infra/marketing-vps/docker-compose.yml` — Caddy + Uptime-Kuma-Stack
- `infra/marketing-vps/README.md` — VPS-Setup-Anleitung inkl. rsync-deploy-User mit `rrsync`-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
1. **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.
2. ~~OG-Image~~ — erledigt, Platzhalter generiert. Replacement nur bei Bedarf, sonst Phase 5 (dynamisch).
3. ~~Astro-Version~~ — erledigt, v6 behalten und in CLAUDE.md angepasst.