[Relay] Account Whitelist + Trust-Gated Access #47

Closed
opened 2026-03-21 00:40:55 +00:00 by replit · 2 comments
Owner

What & Why

Timmy's relay starts with an empty whitelist. Accounts must earn or be granted access. This task builds the account registry, trust-tier promotion logic, and API surface for granting/revoking/querying relay access.

Trust tiers (from existing Nostr identity/trust scoring) map to relay access:

  • new → read only
  • established → write access (posts go to moderation queue)
  • trusted → write access + expedited moderation (Timmy AI auto-approves benign posts)
  • elite → write access + full auto-approval, can vouch for new accounts

Accounts below established can be manually whitelisted by the relay admin.

Done looks like

  • relay_accounts DB table: pubkey (FK nostr_identities), access_level (none/read/write), granted_by, granted_at, revoked_at, notes
  • RelayAccountService: getAccess(pubkey), grant(pubkey, level, reason), revoke(pubkey), syncFromTrustTier(pubkey)
  • POST /api/relay/policy checks relay_accounts; write access → accept; read/none → reject
  • Admin endpoints: GET /api/admin/relay/accounts, POST .../grant, POST .../revoke
  • On first startup, seed Timmy's own pubkey (TIMMY_NOSTR_PUBKEY env var) with elite access
  • TrustService.recordSuccess calls syncFromTrustTier after tier promotion

Out of scope

  • Event moderation queue (separate issue)
  • Admin UI (separate issue)
  • Vouching flow

Tasks

  1. DB schema — Add relay_accounts table with columns above. FK to nostr_identities.pubkey. Run db:push.
  2. RelayAccountService — Four methods. syncFromTrustTier maps tier → access level via configurable env map (established→write, new→read, none→none).
  3. Trust hook — In TrustService.recordSuccess + tier promotion, call RelayAccountService.syncFromTrustTier(pubkey).
  4. Policy endpoint update — Extend POST /api/relay/policy to query relay_accounts. Write → accept; read/missing → reject.
  5. Admin routesGET /api/admin/relay/accounts, POST .../grant, POST .../revoke. Admin auth middleware.
  6. Seed Timmy's pubkey — On startup, if TIMMY_NOSTR_PUBKEY set, upsert nostr_identities and grant elite relay access.

Relevant files

  • lib/db/src/schema/nostr-identities.ts
  • artifacts/api-server/src/lib/trust.ts
  • artifacts/api-server/src/routes/index.ts
## What & Why Timmy's relay starts with an empty whitelist. Accounts must earn or be granted access. This task builds the account registry, trust-tier promotion logic, and API surface for granting/revoking/querying relay access. Trust tiers (from existing Nostr identity/trust scoring) map to relay access: - **new** → read only - **established** → write access (posts go to moderation queue) - **trusted** → write access + expedited moderation (Timmy AI auto-approves benign posts) - **elite** → write access + full auto-approval, can vouch for new accounts Accounts below `established` can be manually whitelisted by the relay admin. ## Done looks like - `relay_accounts` DB table: `pubkey` (FK `nostr_identities`), `access_level` (none/read/write), `granted_by`, `granted_at`, `revoked_at`, `notes` - `RelayAccountService`: `getAccess(pubkey)`, `grant(pubkey, level, reason)`, `revoke(pubkey)`, `syncFromTrustTier(pubkey)` - `POST /api/relay/policy` checks `relay_accounts`; write access → `accept`; read/none → `reject` - Admin endpoints: `GET /api/admin/relay/accounts`, `POST .../grant`, `POST .../revoke` - On first startup, seed Timmy's own pubkey (`TIMMY_NOSTR_PUBKEY` env var) with `elite` access - `TrustService.recordSuccess` calls `syncFromTrustTier` after tier promotion ## Out of scope - Event moderation queue (separate issue) - Admin UI (separate issue) - Vouching flow ## Tasks 1. **DB schema** — Add `relay_accounts` table with columns above. FK to `nostr_identities.pubkey`. Run `db:push`. 2. **RelayAccountService** — Four methods. `syncFromTrustTier` maps tier → access level via configurable env map (established→write, new→read, none→none). 3. **Trust hook** — In `TrustService.recordSuccess` + tier promotion, call `RelayAccountService.syncFromTrustTier(pubkey)`. 4. **Policy endpoint update** — Extend `POST /api/relay/policy` to query `relay_accounts`. Write → `accept`; read/missing → `reject`. 5. **Admin routes** — `GET /api/admin/relay/accounts`, `POST .../grant`, `POST .../revoke`. Admin auth middleware. 6. **Seed Timmy's pubkey** — On startup, if `TIMMY_NOSTR_PUBKEY` set, upsert `nostr_identities` and grant elite relay access. ## Relevant files - `lib/db/src/schema/nostr-identities.ts` - `artifacts/api-server/src/lib/trust.ts` - `artifacts/api-server/src/routes/index.ts`
replit added the backendnostr labels 2026-03-21 00:40:55 +00:00
claude was assigned by Rockachopa 2026-03-22 23:37:27 +00:00
Collaborator

All 6 tasks from this issue are already implemented on main:

  1. DB schemarelay_accounts table exists in lib/db/src/schema/relay-accounts.ts with all required columns (pubkey FK→nostr_identities, access_level, granted_by, granted_at, revoked_at, notes)
  2. RelayAccountService — Full implementation in artifacts/api-server/src/lib/relay-accounts.ts with getAccess(), grant(), revoke(), syncFromTrustTier(), seedElite(), and list()
  3. Trust hook — Both TrustService.recordSuccess() and recordFailure() call relayAccountService.syncFromTrustTier(pubkey) after tier updates
  4. Policy endpointPOST /api/relay/policy in artifacts/api-server/src/routes/relay.ts checks relay_accounts; write+elite→accept, write+non-elite→shadowReject (moderation queue), read/none→reject
  5. Admin routesGET /api/admin/relay/accounts, POST .../grant, POST .../revoke in artifacts/api-server/src/routes/admin-relay.ts with requireAdmin middleware
  6. Seed Timmy's pubkeyseedElite() called at startup in artifacts/api-server/src/index.ts using TIMMY_NOSTR_PUBKEY env var or derived from TIMMY_NOSTR_NSEC

No code changes needed — this was part of the initial codebase. Closing as already-complete.

All 6 tasks from this issue are already implemented on `main`: 1. **DB schema** — `relay_accounts` table exists in `lib/db/src/schema/relay-accounts.ts` with all required columns (pubkey FK→nostr_identities, access_level, granted_by, granted_at, revoked_at, notes) 2. **RelayAccountService** — Full implementation in `artifacts/api-server/src/lib/relay-accounts.ts` with `getAccess()`, `grant()`, `revoke()`, `syncFromTrustTier()`, `seedElite()`, and `list()` 3. **Trust hook** — Both `TrustService.recordSuccess()` and `recordFailure()` call `relayAccountService.syncFromTrustTier(pubkey)` after tier updates 4. **Policy endpoint** — `POST /api/relay/policy` in `artifacts/api-server/src/routes/relay.ts` checks relay_accounts; write+elite→accept, write+non-elite→shadowReject (moderation queue), read/none→reject 5. **Admin routes** — `GET /api/admin/relay/accounts`, `POST .../grant`, `POST .../revoke` in `artifacts/api-server/src/routes/admin-relay.ts` with `requireAdmin` middleware 6. **Seed Timmy's pubkey** — `seedElite()` called at startup in `artifacts/api-server/src/index.ts` using `TIMMY_NOSTR_PUBKEY` env var or derived from `TIMMY_NOSTR_NSEC` No code changes needed — this was part of the initial codebase. Closing as already-complete.
Collaborator

PR #90 created: http://143.198.27.163:3000/replit/timmy-tower/pulls/90

All 6 tasks from the issue were already implemented on main. This PR adds the missing SQL migration file 0009_relay_access.sql with explicit DDL for relay_accounts and relay_event_queue, completing the schema tracking for environments using SQL-based migrations.

PR #90 created: http://143.198.27.163:3000/replit/timmy-tower/pulls/90 All 6 tasks from the issue were already implemented on main. This PR adds the missing SQL migration file `0009_relay_access.sql` with explicit DDL for `relay_accounts` and `relay_event_queue`, completing the schema tracking for environments using SQL-based migrations.
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: replit/timmy-tower#47