3.8 KiB
Mintel Universal Design System - Architecture Manifesto
Dieses Dokument ist der absolute Nordstern für alle Entwickler und KI-Agenten, die an der Mintel Codebase arbeiten. Es definiert, wie wir UI-Komponenten bauen, isolieren und skalieren, ohne in eine "Lock-in"-Falle zu tappen.
1. Das Problem: Die Design System Falle
Wir bauen eine neutrale Basis (@mintel/ui), auf der Web, Print (PDF), Präsentationen und Remotion-Videos basieren.
Das größte Risiko: Komponenten werden im Laufe der Zeit so komplex (mit dutzenden if/else-Switches für Kunden-Sonderfälle), dass niemand sich mehr traut, sie anzufassen, aus Angst, andere Projekte zu zerstören.
2. Die Zwiebel-Architektur (Core vs. Components)
Um dieses Problem zu lösen, teilen wir unser UI-Paket logisch in zwei Ebenen:
Tier 1: Primitives (Der Kern)
- Was ist das? Die absoluten Grundbausteine:
<Box>,<Text>,<Flex>,<Grid>. - Die Regel: Diese Komponenten haben keine Meinung. Sie dienen ausschließlich als saubere, typisierte Wrapper, um Tailwind-Klassen und Props durchzureichen. Sie dürfen sich architektonisch nie ändern.
- Warum? Weil Projekte im Notfall immer auf diese Bausteine zurückfallen können, um eigene, hochgradig individuelle Layouts zu bauen.
Tier 2: Base Components (Der Mintel Standard)
- Was ist das? Fertige Komponenten wie
<Button>,<Card>,<HeroSection>. - Die Regel: Sie haben den "neutralen" Mintel-Standardlook. Sie bauen zu 100% auf Tier 1 Primitives auf.
3. Die 3 Goldenen Regeln gegen den "Lock-in"
Wenn ein spezifisches Projekt (z.B. ein neuer Kunde) eine Komponente braucht, die radikal vom Mintel-Standard abweicht, gelten folgende Eskalationsstufen:
Eskalation 1: Compound Components
Komponenten dürfen niemals gigantische Props-Monster (<Card hideHeader={true} showFooter={false} />) werden.
Wir nutzen Compound Components: Das Projekt setzt die Card selbst aus <Card.Header>, <Card.Body> und <Card.Footer> zusammen. Braucht das Projekt den Header nicht, lässt es ihn einfach weg.
Eskalation 2: Das asChild Pattern (Slot)
Wir sperren Projekte niemals in unsere DOM-Struktur ein. Wenn eine Komponente Logik enthält, nutzen wir das asChild (oder Slot) Pattern.
Beispiel: Ein <Button asChild> rendert kein <button> HTML-Tag, sondern reicht seine Tailwind-Styles und seine Accessibility-Logik transparent an das Kind-Element durch (z.B. einen Next.js <Link>).
Eskalation 3: Der "Eject" (Der Shadcn-Weg)
Wenn eine @mintel/ui Komponente absolut nicht mehr für den Kunden X passt, wird sie nicht durch if (kunde === 'X')-Logik in der Basis "aufgebohrt".
Stattdessen ejecten (kopieren) wir den Source-Code der Komponente physisch in das Projekt von Kunde X (apps/kunde-x/components/). Ab diesem Moment "besitzt" das Projekt diese Komponente und kann sie nach Belieben modifizieren. Die neutrale Basis bleibt sauber!
4. Agenten & LLM Workflow
Jeder KI-Agent, der eine neue Komponente für @mintel/ui baut, muss folgende Checkliste abarbeiten:
- Ladle-First (TDD): Keine Komponente wird ohne eine dazugehörige
.stories.tsxDatei für den Ladle-Katalog akzeptiert. Ladle ist unsere Source of Truth. - Keine Business-Logik: Die Komponente darf keinen State (außer internen UI-State wie
isOpen), keine API-Fetches und keine projektspezifischen Konstanten enthalten. - Universalität prüfen: Die Komponente darf keine reinen Browser-APIs (
window.location) ohne Fallbacks nutzen, damit sie auch serverseitig in der Print-Engine (PDF) und in der Remotion-Engine gerendert werden kann. - Tailwind pur: Nutze ausschließlich Tailwind-Klassen. Keine externen CSS-Module oder
style-Tags, wenn nicht physikalisch zwingend (z.B. bei dynamischer Frame-Interpolation in Videos).
Wer dieses Manifest bricht, sabotiert die Skalierbarkeit des Monorepos. Halte dich an die Zwiebel-Architektur!