# AGENTS.md: PocketBase

## Commands
- Run: `./pocketbase serve` (admin dashboard at `/_/`), or `go run . serve` when extended with Go.
- Schema changes are migrations in `pb_migrations/` (JS) or `migrations/` (Go). Create with `./pocketbase migrate create <name>` or let automigrate generate them from dashboard changes in dev, then commit them. Never change production schema only in the dashboard.
- Check the PocketBase version before using hook/migration APIs; they changed between major versions.

## Access rules
- Every collection has explicit API rules (list, view, create, update, delete). Empty rule = public; `null` (locked) = superusers only. Default to locked and open deliberately.
- Write ownership rules with request context: `@request.auth.id != "" && owner = @request.auth.id`. Protect fields users must not set with `@request.body.<field>:isset = false` (or the version's equivalent).
- Use `hidden` fields for data never returned by the API.

## Server logic
- JS hooks live in `pb_hooks/*.pb.js` (e.g. `onRecordCreateRequest`, `routerAdd`); each handler calls `e.next()` to continue the chain. Go extensions register hooks on `app.OnRecordCreate(...)` etc.
- Validate in hooks and return proper errors (`BadRequestError`, `ForbiddenError`); don't rely on the client.
- Custom routes require auth middleware unless deliberately public.

## Client (JS SDK)
- One `PocketBase` client instance; auth state in `pb.authStore`. Refresh with `authRefresh()` on app start.
- Build filters with parameters: `pb.filter('title ~ {:q} && status = {:s}', { q, s })`. Never concatenate user input into filter strings.
- Request only needed data with `fields` and `expand`; paginate with `getList(page, perPage)` instead of `getFullList` on large collections.
- Realtime: `pb.collection('x').subscribe('*', cb)` and always `unsubscribe()` on unmount.
- Files via the record's file fields and `pb.files.getURL(record, filename, { thumb })`.

## Done when
Migrations committed and applied cleanly on a fresh `pb_data`, API rules tested as anonymous, owner and other user.
