# CLAUDE.md

## Project Overview

Nextcloud 28 app (PHP backend, Vue 3 frontend) for managing scout group (Pfadfinderverein) members, families, fees, camps, and more.

## Tech Stack

- **Backend**: PHP 8.1+, Nextcloud OCP APIs, MariaDB, Doctrine DBAL via `IDBConnection`
- **Frontend**: Vue 3 (Composition API, `<script setup>`), Pinia stores, Vue Router (hash history), `@nextcloud/vue` v9, webpack
- **Build**: `npx webpack --node-env production`, output to `js/`
- **Deploy**: `make redeploy` copies app into running Nextcloud container. Version bump in `appinfo/info.xml` required to bust browser cache (`?v=` hash).

## Critical @nextcloud/vue v9 Gotchas

These caused most bugs in this project. Every contributor must know them:

1. **NcTextField**: Use `:model-value` / `@update:model-value` (Vue 3). NOT `:value` / `@update:value` / `:value.sync` (Vue 2). Fields will appear blank or not emit changes otherwise.
2. **NcSelect**: Always pass `:reduce="o => o.value"` and `label="label"` when options are objects `{value, label}`. Without `:reduce`, the select can't match string model-values to option objects.
3. **NcButton**: Has `overflow: hidden` and `padding: 0` in scoped styles. Global overrides via `<style>` blocks in `.vue` files are unreliable (css-loader may drop rules). Use a `<style>` tag injected from `main.js` after mount instead.
4. **appName/appVersion**: The library reads these two ways: (a) bare global identifier `appName` (use webpack DefinePlugin), (b) Vue `inject('appName')` (use `app.provide()`). Both are needed.
5. **loadState("core","apps")**: Nextcloud 28 returns an object, not an array. `@nextcloud/vue` calls `.find()` on it, which crashes. Patch in `main.js` with `Object.values()` before Vue mounts.

## Code Conventions

### Vue Components
- Always use `<script setup>` with Composition API
- German UI labels with proper Umlauts (Wölflinge, Männlich, Zusätzliche Notizen, etc.)
- Validation: show errors inline during editing, disable submit button until valid
- Emit pattern for form components: `$emit('update', fieldName, value)` — parent handles via `onFormUpdate(field, value)`

### Backend (PHP)
- Controllers extend `OCP\AppFramework\Controller`, return `JSONResponse`
- Services handle business logic, Mappers handle DB queries (Nextcloud ORM pattern)
- Migrations in `lib/Migration/`, class name format `VersionNNNNNNDateYYYYMMDDHHMMSS`
- Use `IQueryBuilder::PARAM_STR` for null values (not `PARAM_NULL` which doesn't exist)
- Wire `AuditService->logCreate/logUpdate/logDelete` into all CRUD service methods

### Stores (Pinia)
- One store per entity (`stores/members.js`, `stores/families.js`, etc.)
- Fetch via `@nextcloud/axios` + `generateUrl()`
- Always expose `clearError()` action

## Testing

All PHPUnit tests must pass (`make test`) before merging. Runs inside the Nextcloud container — no local PHP needed. Zero errors, warnings, and PHP deprecations is the baseline for a commitable PR.

## UI Guidelines

- Buttons must show full text, never truncated. Global fix in `main.js` handles NcButton overflow.
- Sidebar active item must have rounded corners (global fix in `main.js`).
- Sensitive reports/actions use red styling (red border, red text) with tooltip explanation instead of overlapping badges.
- Use the global `SearchBar` component for member search, not inline NcTextField duplicates.
- Tables should show all columns relevant to displayed filters (e.g. if "Geburtstage diesen Monat" filter exists, show Geburtsdatum column).
- Default sensible values for new records (e.g. Eintrittsdatum = today, Status = aktiv, Rolle = mitglied).

## Deployment Notes

- `make deploy` = full clean deploy (build + fresh containers + install NC + copy app + enable)
- `make redeploy` = rebuild JS + copy into running container
- `make clean` = `docker compose down -v` (wipes DB + NC data volumes)
- **Always bump the version when redeploying UI changes.** Without a version bump, Nextcloud serves cached JS/CSS and changes won't reach the browser — even with hard-refresh. Bump all three locations together.

### When changes don't show up in the browser

This is a common problem. Nextcloud aggressively caches JS assets. Escalation path:

1. **Hard-refresh browser** (Ctrl+Shift+R) — clears browser cache
2. **Restart container** — `docker compose restart nextcloud` — clears server-side opcache
3. **Version bump** — the reliable cache-buster. Must update in **three places**:
   - `appinfo/info.xml` (`<version>`)
   - `webpack.config.js` (DefinePlugin `appVersion`)
   - `main.js` (`app.provide('appVersion', ...)`)
   Then run `make redeploy` followed by `occ upgrade` inside the container
4. **Full rebuild** — nuclear option when nothing else works: `make clean && make deploy`. This wipes all Docker volumes (DB included), rebuilds JS, starts fresh containers, reinstalls Nextcloud, and re-enables the app from scratch. You lose all data but guarantee a clean state.

## Workflow

- Each completed feature, bugfix, or enhancement should be committed and pushed immediately after completion.

## Gitea

- Repo: `shahondin1624/Mitgliederverwaltung` on `git.shahondin1624.de`
- Issues use labels: `enhancement`, `bug`, `backend`, `frontend`, `security`, `epic`, `priority:high/medium/low`
- Close issues via commit message: `(Closes #N)`

### Using `tea` CLI

Always use the `tea` CLI for Gitea operations (never the web UI or raw API calls):

```bash
# Pull requests
teaprclose<PR>
teaprclose<PR>
teapr create --head <branch> --title "<title>" --labels "<labels>" --description "<body>"
teapr list
teapr view <PR>
teapr diff <PR>
teapr merge <PR>

# Issues
tei list --state open
tei create --title "<title>" --labels "<labels>"
tei view <Issue>
tei close <Issue>
tei update <Issue> --labels "<new-labels>" --assignees "<user>"

# Labels
tel list
tel create <name> --color "<hex>" --description "<desc>"

# Milestones
tems list
tms create --title "<title>" --deadline "YYYY-MM-DD"
```

**Rules:**
- Before creating a PR: ensure the branch is pushed to origin first, and verify there are actual commits on the branch (never create a PR from a branch identical to main/base)
- Always use `tea pr diff` to verify the PR has the expected changes before merging
- Use `tea pr merge` to merge after review
- Close issues via commit message `(Closes #N)` — `tea` is only for PR/issue management on the Gitea server
