title war fuer Hinweise die falsche Wahl: Es erscheint erst nach einer
Sekunde, sieht auf jedem System anders aus und laesst sich auf Touch-Geraeten
gar nicht aufrufen. Tippy war laengst als Abhaengigkeit da, aber kaum
benutzt.
<Button> nimmt jetzt eine tooltip-Prop, die zugleich als aria-label dient -
ohne das haetten die vielen Icon-Knoepfe beim Wegfall von title ihren Namen
fuer Screenreader verloren. Alle anderen Elemente nutzen die Action direkt.
Die Action selbst konnte bisher nur erzeugen. Sie beherrscht jetzt
Aktualisieren und Aufraeumen: Ein wechselnder Text ("Erledigt" / "Wieder
oeffnen") muss auch im Tooltip wechseln, und eine Instanz, die ihr Element
ueberlebt, haenge als leere Blase im Dokument.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
6.3 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
stammtisch-hersbruck.de is a SvelteKit 5 application using Svelte 5's new runes syntax ($state, $props, etc.) with PocketBase as the backend. The app manages events, runs, riders, times and teams for a motorsport/cycling event organization.
The repository is a monorepo: the SvelteKit app lives in frontend/, the PocketBase instance in backend/.
Development Commands
Alle Frontend-Befehle laufen aus frontend/:
cd frontend
# Start development server (runs on http://stammtisch-hersbruck.de.localhost:31337)
npm run dev
# Build for production
npm run build
# Preview production build
npm run preview
# Type-check Svelte files
npm run check
# Type-check with watch mode
npm run check:watch
# Generate TypeScript types from the schema migration in backend/pb_migrations
# (no running instance, no token, no network access needed)
npm run generate-pocketbase-types
Backend (PocketBase) aus backend/:
cd backend
# PocketBase lokal starten (Admin-UI auf http://127.0.0.1:8090/_/)
docker compose up -d --build
# Stoppen
docker compose down
Architecture
Backend Integration (PocketBase)
- API Base URL: konfigurierbar über
PUBLIC_PB_URLinfrontend/.env. Default ist die produktive Instanzhttps://api.stammtisch-hersbruck.de; für das lokale Backend ausbackend/aufhttp://127.0.0.1:8090umstellen. - Schema: versioniert als Migration in
backend/pb_migrations/, kommt perCOPYins Image (kein Bind-Mount — der würde das Image-Verzeichnis überdecken). Im Admin-UI erzeugte Migrationen liegen deshalb zunächst nur im Container und müssen mitdocker compose cpins Repo geholt werden; siehebackend/README.md. - Type-safe client: The PocketBase client is typed using auto-generated types in
frontend/src/lib/types.d.ts - Collections: users, teams, events, runs, riders, times
- Authentication: Handled through
src/lib/stores/pocketbase.svelte.tswith theAuthStoreclass - File handling: Use
getFileURL(record, file, options)helper for PocketBase file URLs
State Management Pattern
The app uses Svelte 5 runes for state management with a custom store pattern:
-
Global stores in
src/lib/stores/:pocketbase.svelte.ts: PocketBase client, auth, and collection operationsapp.svelte.ts: Global app state (theme, navigation, confirm dialogs, hotkeys)teams.svelte.ts: Example of collection-specific store pattern
-
Collection store pattern:
- Each collection has a context-based store (see
teams.svelte.tsas template) - Use
setTeamContext()in parent andgetTeamContext()in children - Stores provide:
records,refresh(),create(),edit(),remove() - The
collectionshelper inpocketbase.svelte.tsprovides reusable CRUD operations
- Each collection has a context-based store (see
-
Auth flow:
- Auth state lives in
authstore frompocketbase.svelte.ts - Cookie-based persistence available via
auth.cookieflag - Auth store syncs with PocketBase
authStore.onChange()
- Auth state lives in
UI Components
- UI Library: Using shadcn-svelte components (bits-ui based)
- Component path alias:
@/components/ui/*maps to$lib/components/ui/* - Styling: Tailwind CSS 4.x with custom configuration
- Dark mode: Handled by
mode-watcherpackage, toggle withtoggleMode() - Tooltips: Global
tooltipaction available fromapp.svelte.tsusing tippy.js
Important Patterns
Svelte 5 Runes: This project uses Svelte 5 syntax exclusively:
$state()for reactive state (notletwith$:)$props()for component props$derived()for computed values{@render children?.()}for slot content
Type Generation: After modifying the schema migration in backend/pb_migrations/, run npm run generate-pocketbase-types to update frontend/src/lib/types.d.ts. The script reads the collections array straight out of the migration (frontend/scripts/schema-to-json.mjs) — schema and types come from the same versioned source and cannot drift apart. Commit the regenerated file.
Async Data Loading: Root layout (src/routes/+layout.svelte) shows pattern:
{#await load()}
<!-- loading state -->
{:then _}
<!-- main content -->
{/await}
Confirm Dialogs: Use app.confirm.request() for user confirmations (see events.svelte.ts remove pattern).
Hotkeys: Use app.hotkey(event, condition, callback) which auto-ignores input fields and contenteditable elements.
Tooltips: Never use the title attribute for tooltips — appwide. <Button>
takes a tooltip="…" prop (it also becomes the aria-label, so icon-only
buttons keep an accessible name); every other element uses the action:
use:tooltip={{ content: '…' }} from app.svelte.ts. Both render through
tippy.js, which the action initializes, updates and destroys.
Project Configuration
- Repo-Struktur: Monorepo mit
frontend/(SvelteKit) undbackend/(PocketBase). Ein einziges Git-Repo im Root. - Dev server port: 31337 (strict mode, custom domain:
stammtisch-hersbruck.de.localhost) - Path alias:
@/*resolves to./src/lib/*(configured in frontend/svelte.config.js) - Adapter:
@sveltejs/adapter-node— Deployment läuft über Coolify mitnode build.adapter-autoerkennt Coolify nicht und erzeugt keinbuild/. - Node:
enginesverlangt^20.19 || ^22.12 || >=24; mitengine-strict=true(.npmrc) brichtnpm cisonst mitEBADENGINEab. - Deployment-Env:
PUBLIC_PB_URLmuss dort gesetzt sein — sie wird zur Buildzeit eingesetzt, und die lokale.envist gitignored.
File Structure Notes
- Routes are in
src/routes/following SvelteKit conventions - Reusable components in
src/lib/components/ - Stores use
.svelte.tsextension for Svelte 5 runes - Static assets in
static/ components.jsonconfigures shadcn-svelte CLI
When Working with This Codebase
- Always use Svelte 5 runes syntax, never legacy Svelte syntax
- Use the official Svelte MCP server to validate Svelte code
- Collection stores should follow the pattern in
teams.svelte.ts - PocketBase operations go through the
collectionshelper for consistency - UI components should use the shadcn-svelte imports from
@/components/ui/