Baseline: wave 1A server complete, wave 1B Android scaffold + design system green
assembleDebug, testDebugUnitTest, and recordPaparazziDebug all pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016bThmkmyUUdqQpy3MXFFe5
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# Bookshelf server
|
||||
|
||||
PocketBase backend for the Bookshelf app — see `../docs/SPEC.md` for the
|
||||
authoritative data model and API rules. This directory contains everything
|
||||
needed to provision and run it.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
server/
|
||||
pocketbase PocketBase v0.40.2 binary (gitignored — platform-specific)
|
||||
pb_data/ SQLite databases + uploaded files (gitignored — runtime state)
|
||||
pb_migrations/ Schema history, auto-captured — a fresh instance replays
|
||||
these on first boot and ends up with the full schema
|
||||
pb_hooks/ JS hook that closes a PocketBase quirk (see below)
|
||||
setup-schema.sh Idempotent schema/rules provisioning (curl + jq only)
|
||||
create-user.sh Superuser-driven account creation (no public sign-up)
|
||||
deploy/ systemd unit, Docker, backups, remote-access guidance
|
||||
```
|
||||
|
||||
## Quickstart (local dev)
|
||||
|
||||
PocketBase must already be running (see `deploy/README.md` for how to run
|
||||
it as a proper service; for a quick local check you can just run the binary
|
||||
directly: `./pocketbase serve`).
|
||||
|
||||
```sh
|
||||
# 1. Provision the schema + API rules (safe to re-run).
|
||||
./setup-schema.sh http://127.0.0.1:8090 <superuser-email> <superuser-password>
|
||||
|
||||
# 2. Create app accounts — there is no self-registration.
|
||||
./create-user.sh you@example.com "a strong password" "Your Name"
|
||||
```
|
||||
|
||||
Both scripts also read `PB_URL`/`PB_EMAIL`/`PB_PASS` from the environment,
|
||||
or fall back to `.dev-credentials` (gitignored, dev-instance-only — see
|
||||
`.dev-credentials` in this directory if present) if no args are given.
|
||||
|
||||
## Schema summary
|
||||
|
||||
Three collections — `bookcases`, `shelves`, `books` — each requiring
|
||||
authentication for every action (list/view/create/update/delete). Deletion
|
||||
in the app is always a soft `deleted` flag (tombstone), never an actual
|
||||
record delete, so sync can propagate it — see `SyncEngine` in the Android
|
||||
app and `docs/SPEC.md`'s Sync design section.
|
||||
|
||||
The built-in `users` collection is locked down: `createRule = null` means
|
||||
**only a superuser can create an account** (via `create-user.sh`); regular
|
||||
users can view any user (needed to resolve the `added_by` relation) and
|
||||
update only their own record.
|
||||
|
||||
## The pb_hooks quirk
|
||||
|
||||
PocketBase's declarative list/search rule acts as a row-level SQL filter,
|
||||
not a hard gate: an unauthenticated request against a collection whose
|
||||
`listRule` requires auth still gets **`200 OK` with an empty result**,
|
||||
rather than an error — because the rule can't be cleanly separated into
|
||||
"deny the whole request" vs. "just don't return matching rows" (see
|
||||
[pocketbase/pocketbase#6492](https://github.com/pocketbase/pocketbase/discussions/6492)).
|
||||
No private data ever leaks this way, but a `200` is still the wrong signal
|
||||
for "you're not allowed here." `pb_hooks/main.pb.js` adds a small
|
||||
`onRecordsListRequest` hook that turns that into a `403` for the three app
|
||||
collections. It's plain JS, auto-loaded by the stock `pocketbase` binary —
|
||||
no recompilation, no framework — so it ships and deploys exactly like
|
||||
`pb_migrations/`.
|
||||
|
||||
## Verifying a deployment
|
||||
|
||||
```sh
|
||||
# Anonymous requests must be rejected (4xx) for all three collections:
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8090/api/collections/books/records
|
||||
# -> 403
|
||||
|
||||
# Self-registration must be rejected:
|
||||
curl -s -X POST http://127.0.0.1:8090/api/collections/users/records \
|
||||
-H 'Content-Type: application/json' -d '{"email":"x@x.com","password":"password123","passwordConfirm":"password123"}'
|
||||
# -> 403 "Only superusers can perform this action."
|
||||
```
|
||||
|
||||
See `deploy/README.md` for running the server long-term, reaching it from
|
||||
outside your home network, and backups.
|
||||
Reference in New Issue
Block a user