Refresh checkpoint with contact-aware feed
This commit is contained in:
parent
a1445d17a8
commit
387f12fada
1 changed files with 52 additions and 48 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
# Checkpoint — Feed aggregation (2026-08-06)
|
# Checkpoint — Contact-aware feed (2026-08-06)
|
||||||
|
|
||||||
A stopping point you can return to if this session is closed. Everything below was
|
A stopping point you can return to if this session is closed. Everything below was
|
||||||
verified green at the moment this file was written.
|
verified green at the moment this file was written.
|
||||||
|
|
@ -6,53 +6,58 @@ verified green at the moment this file was written.
|
||||||
## Where things are
|
## Where things are
|
||||||
|
|
||||||
- Project: `/home/avi/Projects/skills/nost-feed-manager`
|
- Project: `/home/avi/Projects/skills/nost-feed-manager`
|
||||||
- Git repo: `master` @ `37a9d94` ("Add feed aggregation from enabled relays"), on top of the
|
- Git repo: `master` @ `a1445d1` ("Add contact-aware feed scope").
|
||||||
NIP-46 signer work (`8cbe0b8` README, `ca3203c` approval gate, `73cb08d` signer) described in
|
- Working tree is **clean** — this session's contact-aware feed changes and its checkpoint
|
||||||
earlier checkpoints.
|
are committed.
|
||||||
- The working tree is **clean** — this session's feed feature and its checkpoint are committed.
|
- On top of that sits the NIP-46 signer work and the original feed aggregation, all committed.
|
||||||
- The feed feature spans the Rust `src/feed.rs` module plus IPC/CLI wiring and the frontend
|
|
||||||
Feed screen.
|
|
||||||
|
|
||||||
## What was completed: feed aggregation
|
## What was completed: contact-aware feed
|
||||||
|
|
||||||
The app now has a **Feed screen** (sidebar nav item with a list icon) that shows a read-only,
|
The Feed screen (and CLI) can now be scoped to **My contacts**: instead of showing the global
|
||||||
newest-first list of recent text notes aggregated from the enabled relays. Reading never touches
|
stream, it fetches the active profile's kind 3 contact list from the enabled relays and returns
|
||||||
the user's stored keys: a throwaway identity is used, and the feed never signs or publishes.
|
only recent notes authored by those contacts. This builds on the existing aggregation engine.
|
||||||
|
|
||||||
- **Backend** (`src/feed.rs`): `FeedItem` (note id, author hex + npub, content, created_at,
|
- **Backend** (`src/feed.rs`):
|
||||||
relays seen on), `aggregate_feed(settings, limit)` which connects to every enabled relay,
|
- `contact_feed(settings, limit, owner_hex)` fetches the owner's contact pubkeys
|
||||||
subscribes to kind 1 notes newer than 24h (capped at `limit`, default 50), collects for up to
|
(`contact_pubkeys`) then aggregates only notes from those authors.
|
||||||
15s, then returns de-duplicated, newest-first items. `FeedBuilder` dedupes events across relays
|
- `contact_pubkeys` subscribes to kind 3 (contact list) for the owner, collecting the hex
|
||||||
(tracking the extra relay sources) and stops early once the cap is reached. Empty input (no
|
pubkeys of everyone they follow from `TagStandard::PublicKey` tags, de-duplicated.
|
||||||
relays enabled, or no notes) returns an empty list, not an error. Unit tests cover no-relay
|
- `aggregate_feed` still serves the global feed and now delegates to a private
|
||||||
empty feed, newest-first sorting, cross-relay dedupe, kind filtering, and the fill cap.
|
`aggregate_for(settings, limit, authors)` used by both scopes. When `authors` is set the
|
||||||
- **IPC** (`src/ipc.rs`): new `Request::FeedGet { limit }` → returns the aggregated items. Needs
|
NIP-01 filter restricts to those authors **and** `FeedBuilder` drops any note from someone
|
||||||
no vault unlock, so the feed works even when the vault is locked.
|
else (defence in depth for relays that ignore the `authors` filter).
|
||||||
- **CLI** (`src/main.rs`): `feed [limit]` prints a one-line preview per note (content, npub,
|
- `FeedBuilder::new(limit, authors)` takes an optional author whitelist.
|
||||||
timestamp); a friendly "No notes found…" message when the feed is empty.
|
- `owner_pubkey(npub)` decodes a stored `npub1...` (or hex) to a `PublicKey`; shared by the
|
||||||
- **Electron/React frontend**: the **Feed screen** (`FeedScreen.tsx`, wired in `App.tsx` as the
|
IPC server and the CLI.
|
||||||
`'feed'` screen). Shows author avatar/npub, content, relative date, a "2 relays" badge for
|
- **IPC** (`src/ipc.rs`): `FeedGet` now accepts `contacts_only: Option<bool>`. With
|
||||||
notes seen on multiple relays, and a **Refresh** button. Empty states for "no relays enabled"
|
`contacts_only: true`, it resolves the active profile's npub, decodes it, and calls
|
||||||
(with a button to jump to the Relays screen) and "no notes found", plus a clear error alert on
|
`contact_feed`. Without an active profile it returns a `no_active_profile` error.
|
||||||
failure. Wired through `api.ts` (`feedGet`), `AppProvider`, `navigation.ts` (`'feed'`), and the
|
- **CLI** (`src/main.rs`): `feed [--contacts] [limit]` — `--contacts` filters to the active
|
||||||
sidebar (`Icon 'list'`).
|
profile's contacts; the no-results message is adjusted accordingly.
|
||||||
|
- **Electron/React frontend**: the Feed screen (`FeedScreen.tsx`) gains a segmented **Everyone /
|
||||||
|
My contacts** scope toggle. "My contacts" is disabled when no profile is active (and silently
|
||||||
|
forced back to Everyone). Scope-aware empty states ("No notes from your contacts"), and
|
||||||
|
`feedGet(limit, contactsOnly)` threads the flag from `api.ts` through `AppProvider`.
|
||||||
|
- **Styles** (`styles.css`): a `.segmented` pill control for the scope toggle.
|
||||||
|
|
||||||
## Commits this session (newest first)
|
## Commits
|
||||||
|
|
||||||
- `37a9d94` "Add feed aggregation from enabled relays" — the full feed feature: `src/feed.rs`,
|
- `a1445d1` "Add contact-aware feed scope" — the full feature: `src/feed.rs`
|
||||||
IPC `FeedGet`, CLI `feed`, the frontend Feed screen + tests, and the README update.
|
(`contact_feed`/`contact_pubkeys`/`aggregate_for` + author whitelist), IPC `FeedGet`
|
||||||
|
`contacts_only`, CLI `feed --contacts`, the frontend scope toggle + styles + tests, README.
|
||||||
|
(Parent: `1fd057d` "Refresh checkpoint with feed aggregation".)
|
||||||
|
|
||||||
## How it was verified (all green)
|
## How it was verified (all green)
|
||||||
|
|
||||||
```
|
```
|
||||||
cargo test # 81 passed
|
cargo test # 84 passed
|
||||||
cargo clippy --all-targets # clean
|
cargo clippy --all-targets # clean
|
||||||
cargo fmt --check # clean
|
cargo fmt --check # clean
|
||||||
cargo build --release # builds (rebuilt so the GUI runs the new backend)
|
cargo build --release # builds (rebuilt so the GUI runs the new backend)
|
||||||
npm run typecheck # clean (frontend/)
|
npm run typecheck # clean (frontend/)
|
||||||
npm run lint # clean (pre-existing module warning only)
|
npm run lint # clean (pre-existing module warning only)
|
||||||
npm run format:check # clean
|
npm run format:check # clean
|
||||||
npm test # 75 passed (14 files)
|
npm test # 78 passed (14 files)
|
||||||
npm run electron:build # compiles the Electron main process
|
npm run electron:build # compiles the Electron main process
|
||||||
npm run build # rebuilds the React bundle (dist/)
|
npm run build # rebuilds the React bundle (dist/)
|
||||||
```
|
```
|
||||||
|
|
@ -60,22 +65,21 @@ npm run build # rebuilds the React bundle (dist/)
|
||||||
## How to resume
|
## How to resume
|
||||||
|
|
||||||
1. Open the repo: `cd /home/avi/Projects/skills/nost-feed-manager`
|
1. Open the repo: `cd /home/avi/Projects/skills/nost-feed-manager`
|
||||||
2. State is committed: `git status` should be clean; `git log --oneline -5` shows
|
2. State is committed: `git status` should be clean; `git log --oneline -5` shows `a1445d1`
|
||||||
`37a9d94` at the top.
|
at the top.
|
||||||
3. To try the feed:
|
3. To try the contact feed:
|
||||||
- GUI: `cd frontend && npm start`, then the **Feed** screen in the sidebar. It lists recent
|
- GUI: open the **Feed** screen and switch **Everyone → My contacts**. You need an active
|
||||||
notes from the enabled relays; use **Refresh** to re-query. (Note: `npm start` alone does
|
profile that follows people; the segmented control filters the feed to their notes.
|
||||||
NOT rebuild the React bundle — run `npm run build` first, or use `npm run dev` +
|
- CLI: `./target/release/nostr-manager-backend feed --contacts 10` prints up to 10 recent
|
||||||
`NOSTR_GUI_DEV_URL=http://localhost:5173 npm start` for live reload.)
|
notes from the active profile's contacts.
|
||||||
- CLI: `cargo build --release`, then `./target/release/nostr-manager-backend feed 10` prints
|
|
||||||
up to 10 recent notes from the enabled relays.
|
|
||||||
4. Re-run verification with the commands above.
|
4. Re-run verification with the commands above.
|
||||||
|
|
||||||
## Outstanding / next steps (if you continue)
|
## Outstanding / next steps (if you continue)
|
||||||
|
|
||||||
- The feed currently shows the *global* stream from the enabled relays. A natural follow-up is a
|
- The contact feed depends on the kind 3 contact list being present on the enabled relays; a
|
||||||
**contact-aware feed**: fetch the active profile's kind 3 contact list and filter the feed to
|
profile with no contacts (or a newly created one that has never published a contact list)
|
||||||
those authors (and optionally show link-card previews per note, as hinted in the original
|
produces an empty feed, which is expected but could be surfaced more clearly in the GUI.
|
||||||
"feed aggregation" description).
|
- A live end-to-end check of the feed (global and contacts) against public relays has not been
|
||||||
- Live end-to-end check of the feed against public relays (network call) has not been run in this
|
run in this session; the deterministic parts are covered by unit + frontend tests.
|
||||||
session; the unit + frontend tests cover the deterministic parts.
|
- The checkpoint/session discipline in AGENTS.md says to commit the feature first, then the
|
||||||
|
checkpoint update. This was done: `a1445d1` (feature) then this checkpoint commit.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue