Campus
Anwendungen
KI-Chat
Content Studio
Semantic Explorer
Nextcloud
Entwicklung
Tasks
Protokoll
Contracts
System Explorer
Ressourcen
Dokumentation
File Backup
Contracts
»
View Structure Contract
» Bearbeiten
Contract bearbeiten
Aktuelle Version:
1.0
Neue Version *
Muss sich von der aktuellen Version unterscheiden.
Änderungsbeschreibung
YAML-Inhalt *
contract: name: "View Structure Contract" version: "1.0" status: active created: "2025-12-20" scope: description: "Gilt für CRUD-Ressourcen mit Standard-Views (index, show, new, edit)" includes: - "/src/View/tasks/*.php" - "/src/View/content/*.php" # Bei neuer CRUD-Ressource hier hinzufügen: "/src/View/{resource}/*.php" excludes: - "/src/View/docs/**/*.php" # Eigener Contract: Betriebsdokumentation - "/src/View/chat/**/*.php" # Interaktives Tool, kein CRUD - "/src/View/home/**/*.php" # Landing Pages - "/src/View/layout.php" # Layout-Template onboarding: | Neue CRUD-Ressource hinzufügen: 1. Verzeichnis erstellen: /src/View/{resource}/ 2. Views anlegen: index.php, show.php, new.php, edit.php 3. Contract-Scope erweitern: includes += "/src/View/{resource}/*.php" 4. Referenz: /src/View/tasks/* als Vorlage kopieren principles: - KISS # Keep It Simple, Stupid - DRY # Don't Repeat Yourself - REST # Representational State Transfer - SRP # Single Responsibility Principle # ============================================================================= # RESTful URL Schema # ============================================================================= restful_urls: description: "Jede Ressource folgt dem gleichen URL-Pattern" pattern: index: "/{resource}" show: "/{resource}/{id}" new: "/{resource}/new" edit: "/{resource}/{id}/edit" rules: - id: URL-001 severity: critical rule: "Keine /create URLs - verwende /new" example: wrong: "/content/create" correct: "/content/new" - id: URL-002 severity: critical rule: "Keine /update oder /delete URLs - verwende HTTP-Methoden" example: wrong: "/tasks/1/update" correct: "PUT /api/v1/tasks/1" - id: URL-003 severity: major rule: "Ressourcen-Namen im Plural" example: wrong: "/task/1" correct: "/tasks/1" # ============================================================================= # View-Dateien pro Ressource # ============================================================================= view_files: description: "Jede Ressource hat 4 Standard-Views" required: - index.php # Liste aller Einträge - show.php # Detail-Ansicht eines Eintrags - new.php # Formular für neuen Eintrag - edit.php # Formular zum Bearbeiten directory_pattern: "/src/View/{resource}/" examples: - "/src/View/tasks/index.php" - "/src/View/tasks/show.php" - "/src/View/content/new.php" - "/src/View/content/edit.php" # ============================================================================= # Seitenstruktur: INDEX (Liste) # ============================================================================= index_structure: description: "Listenansicht aller Einträge einer Ressource" elements_order: 1: h1 # Titel der Ressource 2: stats-grid # Statistik-Karten (optional) 3: page-actions # Button für "Neu erstellen" 4: h2 # Untertitel vor Tabelle 5: filters # Suchfeld + Filter-Dropdowns 6: table # Datentabelle 7: links-bar # Links zu Dokumentation template: | <?php ob_start(); ?> <h1>{Ressource}</h1> <div class="stats-grid"> <div class="stat-card">...</div> <div class="stat-card stat-card--warning">...</div> <div class="stat-card stat-card--info">...</div> <div class="stat-card stat-card--success">...</div> </div> <div class="page-actions"> <a href="/{resource}/new" class="btn btn--primary">Neu erstellen</a> </div> <h2>{Einträge}</h2> <div class="filters"> <input type="search" id="{resource}-search" class="form-input" placeholder="Durchsuchen..."> <select id="filter-status" class="form-select--inline">...</select> </div> <table id="{resource}-table" data-sortable> <thead> <tr> <th data-sort="id">ID</th> <th data-sort="title">Titel</th> ... </tr> </thead> <tbody>...</tbody> </table> <p class="links-bar"> <a href="/docs/{resource}">Dokumentation</a> | <a href="/docs/api/{resource}">API</a> </p> <script src="/js/components/data-table.js"></script> <script> document.addEventListener('DOMContentLoaded', () => { new DataTable('{resource}-table', {...}); }); </script> <?php $content = ob_get_clean(); ?> <?php require VIEW_PATH . '/layout.php'; ?> rules: - id: IDX-001 severity: critical rule: "Kein page-container Wrapper" example: wrong: '<div class="page-container">...' correct: "<h1>Tasks</h1>" - id: IDX-002 severity: critical rule: "Keine verschachtelten Cards" example: wrong: '<div class="card"><div class="card">...' correct: "Flache Struktur ohne Card-Wrapper" - id: IDX-003 severity: major rule: "stats-grid hat genau 4 Karten" cards: - stat-card (neutral/gesamt) - stat-card--warning (offen/pending) - stat-card--info (in Arbeit) - stat-card--success (fertig/abgeschlossen) - id: IDX-004 severity: major rule: "Tabelle muss DataTable-Komponente verwenden" requires: - data-sortable Attribut - Suchfeld - JavaScript-Initialisierung # ============================================================================= # Seitenstruktur: SHOW (Detail) # ============================================================================= show_structure: description: "Detail-Ansicht eines einzelnen Eintrags" elements_order: 1: breadcrumb # Navigation zurück 2: h1 # Titel des Eintrags 3: table # Metadaten-Tabelle 4: h2+content # Inhaltsbereiche (Beschreibung, etc.) 5: h2+actions # Aktions-Buttons 6: h2+tables # Verknüpfte Daten (optional) 7: back-link # Link zurück zur Liste template: | <?php ob_start(); ?> <nav class="breadcrumb"> <a href="/{resource}">{Ressource}</a> » {Eintrag} #{id} </nav> <h1><?= htmlspecialchars($item['title']) ?></h1> <table> <tr><th>ID</th><td><?= $item['id'] ?></td></tr> <tr><th>Status</th><td><span class="badge badge--<?= $item['status'] ?>"><?= $item['status'] ?></span></td></tr> <tr><th>Erstellt</th><td><?= $item['created_at'] ?></td></tr> </table> <?php if ($item['description']): ?> <h2>Beschreibung</h2> <p><?= nl2br(htmlspecialchars($item['description'])) ?></p> <?php endif; ?> <h2>Aktionen</h2> <div class="action-bar"> <a href="/{resource}/<?= $item['id'] ?>/edit" class="btn">Bearbeiten</a> <button class="btn btn--success">Aktion 1</button> <button class="btn btn--danger">Aktion 2</button> </div> <?php if (!empty($related_items)): ?> <h2>Verknüpfte Daten</h2> <table data-sortable>...</table> <?php endif; ?> <p style="margin-top: 2rem;"><a href="/{resource}">← Zurück zur Übersicht</a></p> <?php $content = ob_get_clean(); ?> <?php require VIEW_PATH . '/layout.php'; ?> rules: - id: SHW-001 severity: critical rule: "Breadcrumb als erstes Element" format: '<nav class="breadcrumb">...</nav>' - id: SHW-002 severity: critical rule: "Metadaten in einfacher Tabelle, keine Cards" example: wrong: '<div class="card"><div class="config-grid">...' correct: "<table><tr><th>ID</th><td>1</td></tr>..." - id: SHW-003 severity: major rule: "Aktionen in action-bar, nicht verstreut" example: wrong: "Buttons an verschiedenen Stellen der Seite" correct: '<div class="action-bar">alle Buttons hier</div>' - id: SHW-004 severity: major rule: "Zurück-Link am Ende der Seite" format: '<p style="margin-top: 2rem;"><a href="/{resource}">← Zurück zur Übersicht</a></p>' # ============================================================================= # Seitenstruktur: NEW (Erstellen) # ============================================================================= new_structure: description: "Formular zum Erstellen eines neuen Eintrags" elements_order: 1: breadcrumb # Navigation 2: h1 # "Neu erstellen" 3: form # Formular template: | <?php ob_start(); ?> <nav class="breadcrumb"> <a href="/{resource}">{Ressource}</a> » Neu </nav> <h1>Neuer {Eintrag}</h1> <form class="form" method="post" action="/{resource}" style="max-width: 600px;"> <div class="form-group"> <label for="title">Titel *</label> <input type="text" id="title" name="title" class="form-input" required> </div> <div class="form-group"> <label for="description">Beschreibung</label> <textarea id="description" name="description" class="form-textarea" rows="4"></textarea> </div> <div class="form-group"> <label for="type">Typ</label> <select id="type" name="type" class="form-select"> <option value="">-- Auswählen --</option> </select> </div> <div class="form-actions"> <button type="submit" class="btn btn--primary">Erstellen</button> <a href="/{resource}" class="btn">Abbrechen</a> </div> </form> <?php $content = ob_get_clean(); ?> <?php require VIEW_PATH . '/layout.php'; ?> rules: - id: NEW-001 severity: critical rule: "Formular mit class='form' und max-width: 600px" example: wrong: '<form class="card">...' correct: '<form class="form" style="max-width: 600px;">' - id: NEW-002 severity: critical rule: "Keine form-section oder verschachtelte Strukturen" example: wrong: '<div class="form-section"><h2 class="form-section__title">...' correct: '<div class="form-group"><label>...</label><input>...</div>' - id: NEW-003 severity: major rule: "Labels ohne spezielle Klassen" example: wrong: '<label class="form-group__label">' correct: "<label for=\"title\">" - id: NEW-004 severity: major rule: "form-actions am Ende mit Primary-Button zuerst" format: | <div class="form-actions"> <button type="submit" class="btn btn--primary">Erstellen</button> <a href="/{resource}" class="btn">Abbrechen</a> </div> # ============================================================================= # Seitenstruktur: EDIT (Bearbeiten) # ============================================================================= edit_structure: description: "Formular zum Bearbeiten eines bestehenden Eintrags" elements_order: 1: breadcrumb # Navigation mit Link zum Eintrag 2: h1 # "Bearbeiten" 3: form # Formular mit vorausgefüllten Werten 4: form-message # Feedback-Container 5: script # JavaScript für API-Call template: | <?php ob_start(); ?> <nav class="breadcrumb"> <a href="/{resource}">{Ressource}</a> » <a href="/{resource}/<?= $item['id'] ?>">{Eintrag} #<?= $item['id'] ?></a> » Bearbeiten </nav> <h1>{Eintrag} bearbeiten</h1> <form id="{resource}-form" class="form" style="max-width: 600px;"> <div class="form-group"> <label for="title">Titel *</label> <input type="text" id="title" name="title" class="form-input" value="<?= htmlspecialchars($item['title']) ?>" required> </div> <div class="form-actions"> <button type="submit" class="btn btn--primary">Speichern</button> <a href="/{resource}/<?= $item['id'] ?>" class="btn">Abbrechen</a> </div> </form> <div id="form-message" class="form-message"></div> <script> document.getElementById('{resource}-form').addEventListener('submit', async (e) => { e.preventDefault(); const formData = new FormData(e.target); const data = Object.fromEntries(formData.entries()); const response = await fetch('/api/v1/{resource}/<?= $item['id'] ?>', { method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data) }); const result = await response.json(); if (result.success) { window.location.href = '/{resource}/<?= $item['id'] ?>'; } else { document.getElementById('form-message').innerHTML = '<span class="form-message--error">Fehler: ' + result.error + '</span>'; } }); </script> <?php $content = ob_get_clean(); ?> <?php require VIEW_PATH . '/layout.php'; ?> rules: - id: EDT-001 severity: critical rule: "Breadcrumb enthält Link zum Eintrag" example: wrong: '<a href="/tasks">Tasks</a> » Bearbeiten' correct: '<a href="/tasks">Tasks</a> » <a href="/tasks/1">Task #1</a> » Bearbeiten' - id: EDT-002 severity: major rule: "Formular verwendet API mit PUT-Methode" method: "PUT /api/v1/{resource}/{id}" - id: EDT-003 severity: major rule: "Abbrechen-Link führt zum Eintrag, nicht zur Liste" example: wrong: '<a href="/tasks">Abbrechen</a>' correct: '<a href="/tasks/1">Abbrechen</a>' # ============================================================================= # Verbotene Elemente # ============================================================================= forbidden: description: "Diese Elemente/Patterns sind in Views nicht erlaubt" elements: - id: FRB-001 element: "page-container" severity: critical reason: "Unnötige Verschachtelung" - id: FRB-002 element: "page-header" severity: critical reason: "Verwende breadcrumb + h1 separat" - id: FRB-003 element: "card (als Wrapper)" severity: critical reason: "Keine Cards um Formulare oder Inhalte" exception: "result-box für Ergebnisanzeige erlaubt" - id: FRB-004 element: "form-section" severity: critical reason: "Flache Formularstruktur bevorzugen" - id: FRB-005 element: "grid-2, main-column, side-column" severity: major reason: "Einspaltiges Layout bevorzugen" - id: FRB-006 element: "btn--large" severity: minor reason: "Standard-Button-Größe verwenden" - id: FRB-007 element: "form-group__label, form-group__hint" severity: major reason: "Einfache Labels ohne BEM-Modifikatoren" # ============================================================================= # CSS-Klassen Referenz # ============================================================================= css_classes: layout: - breadcrumb # Navigation - stats-grid # Container für Statistik-Karten - stat-card # Einzelne Statistik-Karte - page-actions # Container für Haupt-Aktionen - action-bar # Container für Detail-Aktionen - filters # Container für Suchfeld + Filter - links-bar # Container für Dokumentations-Links - result-box # Container für Ergebnisanzeige forms: - form # Formular-Container - form-group # Label + Input Gruppe - form-input # Text-Input - form-textarea # Textarea - form-select # Select-Dropdown - form-select--inline # Inline-Select (in Filtern) - form-actions # Button-Container - form-message # Feedback-Container - inline-form # Formular in einer Zeile (für Actions) buttons: - btn # Basis-Button - btn--primary # Primäre Aktion - btn--success # Erfolg/Bestätigen - btn--danger # Löschen/Ablehnen - btn--light # Sekundäre Aktion - btn--info # Information badges: - badge # Basis-Badge - badge--{status} # Status-spezifisch (pending, completed, etc.) tables: - data-sortable # Attribut für sortierbare Tabellen - data-sort # Attribut für sortierbare Spalten - empty-state # Leerer Zustand - empty-state--small # Kompakter leerer Zustand # ============================================================================= # Validierung # ============================================================================= validation: pass_threshold: critical: 0 # Keine kritischen Fehler erlaubt major: 2 # Max 2 major Fehler minor: 5 # Max 5 minor Fehler automated_checks: - "Keine page-container Klasse" - "Keine card Wrapper um Formulare" - "Breadcrumb als erstes Element in show/new/edit" - "form hat max-width Style" - "form-actions vor </form>" - "Tabellen haben data-sortable" # ============================================================================= # Beispiele: Korrekte Implementierung # ============================================================================= examples: reference_files: index: "/src/View/tasks/index.php" show: "/src/View/tasks/show.php" new: "/src/View/tasks/new.php" edit: "/src/View/tasks/edit.php" resources_using_contract: - tasks - content
Neue Version speichern
Abbrechen