Commit Graph
5 Commits
Author SHA1 Message Date
Spriteandclaude ab1d294657 server: user auth tokens valid 180 days (was PocketBase default 5)
Phone sync broke 2026-09-17 with HTTP 400: its 5-day token had expired and
the app never refreshes it, so writes arrived anonymous and the rules
rejected them. User chose 180 days. App-side refresh follows in wave 11.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 01:28:12 +00:00
Spriteandclaude 0455794603 server: anonymous LIST of users returns 403, not 200 with an empty array
Found while re-verifying the security posture against the public hostname now
that the server is internet-exposed. pb_hooks/main.pb.js covered bookcases,
shelves and books but never users, so an anonymous GET of the accounts
collection answered 200 with an empty array.

Nothing leaked: two real accounts exist and the declarative listRule filtered
both out, so no account, email or id was ever visible to an anonymous caller.
But "200 with []" is the exact wrong signal this hook exists to remove — some
clients read it as an allowed request — and the accounts collection is the last
place to leave it. Defensible while the server was localhost-only; not now.

Re-verified over the internet after restarting the service: books, shelves,
bookcases and users all 403 anonymous, self-registration 403, health 200.

Also re-verified that login still works, since this hook now runs on a
collection the app authenticates against: auth-with-password returns 200 with a
token, and an authenticated LIST of all four collections still returns 200. The
hook rejects unauthenticated list/search only, and auth-with-password is not a
list request.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPpdG8VnRfS3KkisR3HUAE
2026-09-12 17:47:43 +00:00
Spriteandclaude 1385ad286f 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
2026-09-12 17:32:17 +00:00
claude cf36b27457 Wave 4 (partial): live-sync harness + Library screenshots; fix authors null decode
Both wave-4 workers hit the 5h session limit ~11 minutes in and were then lost
to a sprite suspend. This commit preserves the work that landed before that,
independently verified green (assembleDebug + testDebugUnitTest, 94 tests).

F1-livesync:
- LiveSyncTest + server/live-sync-test.sh: end-to-end exercise against a real
  PocketBase (auth, push with client ids, pull, tombstones, cover round-trip).
  Gated behind LIVE_SYNC=1 so the normal test task stays green with no server.
- Fix: BookDto.authors must be nullable. PocketBase serializes an unset `json`
  field as literal null (unlike text/number, which come back ""/0), so decoding
  any real response with empty authors threw. Found by the live test; no fake
  had ever reproduced it.
- Fix: cover upload derived its media type from the filename instead of
  hardcoding image/jpeg.

F2-release:
- ScreenFixtures + LibraryScreenPaparazziTest: library populated and empty,
  light and dark (4 PNGs).

Still owed by wave 4: screenshots for the other five screens, release keystore
+ signed APK, top-level README.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016mTs3kQXQsQwonXpEq7aEw
2026-09-06 18:56:55 +00:00
claude 6c17e42037 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
2026-09-06 01:58:37 +00:00