# Luna Recipes — Auth v2 Feature-Spezifikation

## Übersicht

Implementierung eines vollständigen Authentifizierungssystems für die Luna Rezept-App mit Multi-User-Support und Haushaltsfunktionalität. Das System ermöglicht es mehreren Nutzern, die App zu verwenden, dabei ihre Daten zu trennen und optional einen gemeinsamen Haushalt zu teilen.

## 1. Datenmodell

### 1.1 Neue Tabellen

#### users
```sql
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email TEXT UNIQUE NOT NULL,
  password_hash TEXT NOT NULL,
  display_name TEXT NOT NULL,
  avatar_url TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE UNIQUE INDEX idx_users_email ON users(email);
```

#### households
```sql
CREATE TABLE households (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name TEXT NOT NULL,
  invite_code TEXT UNIQUE NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE UNIQUE INDEX idx_households_invite_code ON households(invite_code);
```

#### household_members
```sql
CREATE TABLE household_members (
  household_id UUID REFERENCES households(id) ON DELETE CASCADE,
  user_id UUID REFERENCES users(id) ON DELETE CASCADE,
  role TEXT NOT NULL CHECK (role IN ('owner', 'member')),
  joined_at TIMESTAMPTZ DEFAULT NOW(),
  PRIMARY KEY (household_id, user_id)
);
```

#### user_favorites (Neue Tabelle)
```sql
CREATE TABLE user_favorites (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES users(id) ON DELETE CASCADE,
  recipe_id UUID REFERENCES recipes(id) ON DELETE CASCADE,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(user_id, recipe_id)
);
```

### 1.2 Erweiterte bestehende Tabellen

#### shopping_items
```sql
-- Erweitern um User- und Haushaltszuordnung
ALTER TABLE shopping_items ADD COLUMN user_id UUID REFERENCES users(id);
ALTER TABLE shopping_items ADD COLUMN household_id UUID REFERENCES households(id);

-- Migration: NULL user_id wird beim ersten Login zugewiesen
```

#### notes
```sql
-- Erweitern um User-Zuordnung
ALTER TABLE notes ADD COLUMN user_id UUID REFERENCES users(id);

-- Migration: Bestehende Notizen werden dem ersten registrierten User zugewiesen
```

#### recipes
```sql
-- Recipes bleiben global, aber mit Ersteller-Info
ALTER TABLE recipes ADD COLUMN created_by UUID REFERENCES users(id);

-- Migration: Bestehende Rezepte werden dem ersten registrierten User zugewiesen
```

### 1.3 Daten-Ownership

- **Recipes:** Global sichtbar, `created_by` zur Information
- **Shopping Items:** Pro User ODER pro Haushalt (wenn `household_id` gesetzt)
- **Favorites:** Pro User (user_favorites Tabelle)
- **Notes:** Pro User
- **Households:** Gemeinsam für alle Mitglieder

## 2. API Endpoints

### 2.1 Authentication

#### POST /api/auth/register
```json
// Request
{
  "email": "luna@example.com",
  "password": "secure123!",
  "display_name": "Luna"
}

// Response (201 Created)
{
  "success": true,
  "user": {
    "id": "uuid-here",
    "email": "luna@example.com",
    "display_name": "Luna",
    "avatar_url": null,
    "created_at": "2026-02-18T15:30:00Z"
  },
  "access_token": "jwt-token-here"
}

// Error (400 Bad Request)
{
  "success": false,
  "error": "EMAIL_EXISTS",
  "message": "Ein Account mit dieser E-Mail existiert bereits"
}
```

#### POST /api/auth/login
```json
// Request
{
  "email": "luna@example.com",
  "password": "secure123!"
}

// Response (200 OK)
{
  "success": true,
  "user": {
    "id": "uuid-here",
    "email": "luna@example.com",
    "display_name": "Luna",
    "avatar_url": null
  },
  "access_token": "jwt-token-here"
}

// Error (401 Unauthorized)
{
  "success": false,
  "error": "INVALID_CREDENTIALS",
  "message": "E-Mail oder Passwort ungültig"
}
```

