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:
1 parent
26f76bf0f7
commit
1385ad286f
5 files changed
+149
-26
No files matched your search
@@ -124,6 +124,34 @@ that keystore).
|
||||
|
||||
## Deploying the server
|
||||
|
||||
### Where this library's server actually runs today
|
||||
|
||||
The live instance runs **on the development sprite** and is **reachable from
|
||||
the open internet** over HTTPS, on a sprite-issued hostname. That is a
|
||||
deliberate interim choice — it is what the phones are pointed at — and it has
|
||||
one consequence worth stating plainly, because the rest of this README was
|
||||
written under the opposite assumption:
|
||||
|
||||
> **PocketBase's API rules are the only thing standing between this library
|
||||
> and the internet.** There is no home NAT, no VPN, and no reverse proxy in
|
||||
> front of it. The private-by-construction properties described above
|
||||
> (`createRule = null` on `users`, every collection requiring a logged-in
|
||||
> user, and the `pb_hooks` guard that turns an anonymous list into a 403
|
||||
> rather than an empty 200) are load-bearing rather than defence-in-depth.
|
||||
> Verify them against the *public* hostname, not `127.0.0.1` — localhost
|
||||
> cannot tell you what the world can reach. `server/README.md` has the curls.
|
||||
|
||||
The sprite suspends when idle and wakes on an incoming request, so the first
|
||||
call after a quiet period pays a cold start. The app is offline-first, so
|
||||
this shows up as a slower sync rather than a failure.
|
||||
|
||||
Moving to home hardware (a NUC, an old laptop, a Pi) behind Tailscale is
|
||||
still the intended end state, and the deploy docs below describe it. Nothing
|
||||
in the app has to change to make that move: the server URL is entered on the
|
||||
setup screen, never compiled in.
|
||||
|
||||
### Running it on your own hardware
|
||||
|
||||
See [`server/README.md`](server/README.md) for the schema and provisioning
|
||||
scripts, and [`server/deploy/`](server/deploy/) for running PocketBase
|
||||
long-term (systemd or Docker), reaching it from outside your home network
|
||||
@@ -153,17 +181,18 @@ meant to be, publicly distributed.
|
||||
|
||||
Read this before assuming more polish than exists:
|
||||
|
||||
- **The app has never run on a physical device or emulator.** This
|
||||
environment has no KVM, so there is no Android emulator available.
|
||||
Everything here was verified via `./gradlew assembleDebug`,
|
||||
`testDebugUnitTest` (JVM/Robolectric unit tests), and Paparazzi screenshot
|
||||
rendering (`src/test/snapshots/images/`) — real logic paths (ISBN
|
||||
checksums, metadata merging, sync conflict resolution, DAO queries) are
|
||||
unit-tested, and every screen has been rendered to a static PNG in both
|
||||
light and dark theme, but nothing has been tap-tested on an actual screen.
|
||||
Camera/barcode scanning in particular has only been exercised through unit
|
||||
tests of the pure logic (`IsbnBarcodeAnalyzer`/`ScanCodeFilter`), never a
|
||||
live camera.
|
||||
- **No automated testing runs on a device.** The app itself has been
|
||||
installed and used on a real phone since 2026-09-09, and several rounds of
|
||||
fixes came out of that; but this environment has no KVM, so there is no
|
||||
emulator, and every *automated* check is a JVM one. Verification is
|
||||
`./gradlew assembleDebug`, `testDebugUnitTest` (JVM/Robolectric unit
|
||||
tests), and Paparazzi screenshot rendering
|
||||
(`src/test/snapshots/images/`) — real logic paths (ISBN checksums,
|
||||
metadata merging, sync conflict resolution, DAO queries) are unit-tested,
|
||||
and every screen is rendered to a static PNG in both light and dark theme.
|
||||
Camera/barcode scanning is covered only through unit tests of the pure
|
||||
logic (`IsbnBarcodeAnalyzer`/`ScanCodeFilter`); the live camera path is
|
||||
exercised by hand on a phone or not at all.
|
||||
- **Sync has been round-tripped against a real PocketBase exactly once**
|
||||
(a live-server test covering auth, push with client-generated ids, pull,
|
||||
last-write-wins, tombstones, and a byte-for-byte cover round-trip — see
|
||||
|
||||
Reference in new issue
Block a user