# 1. Clone and enter
git clone git@github.com:lnflash/flash.git && cd flash
# 2. Run the setup script (validates env, installs deps, configures credentials)
./dev/setup.sh
# 3. Start the server
make startThe setup script will check your prerequisites, prompt for Ibex sandbox credentials, install dependencies, and start Docker containers. After that, make start launches all four backend services.
GraphQL playground: http://localhost:4002/graphql
Admin API: http://localhost:4002/admin/graphql
Test login: phone +16505554328, code 000000
If you prefer to set things up yourself, or if the setup script fails:
| Tool | Required Version | Install |
|---|---|---|
| Node.js | 24.x (24.0.0+ required) | nvm: nvm install 24 |
| yarn | 1.x | corepack enable && corepack prepare yarn@1 --activate |
| Docker | 20+ with compose v2 | Docker Desktop |
| direnv | any (optional) | direnv.net |
Note: The project specifies
"node": ">=24.0.0 <25"inpackage.json. The repo's.yarnrcsetsignore-engines true, so transitive dependency engine checks are bypassed andyarn installsucceeds on Node 24. Node 24.x (LTS) is required.
Flash uses YAML config files. Ibex OAuth2 credentials go in local config overrides, not env vars.
The base config is at dev/config/base-config.yaml. Secrets and local overrides go in $CONFIG_PATH/dev-overrides.yaml (default: ~/.config/flash/dev-overrides.yaml).
Option A — Run the interactive script:
./dev/config/set-overrides.shOption B — Create manually:
# ~/.config/flash/dev-overrides.yaml
ibex:
clientId: your-sandbox-client-id
clientSecret: your-sandbox-client-secret
environment: sandboxAdditional overrides you might need:
ibex:
webhook:
uri: https://your-ngrok-domain.ngrok-free.app # for webhook testing
sendgrid:
apiKey: SG.your-sendgrid-key # for email notifications
cashout:
email:
to: your-email@example.com # for cashout notification testingFirebase is optional for most local backend development. If GOOGLE_APPLICATION_CREDENTIALS is not set, the server starts but push notification delivery is disabled and logs that Firebase messaging is not loaded.
To test real push notifications locally, you need a Firebase service account JSON for the same Firebase project used by your mobile app build:
export GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/firebase-service-account.json
make startDo not commit the Firebase service account JSON. Keep it outside the repo, for example under ~/.config/flash/.
The local dev config defines default FCM topic names in dev/config/base-config.yaml:
fcmTopics:
- name: "dev-EMERGENCY"
default: true
- name: "dev-ATTENTION"
default: true
- name: "dev-INFO"
default: false
- name: "dev-MARKETING"
default: falseIf you override these topics, use a unique local prefix so your local instance cannot accidentally target another environment's topics.
Real push delivery also requires the mobile app to register an FCM device token from the same Firebase project as the service account. A local backend can only send to device tokens stored for users in MongoDB.
To subscribe existing local device tokens to their configured FCM topics:
MONGODB_CON=mongodb://localhost:27017/galoy \
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/firebase-service-account.json \
node scripts/subscribe-device-tokens-to-topics.jsyarn installIf you hit engine compatibility errors, use
yarn install --ignore-engines.
make start-depsThis starts: MongoDB, Redis, Kratos (auth), Oathkeeper (API gateway), Apollo Router, price service, and OpenTelemetry collector.
If you need a clean slate:
make reset-depsNote: After restarting dependencies, reload environment variables with
direnv reload(or re-source your.envfiles).
make startThis runs four processes in parallel:
| Process | Port | Description |
|---|---|---|
start-main |
4012 (direct), 4002 (via oathkeeper) | Main GraphQL API |
start-trigger |
— | Event trigger processor |
start-ws |
4000 | WebSocket server for subscriptions |
start-ibex-wh |
4008 | Ibex webhook receiver |
Access the API through the oathkeeper proxy at http://localhost:4002/graphql (not the direct 4012 port, which requires a JWT).
For payment event testing, you need a public URL that forwards to your local webhook server (port 4008).
# Install ngrok: https://ngrok.com
ngrok http 4008Copy the forwarding URL and add it to your dev-overrides.yaml:
ibex:
webhook:
uri: https://your-domain.ngrok-free.appTip: Use a static ngrok domain so you don't have to update the config every restart.
Flash uses ERPNext for accounting. The dev config defaults to the Flash test environment at https://erp.test.flashapp.me.
To run Frappe locally:
make start-frappe # start local Frappe
make reset-frappe # clean + start + restore from backup
make stop-frappe # stop local FrappeUpdate your dev-overrides.yaml with local Frappe credentials if running locally.
The Frappe Admin Panel uses the Frappe site config key flash_admin_api_url to
call the Flash admin GraphQL API for pages such as alert-users.
- Local Docker Frappe: use
http://host.docker.internal:4001/graphqlso the Frappe container can reach the backend admin GraphQL server running on the host machine. Compose maps that hostname with Docker's symbolichost-gateway, and the value can be overridden locally withFRAPPE_FLASH_APIif a developer's Docker runtime needs a different host route. - Test / production Kubernetes: do not use
host.docker.internal. Setflash_admin_api_urlfrom the deployment config to the environment-specific Kubernetes-reachable admin GraphQL endpoint, such as an internal service DNS name or routed internal gateway URL. The endpoint should route to the admin GraphQL server's/graphqlpath unless that environment explicitly rewrites a different path.
If a local full Frappe backup includes site_config_backup.json, treat this key
as environment-specific and override it during deployment restore.
make test # full suite (unit + integration)
make unit # unit tests only (no Docker deps needed)
make integration # integration tests (needs Docker deps)
make reset-integration # reset state + run integration testsRun a specific test file:
TEST=utils make unit # runs utils.spec.ts
TEST=01-connection make integration # runs 01-connection.spec.tsKnown issues:
- Integration tests are not fully idempotent — use
make reset-integrationbetween runs - If tests timeout, increase:
JEST_TIMEOUT=120000 yarn test:integration - Use an SSD for Docker volumes (tests are disk-intensive)
Client → Oathkeeper (4002) → GraphQL Main (4012)
→ Admin API (4001)
WebSocket (4000)
Ibex Webhook (4008) ← Ibex payment events
Docker deps:
MongoDB (27017) — primary database
Redis (6378→6379) — caching, pub/sub
Kratos (4433/4434) — identity/auth
Price (50051) — gRPC price service
Apollo Router (4004) — federation
OTEL Collector (4318) — telemetry
| Command | Description |
|---|---|
make start |
Start all servers |
make start-main |
Start only the main GraphQL server |
make start-deps |
Start Docker dependencies |
make clean-deps |
Stop and remove Docker containers |
make reset-deps |
Clean + restart Docker deps |
make watch |
Start with file watching (auto-restart on changes) |
make check-code |
Run all linting/type checks |
yarn prettier -w . |
Format all files |
DEBUG=* make start |
Start in debug mode |
You're hitting the GraphQL server directly (port 4012). Use the oathkeeper proxy at http://localhost:4002/graphql instead, which handles auth for anonymous/public queries.
Flash requires Node 24.x. Switch with nvm use 24 or run yarn install --ignore-engines.
IBEX_URL, HONEYCOMB_DATASET, HONEYCOMB_API_KEY warnings in docker compose output are harmless in dev — these are only needed for the Docker-based server (not used by make start).
SendGrid isn't configured — email notifications won't work. Safe to ignore in dev unless you're testing email features. Add a real key to your dev-overrides.yaml if needed.
The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8)
The lnflash/price:edge image is amd64-only. On Apple Silicon Macs it runs under Rosetta emulation — this is harmless but slow. The warning is safe to ignore.
Check that all Docker deps are healthy: docker compose ps. If MongoDB or Redis failed to start, run make reset-deps.
See CONTRIBUTING.md.
make check-code # ESLint + TypeScript checks
yarn prettier -w . # auto-formatUse editor plugins for ESLint and Prettier for best experience.