#### POST /api/auth/logout
```json
// Response (200 OK)
{
  "success": true,
  "message": "Erfolgreich abgemeldet"
}
```

#### GET /api/auth/me
```json
// Response (200 OK)
{
  "success": true,
  "user": {
    "id": "uuid-here",
    "email": "luna@example.com",
    "display_name": "Luna",
    "avatar_url": "https://example.com/avatar.jpg",
    "household": {
      "id": "household-uuid",
      "name": "Luna & Marc",
      "role": "owner"
    }
  }
}
```

#### PUT /api/auth/me
```json
// Request (Profil bearbeiten)
{
  "display_name": "Luna Schmidt",
  "avatar_url": "https://example.com/new-avatar.jpg"
}

// Response (200 OK)
{
  "success": true,
  "user": {
    "id": "uuid-here",
    "email": "luna@example.com",
    "display_name": "Luna Schmidt",
    "avatar_url": "https://example.com/new-avatar.jpg"
  }
}
```

#### PUT /api/auth/me/password
```json
// Request
{
  "current_password": "old123!",
  "new_password": "new456!"
}

// Response (200 OK)
{
  "success": true,
  "message": "Passwort erfolgreich geändert"
}

// Error (400 Bad Request)
{
  "success": false,
  "error": "INVALID_CURRENT_PASSWORD",
  "message": "Aktuelles Passwort ist falsch"
}
```

### 2.2 Households

#### POST /api/households
```json
// Request (Haushalt erstellen)
{
  "name": "Luna & Marc"
}

// Response (201 Created)
{
  "success": true,
  "household": {
    "id": "household-uuid",
    "name": "Luna & Marc",
    "invite_code": "COOK2024",
    "created_at": "2026-02-18T15:30:00Z",
    "members": [
      {
        "user_id": "user-uuid",
        "display_name": "Luna",
        "role": "owner",
        "joined_at": "2026-02-18T15:30:00Z"
      }
    ]
  }
}
```

#### POST /api/households/:id/invite
```json
// Response (200 OK) - Neuen Einladungscode generieren
{
  "success": true,
  "invite_code": "COOK2025",
  "expires_at": "2026-02-25T15:30:00Z"
}
```

#### POST /api/households/join
```json
// Request
{
  "invite_code": "COOK2024"
}

// Response (200 OK)
{
  "success": true,
  "household": {
    "id": "household-uuid",
    "name": "Luna & Marc",
    "role": "member"
  }
}

// Error (400 Bad Request)
{
  "success": false,
  "error": "INVALID_INVITE_CODE",
  "message": "Einladungscode ungültig oder abgelaufen"
}
```

#### GET /api/households/mine
```json
// Response (200 OK)
{
  "success": true,
  "household": {
    "id": "household-uuid",
    "name": "Luna & Marc",
    "invite_code": "COOK2024",
    "role": "owner",
    "members": [
      {
        "user_id": "user1-uuid",
        "display_name": "Luna",
        "role": "owner",
        "joined_at": "2026-02-18T15:30:00Z"
      },
      {
        "user_id": "user2-uuid",
        "display_name": "Marc",
        "role": "member",
        "joined_at": "2026-02-19T10:15:00Z"
      }
    ]
  }
}
```

## 3. Frontend Pages

### 3.1 Authentication Pages

#### /login
- **Design:** Vollbild-Login mit Luna Recipes Logo
- **Felder:** E-Mail, Passwort, "Angemeldet bleiben" Checkbox
- **Actions:** Login, "Registrieren" Link, "Passwort vergessen" Link (v2.1)
- **Mobile:** Touch-optimierte Input-Felder, große Login-Button
- **Validation:** Client-side Validation mit sofortigem Feedback
- **States:** Loading State beim Login-Prozess

#### /register
- **Design:** Gleiche Basis wie Login-Page
- **Felder:** E-Mail, Passwort, Passwort wiederholen, Display Name
- **Validation:** 
  - E-Mail Format-Check
  - Passwort-Stärke Indikator
  - Passwort-Match Validation
  - Display Name min. 2 Zeichen
- **Actions:** Registrieren, "Schon Account?" Login-Link
- **Flow:** Nach erfolgreicher Registrierung → automatisch eingeloggt → Dashboard

### 3.2 Profile Pages

#### /profile
- **Layout:** Card-basiert, vertikal gestapelt (kein Tab-Interface)
- **Profil-Karte:**
  - Avatar (Upload oder URL)
  - Display Name (inline editierbar)
  - E-Mail (nicht editierbar, mit "Ändern" Link für v2.1)
  - "Passwort ändern" Button
- **Haushalt-Karte:** (immer sichtbar, direkt unter Profil)
  - **Kein Haushalt:** Card mit 🏠 Icon, "Haushalt erstellen" + "Beitreten" Buttons
  - **In Haushalt:** Haushalt-Name, Mitglieder-Avatare, "Verwalten" Button → `/profile/household`
  - Visuell prominent — nicht versteckt in einem Tab!
- **Quick-Actions:** Logout-Button unten
- **Mobile:** Große Avatar-Anzeige, Touch-freundliche Edit-Buttons, 44px Targets

#### /profile/edit
- **Modal oder Fullscreen (Mobile):** Profil bearbeiten
- **Felder:** Display Name, Avatar URL/Upload
- **Actions:** Speichern, Abbrechen
- **Validation:** Display Name required

#### /profile/password
- **Layout:** Focused Passwort-Ändern Page
- **Felder:** Aktuelles Passwort, Neues Passwort, Bestätigung
- **Security:** 
  - Passwort-Stärke Anzeige
  - "Passwort anzeigen" Toggle
  - Session-Refresh nach Änderung
- **UX:** Erfolgs-Toast + Redirect nach Speichern

#### /profile/household
- **States:**
  - **Kein Haushalt:** "Haushalt erstellen" oder "Haushalt beitreten"
  - **Haushalt Owner:** Mitglieder-Liste, Einladungscode verwalten
  - **Haushalt Member:** Mitglieder-Liste, "Haushalt verlassen"
- **Features:**
  - Einladungscode kopieren/teilen
  - QR-Code für Einladung (Mobile-optimiert)
  - Mitglieder-Management (nur Owner)

## 4. Authentication Flow

### 4.1 Token-Strategy

#### JWT Access Token
- **Laufzeit:** 15 Minuten
- **Storage:** Memory (React State + Context)
- **Payload:**
  ```json
  {
    "sub": "user-uuid",
    "email": "luna@example.com",
    "display_name": "Luna",
    "household_id": "household-uuid",
    "iat": 1708272600,
    "exp": 1708273500
  }
  ```

#### Refresh Token
- **Laufzeit:** 30 Tage
- **Storage:** httpOnly Cookie, Secure, SameSite=Strict
- **Rotation:** Neuer Refresh Token bei jedem Access Token Refresh
- **Cookie Name:** `luna_refresh_token`

### 4.2 Auto-Refresh Flow

```typescript
// Auth Context implementiert Auto-Refresh
const authContext = {
  // Access Token im Memory
  accessToken: string | null,
  // User Info aus Token dekodiert
  user: User | null,
  // Auto-refresh 2 Minuten vor Ablauf
  refreshToken: () => Promise<void>,
  logout: () => void
}

// Axios Interceptor für Auto-Refresh
axios.interceptors.response.use(
  (response) => response,
  async (error) => {
    if (error.response?.status === 401) {
      await authContext.refreshToken()
      // Retry original request
      return axios.request(error.config)
    }
    return Promise.reject(error)
  }
)
```

### 4.3 Route Protection

```typescript
// Protected Route Component
function ProtectedRoute({ children }: { children: React.ReactNode }) {
  const { user, loading } = useAuth()
  
  if (loading) return <LoadingSpinner />
  if (!user) return <Navigate to="/login" replace />
  
  return <>{children}</>
}

// App Router
<Routes>
  <Route path="/login" element={<LoginPage />} />
  <Route path="/register" element={<RegisterPage />} />
  <Route path="/" element={
    <ProtectedRoute>
      <Dashboard />
    </ProtectedRoute>
  } />
</Routes>
```

### 4.4 Login Flow States

1. **Unauthenticated:** Redirect zu `/login`
2. **Login Success:** 
   - Set Access Token in Memory
   - Set Refresh Token in Cookie
   - Redirect zu ursprünglicher Route oder `/`
3. **Token Expired:** Auto-refresh, bei Fehler → Logout
4. **Logout:** Clear Token + Cookie, Redirect zu `/login`

## 5. Haushalt-Feature

### 5.1 Haushalt erstellen

1. User klickt "Haushalt erstellen" in `/profile/household`
2. Modal: Haushalt-Name eingeben
3. Backend erstellt Haushalt + generiert Einladungscode
4. User wird automatisch als Owner hinzugefügt
5. Einladungscode wird angezeigt zum Teilen

### 5.2 Haushalt beitreten

#### Flow
1. User erhält Einladungscode (per Link, QR-Code oder manuell)
2. In `/profile/household` → Button "Haushalt beitreten"
3. **Eingabe:** 6-stelliger Code (uppercase, alphanumerisch, z.B. `COOK2A`)
4. Backend validiert Code → fügt User als `member` hinzu
5. Erfolg: Konfetti 🎉 + Toast "Willkommen bei [Haushalt-Name]!"
6. Einkaufsliste zeigt ab sofort Haushalt-Items

#### Deep Link Support
- URL-Format: `https://luna.supertoll.xyz/join/{invite_code}`
- Wenn eingeloggt → direkt beitreten (mit Bestätigungs-Dialog)
- Wenn nicht eingeloggt → Redirect zu `/login?redirect=/join/{code}`
- Nach Login → automatisch Join-Flow fortsetzen

#### QR-Code
- Owner kann QR-Code generieren (enthält Deep Link)
- Share-Button: QR als Bild teilen oder Code kopieren
- Library: `qrcode.react` (lightweight)

#### Fehlerbehandlung
- `INVALID_INVITE_CODE` → "Code ungültig oder abgelaufen"
- `ALREADY_IN_HOUSEHOLD` → "Du bist bereits in einem Haushalt. Zuerst verlassen?"
- `HOUSEHOLD_FULL` → "Haushalt hat maximale Mitgliederzahl erreicht" (Limit: 10)
- Netzwerkfehler → Retry-Button

#### Haushalt verlassen
- Member können jederzeit verlassen (Bestätigungs-Dialog)
- Owner kann nur verlassen wenn ein anderer Member zum Owner gemacht wird
- Letzter Member → Haushalt wird gelöscht
- Nach Verlassen: eigene Shopping-Items bleiben privat erhalten

### 5.3 Gemeinsame Einkaufsliste

#### Datenlogik
- Shopping Items mit `household_id` sind für alle Haushaltsmitglieder sichtbar
- Shopping Items mit nur `user_id` sind privat
- Standard: Neue Items werden Haushalt zugeordnet (wenn User in Haushalt ist)
- Toggle: "Privat" Checkbox beim Hinzufügen

#### UI/UX
- **Indicator:** Haushalt-Items haben kleines Haushalt-Icon
- **Filter:** "Alle", "Haushalt", "Privat" Tabs in Shopping Liste
- **Mobile:** Swipe-Actions: "Als privat markieren" / "Mit Haushalt teilen"

### 5.4 Smarte Mengenabfrage beim Rezept-Einkauf

Aktuell werden beim "Zur Einkaufsliste hinzufügen" alle Zutaten 1:1 übernommen. Aber oft hat man schon Mehl, Eier, Zucker etc. daheim. Statt blind alles draufzupacken → User fragen was noch fehlt.

