# Backend-Architektur

## Übersicht

Das Backend folgt einer modernen, klassenbasierten Architektur mit klarer Trennung der Verantwortlichkeiten (Separation of Concerns).

## Architektur-Schichten

```
┌─────────────────────────────────────┐
│         Routes (Express)            │  ← HTTP-Endpunkte definieren
├─────────────────────────────────────┤
│      Controller-Klassen             │  ← HTTP Request/Response Handling
├─────────────────────────────────────┤
│      Service-Klassen                │  ← Business-Logik
├─────────────────────────────────────┤
│      Models                         │  ← Datenmodelle & Validierung
├─────────────────────────────────────┤
│      Datenspeicher                  │  ← In-Memory / Datenbank
└─────────────────────────────────────┘
```

## Komponenten

### 1. Routes (`src/routes/`)
**Verantwortlichkeit:** Definition der HTTP-Endpunkte

```javascript
// src/routes/timeEntries.js
router.get('/', timeEntryController.getAllEntries.bind(timeEntryController));
```

- Definiert URL-Pfade und HTTP-Methoden
- Bindet Endpunkte an Controller-Methoden
- Keine Business-Logik

### 2. Controller (`src/controllers/`)
**Verantwortlichkeit:** HTTP Request/Response Handling

```javascript
// src/controllers/TimeEntryController.js
class TimeEntryController {
  async getAllEntries(req, res) {
    try {
      const entries = timeEntryService.getAllEntries();
      res.json(entries);
    } catch (error) {
      res.status(500).json({ error: 'Fehler...' });
    }
  }
}
```

**Controller sind zuständig für:**
- ✅ Request-Parameter extrahieren
- ✅ Service-Methoden aufrufen
- ✅ HTTP-Statuscodes setzen
- ✅ Response formatieren
- ✅ Error-Handling (HTTP-spezifisch)

**Controller sind NICHT zuständig für:**
- ❌ Business-Logik
- ❌ Datenvalidierung (außer HTTP-Parameter)
- ❌ Datenbankzugriff
- ❌ Komplexe Berechnungen

### 3. Services (`src/services/`)
**Verantwortlichkeit:** Business-Logik

```javascript
// src/services/TimeEntryService.js
class TimeEntryService {
  createEntry(entryData) {
    // Validierung
    const runningEntry = this.timeEntries.find(e => e.isRunning);
    if (runningEntry) {
      throw new Error('Es läuft bereits ein Timer...');
    }
    
    // Business-Logik
    const newEntry = new TimeEntry({ ... });
    newEntry.validate();
    
    // Speichern
    this.timeEntries.push(newEntry);
    return newEntry;
  }
}
```

**Services sind zuständig für:**
- ✅ Komplette Business-Logik
- ✅ Datenvalidierung
- ✅ Datenzugriff
- ✅ Berechnungen
- ✅ Business-Rules
- ✅ Transaktionen

**Services sind NICHT zuständig für:**
- ❌ HTTP-spezifische Logik
- ❌ Response-Formatierung
- ❌ HTTP-Statuscodes

### 4. Models (`src/models/`)
**Verantwortlichkeit:** Datenmodelle und Validierung

```javascript
// src/models/TimeEntry.js
class TimeEntry {
  constructor(data) { ... }
  
  validate() {
    if (!this.startTime) {
      throw new Error('Startzeit ist erforderlich');
    }
  }
  
  calculateDuration() { ... }
  getFormattedDuration() { ... }
}
```

**Models sind zuständig für:**
- ✅ Datenstruktur definieren
- ✅ Datenvalidierung
- ✅ Hilfsmethoden für Daten
- ✅ Formatierung

## Vorteile dieser Architektur

### 1. **Separation of Concerns**
Jede Schicht hat eine klar definierte Verantwortlichkeit:
- Routes → Routing
- Controller → HTTP-Handling
- Services → Business-Logik
- Models → Datenmodelle

### 2. **Testbarkeit**
```javascript
// Services können isoliert getestet werden
const service = new TimeEntryService();
const entry = service.createEntry({ project: 'Test' });
```

### 3. **Wiederverwendbarkeit**
Services können von verschiedenen Controllern oder anderen Services verwendet werden.

### 4. **Wartbarkeit**
Änderungen an der Business-Logik betreffen nur Services, nicht Controller oder Routes.

### 5. **Skalierbarkeit**
- Services können einfach auf Microservices aufgeteilt werden
- Einfache Integration von Datenbanken
- Caching-Schichten hinzufügen

## Datenfluss

### Beispiel: Neuen Zeiteintrag erstellen

```
1. HTTP POST Request
   ↓
2. Route: POST /api/time-entries
   ↓
3. Controller.createEntry()
   - Extrahiert req.body
   - Ruft Service auf
   ↓
4. Service.createEntry()
   - Validiert Daten
   - Prüft Business-Rules
   - Erstellt Model
   - Speichert Daten
   ↓
5. Controller.createEntry()
   - Setzt Status 201
   - Sendet JSON Response
   ↓
6. HTTP Response
```

## Singleton-Pattern

Sowohl Controller als auch Services werden als Singleton exportiert:

```javascript
// Am Ende der Datei
module.exports = new TimeEntryService();
```

**Vorteile:**
- Gleicher Datenspeicher über alle Requests
- Keine Instanziierung bei jedem Request
- Shared State (für In-Memory Storage)

**Hinweis:** Bei Datenbank-Integration kann auf Singleton verzichtet werden.

## Erweiterte Features

### Service-Features

Die `TimeEntryService`-Klasse bietet erweiterte Funktionen:

```javascript
// Statistiken mit Zeitfilter
getStatistics() → {
  totalEntries,
  projectStats,
  timeStats: { today, week, month }
}

// Laufenden Timer abrufen
getRunningEntry()

// Nach Projekt filtern
getEntriesByProject(projectName)

// Datumsbereich filtern
getEntriesByDateRange(startDate, endDate)
```

### Controller-Features

Der `TimeEntryController` bietet zusätzliche Endpunkte:

```javascript
// GET /api/time-entries/running
getRunningEntry()

// GET /api/time-entries/project/:projectName
getEntriesByProject()
```

## Best Practices

### 1. Error Handling

**In Services:**
```javascript
throw new Error('Beschreibende Fehlermeldung');
```

**In Controllern:**
```javascript
catch (error) {
  if (error.message.includes('nicht gefunden')) {
    return res.status(404).json({ error: '...' });
  }
  res.status(500).json({ error: '...' });
}
```

### 2. Async/Await

Controller-Methoden sind `async`, auch wenn Services aktuell synchron sind:

```javascript
async getAllEntries(req, res) {
  // Vorbereitet für asynchrone Service-Calls (z.B. Datenbank)
}
```

### 3. Binding

Bei Klassen-Methoden als Express-Handler muss `bind()` verwendet werden:

```javascript
router.get('/', controller.method.bind(controller));
```

## Migration auf Datenbank

Die Architektur ist vorbereitet für Datenbank-Integration:

```javascript
class TimeEntryService {
  async createEntry(entryData) {
    // Statt In-Memory:
    // return await TimeEntryModel.create(entryData);
  }
}
```

Nur die Service-Schicht muss angepasst werden, Controller bleiben unverändert!

## Zusammenfassung

| Schicht | Datei | Verantwortlichkeit | Beispiel |
|---------|-------|-------------------|----------|
| **Routes** | `timeEntries.js` | URL-Mapping | `router.get('/', ...)` |
| **Controller** | `TimeEntryController.js` | HTTP-Handling | `res.json(data)` |
| **Service** | `TimeEntryService.js` | Business-Logik | `validateData()` |
| **Model** | `TimeEntry.js` | Datenmodell | `validate()` |

Diese Architektur ermöglicht eine professionelle, wartbare und skalierbare Backend-Anwendung! 🚀



