Setting up
Everything needed to run any part of this repository on your own machine, and to get a change merged.
On this page
Tools
package.json allows ≥ 20.19, but the member build fails under 20.11package-lock.jsonbun testInstall
The root package.json is two things at once: the Hardhat toolchain for contracts/, and an npm
workspace over apps/member, apps/merchant, apps/rewards, apps/pay, apps/command and
packages/*. One install covers both.
npm installapps/api is not part of the workspace. It installs on its own, with Bun, and links the
packages it needs with file::
cd apps/api && bun installIt carries a package-lock.json from before it moved to Bun; bun.lock is the one that counts.
Environment
Each surface reads its own file. None is committed; copy the example beside it.
.env.example → .envDEPLOYER_PRIVATE_KEY, ALCHEMY_API_KEY; ETHERSCAN_API_KEY to verifyapps/api/env.example → apps/api/.envDATABASE_URL, REDIS_URL, then the providers you are working onapps/member/.env.local.example → apps/member/.env.localVITE_PRIVY_APP_ID (required), VITE_API_BASE_URLapps/merchant/.env.example → .envVITE_PRIVY_APP_ID, VITE_API_BASE_URLapps/pay/.env.example → .envVITE_API_BASE_URLapps/command/.env.example → .envVITE_PRIVY_APP_ID, VITE_API_BASE_URLVITE_API_BASE_URL if the API is not on localhost:3001The member app's .env.example files are incomplete. The env table in
apps/member/README.md is the reference.
Anything prefixed VITE_ ends up in the browser bundle. Never give a secret that prefix. The
member build scans its bundle for secrets and fails if it finds one (npm run scan:secrets).
The API boots without Postgres or Redis, with a warning, but routes backed by the member store
return 503 until DATABASE_URL is set. For Redis locally:
docker compose -f apps/api/docker-compose.yml up -d redisRunning
npm run dev --workspace @clear/membernpm run dev --workspace @clear/merchantnpm run dev --workspace @clear/rewardsnpm run dev --workspace @clear/paynpm run dev --workspace @clear/commandcd apps/api && bun run devThe apps call the API at VITE_API_BASE_URL, http://localhost:3001 by default.
Signing in needs Privy, a backend and real accounts. To look at screens without any of that, the
member, merchant, rewards, pay and command apps each serve a preview harness at ?preview=1 — for
example http://localhost:5173/?preview=1 — drawn with fixed sample data. See each app's README.
The installed merchant app
The merchant app's web build, wrapped with Capacitor for iOS and Android
(apps/merchant/capacitor.config.ts): appId
org.useclear.merchant, name "Clear for Merchants", native projects in apps/merchant/ios and
apps/merchant/android. It adds the Stripe Reader M2 over Bluetooth and Tap to Pay; in a browser
the app drives smart readers only.
npm run cap:ios # in apps/merchant: build, sync, open in Xcode
npm run cap:android # build, sync, open in Android Studio- Set
VITE_API_BASE_URLto the API's full URL at build time. The installed app loads its pages from the bundle and has no/apiof its own. - The API must allow the app's origins:
capacitor://localhost(iOS) andhttps://localhost(Android) (Going live → Cross-origin). - Tap to Pay on iOS needs Apple's Tap to Pay entitlement. The iOS project has no entitlements file for it.
- Nothing sets up an App Store or Google Play release.
Contracts
npm run compile
npm run test # every Hardhat suite
npm run test:core # test/core only
npm run test:coverage
npm run test:gasDeploying is in Operators.
Before you push
npx turbo run typecheck test --affected--affected compares with dev. It can pass from turbo's cache when a clean run would fail, so for
an app you changed, check it directly too:
apps/membernpm run build in apps/member — tsc -b, then the Vite build and the secrets scan. tsc --noEmit -p . misses errors tsc -b catchesapps/merchantnpm run typecheck in apps/merchantapps/apibun test src in apps/api, and the member tests: some of them read API source as text and assert on itcontracts/npm run testCI does not run the API's own suite. apps/api is outside the workspace, so turbo cannot see it;
CI only reruns the member tests when it changes. Run bun test src yourself.
End-to-end suites are Playwright, run by hand: npm run test:e2e in apps/merchant, and the specs
in apps/command/e2e.
Getting a change merged
- Branches.
mainis production;devis where work lands, and whatdemo.useclear.org,merchant.useclear.organdcommand.useclear.orgfollow. Work on a short-lived branch, open a pull request intodev, and delete the branch once it is merged. - The
cicheck is what blocks a merge. It runs the affected apps' typecheck and tests, the Hardhat suite when contracts change, and a check that every relative link in the docs resolves (node scripts/check-doc-links.mjs). Lint runs but does not block yet. - Vercel previews are built only for a branch with a pull request, and only for the apps it touches. Push at the end of a piece of work rather than after every commit, and put
[skip preview]in the message of a push that only touches docs (Going live → Builds and deploys). - Docs move with the code. If you change an interface or a workflow, change its page in the same pull request.