#### Flow: "Was brauchst du noch?"
1. User klickt "Zutaten zur Einkaufsliste" auf der Rezeptseite
2. **Modal/Sheet öffnet sich** mit allen Zutaten als Checkliste
3. Jede Zutat hat:
   - ☑️ Checkbox (Standard: alle an)
   - Name + Menge aus Rezept
   - Optional: Menge anpassen (z.B. "hab noch 200g, brauch nur 300g")
4. User deaktiviert was schon da ist
5. Button: "X Artikel hinzufügen" (zeigt Anzahl der aktiven)
6. Nur ausgewählte Zutaten landen auf der Liste

#### Quick-Actions im Modal
- **"Alles"** — alle Checkboxen an (default)
- **"Basics abwählen"** — typische Vorrats-Zutaten automatisch deaktivieren (Salz, Pfeffer, Öl, Wasser)
- **"Nichts"** — alle aus, manuell auswählen

#### Basics-Liste (konfigurierbar pro User/Haushalt)
Standard-Basics die man meistens daheim hat:
- Salz, Pfeffer, Zucker, Mehl, Öl, Wasser, Butter, Eier
- User kann in Settings eigene Basics definieren
- Passt zu Luna: Mehl ✅ Zucker ✅ Eier ✅ Backpulver ✅ (Butter ❌ muss immer drauf 😄)

#### Späterer Ausbau (v2+: Vorratskammer/Pantry)
- Automatischer Abgleich mit Vorratskammer
- "Hab ich schon" wird automatisch vorausgewählt
- Fehlmengen werden berechnet (Rezept braucht 500g, hast 200g → 300g auf Liste)

### 5.5 Manuelle Artikel zur Einkaufsliste hinzufügen

Aktuell kommen Shopping-Items nur aus Rezepten. User sollen auch eigene Artikel hinzufügen können (z.B. "Klopapier", "Spülmittel", Zutaten ohne Rezept).

#### API

##### POST /api/shopping/manual
```json
// Request
{
  "name": "Klopapier",
  "amount": "1",
  "unit": "Packung",
  "private": false
}

// Response (201 Created)
{
  "success": true,
  "item": {
    "id": "uuid",
    "name": "Klopapier",
    "amount": "1",
    "unit": "Packung",
    "checked": false,
    "recipe_id": null,
    "user_id": "user-uuid",
    "household_id": "household-uuid",
    "created_at": "2026-02-18T16:00:00Z"
  }
}
```

#### DB-Erweiterung
```sql
-- recipe_id wird NULLABLE (ist es vermutlich schon)
-- Manuelle Items haben recipe_id = NULL
-- Optional: source-Feld um Herkunft zu unterscheiden
ALTER TABLE shopping_items ADD COLUMN source TEXT DEFAULT 'recipe' 
  CHECK (source IN ('recipe', 'manual'));
```

#### Frontend UI

##### Eingabefeld (oben in der Einkaufsliste)
- **Sticky Input-Bar** oben auf der Shopping-Page
- Textfeld mit Placeholder "Artikel hinzufügen..." + ➕ Button
- **Smart Parsing:** "2 Liter Milch" → amount: "2", unit: "Liter", name: "Milch"
- **Autocomplete:** Vorschläge aus bisherigen Items (häufig gekaufte)
- Enter oder ➕ fügt hinzu, Feld wird geleert
- Standard: Haushalt-Item (wenn in Haushalt), sonst privat

##### Smart Parsing Regeln
```
"Milch"              → name: "Milch", amount: null, unit: null
"2 Milch"            → name: "Milch", amount: "2", unit: null  
"2 Liter Milch"      → name: "Milch", amount: "2", unit: "Liter"
"500g Mehl"          → name: "Mehl", amount: "500", unit: "g"
"1 Packung Butter"   → name: "Butter", amount: "1", unit: "Packung"
```

