# PrintshopCreator Design System
**Version:** 1.0
**Letzte Aktualisierung:** 2025-12-22
**Status:** Living Document
---
## Inhaltsverzeichnis
1. [Einleitung](#einleitung)
2. [Architektur](#architektur)
3. [Farbsystem](#farbsystem)
4. [Typografie](#typografie)
5. [Spacing & Layout](#spacing--layout)
6. [Komponenten-Bibliothek](#komponenten-bibliothek)
7. [Layout-Patterns](#layout-patterns)
8. [Code-Standards](#code-standards)
9. [Barrierefreiheit](#barrierefreiheit)
10. [Migration Guide](#migration-guide)
---
## Einleitung
### Zweck
Dieses Design System definiert die visuellen und funktionalen Standards für alle Module im PrintshopCreator Backend. Es gewährleistet:
- **Konsistenz**: Einheitliches Erscheinungsbild über alle 32 Bundles hinweg
- **Effizienz**: Wiederverwendbare Komponenten reduzieren Entwicklungszeit
- **Wartbarkeit**: Zentrale Standards erleichtern Updates und Änderungen
- **User Experience**: Konsistente Interaktionsmuster verbessern die Benutzerfreundlichkeit
### Zielgruppe
- Frontend-Entwickler
- Backend-Entwickler (Symfony/Twig)
- UI/UX Designer
- Product Owner
---
## Architektur
### Tech Stack
| Technologie | Version | Verwendung |
|------------|---------|------------|
| **Tailwind CSS** | 3.x | Primäres CSS-Framework |
| **Alpine.js** | 3.x | UI State Management |
| **Symfony** | 6.x | Backend Framework |
| **Twig** | 3.x | Template Engine |
| **Font Awesome** | 5.7.2 | Icon Library |
### Framework-Strategie
**Primär: Tailwind CSS**
- Alle neuen Komponenten und Module verwenden Tailwind CSS
- Utility-First Ansatz für maximale Flexibilität
- Custom PSC-Farbschema über Tailwind-Konfiguration
**Legacy: Bootstrap 4/5**
- Wird schrittweise durch Tailwind ersetzt
- Keine neuen Bootstrap-Komponenten mehr erstellen
- Bestehende Bootstrap-Komponenten bei Änderungen zu Tailwind migrieren
### Dateistruktur
```
templates/
├── backend_tailwind_base.html.twig # Primäres Base-Template (verwenden!)
├── backend_base.html.twig # Legacy Bootstrap (nicht verwenden)
├── form_div_layout_tailwind.html.twig # Form Theme (verwenden!)
└── [bundle]/
└── backend/
├── edit.html.twig
├── list.html.twig
└── components/
assets/
├── tailwind/
│ ├── backend.css # Hauptstyles
│ └── login.css
└── backend/dashboard/ # Legacy (nicht verwenden)
```
---
## Farbsystem
### Primäre Farbpalette
#### PSC Brand Color
```css
/* Primary Brand Color */
--color-psc-50: #f0f9ff;
--color-psc-100: #e0f2fe;
--color-psc-200: #bae6fd;
--color-psc-300: #7dd3fc;
--color-psc-400: #38bdf8;
--color-psc-500: #0ea5e9; /* Haupt-Markenfarbe */
--color-psc-600: #0284c7;
--color-psc-700: #0369a1;
--color-psc-800: #075985;
--color-psc-900: #0c4a6e;
```
**Tailwind-Klassen:** `bg-psc-500`, `text-psc-600`, `border-psc-400`, etc.
#### Status-Farben
```css
/* Success - Grün */
--color-success: #10b981; /* bg-green-500 */
--color-success-light: #d1fae5; /* bg-green-100 */
/* Warning - Orange/Gelb */
--color-warning: #f59e0b; /* bg-orange-500 */
--color-warning-light: #fef3c7; /* bg-orange-100 */
/* Error - Rot */
--color-error: #ef4444; /* bg-red-500 */
--color-error-light: #fee2e2; /* bg-red-100 */
/* Info - Blau */
--color-info: #3b82f6; /* bg-blue-500 */
--color-info-light: #dbeafe; /* bg-blue-100 */
```
#### Neutrale Farben
```css
/* Graustufen */
--color-gray-50: #f9fafb;
--color-gray-100: #f3f4f6;
--color-gray-200: #e5e7eb;
--color-gray-300: #d1d5db;
--color-gray-500: #6b7280;
--color-gray-700: #374151;
--color-gray-900: #111827;
```
### Dark Mode
```css
/* Dark Mode Variablen */
dark:bg-boxdark /* #24303f */
dark:bg-strokedark /* #2e3a47 */
dark:text-bodydark /* #aeb7c0 */
```
**Verwendung:**
```html
Titel
```
### Badge-Farben
**WICHTIG: Für Ja/Nein-Anzeigen immer `badge-yes` und `badge-no` Klassen verwenden!**
| Typ | Klasse | Farbe | Verwendung |
|-----|--------|-------|------------|
| **Ja / Aktiv** | `badge-yes` | Grün (`bg-lime-500` + weiß) | true, ja, aktiv, enabled |
| **Nein / Inaktiv** | `badge-no` | Orange (`bg-orange-500` + weiß) | false, nein, inaktiv, disabled |
| Info | - | `bg-blue-500` + `text-white` | Information, Hinweis |
| Draft | - | `bg-yellow-100` + `text-yellow-800` | Entwurf, In Bearbeitung |
---
## Typografie
### Schriftarten
```css
/* System Font Stack */
font-family: system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial,
sans-serif;
```
**Tailwind-Klasse:** `font-sans` (Standard)
### Schriftgrößen
| Größe | Tailwind | Pixel | Verwendung |
|-------|----------|-------|------------|
| XS | `text-xs` | 12px | Labels, Badges, Hinweise |
| SM | `text-sm` | 14px | Body Text, Formulare |
| Base | `text-base` | 16px | Standard Body Text |
| LG | `text-lg` | 18px | Hervorgehobener Text |
| XL | `text-xl` | 20px | Überschriften (H3) |
| 2XL | `text-2xl` | 24px | Überschriften (H2) |
| 3XL | `text-3xl` | 30px | Seitentitel (H1) |
### Schriftgewichte
| Gewicht | Tailwind | Wert | Verwendung |
|---------|----------|------|------------|
| Normal | `font-normal` | 400 | Body Text |
| Medium | `font-medium` | 500 | Buttons, Labels |
| Semibold | `font-semibold` | 600 | Wichtige Labels |
| Bold | `font-bold` | 700 | Überschriften |
### Typografie-Beispiele
```html
Seitentitel
Abschnittstitel
Feldname
Beschreibungstext
```
---
## Spacing & Layout
### Spacing-System
Tailwind verwendet ein 4px-basiertes Spacing-System:
| Wert | Pixel | Verwendung |
|------|-------|------------|
| `0.5` | 2px | Minimaler Abstand |
| `1` | 4px | Sehr enger Abstand |
| `2` | 8px | Enger Abstand |
| `4` | 16px | Standard Abstand |
| `6` | 24px | Mittlerer Abstand |
| `8` | 32px | Großer Abstand |
| `12` | 48px | Sehr großer Abstand |
### Layout-Konstanten
```css
/* Sidebar */
--sidebar-width: 20rem; /* 320px */
--collapsed-sidebar-width: 5.4rem; /* 86px */
/* Container */
--max-content-width: 1280px; /* max-w-7xl */
```
### Responsive Breakpoints
```css
/* Tailwind Breakpoints */
sm: 640px /* Tablet Portrait */
md: 768px /* Tablet Landscape */
lg: 1024px /* Desktop */
xl: 1280px /* Large Desktop */
2xl: 1536px /* Extra Large Desktop */
```
### Grid-System
```html
```
---
## Komponenten-Bibliothek
### 1. Buttons
**WICHTIG: Einheitliche Rundung - Alle interaktiven Elemente verwenden `rounded-md` (6px)**
#### Primary Button (Haupt-Aktion)
```html
Speichern
```
**Verwendung:** Primäre Aktionen (Speichern, Erstellen, Absenden)
**CSS-Klasse:** `.psc-button-save` (bereits definiert in `backend.css`)
#### Secondary Button
```html
Abbrechen
```
**Verwendung:** Sekundäre Aktionen (Abbrechen, Zurück)
#### Danger Button
```html
Löschen
```
**Verwendung:** Destruktive Aktionen (Löschen, Entfernen)
#### Text Button / Link
```html
Bearbeiten
```
**Verwendung:** Tertäre Aktionen, Links
#### Button-Gruppe
```html
Links
Mitte
Rechts
```
### 2. Cards
#### Standard Card
```html
```
#### Compact Card
```html
```
#### Dashboard Stat Card
```html
```
### 3. Forms
#### Text Input
```html
```
#### Select / Dropdown
```html
Auswahl
Option 1
Option 2
Option 3
```
#### Checkbox
```html
Checkbox Label
```
#### Toggle Switch
```html
Toggle Label
```
#### Form Validation States
```html
```
### 4. Tables
#### Standard Datentabelle
**WICHTIG: Neue verbesserte Table-Header Styles**
**Design-Specs für Table-Header:**
- **Background:** `bg-slate-50` (heller als Body) / `dark:bg-gray-800`
- **Border:** `border-b-2 border-gray-200` (doppelte Stärke für Trennung)
- **Text:** `text-xs font-semibold text-gray-600 uppercase tracking-wider`
- **Padding:** `px-4 py-4` (mehr vertikales Padding als Body)
- **Font-Weight:** `font-semibold` (600) statt `font-medium`
**Design-Specs für Table-Body:**
- **Border:** `border-t border-gray-100` (subtiler als Header)
- **Padding:** `px-4 py-3` (konsistent mit Header horizontal)
- **Hover:** `hover:bg-gray-50 dark:hover:bg-gray-800/50`
- **Transition:** `transition-colors` für smooth Hover-Effekte
- **Text:** `text-gray-900 dark:text-gray-100` für normale Zellen
```html
Name
Status
Aktionen
Beispiel Name
Aktiv
```
#### Responsive Table (Mobile-Friendly)
```html
Name:
Beispiel
Status:
Aktiv
```
#### UID/ID Badges in Tabellen
**Design für technische IDs/UIDs als klickbare Badges**
```html
123
```
**Nicht-klickbare UID (falls kein Link benötigt):**
```html
ABC-123
```
**Design-Specs für UID/ID Badges:**
- **Font:** `font-mono` (Monospace für technische Werte)
- **Größe:** `text-xs` (12px)
- **Padding:** `px-2.5 py-1`
- **Rundung:** `rounded-md` (mittlere Rundung)
- **Icon:** Hash (#) Symbol, `w-3.5 h-3.5`
- **Hover:** PSC-Farbe bei Links
- **Border:** Subtiler Border für bessere Abgrenzung
**In Twig:**
```twig
{# Klickbare UID #}
{{ item.id }}
```
#### Tabellen-Aktionen mit Icons
**WICHTIG: Einheitliche Aktions-Icon-Farben**
Alle Aktions-Icons in Tabellen müssen folgende Farben verwenden:
| Aktion | Farbe | Tailwind-Klasse | Verwendung |
|--------|-------|-----------------|------------|
| **Löschen** | Rot | `text-red-600` | Alle Delete/Remove-Aktionen |
| **Bearbeiten** | Grün | `text-green-600` | Alle Edit/Update-Aktionen |
| **Alle anderen** | Blau | `text-blue-600` | View, Download, Info, etc. |
**Icon-Größe:** Alle Tabellen-Icons sollten die Klasse `table-icon` (entspricht `w-6`) verwenden.
```html
```
**Weitere Icon-Aktionen (alle BLAU):**
- Info/Hilfe: `text-blue-600`
- Kopieren/Duplizieren: `text-blue-600`
- Export: `text-blue-600`
- Drucken: `text-blue-600`
- Verschieben: `text-blue-600`
- Teilen: `text-blue-600`
### 5. Badges & Tags
#### Ja/Nein Status Badges
**WICHTIG: Einheitliche Ja/Nein-Anzeige**
Für Ja/Nein-Anzeigen (Boolean-Werte) in Tabellen und Listen müssen **immer** die vordefinierten Klassen verwendet werden:
| Status | Klasse | Farbe | Verwendung |
|--------|--------|-------|------------|
| **Ja** | `badge-yes` | Grün (`bg-lime-500`) | true, aktiv, ja, enabled |
| **Nein** | `badge-no` | Orange (`bg-orange-500`) | false, inaktiv, nein, disabled |
```html
Ja
Nein
```
**In Twig Templates:**
```twig
{# Boolean-Wert anzeigen #}
{% if item.active %}
{{'yes'|trans}}
{% else %}
{{'no'|trans}}
{% endif %}
{# In Tabellen #}
{% if product.isPublished %}
Veröffentlicht
{% else %}
Entwurf
{% endif %}
```
**CSS-Definition (bereits in `assets/tailwind/css/backend.css`):**
```css
.badge-yes {
@apply inline-flex items-center rounded-full bg-lime-500 px-2 py-1
text-xs font-medium text-white hover:bg-opacity-90
justify-center shadow-xl;
}
.badge-no {
@apply inline-flex items-center rounded-full bg-orange-500 px-2 py-1
text-xs font-medium text-white hover:bg-opacity-90
justify-center shadow-xl;
}
```
**Design-Specs:**
- **Rundung:** `rounded-full` (vollständig abgerundet)
- **Schriftgröße:** `text-xs` (12px)
- **Padding:** `px-2 py-1` (horizontal 8px, vertikal 4px)
- **Font-Weight:** `font-medium` (500)
#### Weitere Status Badges
```html
Information
Warnung
Erfolgreich
Entwurf
Fehler
```
**WICHTIG:** Alle Status-Badges verwenden:
- `rounded-full` für vollständige Rundung
- `text-xs` für einheitliche Schriftgröße (12px)
- `px-2 py-1` für konsistentes Padding
#### Count Badge
```html
Benachrichtigungen
3
```
### 6. Alerts & Flash Messages
#### Success Alert
```html
Erfolgreich!
Ihre Änderungen wurden gespeichert.
```
#### Error Alert
```html
Fehler!
Es ist ein Problem aufgetreten.
```
#### Warning Alert
```html
Achtung!
Bitte überprüfen Sie Ihre Eingaben.
```
#### Info Alert
```html
Hinweis:
Zusätzliche Informationen...
```
### 7. Modal / Dialog
```html
Modal öffnen
```
#### Alpine.js Modal (empfohlen)
```html
Modal öffnen
Modal Titel
Abbrechen
Bestätigen
```
### 8. Navigation
#### Sidebar Navigation
Siehe `backend_tailwind_base.html.twig` für vollständige Implementierung.
**Key Features:**
- Collapsible mit Alpine.js
- Icons (Font Awesome)
- Active States
- Responsive (Mobile-Toggle)
```html
```
#### Breadcrumbs
```html
Home
Produkte
Produktdetails
```
#### Tabs
```html
```
### 9. Pagination
```html
Zeige {{ pagination.first }} bis
{{ pagination.last }} von
{{ pagination.total }} Ergebnissen
{% for page in pagination.pagesInRange %}
{% endfor %}
```
### 10. Loading States
#### Spinner
```html
Lädt...
```
#### Skeleton Loader
```html
```
#### Progress Bar
```html
```
### 11. Dropdowns
```html
```
### 12. Empty States
```html
Keine Einträge vorhanden
Erstellen Sie Ihren ersten Eintrag, um loszulegen.
Neu erstellen
```
---
## Layout-Patterns
### Standard-Seitenlayout
```twig
{# templates/your-bundle/backend/list.html.twig #}
{% extends 'backend_tailwind_base.html.twig' %}
{% block title %}Seitentitel{% endblock %}
{% block body %}
{# Page Header #}
{# Flash Messages #}
{% for label, messages in app.flashes %}
{% for message in messages %}
{{ message }}
{% endfor %}
{% endfor %}
{# Main Content #}
{% endblock %}
```
### Liste-Seite (CRUD List)
```twig
{% extends 'backend_tailwind_base.html.twig' %}
{% block body %}
{# Header mit Search & Filters #}
{# Table Card #}
{{ knp_pagination_sortable(pagination, 'Name', 'name') }}
Status
Aktionen
{% for item in pagination %}
{{ item.name }}
{% if item.active %}
Aktiv
{% else %}
Inaktiv
{% endif %}
Bearbeiten
Löschen
{% else %}
Keine Einträge vorhanden
{% endfor %}
{# Pagination #}
{{ knp_pagination_render(pagination, 'tailwind_pagination.html.twig') }}
{% endblock %}
```
#### List-Header im `block header` (Titel + Aktion rechts)
```twig
{% block header %}
{% endblock %}
```
#### KNP Pagination mit Sortable-Template
```twig
{{ knp_pagination_render(pagination, 'tailwind_pagination.html.twig', {}, {
'sortableTemplate': 'tailwind_sortable.html.twig'
}) }}
```
### Edit/Create-Seite (CRUD Form)
**WICHTIG: Verwende immer das vertikale Tab-Layout für Edit/Create-Seiten mit mehreren Sektionen!**
#### Standard Edit-Seite mit vertikalen Tabs
```twig
{% extends 'backend_tailwind_base.html.twig' %}
{% form_theme form 'form_div_layout_tailwind.html.twig' %}
{% block header %}
Module Name Bearbeiten
{% endblock %}
{% block body %}
{{ form_start(form, {attr: {class: ''}}) }}
{# Vertikales Tab-Layout #}
{# Tab Navigation - Links (2/12) #}
{# Content Area - Rechts (10/12) #}
{# General Tab #}
Allgemein
{# Felder in 3er-Gruppen (4/12 Breite) #}
{{ form_row(form.title) }}
{{ form_row(form.position) }}
{{ form_row(form.active) }}
{# Felder in 2er-Gruppen (6/12 Breite) #}
{{ form_row(form.startDate) }}
{{ form_row(form.endDate) }}
{# Einzelnes Feld (volle Breite) #}
{{ form_row(form.description) }}
{# Settings Tab #}
Einstellungen
{{ form_row(form.settings) }}
{# Save Button außerhalb der Card #}
{{ form_widget(form.save, {
attr: {
class: 'inline-flex items-center justify-center py-1 gap-1 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-psc-500 hover:bg-psc-600 hover:ring-2 hover:ring-psc-500 hover:ring-offset-2 min-h-[2.25rem]'
}
}) }}
{{ form_end(form) }}
{# Changes History (nur bei Edit, nicht bei Create) #}
Änderungen
{% for change in changes %}
{{ change.created|date('H:i:s d.m.Y') }}
{{ change.username }}
{% for key, set in change.changeset %}
{% if set|length > 1 and set[1] is not iterable %}
{{ key }} {{ set[0] }} {% if set[1] is null %}0{% else %}{{ set[1] }}{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% endblock %}
```
### Delete-Seite (Confirmation Card)
**WICHTIG: Delete immer als eigene Bestätigungs-Card mit Header, Body, Footer.**
```twig
{% extends 'backend_tailwind_base.html.twig' %}
{% form_theme form 'form_div_layout_tailwind.html.twig' %}
{% block header %}
Module Name Löschen
{% endblock %}
{% block body %}
Bist du sicher, dass du diesen Eintrag löschen willst?
{{ item.title }}
Diese Aktion kann nicht rückgängig gemacht werden.
{{ form_start(form) }}
{{ form_widget(form.no, {
attr: {
class: 'inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-psc-600 border border-psc-500 bg-white hover:bg-gray-50 hover:ring-2 hover:ring-psc-500 hover:ring-offset-1 shadow-sm'
}
}) }}
{{ form_widget(form.yes, {
attr: {
class: 'inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-red-500 hover:bg-red-600 hover:ring-2 hover:ring-red-500 hover:ring-offset-1'
}
}) }}
{{ form_end(form) }}
{% endblock %}
```
#### Design-Specs für Edit/Create-Seiten
**Header:**
- **Titel:** Links mit Icon, Format: `Module Name Aktion `
- **Zurück-Button:** Rechts, **IMMER Grau** (`bg-gray-500`), nie PSC-Farbe
- **Icon:** Entsprechend dem Modul (Payment, CMS, etc.)
**Vertikale Tab-Navigation:**
- **Breite:** `w-full md:w-2/12` (2 von 12 Spalten auf Desktop)
- **Position:** Links
- **Indikator:** Blaue Linie links (`w-1 bg-psc-500`)
- **Tab-Links:** Mit Icons, `px-4 py-2`, aktiver Tab: `class="active"`
- **Rundung:** `rounded-md`
**Content-Bereich:**
- **Breite:** Volle Breite minus Tab-Navigation
- **Card:** `rounded-md border bg-white p-5 shadow-lg`
- **Tab-Content:** Erstes Tab `class="block"`, andere `class="hidden"`
- **Überschrift:** `text-sm mt-3 mb-6 font-bold uppercase`
**Feld-Layout (Flex-Wrap System):**
```html
{# 3 Felder nebeneinander (Desktop) #}
{{ form_row(form.field1) }}
{{ form_row(form.field2) }}
{{ form_row(form.field3) }}
{# 2 Felder nebeneinander (Desktop) #}
{{ form_row(form.field1) }}
{{ form_row(form.field2) }}
{# 1 Feld (volle Breite) #}
{{ form_row(form.description) }}
```
**WICHTIG: Grid vs. Flex-Wrap:**
- ❌ **NICHT verwenden:** `grid grid-cols-1 md:grid-cols-2 gap-6`
- ✅ **Verwenden:** `flex flex-wrap` mit `w-full lg:w-4/12 px-4`
**Save-Button:**
- **Position:** Außerhalb der Card, rechts (`text-end my-2`)
- **Farbe:** PSC-Orange (`bg-psc-500`)
- **Rundung:** `rounded-md`
- **WICHTIG:** Verwende `{{ form_widget(form.save, {attr: {...}}) }}` statt manuellem `` Tag, um doppelte Buttons zu vermeiden
**Button-Farbschema:**
- **Zurück:** Grau (`bg-gray-500`) - Neutrale Aktion
- **Speichern:** PSC (`bg-psc-500`) - Primäre Aktion
- **Abbrechen:** Weiß mit PSC-Border - Sekundäre Aktion
- **Löschen:** Rot (`bg-red-500`) - Destruktive Aktion
**Changes-History:**
**WICHTIG: Changes-History kommt NACH dem Formular, NICHT als Tab!**
Die Changes-History wird als separate Card **nach `{{ form_end(form) }}`** platziert, nicht als Tab in der vertikalen Navigation.
```twig
{{ form_end(form) }}
{# Changes History Card - NACH dem Formular #}
{{ 'Changes'|trans }}
{# Header-Zeile #}
{# Daten-Zeilen #}
{% for change in changes %}
{{ change.created|date('H:i:s d.m.Y') }}
{{ change.username }}
{% for key, set in change.changeset %}
{% if set|length > 1 and set[1] is not iterable %}
{{ key }}
{{ set[0] }}
{% if set[1] is null %}0{% else %}{{ set[1] }}{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
```
**Design-Specs:**
- **Position:** Nach `{{ form_end(form) }}`, **NICHT als Tab**
- **Nur bei Edit:** Nicht bei Create-Seiten zeigen
- **Layout:** Grid mit 10 Spalten (`grid-cols-10`)
- Spalte 1: Datum (`col-span-2`)
- Spalte 2: Benutzer (`col-span-2`)
- Spalte 3: Änderungen (`col-span-6`)
- **Header:** `bg-slate-100` mit `font-medium`, `py-4.5`
- **Daten-Zeilen:** `border-t border-stroke`, `py-4.5`
- **Badges für Änderungen:**
- Alter Wert (gelöscht): `Wert ` (Orange/Rot)
- Neuer Wert: `Wert ` (Grün)
- **Rundung:** `rounded-md` für die Card
- **Titel:** `text-psc text-xl font-medium mb-4`
### Dashboard Layout
```twig
{% extends 'backend_tailwind_base.html.twig' %}
{% block body %}
Dashboard
{# Stats Grid #}
{% for stat in stats %}
{{ stat.label }}
{{ stat.value }}
{{ stat.icon|raw }}
{% if stat.change %}
{{ stat.change > 0 ? '+' : '' }}{{ stat.change }}%
{% endif %}
{% endfor %}
{# Content Grid #}
{# Chart Card #}
Statistiken
{# Chart here #}
{# Activity List #}
Letzte Aktivitäten
{% for activity in activities %}
{{ activity.description }}
{{ activity.timestamp|date('d.m.Y H:i') }}
{% endfor %}
{% endblock %}
```
---
## Code-Standards
### Tailwind CSS Richtlinien
#### 1. Utility-First Prinzip
**Gut:**
```html
Button
```
**Schlecht (Custom CSS vermeiden):**
```html
Button
```
#### 2. Wiederverwendbare Komponenten via @apply
Nur für häufig genutzte Pattern in `assets/tailwind/backend.css`:
```css
/* Gut: Wiederverwendbare Button-Klasse */
.psc-button-save {
@apply inline-flex items-center justify-center gap-2 px-4 py-2
text-sm font-medium text-white
bg-psc-500 hover:bg-psc-600
rounded-sm shadow-lg
hover:ring-2 hover:ring-psc-500 hover:ring-offset-1
transition-all duration-200;
}
/* Gut: Wiederverwendbare Badge-Klasse */
.badge-yes {
@apply inline-flex items-center px-2 py-1 rounded-sm
text-xs font-medium bg-lime-500 text-white;
}
```
**Verwendung:**
```html
Speichern
Aktiv
```
#### 3. Responsive Design
Mobile-First Ansatz verwenden:
```html
```
#### 4. Dark Mode Konsistenz
Immer Dark Mode Varianten hinzufügen:
```html
Content
```
### Twig Template Richtlinien
#### 1. Base Template Verwendung
**Immer verwenden:**
```twig
{% extends 'backend_tailwind_base.html.twig' %}
```
**Nie verwenden:**
```twig
{% extends 'backend_base.html.twig' %} {# Legacy Bootstrap #}
```
#### 2. Block-Struktur
```twig
{% extends 'backend_tailwind_base.html.twig' %}
{% block title %}Seitentitel{% endblock %}
{% block body %}
{# Hauptinhalt #}
{% endblock %}
{% block javascripts %}
{{ parent() }}
{# Zusätzliche Scripts #}
{% endblock %}
```
#### 3. Form Theme
```twig
{% form_theme form 'form_div_layout_tailwind.html.twig' %}
```
**Nicht verwenden:**
```twig
{% form_theme form 'tailwind_formtheme.html.twig' %}
```
#### 4. Naming Conventions
**Routen:**
```yaml
# Gut: Konsistentes Naming
psc_product_list:
path: /products
psc_product_create:
path: /products/create
psc_product_edit:
path: /products/{id}/edit
psc_product_delete:
path: /products/{id}/delete
```
**Templates:**
```
templates/
product/
backend/
list.html.twig
edit.html.twig
_form.html.twig # Partial
```
### Alpine.js Richtlinien
#### 1. State Management
**Globaler Store (in Base Template):**
```javascript
Alpine.store('sideBar', {
isOpen: true,
toggle() {
this.isOpen = !this.isOpen
}
})
```
**Lokaler State:**
```html
```
#### 2. Event Handling
```html
Open
Menu
```
#### 3. Transitions
Immer Tailwind-kompatible Transitions:
```html
Content
```
### Icon-Verwendung
#### Font Awesome
**Standard-Größen:**
```html
```
**Mit Tailwind:**
```html
Neu erstellen
```
**Häufig verwendete Icons:**
- `fa-plus` - Erstellen/Hinzufügen
- `fa-edit` - Bearbeiten
- `fa-trash` - Löschen
- `fa-save` - Speichern
- `fa-times` - Schließen/Abbrechen
- `fa-check` - Bestätigen/Erfolg
- `fa-exclamation-triangle` - Warnung
- `fa-info-circle` - Information
- `fa-search` - Suchen
- `fa-filter` - Filtern
- `fa-cog` - Einstellungen
- `fa-user` - Benutzer
- `fa-chevron-down` - Dropdown
- `fa-chevron-right` - Pfeil/Navigation
### CSS Klassen-Organisation
**Reihenfolge der Utility-Klassen:**
```html
Content
```
---
## Barrierefreiheit
### ARIA Labels
```html
Fehler: Feld ist erforderlich
```
### Keyboard Navigation
```html
Klickbar
Zum Hauptinhalt springen
```
### Focus States
Immer sichtbare Focus States:
```html
Button
```
### Screen Reader Only
```html
Nur für Screen Reader
```
---
## Migration Guide
### Von Bootstrap zu Tailwind
#### Button-Migration
**Vorher (Bootstrap):**
```html
Speichern
```
**Nachher (Tailwind):**
```html
Speichern
```
#### Card-Migration
**Vorher (Bootstrap):**
```html
```
**Nachher (Tailwind):**
```html
```
#### Form-Migration
**Vorher (Bootstrap):**
```html
Feldname
```
**Nachher (Tailwind):**
```html
Feldname
```
### Checkliste für neue Module
- [ ] Verwendet `backend_tailwind_base.html.twig` als Base-Template
- [ ] Form Theme auf `form_div_layout_tailwind.html.twig` gesetzt
- [ ] Alle Komponenten verwenden Tailwind CSS (kein Bootstrap)
- [ ] Dark Mode Support implementiert (`dark:` Varianten)
- [ ] Responsive Design implementiert (Mobile-First)
- [ ] Wiederverwendbare PSC-Button-Klassen verwendet
- [ ] Standard Badge-Klassen für Status verwendet
- [ ] Icons mit konsistenten Größen (w-4, w-5, w-6)
- [ ] Spacing konsistent mit Tailwind-System (px-7.5, py-6, etc.)
- [ ] Alpine.js für interaktive Komponenten verwendet
- [ ] ARIA-Labels für Barrierefreiheit hinzugefügt
- [ ] Focus States sichtbar und konsistent
- [ ] KnpPagination mit Tailwind-Theme
---
## Best Practices
### Performance
1. **Lazy Loading für Bilder:**
```html
```
2. **Alpine.js x-cloak:**
```html
```
3. **Minimize DOM Queries:**
```javascript
// Gut: State in Alpine.js
// Schlecht: jQuery DOM Manipulation
$('#count').text(count);
```
### Security
1. **XSS Prevention in Twig:**
```twig
{# Gut: Auto-escaped #}
{{ user.name }}
{# Vorsicht: Raw HTML #}
{{ content|raw }} {# Nur für vertrauenswürdigen Content! #}
```
2. **CSRF Protection:**
```twig
{{ form_start(form) }} {# CSRF Token automatisch inkludiert #}
```
3. **SQL Injection Prevention:**
```php
// Gut: Doctrine QueryBuilder
$qb->where('u.email = :email')
->setParameter('email', $email);
```
### Maintenance
1. **Kommentare für komplexe Logik:**
```html
{# Complex Alpine.js state management - do not modify without testing #}
```
2. **TODO-Kommentare:**
```twig
{# TODO: Migrate to Tailwind pagination once KnpPaginator theme is ready #}
{{ knp_pagination_render(pagination) }}
```
3. **Deprecation Warnings:**
```twig
{# @deprecated Use backend_tailwind_base.html.twig instead #}
{% extends 'backend_base.html.twig' %}
```
---
## Ressourcen
### Dokumentation
- **Tailwind CSS:** https://tailwindcss.com/docs
- **Alpine.js:** https://alpinejs.dev
- **Symfony Twig:** https://twig.symfony.com
- **Font Awesome:** https://fontawesome.com/v5/search
### Tools
- **Tailwind CSS IntelliSense** (VS Code Extension)
- **Alpine.js DevTools** (Browser Extension)
- **Symfony Toolbar** (Development)
### Weitere Module/Bundles
- **KnpMenuBundle:** Navigation-Generierung
- **KnpPaginatorBundle:** Pagination
- **LiipImagineBundle:** Image Processing
---
## Changelog
| Version | Datum | Änderungen |
|---------|-------|------------|
| 1.0 | 2025-12-22 | Initiales Design System basierend auf Codebase-Analyse |
---
## Kontakt & Feedback
Für Fragen, Vorschläge oder Verbesserungen zum Design System bitte ein Issue im Projekt-Repository erstellen oder das Entwicklungsteam kontaktieren.
---
**Hinweis:** Dieses Dokument ist ein "Living Document" und wird kontinuierlich aktualisiert, wenn neue Komponenten hinzugefügt oder bestehende Patterns verbessert werden.