A terminal reader, ipx; the server is ipxd (#437)

ipx-tui (crates/tui) is iPX's reader in ratatui: your feeds, a feed's
items, an item's text as plain text, read and flagged as on the page,
through the API with an API token. It installs as `ipx`, so the daemon's
binary is now `ipxd`: the Dockerfile, release script, tests and every
doc and message that names its commands follow.

Naming the binary ipxd alone renamed its crate, and with it every log
target (ipx::scan became ipxd::scan): the default filters are ipx=info,
so nearly every line would have been dropped and the dashboard's queries
on the targets gone blank. The daemon's code is now a library still
called ipx, under a five-line ipxd main.rs, and the targets are as they
were.

ratatui is taken without its default features: 32 new packages in place
of 78.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RqkrVDqdiQEMWAkNGQ2tYA
This commit is contained in:
2026-11-09 11:52:10 +00:00
parent f844cf349a
commit 711b0395f1
40 changed files with 1128 additions and 238 deletions

View File

@@ -112,7 +112,7 @@ next build makes it again with the new config.
The containers have no Docker healthcheck (#218): Docker runs one with `exec`, which on Tower
fails whenever root is logged out, because elogind removes `/run/user/0`, where containerd puts
each exec's state. Whether ipx is well is Prometheus's question (`up`, the worker's job and time)
and `ipx status` against the control socket, which says the daemon answers and can read its
and `ipxd status` against the control socket, which says the daemon answers and can read its
database. The socket answers `status` itself instead of queuing it behind the worker's current
job, so a worker stuck on one job still answers it. The containers restart on their own after a
reboot.
@@ -239,7 +239,8 @@ session was stopped. So:
| `crates/ipx/` | `cargo test -p ipx`; the browser tests too if the API changed |
| `crates/directory/` | `cargo test -p ipx-directory`, then `-p ipx` |
| `crates/feed/` | `cargo test -p ipx-feed`, then `-p ipx-directory`, then `-p ipx` |
| `Cargo.toml`, `Cargo.lock` | all three, one at a time |
| `crates/tui/` | `cargo test -p ipx-tui`; it uses only the API, none of the other crates |
| `Cargo.toml`, `Cargo.lock` | all four, one at a time |
The pre-commit hook's clippy follows the same table. The whole browser suite once, at the end
of a change to the page or the API; never `cargo test` for the workspace in one command.
@@ -287,7 +288,7 @@ seeking through files, a flood of wrong passwords. Things about them:
127.0.0.1, as production trusts Cloudflare Access's; only the sign-in test uses a password.
* Each threshold is a budget well above what the request takes now: it is there to catch a query
that has started asking once per feed, or writers queueing on a lock, not a slow minute.
* `ipx status` runs every second throughout, and a run fails if one takes 5s.
* `ipxd status` runs every second throughout, and a run fails if one takes 5s.
* One at a time: `node tests/load/run.ts signin`. All four take about six minutes.
* The daemon is on **SQLite** unless `--postgres`, which puts it in `IPX_TEST_DATABASE_URL`, in
a schema of its own (`ipx_load`) dropped and made again each run. That URL, in `/src/.envrc`, is
@@ -377,13 +378,13 @@ ms in ipx, the difference being new connections, 80-330 ms each to open (#241).
go blank without an error; regenerate the dashboard to match. Routine lines (a request that went
well, a scan's end) are debug: the admin page's Log view has them, Loki does not.
* `/api/settings` answering `200` does **not** mean the daemon is well — the web server is a
different task. `ipx status` checks the control socket and the database; to see the worker
different task. `ipxd status` checks the control socket and the database; to see the worker
getting through its jobs, watch for `scan complete` in the log.
* **The database goes through SeaORM, and the entities in `crates/ipx/src/entity.rs` are the schema.**
`Db::open` creates any missing table or index from them (`create_missing`), on every `ipx`
command, the healthcheck's `ipx status` included, so it must never write when nothing is
command, the healthcheck's `ipxd status` included, so it must never write when nothing is
missing: SeaORM's experimental schema sync dropped and remade an index on every open, the
write lock that took made `ipx status` time out behind a busy daemon, and it was removed for
write lock that took made `ipxd status` time out behind a busy daemon, and it was removed for
it. A new column on an existing table needs its own `ALTER`; nothing adds one for you. Look for
the column first and alter only when it is missing, as `feeds.description` does.
* **SQL written by hand in `db.rs` has to run on SQLite and Postgres both** (issue #18): `$1`