##### Visuelle Unterscheidung
- Rezept-Items: normaler Style + Rezept-Name als Subtitle
- Manuelle Items: leicht anderer Style (z.B. 📝 Icon oder kursiver Subtitle "Manuell hinzugefügt")
- Haushalt-Items: 🏠 Badge
- Private Items: 🔒 Badge

##### Quick-Add Vorschläge
- Unter dem Input: Chips mit häufig hinzugefügten Artikeln
- Max 5 Vorschläge, basierend auf History
- Tap = sofort hinzufügen

### 5.4 Persönliche Favoriten

- Favoriten sind immer pro User (`user_favorites` Tabelle)
- Keine Sharing-Option für Favoriten in v2
- Favoriten-Liste zeigt nur eigene Favoriten

## 6. Migration Strategy

### 6.1 Backwards Compatibility

- **Anonymous Access:** Rezepte bleiben öffentlich zugänglich ohne Login
- **URLs:** Alle bestehenden Recipe-URLs funktionieren weiterhin
- **Features:** Basis-Funktionen (Rezepte suchen, ansehen) ohne Auth

### 6.2 Daten-Migration

#### Phase 1: Schema Updates
```sql
-- Neue Tabellen erstellen (siehe Datenmodell)
-- Bestehende Tabellen erweitern (users_id Spalten als optional)

-- Default User erstellen für Migration
INSERT INTO users (id, email, display_name, password_hash) 
VALUES (
  'migration-user-uuid', 
  'migration@luna-recipes.local', 
  'Luna (Migration)', 
  'no-login'
);
```

#### Phase 2: Daten zuweisen
```sql
-- Bestehende Rezepte dem Migration User zuweisen
UPDATE recipes 
SET created_by = 'migration-user-uuid' 
WHERE created_by IS NULL;

-- Bestehende Notes dem Migration User zuweisen
UPDATE notes 
SET user_id = 'migration-user-uuid' 
WHERE user_id IS NULL;

-- Shopping Items vorerst ohne user_id lassen
-- Werden beim ersten User-Login zugewiesen
```

#### Phase 3: Erste echte User
- Erste User die sich registrieren bekommen alle bestehenden Daten zugewiesen
- Migration User wird nach erstem echten User gelöscht
- Shopping Items ohne user_id werden beim Login zugewiesen

### 6.3 Rollback Plan

- Auth-Features sind additiv, keine Breaking Changes
- Bei Problemen: Auth-Routes deaktivieren, App läuft weiter ohne Auth
- Datenbank-Rollback: user_id Spalten auf NULL setzen

## 7. Sicherheit

### 7.1 Passwort-Sicherheit

```javascript
// bcrypt mit 12 Rounds (Backend)
const passwordHash = await bcrypt.hash(password, 12)

// Passwort-Validierung (Frontend + Backend)
const passwordRules = {
  minLength: 8,
  requireUppercase: false, // UX-freundlich für v2
  requireNumbers: false,
  requireSpecialChars: false
}
```

### 7.2 JWT Security

```javascript
// JWT Signing (Backend)
const accessToken = jwt.sign(
  {
    sub: user.id,
    email: user.email,
    display_name: user.display_name,
    household_id: user.household_id
  },
  process.env.JWT_SECRET,
  { expiresIn: '15m' }
)

// httpOnly Cookie Config
res.cookie('luna_refresh_token', refreshToken, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'strict',
  maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
})
```

### 7.3 Rate Limiting

```javascript
// Login Rate Limiting
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 attempts per IP
  message: 'Zu viele Login-Versuche, bitte warten Sie 15 Minuten',
  standardHeaders: true
})

// Registration Rate Limiting
const registerLimiter = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 3, // 3 registrations per IP per hour
  message: 'Zu viele Registrierungen, bitte warten Sie'
})
```

### 7.4 Input Validation

