docs: the server is on the sprite and internet-exposed

The long-standing open question "where will the server actually live" is
answered for now: it stays on this sprite, bound to 0.0.0.0:8090 and published
over HTTPS by the sprite proxy. Several docs asserted the opposite — HANDOFF
said "127.0.0.1:8090, deliberately NOT internet-exposed (no --http-port, so the
sprite proxy can't reach it)", which is flatly wrong today.

The consequence is the part worth writing down: PocketBase's API rules are now
the only thing between this library and the internet. There is no NAT, no VPN,
no reverse proxy. So the anonymous-access curls stop being a formality, and they
have to run against the PUBLIC hostname — localhost cannot tell you what the
world can reach. Re-verified that way: books/shelves/bookcases LIST all 403,
self-registration 403, health 200.

One gap found while re-verifying, recorded but NOT fixed: users LIST answers 200
with an empty array instead of 403. Nothing is disclosed — two real accounts
exist and the listRule filters both out — but it is the same wrong-signal quirk
pb_hooks/main.pb.js exists to close, and that hook never listed the users
collection.

SPEC's offline-first rationale is amended rather than its rule: the reason is no
longer residential NAT but a sprite that suspends when idle and wakes on
request. The rule is unchanged and does not depend on which.

server/deploy/ still documents systemd/Docker/Tailscale on home hardware; it now
says up front that this is the intended end state, not what is running.

Also corrected, since it was adjacent and plainly false: README still claimed the
app had never run on a physical device. It has, since 2026-09-09. What is true is
that no *automated* test runs on a device — there is no emulator on this box.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPpdG8VnRfS3KkisR3HUAE
This commit is contained in:
Spriteandclaude committed 2026-09-12 17:32:17 +00:00
1 parent 26f76bf0f7
commit 1385ad286f
5 files changed
+149 -26

No files matched your search

+33 -4
View File
@@ -66,16 +66,45 @@ no recompilation, no framework — so it ships and deploys exactly like
## Verifying a deployment
**Run these against the address the outside world uses, not `127.0.0.1`.**
A localhost curl cannot tell you what is reachable from the internet, and
the live instance of this server (see below) *is* on the internet, with
these rules as its only protection.
```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
BASE=https://your-server.example # the PUBLIC base URL, not localhost
# Anonymous requests must be rejected for all three collections:
for c in books shelves bookcases; do
curl -s -o /dev/null -w "$c %{http_code}\n" "$BASE/api/collections/$c/records"
done
# -> 403, 403, 403
# Self-registration must be rejected:
curl -s -X POST http://127.0.0.1:8090/api/collections/users/records \
curl -s -X POST "$BASE/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."
```
A `200` with a non-empty `items` array from any of those is a breach, and a
`200` with an empty one means the `pb_hooks` guard is not loaded — see the
quirk described above.
> **Known gap:** `GET /api/collections/users/records` currently answers
> **200 with an empty array** rather than 403. Nothing is disclosed — the
> `listRule` filters every row out, so an anonymous caller sees no accounts,
> no emails, no ids — but it is the same wrong-signal quirk as above, and
> `pb_hooks/main.pb.js` does not yet cover the `users` collection. Adding it
> to that hook's collection list closes it.
## Where the live server runs
The instance these phones talk to runs **on the development sprite**, bound
to `0.0.0.0:8090` and published over HTTPS on a sprite-issued hostname, so
it is **internet-exposed**. That is an interim arrangement; `deploy/` covers
the intended move to home hardware behind Tailscale. The app never hardcodes
a server URL — it is entered on the first-run setup screen — so that move
needs no code change, only re-pointing each phone.
See `deploy/README.md` for running the server long-term, reaching it from
outside your home network, and backups.