# Mobile Spec (Vue Frontend Analyse)

## 1) Routen / Screens (vue-router)
Quelle: `frontend/src/router.js`

| Pfad | Screen-Komponente | Route-Parameter | Router-Guard |
|---|---|---|---|
| `/register` | `Register.vue` | - | keiner |
| `/login` | `Login.vue` | - | keiner |
| `/activate/:activationCode` | `Activate.vue` | `activationCode` | keiner |
| `/forgot-password` | `ForgotPassword.vue` | - | keiner |
| `/reset-password/:token` | `ResetPassword.vue` | `token` | keiner |
| `/` | `Home.vue` | - | keiner |
| `/createclub` | `CreateClub.vue` | - | keiner |
| `/showclub/:clubId` | `ClubView.vue` | `clubId` | keiner |
| `/members` | `MembersView.vue` | - | keiner |
| `/diary` | `DiaryView.vue` | - | keiner |
| `/pending-approvals` | `PendingApprovalsView.vue` | - | keiner |
| `/schedule` | `ScheduleView.vue` | - | keiner |
| `/tournaments` | `TournamentsView.vue` | - | keiner |
| `/training-stats` | `TrainingStatsView.vue` | - | keiner |
| `/club-settings` | `ClubSettings.vue` | - | keiner |
| `/predefined-activities` | `PredefinedActivities.vue` | - | keiner |
| `/mytischtennis-account` | `MyTischtennisAccount.vue` | - | keiner |
| `/team-management` | `TeamManagementView.vue` | - | keiner |
| `/permissions` | `PermissionsView.vue` | - | keiner |
| `/logs` | `LogsView.vue` | - | keiner |
| `/member-transfer-settings` | `MemberTransferSettingsView.vue` | - | keiner |
| `/personal-settings` | `PersonalSettings.vue` | - | keiner |
| `/impressum` | `Impressum.vue` | - | keiner |
| `/datenschutz` | `Datenschutz.vue` | - | keiner |

## 2) Effektive Guard-Logik (außerhalb vue-router)
Es gibt **keine** `router.beforeEach`, keine `beforeEnter`-Guards und keine `meta.requiresAuth`-Strategie.

Stattdessen wird Zugriff so gesteuert:

1. UI-/Navigations-Gating in `App.vue`
- Menüeinträge werden abhängig von Vuex-Permissions (`hasPermission`, `isClubOwner`, `userRole`) ein-/ausgeblendet.
- Nicht authentifizierte User sehen primär Login/Register-Navigation.

2. Imperative Redirects
- `App.vue -> loadClub()`:
  - bei fehlender Statistik-Leseberechtigung Redirect auf `/showclub/:clubId`
  - sonst Redirect auf `/training-stats`
- `App.vue -> watch(currentClub)`:
  - `currentClub === 'new'` -> `/createclub`
- `TournamentTab.vue -> created()`:
  - wenn nicht authentifiziert -> `/login`

3. API-basierte Sitzungsprüfung
- `App.vue` pollt `/session/status`.
- `apiClient` Response-Interceptor triggert bei `401` automatisch `store.dispatch('logout')`.

## 3) State Management

### Ergebnis
- **Pinia:** nicht verwendet
- **Vuex:** verwendet (`frontend/src/store.js`)
- Store-Struktur: **ein zentraler Root-Store**, keine Module

### Store: `frontend/src/store.js`

#### State-Struktur
```ts
state = {
  token: string | null,                 // sessionStorage
  username: string,                     // sessionStorage
  currentClub: string | null,           // sessionStorage
  clubs: Array<Club>,                   // localStorage (JSON)
  permissions: {
    [clubId: string]: {
      role: string,
      isOwner: boolean,
      permissions: Record<string, Record<string, boolean>>
    }
  },                                    // localStorage (JSON)
  dialogs: Array<{
    id: number,
    ...dialogProps,
    isMinimized: boolean,
    zIndex: number,
    position: { x: number, y: number }
  }>,
  dialogCounter: number,
  sidebarCollapsed: boolean,            // localStorage
  language: string | null               // localStorage
}
```

#### Mutations (Auszug)
- Auth/Session: `setToken`, `clearToken`, `setUsername`, `clearUsername`, `setClub`
- Club/Permission: `setClubsMutation`, `setPermissions`, `clearPermissions`
- UI: `setSidebarCollapsed`, `setLanguage`
- Dialog-System: `openDialog`, `closeDialog`, `minimizeDialog`, `restoreDialog`, `bringDialogToFront`

#### Actions (Auszug)
- `login({ token, username })` -> setzt Auth-State, lädt `/clubs`
- `logout()` -> State reset + Redirect `/login`
- `setCurrentClub(club)` -> setzt Club + lädt Permissions
- `loadPermissions(clubId)` -> `/permissions/:clubId`, Fallback auf read-only default bei Fehler

#### Getter (Auszug)
- Auth: `isAuthenticated`, `token`, `username`
- Club: `currentClub`, `clubs`, `currentClubName`
- Permission: `currentPermissions`, `hasPermission(resource, action)`, `isClubOwner`, `userRole`
- Dialog: `dialogs`, `minimizedDialogs`, `activeDialogs`

