Scope: Root project (applies to all subdirectories unless overridden by a nested AGENTS.md)
- Primary language: TypeScript (React 19 frontend, Node.js backend)
- Package manager: pnpm 9 — always use
pnpm, nevernpmoryarn - Monorepo tool: Turborepo (
turbo.jsonat root) - Linter / Formatter: Biome (
biome.jsonat root) — replaces ESLint + Prettier - Branching:
develop(staging/dev),main(production) - CI/CD: GitHub Actions → Docker images pushed to GCR (
gcr.io/bright-meridian-316511/...)
subsquid-network-app/
├── packages/
│ ├── client/ # React 19 SPA (Vite + MUI v7 + wagmi/RainbowKit)
│ ├── server/ # tRPC API server (Node.js, proxies Squid GraphQL + on-chain data)
│ └── common/ # Shared ABI definitions, contract addresses, constants
├── nginx/ # nginx template for static-file serving in Docker
├── .github/workflows/ # build-web.yaml, build-server.yaml
├── Dockerfile # Multi-stage: `server` target and `web` (nginx) target
├── biome.json # Root lint + format config (covers all packages)
├── turbo.json # Turborepo task graph
└── .env / .env.example # Runtime environment variables
| Directory | Purpose |
|---|---|
api/ |
tRPC client setup and typed query hooks |
components/ |
Reusable UI components (MUI v7-based) |
contexts/ |
React context providers (wallet, network, settings, etc.) |
hooks/ |
Custom hooks — includes network/useSubsquidNetwork (mainnet vs tethys) |
layouts/ |
Page layouts; NetworkLayout/ is the primary shell with sidebar nav |
pages/ |
Route-level page components (Workers, Gateways, Portals, Delegations, …) |
theme/ |
MUI theme customization — theme.tsx, theme.components.ts, palette files |
schema/ |
Yup validation schemas |
i18n/ |
Internationalisation strings |
icons/ |
Custom SVG icon components |
lib/ |
Utility helpers and third-party adapters |
logger/ |
Sentry + console logging setup |
| Directory / File | Purpose |
|---|---|
routers/ |
tRPC routers (account, worker, gateway, network, pool, price, etc.) |
services/ |
Data-fetching services: graphql.ts (Squid API), blockchain.ts |
main.ts |
Express server entry point |
router.ts |
Root tRPC router composition |
trpc.ts |
tRPC initialisation helpers |
generated/ |
Auto-generated GraphQL typed documents (do not edit) |
Shared constants, contract ABIs (abi/), and chain addresses (addresses.ts). Imported by both client and server.
- Node.js 22
- pnpm 9:
npm install -g pnpmor via Corepack:corepack enable && corepack prepare pnpm@latest --activate - Docker (for production image builds)
cp .env.example .env # fill in real values (see below)
pnpm install # installs all workspaces
pnpm dev # client (port 3005) + server (port 3001) in parallel| Variable | Purpose |
|---|---|
NETWORK |
mainnet or tethys — selects chain + API endpoints |
WALLET_CONNECT_PROJECT_ID |
WalletConnect v2 project ID |
TESTNET_SQUID_API_URL |
Squid GraphQL endpoint for testnet (tethys) |
MAINNET_SQUID_API_URL |
Squid GraphQL endpoint for mainnet |
TESTNET_POOL_SQUID_API_URL |
Pool Squid GraphQL endpoint for testnet |
MAINNET_POOL_SQUID_API_URL |
Pool Squid GraphQL endpoint for mainnet |
RPC_URL |
Arbitrum RPC endpoint |
SERVER_PORT |
Port for the tRPC server (default: 3001) |
SENTRY_DSN |
Sentry DSN (dev only — not set in prod) |
ENABLE_DEMO_FEATURES |
true on develop, false on main |
APP_VERSION |
Injected by CI (short git SHA) |
Run
pnpm codegenafter any changes to GraphQL queries or contract ABIs.
The root turbo.json defines five tasks:
| Task | dependsOn |
Notes |
|---|---|---|
dev |
["^build"] |
Starts persistent dev servers; builds common first; not cached |
build |
["^build"] |
Builds dependencies first; outputs cached under build/** and dist/** |
tsc |
["transit"] |
Type-check; runs in parallel across packages but cache-invalidates when deps change |
lint |
[] |
Biome check + fix; runs in parallel across all packages, no inter-package dependencies |
transit |
["^transit"] |
Virtual transit node — no script, creates cache-invalidation links between packages |
packages/client/turbo.json extends the root and adds the full list of build-time environment variables to the build task (so Turbo cache-busts on env changes).
Key rules for agents working with Turbo in this repo:
- Always use
turbo run <task>in scripts and CI — never the bareturbo <task>shorthand. - Do not chain Turbo tasks with
&&; usedependsOninturbo.jsoninstead. - The
transittask is a transit node pattern: it holds no script but propagates cache hashes from upstream packages, allowingtscto run in parallel while correctly invalidating when any dependency's source changes. - To run a single package:
npx turbo run build --filter=@subsquid/client - To run only what changed vs a branch:
npx turbo run build --affected
- No automated test suite is configured at this time. TypeScript compilation (
pnpm tsc) serves as the primary correctness gate. - Linting: Biome — run
pnpm lintbefore committing. CI does not run lint, so fix issues locally. - Type-check: CI runs
npx turbo run tsc --filter=@subsquid/client(web) andnpx turbo run tsc --filter=@subsquid/server(server) before building. - Generated files: Never edit
packages/server/src/generated/or any*.generated.*files by hand; always regenerate withpnpm codegen. - Import order: Biome enforces a specific import order (Node built-ins → react → third-party → internal aliases). The internal aliases
@components,@contexts,@hooks,@api,@network,@libare grouped last.
- Branches: Feature branches off
develop;develop→mainfor releases. - CI triggers: Pushing to
developormainautomatically builds and deploys Docker images to GCR for the affected package.build-web.yamlbuilds bothmainnetandtethysvariants as a matrix job.build-server.yamlbuilds a single server image.
- Network variants: The client is deployed twice per environment — once for
mainnet, once fortethys. Ensure UI changes work for both (the active network is driven byNETWORKenv var at build time). - Feature flags:
ENABLE_DEMO_FEATURES=trueis set ondevelopbuilds. Gate experimental UI behind this flag via the config context. - Secrets: WalletConnect project IDs differ per network variant (see CI workflow). Never hardcode project IDs.
- The client talks exclusively to the server via tRPC (not directly to the Squid GraphQL API or the blockchain). The server aggregates and transforms data from:
- Squid GraphQL APIs (indexed on-chain state)
- Direct Arbitrum RPC calls via
viem
- The common package exposes contract ABIs and addresses shared by both client and server.
- Wallet connectivity uses RainbowKit + wagmi v2 targeting Arbitrum One (mainnet) or Arbitrum Sepolia (tethys).
- UI is built with MUI v7.
- Update
README.mdwhen setup steps, scripts, or environment variables change materially. - Update
.env.examplewhenever new environment variables are added. - Run
pnpm codegenand commit the generated output whenever GraphQL queries or contract ABIs change.
- Run
pnpm lintand fix any Biome errors before committing - Run
pnpm tscto confirm no TypeScript errors - Run
pnpm codegenif GraphQL queries or contract ABIs were modified - Update
.env.exampleif new environment variables were introduced - Update
README.mdif setup instructions or scripts changed - Summarize changes in conventional commit format (e.g.,
feat: ...,fix: ...,chore: ...,refactor: ...)