Skip to content

Migrate consumers to URL-scoped /providers/:pp/... endpoints#107

Merged
AquiGorka merged 5 commits into
mainfrom
feat/pp-url-scoping
Jun 1, 2026
Merged

Migrate consumers to URL-scoped /providers/:pp/... endpoints#107
AquiGorka merged 5 commits into
mainfrom
feat/pp-url-scoping

Conversation

@AquiGorka

Copy link
Copy Markdown
Contributor

Summary

  • Migrate every consumer in this repo to the URL-scoped surface introduced by URL-scope every per-provider endpoint + signed-challenge entity submission provider-platform#107. Affected: e2e/dashboard.ts (channels/mempool/operations/treasury/metrics/audit-export), e2e/main.ts, e2e/pos-instant/main.ts, e2e/governance/uc2-approve-reject.ts, lifecycle/{main,testnet-verify,ci-test}.ts, testnet/main.ts, setup-pp.{sh,ts}, lib/client/bundle.ts. Comments and section headers updated to name the new URLs.
  • Add lib/client/register-entity.ts — a shared SEP-43/SEP-53 signed-challenge KYC submission helper, replacing six in-place registerEntity copies across e2e/, lifecycle/, testnet/ that hit the bare-deleted POST /api/v1/entities. Living under lib/client/ so every docker-compose test-runner that already copies /lib-src/client/ reaches it.
  • Rewrite send-loop.ts:forceExpireBundles to write status='EXPIRED' + back-dated TTL directly to the provider-platform PostgreSQL via postgres. Replaces the bare-deleted HTTP admin endpoint POST /api/v1/dashboard/bundles/expire; the back-dated TTL lets the platform's mempool TTL-check sweep purge the in-memory slot via the same path it uses for natural TTL expiry. There's a short race window: when the executor wins the race to settle, the verifier later transitions the bundle to COMPLETED; when our UPDATE + back-dated TTL win, the bundle stays EXPIRED. In both cases the bundle reaches a terminal status, which is what INJECT_EXPIRE exists to produce. (A race-free guarantee would require in-process mempool access we deliberately don't expose over HTTP.)

Test-infra fix

  • docker-compose.pos-instant.yml's test-runner entrypoint only copied top-level lib/*.ts into the container — it skipped the lib/client/ subdirectory the other suites already copy. After register-entity.ts moved into lib/client/, the suite errored with Module not found "file:///app/lib/client/register-entity.ts". Adding cp -r /lib-src/client lib/ aligns pos-instant with the other suites' mount shape; the import path becomes ./lib/client/register-entity.ts to match the container-flattened layout the other pos-instant imports use (./moonlight-pay-lib/…, ./e2e/…).

URL changes (consumer side)

e2e/governance/lifecycle/testnet/setup-pp now hit:
  POST   /providers/:pp/entity/bundles                 (user-mode submit)
  GET    /providers/:pp/entity/bundles/:id             (user-mode poll)
  POST   /providers/:pp/council/join                   (operator)
  GET    /providers/:pp/council/membership             (operator)
  POST   /providers/:pp/council/membership             (operator sync)
  GET    /providers/:pp/{channels,mempool,operations,
         treasury,metrics,audit-export}                (operator dashboard)

entity registration uses lib/client/register-entity.ts:
  POST   /providers/:pp/entities/challenge             (issue nonce)
  POST   /providers/:pp/entities                       (signed submit)

Companion PRs

Test plan

  • deno fmt --check, deno lint (23 pre-existing warnings, none new)
  • test.sh e2e, otel, governance, lifecycle, pos-instant, invite-gate — all green against the companion branches
  • testnet/run-local.sh payment + lifecycle — 23 OTEL checks each, green
  • send-loop.ts EXPIRE=true — 12-country cycle, force-expire writes EXPIRED to DB (force-expired 1 of 1 bundle(s) via DB (TTL back-dated…)); at-rest DB shows EXPIRED for the one bundle whose UPDATE landed before settlement and COMPLETED for the others (race outcome, both terminal — see Summary)

AquiGorka added 5 commits June 1, 2026 16:58
* e2e/governance/lifecycle/testnet/setup-pp harnesses now hit:
  - POST /providers/:pp/entity/bundles                 (user-mode submit)
  - GET  /providers/:pp/entity/bundles/:id             (user-mode poll)
  - POST /providers/:pp/council/join                   (operator)
  - GET  /providers/:pp/council/membership             (operator)
  - POST /providers/:pp/council/membership             (operator sync)
  - GET  /providers/:pp/{channels,mempool,operations,treasury,metrics,
    audit-export}                                       (operator dashboard)
* lib/register-entity.ts — shared helper for the SEP-53 signed-challenge
  KYC submission flow. Replaces six in-place registerEntity copies that hit
  the now-410'd POST /api/v1/entities.
* send-loop INJECT_EXPIRE switches from the bare-deleted HTTP admin
  endpoint (POST /api/v1/dashboard/bundles/expire) to a direct PostgreSQL
  UPDATE on operations_bundles, back-dating the bundle's TTL so the
  mempool's own TTL-check sweep purges it via the platform's normal path.
  Adds postgres npm dep to deno.json.
…can reach it

The docker-compose test-runner entrypoints (e2e, otel, lifecycle, pos-instant)
only copy /lib-src/client into the container — lib/register-entity.ts at the
parent path is invisible. Moving the helper into lib/client/ (next to its
peer client helpers auth.ts/bundle.ts/send.ts) lets the existing compose mount
pattern reach it without touching the entrypoint shell.
The pos-instant test-runner's docker-compose entrypoint copied only
/lib-src/*.ts into /app/lib/, skipping the lib/client/ subdirectory that
every other suite already copies. After register-entity moved into
lib/client/, the import resolved correctly on the host but failed in the
container with 'Module not found'. Aligning the cp pattern with the other
suites' shape (add cp -r /lib-src/client lib/) plus switching the import
to the container-relative form (./lib/client/register-entity.ts, matching
the existing ./moonlight-pay-lib/ and ./e2e/ imports) makes the suite
green.
…kflows

The reusable workflows previously hardcoded ref: main when checking out
local-dev. Cross-repo migrations (consumer PRs that depend on a not-yet-
merged local-dev change) had no way to test against the matching local-dev
branch and would fail CI against stale main. The new local_dev_ref input
defaults to "main" so existing callers keep their behaviour; consumer PRs
override it to their matching local-dev branch.
Reverts de99c41. The local_dev_ref input + dynamic ref change was an
unauthorized infra edit — those workflow files are not in this PR's scope.
@AquiGorka AquiGorka merged commit b134ed0 into main Jun 1, 2026
6 of 7 checks passed
@AquiGorka AquiGorka deleted the feat/pp-url-scoping branch June 1, 2026 23:09
AquiGorka added a commit that referenced this pull request Jun 2, 2026
…KYC route (#108)

## Summary

* Tighten the playwright full-flow suite so it actually fails when the
payment doesn't settle. The previous assertions accepted UI scaffolding
visibility regardless of whether anything landed protocol-side — the
suite passed against backends silently returning errors.
* Exercise the new public KYC route
(`#/entities/register?provider=<ppPubkey>`) introduced by
Moonlight-Protocol/provider-console#37: connect Freighter → sign
SEP-43/raw challenge → submit name → success card.
* Fix three pre-existing test bugs the loose assertions had hidden:
silent psql-based cleanup, stale `council_pps` accumulation, and a
wrong-pubkey fill in Step 8.

## Bugs the loose assertions hid

| # | Bug | Surfaced now via |
|---|-----|------------------|
| 1 | Step 12 asserted only `#pos-status` visible + non-empty.
moonlight-pay writes BOTH success and failure text into that element. |
Step 12 now reads the text and fails on
`failed|reject|error|expired|insufficient`. |
| 2 | Step 13 asserted "balance display OR tx list visible" — both
render on a freshly-loaded page regardless of any payment. | Step 13 now
queries `pay-platform.transactions` for a COMPLETED IN row with
`wallet_public_key = merchant.publicKey` and asserts
`sum(amount_stroops) > 0`. |
| 3 | `beforeAll` used `execSync("psql …")` to truncate stale rows —
psql isn't in the test-runner container, the call no-op'd ("DB cleanup
skipped"). | Replaced with `helpers/db.ts:cleanupPayPlatformDb()` using
node-pg, now truncating `councils`, `pay_accounts`, AND `council_pps`
CASCADE. Adds `pg` + `@types/pg` to `playwright/package.json`. |
| 4 | Step 8 filled `#pp-pk` with `profiles.provider.publicKey` (the
operator wallet pubkey), but provider-console registers a *derived* PP
keypair — pay-platform stored the wrong key and `instant-execute` 500'd
with "PP not found or inactive". | New Step 6b discovers the actual PP
pubkey via `helpers/db.ts:fetchActivePpPublicKey()`; Step 8 now fills it
with `ppPublicKey`. |
| 5 | `provider-platform`'s add-bundle gate requires the submitter's
entity row to be APPROVED. `pay-service` (the bundle submitter for
POS-instant) is auto-created as UNVERIFIED via SEP-10 first-time auth
and never promoted — bundle would 403. | Step 6b registers pay-service
as APPROVED via `helpers/register-entity.ts` (SEP-43/raw
signed-challenge POST to `/providers/:pp/entities`). |

## New surface

* `helpers/db.ts` — node-pg helpers: cleanup, PP discovery,
completed-inbound-stroops query.
* `helpers/register-entity.ts` — the SEP-43/raw signed-challenge flow
against `POST /providers/:pp/entities`.
* New steps:
- **Step 6b** (after council approval, before admin onboarding) —
discover PP pubkey + register pay-service as APPROVED.
- **Step 13b** (after merchant verification) — exercise the new public
KYC route end-to-end with the POS user's Freighter wallet.

## Test plan

- [x] `./test.sh playwright` — **16/16 steps pass** (was 14/14 passing
against a broken backend; now 16/16 passing against a working one).
Tested locally against the four PRs merged to main:
  - Moonlight-Protocol/provider-platform#107
  - Moonlight-Protocol/provider-console#37
  - Moonlight-Protocol/pay-platform#36
  - #107
- [x] Empirical confirmation of the original false-green: ran playwright
+ parallel `docker logs provider` capture; bundle submission 500'd with
`resolveChannelContext: PP GBOTA2… not found or inactive`,
`operations_bundles` table was empty, yet all 14 original steps passed.

## Companion / follow-up

None — this is a test-only PR on `local-dev`. No changes to platform
behaviour.
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