# Integration Test Plan & Report -- Mitgliederverwaltung

**Test Plan:** [Gitea Issue #123](https://git.shahondin1624.de/shahondin1624/Mitgliederverwaltung/issues/123)
**Execution Date:** 2026-04-09
**Tester:** Claude (Playwright interactive testing)
**Environment:** Nextcloud 28, localhost:8080, admin user
**App Version:** 0.0.3

---

## Test Plan (from Issue #123)

This test plan covers black-box UI testing of all features against the requirements spec (`docs/requirements.md`). Testing uses Playwright MCP tools to interact with the UI as an admin user.

### Phases

| Phase | Area | Status |
|-------|------|--------|
| 0 | Build & Deployment | PASS |
| 1 | Navigation & App Shell | PASS (partial) |
| 2 | Member Management | FAIL (blocked by #125) |
| 3 | Family Management | PASS |
| 4 | Stufen Management | PARTIAL |
| 5 | Fee System | PASS (with issues) |
| 6 | Search & Filtering | PARTIAL |
| 7 | Reports & Exports | PASS |
| 8 | Lagertracking | PASS (empty state) |
| 9 | Injury Tracking | PASS (empty state) |
| 10 | Audit Log | FAIL |
| 11 | Settings & Permissions | PASS (with issues) |
| 12 | Soft Deletion & DSGVO | NOT TESTED |
| 13 | Milestones | NOT TESTED |
| 14 | Data Validation Edge Cases | NOT TESTED (blocked by #125) |

### Linked Issues

| Issue | Title | Priority | Status |
|-------|-------|----------|--------|
| #125 | Member detail form fields render blank | high | open |
| #126 | Audit log not recording any events | high | open |
| #127 | Fee table shows member IDs instead of names | medium | open |
| #128 | No default Stufen seeded on install | low | open |
| #129 | Missing Lagerhistorie and Verletzungsprotokoll reports | low | open |
| #130 | TypeError: e.find is not a function | low | open |
| #131 | @nextcloud/vue appName/appVersion not configured | low | open |
| #133 | Inline member search does not filter | medium | open |
| #134 | Stufe column shows raw stufeId instead of name | medium | open |
| #135 | Add missing pages to sidebar navigation | medium | open |
| #136 | UX: Various minor UI polish issues | low | open |

---

## Executive Summary

The Mitgliederverwaltung app has a solid architecture with many features already implemented. However, there is a **critical, pervasive bug** affecting all `NcTextField` form fields: values from the Vue store are not rendered into the form inputs. This affects member detail view, new member creation, Stufe name display in settings, and likely other form-based features. Additionally, the inline member search does not filter results.

---

## 1. Member Management

### 1.1 Member List (`#/`)
| Test Case | Status | Notes |
|-----------|--------|-------|
| Page loads with member table | PASS | 5 members displayed correctly |
| Columns: Name, Stufe, Status, Alter, Rolle | PASS | All visible |
| Filter: Alle | PASS | Shows all 5 members |
| Filter: Aktive | PASS | Hides inactive Thomas Schmidt, shows 4 |
| Filter: Inaktive | PASS | Shows only Thomas Schmidt |
| Filter: Unbezahlte Beitraege | PASS | Button renders (not tested with data) |
| Filter: Geburtstage diesen Monat | PASS | Button renders (not tested with data) |
| Sorting by Name | PASS | Default sort ascending, toggleable |
| Inline search | **FAIL** | Typing "Weber" does not filter the list. `NcTextField` `@update:value` event does not fire properly, so `store.searchMembers()` is never called |
| Click row navigates to detail | PASS | Routes to `#/members/:id` |
| Pagination | PASS | Implemented but not visible with only 5 members |

#### Bugs
- **BUG-001 (Critical)**: Inline search field does not filter the member list. The `NcTextField` uses `:value.sync` (Vue 2 syntax) which may not work in Vue 3, and the `@update:value` event is not triggered by user input.
- **BUG-002 (Medium)**: Stufe column shows raw `stufeId` value (or "---") instead of the Stufe name. See `MemberList.vue:107`: `{{ member.stufeId || '---' }}` should resolve to Stufe name.

#### UX Issues
- **UX-001**: Two search bars visible -- one global SearchBar in the header and one inline NcTextField in the member list header. Confusing which to use. Consider removing one or clarifying their purpose.
- **UX-002**: "Neues Mitglied" button text truncates to "Neues ..." at certain viewport widths.

### 1.2 Member Detail (`#/members/:id`)
| Test Case | Status | Notes |
|-----------|--------|-------|
| Header shows member name | PASS | "Max Mustermann" displayed correctly |
| Info banner (Alter, Mitgliedsdauer, Status) | PASS | "13 Jahre", "6 Jahre, 3 Monate", green "Aktiv" badge |
| Tab navigation (7 tabs) | PASS | Persoenlich, Familie, Beitrag, Lager, Verletzungen, Dateien, Verlauf |
| Persoenlich tab -- form fields display | **FAIL** | All text fields are empty despite store having correct data |
| Edit mode toggle | PASS | "Bearbeiten" enables fields, shows "Speichern"/"Abbrechen" |
| Edit mode -- sub-entity buttons appear | PASS | "Adresse hinzufuegen", "Telefonnummer hinzufuegen", "E-Mail hinzufuegen" |
| Zurueck button | PASS | Navigates back to member list |
| Familie tab | NOT IMPL | Placeholder: "Wird in einem spaeteren Milestone implementiert." |
| Beitrag tab | NOT IMPL | Placeholder |
| Lager tab | NOT IMPL | Placeholder |
| Verletzungen tab | NOT IMPL | Placeholder |
| Dateien tab | PASS | FileExplorer works, shows folder path, offers "Ordner erstellen" |
| Verlauf tab | NOT IMPL | Placeholder |

#### Bugs
- **BUG-003 (Critical)**: All form fields in MemberForm.vue display empty values in both view and edit mode. The `NcTextField` `:value` prop does not render the bound data. The Vue store (`members.currentMember`) has correct data (`{vorname: "Max", nachname: "Mustermann", ...}`) but inputs show empty. Root cause: likely `NcTextField` expects `:modelValue` instead of `:value` in the Nextcloud Vue 8.x library used with Vue 3.
- **BUG-004 (Critical)**: Saving a new member fails with 400 "Missing required fields: vorname, nachname, geburtsdatum, eintritt" because the `NcTextField` `@update:value` events don't fire, so `formData` stays at initial empty values even though the user typed into the fields.

### 1.3 New Member (`#/members/new`)
| Test Case | Status | Notes |
|-----------|--------|-------|
| Form renders in edit mode | PASS | All fields enabled |
| Status field disabled for new members | PASS | Correct behavior |
| Rolle dropdown works | PASS | Shows "Mitglied", "Erziehungsberechtigter" |
| Save new member | **FAIL** | 400 error due to BUG-004 |

#### UX Issues
- **UX-003**: "Erziehungsberechtigter" text breaks across lines in the NcSelect dropdown ("Erziehungsbe" / "rechtigter"). Dropdown needs `min-width` or `white-space: nowrap`.

---

## 2. Family Management

### 2.1 Family List (`#/families`)
| Test Case | Status | Notes |
|-----------|--------|-------|
| Page loads | PASS | Shows "Keine Familien" empty state |
| Empty state with CTA | PASS | "Erste Familie anlegen" button shown |
| Search field | PASS | "Familien suchen..." placeholder |
| "Neue Familie" button | PASS | Visible but text may truncate |

### 2.2 Family Detail (`#/families/new`)
| Test Case | Status | Notes |
|-----------|--------|-------|
| Form loads | PASS | Familienname, Bankverbindung fields |
| Bankverbindung section | PASS | Kontoinhaber, IBAN (with example format), BIC, Kreditinstitut |
| Form buttons | PASS | Speichern, Abbrechen |

#### UX Issues
- **UX-004**: "Neue..." button text truncation on family list page.

---

## 3. Fee System (`#/fees`)

### 3.1 Fee Overview
| Test Case | Status | Notes |
|-----------|--------|-------|
| Page loads with fee records | PASS | 3 records at 60.00 EUR each |
| Summary banner | PASS | Gesamt erwartet, Bezahlt, Ausstehend |
| Year selector | PASS | Dropdown with 2026, 2025 |
| "Beitraege berechnen" button | PASS | Visible and clickable |
| Mark fee as paid | PASS | Updates to "Ja", sets Zahlungsdatum, updates summary |
| "Betrag aendern" button | PASS | Visible (not tested action) |
| "Notiz" button | PASS | Visible (not tested action) |
| Erziehungsberechtigter excluded | PASS | Sabine Mustermann not in fee list |
| Inactive member excluded | PASS | Thomas Schmidt not in fee list |

#### Bugs
- **BUG-005 (Medium)**: Members display as "Mitglied #1", "Mitglied #3", "Mitglied #5" instead of actual names (e.g., "Max Mustermann"). The member name resolution is broken.

---

## 4. Lager (Camp) Management (`#/lager`)
| Test Case | Status | Notes |
|-----------|--------|-------|
| Page loads | PASS | Shows table header and "Keine Lager gefunden" |
| Filter dropdowns | PASS | "Alle Jahre", "Alle Stufen" |
| "Neues Lager" button | PASS | Visible |
| Table columns | PASS | Name, Startdatum, Enddatum, Ort, Teilnehmer, Aktionen |

#### UX Issues
- **UX-005**: Empty state lacks an icon/illustration (unlike other empty states that use NcEmptyContent).

---

## 5. Injury Tracking (`#/injuries`)
| Test Case | Status | Notes |
|-----------|--------|-------|
| Page loads | PASS | "Verletzungsprotokoll" with table |
| Date range filters | PASS | Two date pickers |
| "Neue Verletzung" button | PASS | Visible |
| Table columns | PASS | Datum, Mitglied, Lager/Aktivitaet, Beschreibung, Beteiligte, Aktionen |

#### UX Issues
- **UX-006**: Injuries page is not accessible from the sidebar navigation. It requires direct URL or is only reachable from the member detail tab. Consider adding it to the sidebar.

---

## 6. Reports (`#/reports`)
| Test Case | Status | Notes |
|-----------|--------|-------|
| Report cards grid | PASS | 8 report types in 2x4 grid |
| Report types | PASS | Mitgliederliste, Beitragsliste, Stufenliste, Allergieliste, Geburtstagsliste, Kontaktliste, Bankverbindungen, Familienliste |
| "Sensibel" badge on Bankverbindungen | PASS | Nice security awareness feature |
| Click report shows filter | PASS | Status filter dropdown appears |
| Preview (Vorschau) | PASS | Shows member table with correct data |
| Preview data formatting | PASS | German date format (DD.MM.YYYY) |
| Download buttons | PASS | PDF, CSV, Verschluesselt options shown |

#### UX Issues
- **UX-007**: "Bankverbindungen" text truncated on the card ("Bankverbindung...").

---

## 7. Import Wizard (`#/import`)
| Test Case | Status | Notes |
|-----------|--------|-------|
| Page loads with step indicator | PASS | 5 steps: Hochladen, Zuordnung, Vorschau, Dry-Run, Ergebnis |
| File upload field | PASS | "Choose file" button with file input |
| Separator/encoding options | PASS | Trennzeichen (Komma), Kodierung (UTF-8) |

#### UX Issues
- **UX-008**: "Choose file" button shows English text (browser default). Consider using a custom styled button with German label "Datei auswaehlen".
- **UX-009**: Import page not accessible from sidebar navigation. Only accessible via direct URL.

---

## 8. Query Builder (`#/queries`)
| Test Case | Status | Notes |
|-----------|--------|-------|
| Page loads | PASS | "Abfrage-Builder" with saved queries panel |
| AND/OR toggle | PASS | UND/ODER buttons |
| Add condition | PASS | Creates row with field/operator/value |
| Default condition | PASS | "Vorname ist gleich Wert..." |
| Action buttons | PASS | Abfrage ausfuehren, Speichern, Zuruecksetzen |
| Saved queries panel | PASS | "Noch keine gespeicherten Abfragen" |
| Add group | PASS | Button present (not tested) |

#### UX Issues
- **UX-010**: Query builder page not accessible from sidebar navigation.

---

## 9. Audit Log (`#/audit-log`)
| Test Case | Status | Notes |
|-----------|--------|-------|
| Page loads | PASS | Filter panel with 5 filter fields |
| Filters: Entitaet, Benutzer, Entitaet-ID, Von, Bis | PASS | All rendered correctly |
| "Filter zuruecksetzen" button | PASS | Visible |
| Empty state | PASS | "Keine Eintraege" with helpful message |

#### Bugs
- **BUG-006 (Medium)**: No audit entries logged despite performing state-changing operations (marking fee as paid). Audit logging may not be connected to fee operations, or there's a backend issue.

---

## 10. Settings (`#/settings`)

### 10.1 Stufen verwalten
| Test Case | Status | Notes |
|-----------|--------|-------|
| Stufe list renders | PASS | 3 Stufen with age ranges and colors |
| Age range fields | PASS | 6-12, 12-17, 18-99 |
| Color pickers | PASS | Yellow, Green, Red |
| Reorder arrows | PASS | Up/down arrows visible |
| "Neue Stufe" button | PASS | Visible |
| Member count per Stufe | PASS | Shows 0 for all (no members assigned) |

#### Bugs
- **BUG-007 (Medium)**: Stufe name fields appear empty (same NcTextField binding issue as BUG-003). Names were configured but don't display.

### 10.2 Beitragsregeln
| Test Case | Status | Notes |
|-----------|--------|-------|
| Fee rule form | PASS | Gueltig ab Jahr, Grundbeitrag fields |
| Preview calculation | PASS | Shows 1. Kind 60 EUR, 2. Kind 45 EUR, Gesamt 105 EUR |
| Existing rules table | PASS | Shows 2026 rule (60.00 EUR) |
| "Regel speichern" button | PASS | Visible |

### 10.3 Berechtigungen verwalten
| Test Case | Status | Notes |
|-----------|--------|-------|
| User list | PASS | Shows admin user |
| User filter | PASS | "Benutzer filtern..." search field |
| Access level dropdown | PASS | "Kein Zugriff" shown for admin |
| "Bankdaten sichtbar" checkbox | PASS | Visible, unchecked |

#### UX Issues
- **UX-011**: Admin user shows "Kein Zugriff" (No Access) as default permission. This is confusing since the admin clearly has access. Consider auto-assigning admin role or showing a different default.

---

## 11. Navigation & Global UX

### 11.1 Sidebar Navigation
| Item | Status | Route |
|------|--------|-------|
| Mitglieder | PASS | `#/` |
| Familien | PASS | `#/families` |
| Beitraege | PASS | `#/fees` |
| Lager | PASS | `#/lager` |
| Berichte | PASS | `#/reports` |
| Audit-Log | PASS | `#/audit-log` |
| Einstellungen | PASS | `#/settings` |

#### Missing from sidebar:
- Verletzungen (`#/injuries`)
- Import (`#/import`)
- Abfragen (`#/queries`)

### 11.2 Global Search (SearchBar component)
The global SearchBar in the header is a separate, API-powered search with a dropdown results panel. It supports keyboard navigation, minimum 2-character input, and navigates to member detail on selection. This is distinct from the broken inline search in MemberList.

### 11.3 Console Errors
| Error | Severity | Description |
|-------|----------|-------------|
| `@nextcloud/vue: appName not set` | Low | Configuration warning -- set appName in webpack config |
| `@nextcloud/vue: appVersion not set` | Low | Configuration warning -- set appVersion in webpack config |
| `TypeError: e.find is not a function` | Medium | Occurs on initial page load, likely in a store/component setup function trying to call `.find()` on a non-array value |

---

## 12. Not Implemented (Placeholder Tabs)

The following features show "Wird in einem spaeteren Milestone implementiert":
- Member detail: Familie tab (linking member to family from detail view)
- Member detail: Beitrag tab (showing fee history per member)
- Member detail: Lager tab (showing camp participation per member)
- Member detail: Verletzungen tab (showing injuries per member)
- Member detail: Verlauf tab (showing change history per member)

---

## 13. Summary of Findings

### Critical Bugs (Must Fix)
| ID | Description | Impact |
|----|-------------|--------|
| BUG-003 | NcTextField `:value` prop does not display data | All form views show empty fields |
| BUG-004 | NcTextField `@update:value` does not emit on input | Cannot save new members or edit existing ones |

**Root Cause Analysis:** Both BUG-003 and BUG-004 stem from the same issue. The app uses `NcTextField` with `:value` and `@update:value`, but the Nextcloud Vue 8.x library for Vue 3 likely expects `:modelValue` and `@update:modelValue`. This is the migration pattern from Vue 2 to Vue 3. The fix would be to update all `NcTextField` usages:
```vue
<!-- Before (broken) -->
<NcTextField :value="member.vorname" @update:value="..." />

<!-- After (fixed) -->
<NcTextField :model-value="member.vorname" @update:model-value="..." />
```

Similarly, in `MemberList.vue`, the `:value.sync` modifier is Vue 2 syntax that doesn't work in Vue 3.

### Medium Bugs
| ID | Description |
|----|-------------|
| BUG-001 | Inline member search does not filter the list |
| BUG-002 | Stufe column shows raw ID instead of name |
| BUG-005 | Fee overview shows "Mitglied #N" instead of member names |
| BUG-006 | Audit log shows no entries despite state changes |
| BUG-007 | Stufe names not displayed in settings |

### UX Improvements
| ID | Description | Priority |
|----|-------------|----------|
| UX-001 | Remove duplicate search bar or clarify purpose | Medium |
| UX-002 | Fix "Neues Mitglied" button text truncation | Low |
| UX-003 | Fix "Erziehungsberechtigter" text wrapping in dropdown | Low |
| UX-004 | Fix "Neue..." button text truncation on family list | Low |
| UX-005 | Add empty state icon to Lager list | Low |
| UX-006 | Add Injuries to sidebar navigation | Medium |
| UX-007 | Fix "Bankverbindungen" text truncation on report card | Low |
| UX-008 | Localize "Choose file" button to German | Low |
| UX-009 | Add Import to sidebar navigation | Medium |
| UX-010 | Add Query Builder to sidebar navigation | Medium |
| UX-011 | Clarify admin permission default in settings | Medium |

### Working Features (Verified)
- Member list with filter chips (Alle, Aktive, Inaktive, etc.)
- Member list sorting by all columns
- Member detail header with derived fields (age, membership duration)
- Member detail tab navigation
- Member detail Files tab (FileExplorer with Nextcloud Files integration)
- Family list with empty state and creation form
- Fee overview with summary, year selection, and payment tracking
- Lager list with filters
- Injury tracking list with date range filters
- Reports with 8 types, preview, and PDF/CSV/encrypted download
- Import wizard with 5-step process
- Query builder with AND/OR logic, conditions, groups, and saved queries
- Audit log with comprehensive filters
- Settings with Stufe management, fee rules, and permission management
- Global search (SearchBar) with API-powered dropdown results
- Sidebar navigation for main sections

---

## 14. Remaining Test Plan (Not Yet Executed)

The following phases from the test plan (Issue #123) were not tested in this session, either because they were blocked by #125 or require more complex setup:

### Phase 12: Soft Deletion & DSGVO (Req 4.5, 4.6)
- [ ] Soft-delete member -> status=geloescht
- [ ] Hidden from normal views
- [ ] Archiv view shows deleted members (Admin only)
- [ ] Sensitive data hard-deleted on soft-delete
- [ ] DSGVO export (Auskunftsrecht)
- [ ] DSGVO full delete (Recht auf Loeschung)

### Phase 13: Milestones (Req 2.8)
- [ ] Milestones view -> "Anstehende Jubilaeen"
- [ ] Milestone thresholds configurable (25, 50, 60, 70 years)

### Phase 14: Data Validation Edge Cases (Req 4.4)
Blocked by #125 -- cannot test form validation when forms don't accept input.
- [ ] Invalid IBAN -> rejection with error
- [ ] Phone without E.164 -> rejection
- [ ] Birthday > 120 years ago -> rejection
- [ ] Eintritt before Geburtsdatum -> rejection
- [ ] Duplicate member detection (same Vorname+Nachname+Geburtsdatum)

### Deeper Testing (after #125 is fixed)
- [ ] Create member via UI and verify persistence
- [ ] Edit member and verify changes persist
- [ ] Delete member and verify soft-delete behavior
- [ ] Add addresses, phones, emails to member
- [ ] Create family and link members
- [ ] IBAN validation on family banking
- [ ] Assign member to Stufe and verify history
- [ ] Save and load queries in query builder
- [ ] Run complex queries (Status=aktiv AND Alter<14)
- [ ] Download PDF/CSV reports and verify content
- [ ] Encrypted export with password prompt
- [ ] Lager creation with participant management
- [ ] Injury creation from member detail
