This commit is contained in:
Hymmel 2026-01-21 10:06:51 +01:00
parent a93c45f1b6
commit aeea6bfb84
2 changed files with 170 additions and 1 deletions

View file

@ -0,0 +1,169 @@
# Technische Dokumentation: Frontend Architektur (IHK/Ausbildung)
## 1. Einleitung & Technologiewahl
Diese Dokumentation beschreibt die Frontend-Architektur des IT-Ticketsystems. Ziel ist es, die Funktionsweise, die verwendeten Patterns und die TypeScript-spezifische Implementierung für die IHK-Abschlussprüfung verständlich darzulegen.
**Techn Stack:**
- **Framework**: Next.js (React)
- *Begründung*: Next.js bietet "Server-Side Rendering" (SSR) und einfaches Routing, was die Performance und SEO verbessert. Es strukturiert React-Anwendungen klar.
- **Sprache**: TypeScript
- *Begründung*: Typsicherheit minimiert Laufzeitfehler. Interfaces (`User`, `Ticket`) definieren klare Datenstrukturen, was besonders bei Teamarbeit und Wartung essenziell ist.
- **State Management**: React Context API
- *Begründung*: Vermeidung von "Prop Drilling" (Weiterreichen von Daten über viele Ebenen). Zustände wie `user` oder `tickets` werden global verfügbar gemacht.
---
## 2. Projektstruktur & Scopes
Die Dateien sind logisch getrennt:
- `app/`: Enthält die **Seiten (Pages)** und **Routen**. (Next.js App Router).
- `components/`: Enthält wiederverwendbare **UI-Elemente** (Buttons, Cards, Tabellen).
- `lib/`: Enthält **Logik**, **Typen** und **Konfigurationen** (z.B. `auth-context.tsx`, `types.ts`).
### TypeScript Besonderheit: Interfaces (`lib/types.ts`)
In JavaScript wüssten wir nicht, welche Eigenschaften ein "Ticket" hat. In TypeScript definieren wir einen Bauplan (Interface):
```typescript
// lib/types.ts
export type TicketStatus = "OPEN" | "IN_PROGRESS" | "CLOSED" // Union Type: Nur diese 3 Werte sind erlaubt
export interface User {
id: number;
name: string;
role: "LEHRKRAFT" | "RAUMBETREUER"; // Enforced Role
supervisedRooms?: Room[]; // Optionales Array (?): Nicht jeder User hat Räume
}
export interface Ticket {
id: number;
description: string;
status: TicketStatus; // Verwendet den Type von oben
owner: User; // Referenziert das User Interface
}
```
**Warum?** Wenn ich nun `ticket.statu` schreibe, warnt mich VS Code sofort ("Did you mean 'status'?"). Das verhindert Tippfehler und Logikfehler.
---
## 3. Kernlogik: Der AuthContext (`lib/auth-context.tsx`)
Das "Gehirn" der Anwendung. Hier passiert die Kommunikation mit dem Backend.
### Konzept: Provider Pattern
Der `AuthProvider` ist eine Komponente, die um die gesamte App gewickelt wird. Alle Komponenten *innerhalb* dieses Providers können auf seine Daten zugreifen.
**Code-Analyse (vereinfacht):**
```typescript
// Definition des Context-Typs (Was bietet der Context an?)
interface AuthContextType {
user: User | null; // Kann null sein, wenn ausgeloggt
tickets: Ticket[];
login: (e: string, p: string) => Promise<boolean>; // Asynchrone Funktion, gibt true/false zurück
}
// Erstellen des Contexts
const AuthContext = createContext<AuthContextType | null>(null);
// Der Provider (Die Komponente, die Daten bereitstellt)
export function AuthProvider({ children }: { children: ReactNode }) {
// Lokaler State im Provider
const [user, setUser] = useState<User | null>(null); // Generics: <User | null>
// Funktion zum Daten holen
const fetchTickets = useCallback(async (authHeader: string) => {
// API Call
const res = await fetch(\`\${process.env.NEXT_PUBLIC_API_URL}/tickets\`, {
headers: { Authorization: authHeader }
});
const data = await res.json();
setTickets(data); // TypeScript weiß: data muss Ticket[] sein
}, []); // Empty dependency array: Funktion wird nicht ständig neu erstellt
// Diese Werte werden "nach unten" gegeben
return (
<AuthContext.Provider value={{ user, tickets, login, /*...*/ }}>
{children}
</AuthContext.Provider>
);
}
```
**Erklärung für die Doku:**
1. **State**: Wir nutzen `useState`, um Daten zu speichern. TypeScript sorgt dafür, dass wir in `tickets` nur echte Tickets speichern können.
2. **Generics**: `useState<User | null>` sagt: "Dieser State darf nur ein User-Objekt oder null sein".
3. **Hooks**:
- `useEffect`: "Mach das, wenn die App lädt" (z.B. User prüfen).
- `useCallback`: Speichert eine Funktion, damit sie nicht bei jedem Neuladen der Seite neu erstellt wird (Performance).
---
## 4. Komponenten-Logik (Beispiel: `SupervisorDashboard`)
Hier sehen wir, wie die Daten konsumiert werden.
```typescript
export function SupervisorDashboard() {
// 1. Hook nutzen: Zugriff auf globale Daten
const { user, tickets } = useAuth();
// 2. Optional Chaining (?.)
// Wenn user null ist, stürzt die App nicht ab, sondern gibt undefined zurück.
// || [] bedeutet: Wenn undefined/null, nutze leeres Array.
const supervisedRooms = user?.supervisedRooms || [];
// 3. Computed Values (useMemo)
// Berechne 'roomTickets' nur neu, wenn sich 'tickets' oder 'supervisedRooms' ändern.
const roomTickets = useMemo(() => {
if (!supervisedRooms.length) return [];
// Array Methoden: map() und filter()
const roomIds = supervisedRooms.map(r => r.id); // [101, 102]
return tickets.filter((t) => roomIds.includes(t.room.id));
}, [tickets, supervisedRooms]);
return (
<div>
{/* Conditional Rendering: Zeige Badge nur wenn count > 0 */}
{stats.open > 0 && <Badge>{stats.open}</Badge>}
</div>
);
}
```
**Wichtige Konzepte:**
- **Destructuring**: `const { user } = useAuth()` zieht nur die `user`-Variable aus dem Context.
- **Array High-Order Functions**: `map`, `filter`, `reduce` sind Standard in modernem JS/TS, um Daten umzuwandeln.
- **Dependency Arrays**: `[tickets, supervisedRooms]` sagt React: "Führe diese Berechnung nur aus, wenn sich EINE dieser Variablen geändert hat".
---
## 5. Authentifizierung (NextAuth & Middleware)
**Ablauf:**
1. User gibt Daten ein -> `signIn("credentials", ...)`
2. NextAuth sendet Request an unser Backend (`route.ts`).
3. Backend antwortet: "OK, hier ist der User".
4. Frontend speichert User in der **Session**.
5. Der `NextAuthSessionProvider` in `layout.tsx` hält die Session aktiv.
**Code (`route.ts`):**
```typescript
async authorize(credentials) {
// API Anfrage an eigenes Java Backend
const res = await fetch(API_URL + "/login", { ...body });
if (res.ok) {
const user = await res.json();
return user; // NextAuth speichert diesen User
}
return null; // Login fehlgeschlagen
}
```
Wir nutzen NextAuth als "Mittelsmann". Es kümmert sich um Cookies und Security, während unser Backend die eigentliche Prüfung macht.
---
## Zusammenfassung für die Präsentation
"Die Architektur basiert auf einer klaren Trennung von UI (Components) und Logik (Context/Hooks). Durch den Einsatz von TypeScript werden Datenstrukturen wie User und Tickets strikt typisiert, was die Fehleranfälligkeit drastisch reduziert. Das State Management erfolgt effizient über React Context, wodurch alle Komponenten stets synchronen Zugriff auf den aktuellen Anwendungszustand haben, ohne dass Daten mühsam durchgereicht werden müssen (`Prop Drilling`)."

View file

@ -30,7 +30,7 @@ services:
container_name: ticketsystem-frontend
environment:
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://projekt.lona-development.org/api}
API_URL: http://backend:8080
API_URL: ${API_URL:-http://projekt.lona-development.org/api}
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
NEXTAUTH_URL: ${NEXTAUTH_URL}
depends_on: