feat(entities): record unauthorized interactions + operator list endpoint#118
Merged
Merged
Conversation
…oint
Persist a pp_entity_approvals row at the two unauthorized-interaction points
(SEP-10 connect + bundle-submit 403) so unauthorized pubkeys become visible to
operators, and expose them via GET /providers/:ppPublicKey/entities.
- recordInteraction: insert UNVERIFIED if absent, touch updated_at if already
UNVERIFIED, never modify an APPROVED/PENDING/BLOCKED row (single ON CONFLICT
upsert with setWhere status = UNVERIFIED).
- listByPp: non-deleted rows joined to entity identity, updated_at DESC.
- Wire both write-points best-effort (a write failure never breaks the auth
response or changes the 403).
- Operator list endpoint mirrors the metrics endpoint (jwt + requirePpOwnership,
{ data } envelope).
- Reuses the existing table + enum; no migration.
Relates to ClickUp 86ca439ah
AquiGorka
force-pushed
the
feat/entities-record-interactions-list-endpoint
branch
from
June 11, 2026 22:03
e001f4c to
df30e56
Compare
AquiGorka
added a commit
to Moonlight-Protocol/provider-console
that referenced
this pull request
Jun 12, 2026
…38) ## Summary Adds an "Entities" section to the provider detail page showing every pubkey that has interacted with the provider — the KYC-approved ones plus the unauthorized pubkeys now recorded by Moonlight-Protocol/provider-platform#118 (SEP-10 connect + bundle-submit 403). UI side of the vertical slice; backend is Moonlight-Protocol/provider-platform#118. ## What changed - New `getEntities(ppPublicKey)` client call (`lib/api.ts`) following the existing URL-scoped pattern (`{ data }` envelope). - New **Entities** section in `views/provider.ts`, **below** all existing sections (OpEx / Councils / Dashboard / sparklines). Columns: Date (`updated_at`, relative — matching the console's existing date helper), Public Key (truncated + copy affordance), Status (badge per status). Loading / empty ("No entities have interacted with this provider yet") / error states match the sibling sections. - `.badge-unverified` neutral grey variant in `app-styles.css` (the lib ships active/pending/inactive; UNVERIFIED has no semantic colour). ## Testing - `deno fmt --check`, `deno task lint`, `deno task test`, `deno task build` all green. - Live local smoke (isolated Docker stack built from this branch + provider-platform#118): the section renders three real rows — two UNVERIFIED (from the connect + bundle-403 write-points) and one APPROVED (KYC) — in `updated_at` DESC, below the existing sections. Screenshot captured. ## Note The `Date` column uses the console's existing relative-time helper (`fmtRelativeTime`) — the only date format the console currently ships — to match convention. Happy to switch to an absolute timestamp if preferred. Relates to ClickUp 86ca439ah
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A PP operator had no way to see which entities have interacted with their provider. Entities that registered via KYC self-serve get an APPROVED row in
pp_entity_approvals; entities that interact but are NOT authorized (SEP-10 connect with no approval, or a bundle-submit 403) left zero persistent trace. This persists a record at those two unauthorized-interaction points and exposes an operator-facing list endpoint.Vertical slice with the UI side in Moonlight-Protocol/provider-console#38.
What changed
recordInteraction(pp, pubkey)— singleON CONFLICT … DO UPDATE … setWhere status = 'UNVERIFIED'upsert: insert UNVERIFIED if absent, touchupdated_atif the row is already UNVERIFIED, and never modify an APPROVED/PENDING/BLOCKED row.listByPp(pp)— non-deleted rows for the PP joined to entity identity (name/jurisdictions) via account → entity,updated_atDESC.attach-entity-status.ts) and the bundle-submit 403 gate (add-bundle.process.ts, both branches). Both are best-effort: a write failure never breaks the auth response and never changes the 403.GET /api/v1/providers/:ppPublicKey/entities— operator JWT +requirePpOwnership, mirroring the metrics endpoint ({ data }envelope).entity_statusenum — no migration.Testing
listByPpordering + join + soft-delete/PP scoping.updated_atDESC + ownership (owner passes, non-owner denied).updated_aton the existing row; operator endpoint returns all three in DESC; non-owner denied. No authorization regression.deno fmt --check,deno lint,deno task test(200 passed) all green.Intentional deviation from the prompt text
A non-owning operator receives 404 ("Provider not found"), not 403 —
requirePpOwnershipreturns 404 for any PP the operator doesn't own, identical to every other/providers/:ppendpoint (it doesn't distinguish "exists-but-not-yours" from "absent"). The ownership property holds; only the status code differs. Tests assert the real 404.Relates to ClickUp 86ca439ah