```javascript
// Zod Schema für API Validation (Backend)
const registerSchema = z.object({
  email: z.string().email('Ungültige E-Mail-Adresse'),
  password: z.string().min(8, 'Passwort muss mindestens 8 Zeichen haben'),
  display_name: z.string().min(2, 'Name muss mindestens 2 Zeichen haben')
    .max(50, 'Name darf maximal 50 Zeichen haben')
})

// XSS Protection für User-generierte Inhalte
const sanitizedDisplayName = DOMPurify.sanitize(display_name)
```

## 8. Mobile-First UX Considerations

### 8.1 Touch Targets
- **Minimum Size:** 44px × 44px für alle Buttons
- **Spacing:** 8px minimum zwischen clickbaren Elementen
- **Form Fields:** 48px Höhe für bessere Touch-Ergonomie

### 8.2 Responsive Breakpoints
```css
/* Mobile First */
.auth-form {
  width: 100%;
  padding: 1rem;
}

/* Tablet */
@media (min-width: 768px) {
  .auth-form {
    max-width: 400px;
    margin: 0 auto;
    padding: 2rem;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  }
}
```

### 8.3 Keyboard & Input Handling
```jsx
// Input Types für bessere Mobile Keyboards
<input 
  type="email" 
  inputMode="email"
  autoComplete="username"
  placeholder="luna@example.com"
/>

<input 
  type="password"
  autoComplete="current-password"
  placeholder="Passwort"
/>

// Auto-focus Management
<input ref={emailRef} autoFocus onSubmit={focusPassword} />
```

### 8.4 Loading States
- **Skeleton Loading:** Für User Profile, Haushalt-Listen
- **Button States:** Loading Spinner in Buttons während API Calls
- **Toast Messages:** Für Success/Error Feedback
- **Optimistic Updates:** Favoriten, Haushalt beitreten

### 8.5 Offline Considerations
- **Service Worker:** Caching für Auth-relevante Pages
- **Network Awareness:** Retry-Mechanismus für failed Requests
- **Local Storage:** Backup für kritische User Preferences

## 9. Testing Strategy

### 9.1 Unit Tests
- Auth Context / Hook Tests
- Password Validation Tests
- JWT Token Handling Tests
- API Response Validation Tests

### 9.2 Integration Tests
- Login/Register Flow End-to-End
- Token Refresh Flow
- Haushalt erstellen/beitreten Flow
- Migration Logic Tests

### 9.3 Security Tests
- SQL Injection Prevention
- XSS Prevention
- CSRF Protection Validation
- Rate Limiting Effectiveness

## 10. Performance

### 10.1 Bundle Size
- **Code Splitting:** Auth-Pages lazy loaded
- **Tree Shaking:** Nur genutzte Auth-Libraries
- **JWT Library:** Lightweight jwt-decode statt vollständiger Library

### 10.2 API Optimization
- **Response Caching:** User Profile Daten
- **Debounced Requests:** Profile Updates
- **Batch Requests:** Initial App Load (User + Household in einem Call)

### 10.3 Database Performance
```sql
-- Wichtige Indizes für Auth Queries
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_household_members_user_id ON household_members(user_id);
CREATE INDEX idx_shopping_items_user_household ON shopping_items(user_id, household_id);
CREATE INDEX idx_user_favorites_user_id ON user_favorites(user_id);
```

---

## Implementierungs-Prioritäten

### Phase 1 (MVP)
1. ✅ Datenbank Schema + Migration
2. ✅ Backend Auth Endpoints
3. ✅ Frontend Login/Register Pages
4. ✅ JWT Token Flow + Auto-Refresh
5. ✅ Route Protection

### Phase 2 (Multi-User)
1. User Profile Management
2. Shopping Items User-Zuordnung
3. Favorites pro User
4. Notes pro User

### Phase 3 (Households)
1. Household Creation + Joining
2. Shared Shopping Lists
3. Household Management UI
4. Invite Code Generation

### Phase 4 (Polish)
1. Avatar Upload
2. Advanced Security Features
3. Performance Optimizations
4. Mobile UX Improvements

**Geschätzte Entwicklungszeit:** 3-4 Wochen für komplette Implementierung