Skip to content

feat(provider): entities-interacting section on provider detail page#38

Merged
AquiGorka merged 2 commits into
mainfrom
feat/provider-entities-section
Jun 12, 2026
Merged

feat(provider): entities-interacting section on provider detail page#38
AquiGorka merged 2 commits into
mainfrom
feat/provider-entities-section

Conversation

@AquiGorka

Copy link
Copy Markdown
Contributor

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

Add an "Entities" section below the existing sections of the provider detail
page, listing every pubkey that has interacted with the provider: Date
(updated_at), Public Key (truncated + copy), Status (badge per status). Loading
/ empty / error states match the sibling sections; UNVERIFIED uses a neutral
local badge variant. Backed by GET /providers/:pp/entities.

Relates to ClickUp 86ca439ah
@AquiGorka AquiGorka merged commit 21dabd5 into main Jun 12, 2026
6 checks passed
@AquiGorka AquiGorka deleted the feat/provider-entities-section branch June 12, 2026 01:08
AquiGorka added a commit to Moonlight-Protocol/provider-platform that referenced this pull request Jun 12, 2026
…oint (#118)

## 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)`** — single `ON CONFLICT … DO UPDATE
… setWhere status = 'UNVERIFIED'` upsert: insert UNVERIFIED if absent,
touch `updated_at` if 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_at` DESC.
- **Write-points** — SEP-10 connect (`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).
- Reuses the existing table + `entity_status` enum — **no migration**.

## Testing

- Unit (PGlite, real migrations): the upsert invariant across all
branches (insert / touch-when-UNVERIFIED /
no-op-when-APPROVED/PENDING/BLOCKED), plus `listByPp` ordering + join +
soft-delete/PP scoping.
- Integration: endpoint envelope + `updated_at` DESC + ownership (owner
passes, non-owner denied).
- Live local smoke (isolated Docker stack built from this branch):
approved entity submits a real bundle; unauthorized connect records
UNVERIFIED; unauthorized bundle 403s and advances `updated_at` on 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 —
`requirePpOwnership` returns 404 for any PP the operator doesn't own,
identical to every other `/providers/:pp` endpoint (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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant