refactor: support for mockgatehub in local environment - #2188
Conversation
There was a problem hiding this comment.
Pull request overview
Refactors local development to support MockGatehub + a new local/ Docker stack, and adjusts wallet frontend/backend configuration to work correctly when running inside containers (middleware/SSR using internal hostnames).
Changes:
- Add a new
local/docker-compose stack (Postgres/Redis/Rafiki/Mockgatehub) plus helper scripts and env examples. - Update wallet frontend middleware + HTTP client to call the backend via an internal Docker hostname on the server.
- Add backend support for overriding GateHub base URLs via
GATEHUB_API_BASE_URL, and add a couple of GateHub service race-condition guards.
Reviewed changes
Copilot reviewed 24 out of 26 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-workspace.yaml | Adds e2e workspace entry. |
| pnpm-lock.yaml | Adds lock entries for the new e2e importer + Playwright deps. |
| packages/wallet/frontend/src/utils/helpers.ts | Changes amount formatting truncation logic. |
| packages/wallet/frontend/src/middleware.ts | Replaces userService call with direct fetch to internal backend URL. |
| packages/wallet/frontend/src/lib/httpClient.ts | Switches server-side base URL to internal backend hostname. |
| packages/wallet/frontend/next.config.js | Introduces BACKEND_INTERNAL_URL env mapping + env override for features flag. |
| packages/wallet/frontend/Dockerfile.dev | Adds build args/ENV for Next public env vars. |
| packages/wallet/backend/src/middleware/withSession.ts | Adjusts cookie domain logic (avoid Domain=localhost). |
| packages/wallet/backend/src/gatehub/service.ts | Adds early-return checks to reduce concurrent customer/account creation. |
| packages/wallet/backend/src/gatehub/client.ts | Uses GATEHUB_API_BASE_URL when provided (e.g., Mockgatehub). |
| packages/wallet/backend/src/config/env.ts | Adds GATEHUB_API_BASE_URL env var. |
| local/scripts/rafiki-setup.js | New script to configure Rafiki tenant/assets/liquidity. |
| local/init/dbinit.sql | New local DB init for multiple service DBs/users. |
| local/docker-compose.yml | New local compose stack including Mockgatehub. |
| local/.gitignore | Ignores local pg data artifacts. |
| local/.env.example | New example env for the local compose stack. |
| docker/temp/private-key.pem | Removes committed key material. |
| docker/prod/kratos.yml | Removed legacy prod docker config. |
| docker/prod/docker-compose.yml | Removed legacy prod docker config. |
| docker/prod/.env.example | Removed legacy prod env example. |
| docker/identity.schema.json | Removed legacy Kratos identity schema. |
| docker/entrypoint.sh | Removed legacy Kratos entrypoint. |
| docker/dev/kratos.yml | Removed legacy dev docker config. |
| docker/dev/docker-compose.yml | Removed legacy dev docker config. |
| docker/dev/.env.example | Removed legacy dev env example. |
| .github/copilot-instructions.md | Adds repo instructions (currently still referencing removed docker/dev/*). |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const scaledValue = Number(`${value}e-${assetScale}`) | ||
| const flooredValue = | ||
| Math.floor(Math.round(scaledValue * 10 ** displayScale)) / | ||
| Math.floor(Math.round(scaledValue * 10 ** (displayScale + 4)) / 10 ** 4) / |
There was a problem hiding this comment.
why + 4 is added here?
There was a problem hiding this comment.
I was messing around, forgot to take it out.
I was fighting with some floating point issues causing my tests to fail. I think we can live without it.
| } | ||
| if (cookieVal) { | ||
| try { | ||
| const meRes = await fetch(`${backendUrl}/me`, { |
There was a problem hiding this comment.
use existent service method for the request await userService.me( ${cookieName}=${req.cookies.get(cookieName)?.value} )
There was a problem hiding this comment.
will now use use userService.me() instead of raw fetch
There was a problem hiding this comment.
package.json scripts need to be updated based on the new docker compose file
There was a problem hiding this comment.
update compose path to ./local/docker-compose.yml, remove stale prod scripts
| const key = line.slice(0, idx).trim() | ||
| const value = line.slice(idx + 1).trim() | ||
| result[key] = value | ||
| } |
There was a problem hiding this comment.
new line before return and after block
There was a problem hiding this comment.
add braces to one-line if statements, added blank line before return
| // ---- helpers --------------------------------------------------------------- | ||
| function loadDotEnv(envPath) { | ||
| const result = {} | ||
| if (!fs.existsSync(envPath)) return result |
There was a problem hiding this comment.
use blocks for one line if statements as well.
| const scaledValue = Number(`${value}e-${assetScale}`) | ||
| const flooredValue = | ||
| Math.floor(Math.round(scaledValue * 10 ** displayScale)) / | ||
| Math.floor(Math.round(scaledValue * 10 ** displayScale) / 10 ** 4) / |
There was a problem hiding this comment.
is this change needed?
There was a problem hiding this comment.
Good point. Thank you.
formatAmount is now the same as that of main.
| "lint:fix": "eslint --max-warnings=0 --fix .", | ||
| "compose": "docker compose -f ./docker/dev/docker-compose.yml", | ||
| "compose:prod": "docker compose -f ./docker/prod/docker-compose.yml", | ||
| "compose": "docker compose -f ./local/docker-compose.yml", |
There was a problem hiding this comment.
as FE were added to dev compose files, the dev commands need no be updated
There was a problem hiding this comment.
After a long back and forth with myself on this topic I decided to make the FE run on the host and not in docker. The reason is because when running FE in docker on a Mac then the watch mechanism does always work as expected. So in the end I reverted back to have the applications run on the host for the local environment.
There was a problem hiding this comment.
seems to not be in sync with current branch
| RATE_LIMIT_LEVEL=LAX | ||
| GATEHUB_ACCOUNT_PRODUCT_CODE=DEFAULT | ||
| GATEHUB_CARD_PRODUCT_CODE=DEFAULT | ||
| GATEHUB_NAME_ON_CARD=TEST USER |
There was a problem hiding this comment.
GATEHUB_NAME_ON_CARD: [ 'Only alphanumeric characters are allowed' ], change to TESTUSER maybe
| REDIS_URL: ${REDIS_URL:-redis://redis:6379/0} | ||
| GATEHUB_API_BASE_URL: ${GATEHUB_API_BASE_URL:-http://mockgatehub:8080} | ||
| GATEHUB_ENV: ${GATEHUB_ENV:-sandbox} | ||
| GATEHUB_IFRAME_BASE_URL: ${GATEHUB_IFRAME_BASE_URL:-http://localhost:8080} |
There was a problem hiding this comment.
the env var is defined but it is not used in the app, resulting in incorrect iframe link on FE http://mockgatehub:8080/?bearer=iframe-token-4dfcdb88-fe38-4906-9b34-fb3a832a3e30
| - ./init/dbinit.sql:/docker-entrypoint-initdb.d/init.sql | ||
|
|
||
| # MockGatehub - Mock Gatehub API service for local development | ||
| mockgatehub: |
There was a problem hiding this comment.
on manual deposits the webhook has "deposit_type":"external" , it should have a different value - this is causing double entries in trx list now
There was a problem hiding this comment.
another issue: on trx, the account balance show double of the amount in the trx - but the gain should actually be 0 as the trx is between 2 WA in the same account
There was a problem hiding this comment.
looks like the balance is increased even when it should be decreased in a trx
There was a problem hiding this comment.
So it turns out that Mockgatehub was doing an additional pending webhook which caused the double transaction issue. I checked and this is out of spec and I'm not sure why that ended up in mockgatehub.
I removed it from mockgatehub in 1.12.4 and should be resolved.
sequenceDiagram
actor User
participant FE as Wallet Frontend
participant WBE as Wallet Backend
participant MGH as MockGatehub
User->>FE: Clicks Deposit on account page
FE->>User: Opens DepositDialog popup
User->>FE: Fills amount, clicks Submit
FE->>WBE: POST /accounts/:accountId/fund<br/>{amount: 11}
WBE->>MGH: POST /core/v1/transactions<br/>{type:1(DEPOSIT), network:8(MANUAL),<br/>receiving_address, vault_uuid, amount}
MGH->>MGH: Creates transaction (status: PENDING)
MGH-->>WBE: Webhook: core.deposit.completed<br/>{deposit_type:"external", status:"pending", tx_uuid}
MGH->>WBE: 201 Created {transaction}
WBE->>WBE: handleDepositWebhook()<br/>→ INSERT Transaction row #1 into DB
WBE->>FE: 200 OK "Account funded"
FE->>User: Shows "Deposit success" toast
Note over MGH: 2 second delay
MGH-->>WBE: Webhook: core.deposit.completed<br/>{deposit_type:"external", status:"completed", tx_uuid}
MGH->>MGH: Updates balance in MockGatehub store
WBE->>WBE: handleDepositWebhook()<br/>→ INSERT Transaction row #2 into DB ⚠️ BUG
User->>FE: Navigates to Transactions page
FE->>User: Shows 2 transaction rows for the same deposit
I do worry that this points to other problems inside TestNet which might need some attention. I will create separate tasks for the following hardening issues which we can discuss separately
- only process webhooks where
data.status === 'completed' - Before inserting, check whether a
Transactionrow withpaymentId === data.tx_uuidalready exists and skip if so
|
Looks like for Safari the page does not go to KYC, it gets stuck in Login (with chrome it gets to the KYC with problem) Screen.Recording.2026-04-01.at.10.30.12.mov |
3fb3d02 to
a96d903
Compare
* feat: Automatically approve blocked deposits * fix: Automatically approve blocked deposits * fix: enforce subject and access ownership checks for grants (#2199) * fix(wallet): enforce subject and access ownership checks for grants * fix(wallet): PR review improvement * refactor: support for mockgatehub in local environment (#2188) * refactor: support for mockgatehub in local environment * fix: fixed linting issues * fix: clean up * fix: repaired broken test related to emailService * fix: removed the +4 precision guard we don't need * fix: address PR review feedback and fix Docker build * fix: removed changes to formatAmount * refactor(local): breaking up into multiple service files * ci: changed configuration scheme to fail fast if misconfigured * ci: makefile target for rafiki assets * ci: default rafiki seeder will only seed two currencies for now * fix: resolved dependency issues and aligned with workspace * refactor: ci now part of local * ci: removal of makefiles * docs: updated readme * lint: fixed all linting problems * fix: cleanup of debug * test: wallet unittest configuration fixes * style: prettier automatic fixes to resolve linting * fix: better secure domain handling * wip: experimenting * refactor: wallet and boutique now run on host * fix: examples are now useful * ci: added npm run to make testing easy * style: linting issues in rafiki setup file * docs: cleanup instructions * style: fixed linting issues introduced when I added th elogging * fix: added validation rules to boutique config * style: fixed linting * style: prettier * fix: removed hardcoded interledger.cards * fix: update dev start * fix: flaky tests resolution * fix: backends will not fail silently * fix: correcting secrets * fix: resolved issue where hosted balances were incorrectly calculated * ci: will now pull before up * fix: we will not ask for sudo if we don't need it anymore * style: prettier lint fix * test: resolved test issue where faker was creating short strings * docs: github copilot instructions update * docs: tweaks to readme * style: prettier fix * fix: removed dangling e2e workspace * fix: minor edit to prevent 'cannot update RefundProvider' bug * fix: solve rafiki connection issues * fix: rafiki assets creation script should fail fast on error * docs: cleaned up documentation and examples * fix: upgraded local environment to use Traefik v3.6 * style: prettier linting * style: did pnpm format * fix(local): traefik will now auth.interledger.test/graphql --------- Co-authored-by: dragosp1011 <dragosh1011@gmail.com> Co-authored-by: Andrei Mihai <andreimihai@Andreis-MacBook-Pro.local> * feat: check if sendingwallet exists * feat: update payload * fix: Format type * fix: update Date Format * fix: Format * fix: add parallel proccessing when approving Transactions * fix: Format --------- Co-authored-by: Andrei Mihai <andrei@interledger.foundation> Co-authored-by: Adrian Boros <adiboros@hotmail.com> Co-authored-by: Stephan Butler <stephan.butler@deepsouthdevels.net> Co-authored-by: dragosp1011 <dragosh1011@gmail.com> Co-authored-by: Andrei Mihai <andreimihai@Andreis-MacBook-Pro.local>
|
🎉 This PR is included in version 1.1.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 1.1.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |

Introduces various changes to the packages to allow for a local environment where we can easily change between pointing to the real Gatehub Sandbox environment, or to a locally hosted mock instance of MockGatehub.
This is part of the greater effort of implementing real Continuous Integration for this project to allow for long term maintenance.