Files

6.3 KiB

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 containerdocker 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):

# 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