74 lines
3.8 KiB
Markdown
74 lines
3.8 KiB
Markdown
# moments
|
|
|
|
Personal activity timeline for [rob.tn](https://rob.tn). Polls public sources (GitHub, Gitea, hg-edge.mozilla.org, bugzilla.mozilla.org), stores raw payloads in Postgres, and serves a reshaped timeline to a static React frontend.
|
|
|
|
Successor to the now-defunct [grenade-events-react](https://github.com/grenade/grenade-events-react), which depended on MongoDB Stitch (retired by MongoDB in September 2022).
|
|
|
|
## Layout
|
|
|
|
```
|
|
crates/
|
|
moments-entities/ # types and DTOs
|
|
moments-core/ # ingestion + reshape logic
|
|
moments-data/ # postgres adapter + migrations
|
|
moments-api/ # axum read-only HTTP API (binary)
|
|
moments-worker/ # ingestion daemon (binary)
|
|
ui/ # vite + react + swc + ts frontend
|
|
asset/ # systemd, nginx, firewalld, manifest.yml
|
|
script/deploy.sh
|
|
```
|
|
|
|
Architectural conventions follow [grenade/architecture/generic.md](https://git.lair.cafe/grenade/architecture/src/branch/main/generic.md).
|
|
|
|
## Local development
|
|
|
|
```sh
|
|
cargo build --workspace
|
|
cargo run -p moments-api # serves on 127.0.0.1:8080
|
|
cargo run -p moments-worker # one-shot ingest tick (until --interval is wired up)
|
|
```
|
|
|
|
The API expects a Postgres reachable at `DATABASE_URL`. For magrathea, that's an mTLS connection using the host cert. For local dev against a throwaway database:
|
|
|
|
```sh
|
|
DATABASE_URL=postgres://localhost/moments cargo run -p moments-api
|
|
```
|
|
|
|
Migrations live in `crates/moments-data/migrations/` and run automatically on worker startup. The API connects as `moments_ro` and never runs migrations — the worker (as `moments_rw`) is the schema owner.
|
|
|
|
## Deployment
|
|
|
|
```sh
|
|
./script/deploy.sh prod all # api + worker + web
|
|
./script/deploy.sh prod api worker # subset
|
|
./script/deploy.sh prod default # api + web only (worker untouched)
|
|
./script/deploy.sh prod all --dry-run
|
|
```
|
|
|
|
Topology:
|
|
|
|
| Component | Host | Notes |
|
|
| --------- | --------------------------------- | ------------------------------------------------------------------ |
|
|
| api | `nikola.kosherinata.internal` | binds `0.0.0.0:42424`; firewalld service `moments-api` |
|
|
| worker | `frootmig.kosherinata.internal` | no listening port; pollers only |
|
|
| web | `oolon.kosherinata.internal` | per-site nginx ingress for rob.tn; `/api/*` → nikola across the WG |
|
|
| db | `magrathea.kosherinata.internal` | postgres mTLS, passwordless |
|
|
|
|
Postgres roles `moments_rw` and `moments_ro` must exist on the primary, with `pg_ident.conf` mappings in place for `nikola.kosherinata.internal` → `moments_ro` and `frootmig.kosherinata.internal` → `moments_rw`. See `asset/sql/bootstrap-moments.sql` and `asset/postgres/ident.conf.tmpl`.
|
|
|
|
Inter-host traffic over the WG mesh: oolon's nginx connects to `http://nikola.kosherinata.internal:42424` in plaintext. The mesh provides the encryption layer; per-hop TLS for an internal HTTP read-only API on already-public data is deferred. If that changes, swap the api binary to rustls + the host cert pair, and update the nginx upstream to `https://`.
|
|
|
|
Secrets resolved by `deploy.sh` via `pass`:
|
|
|
|
- `github.com/grenade/admin-token` — GitHub PAT for events + search APIs (worker only).
|
|
|
|
Optional, set if needed in `worker.env`: `GITEA_TOKEN`, `BUGZILLA_API_KEY`.
|
|
|
|
### DNS cutover
|
|
|
|
`rob.tn` currently resolves to GitHub Pages. After the first successful prod deploy:
|
|
|
|
1. Update Cloudflare DNS for `rob.tn` to the WAN IP that fronts `nikola` (unproxied — see architecture doc §11).
|
|
2. Confirm `curl -fsS https://rob.tn/api/v1/healthz` returns `ok`.
|
|
3. Add an archival notice to the top of [grenade-events-react/readme.md](https://github.com/grenade/grenade-events-react) pointing at this repo, and archive the GitHub repo.
|