Operations guide
Running the system locally, configuring it, deploying it, and keeping it healthy.
For a complete deployment walkthrough, follow the deployment runbook.
Local development
You need Node.js 20 with Corepack, and an Ethereum mainnet JSON-RPC endpoint. Local runs keep events and the checkpoint on disk under data/local-storage, so no cloud account is needed.
Copy the example environment file, paste your RPC URL into GOOGLE_BLOCKCHAIN_RPC_URL, then run the indexer and the API from the repository root:
cp .env.example .env corepack enable pnpm install --frozen-lockfile pnpm indexer:once # one cycle, or: pnpm indexer pnpm api
In another terminal, start the website. Its example configuration points the browser at the local API on port 3001:
cp frontend/.env.example frontend/.env.local pnpm --dir frontend install --frozen-lockfile pnpm --dir frontend dev
Never commit .env, frontend/.env.local, credentials, Terraform variables or local state. The ignore rules cover them.
Configuration
The services read their settings from environment variables. These shape what the monitor shows:
| Variable | Default | Effect |
|---|---|---|
MIN_AMOUNT | 100000 | Indexing threshold in tokens |
CONFIRMATION_BUFFER | 6 | Blocks behind the tip before a block is read |
POLL_INTERVAL_MS | 30000 | Indexer poll interval |
BLOCK_BATCH_SIZE | 5 | Blocks per processed range |
RETENTION_DAYS | 7 | History the API serves |
API_REFRESH_MS | 30000 | How often the API reloads its index |
API_MAX_STALE_MS | 600000 | Index age after which query endpoints return 503 |
API_MAX_PAGE_SIZE | 50 | Largest allowed limit |
The website is configured at build time:
| Variable | Effect |
|---|---|
NEXT_PUBLIC_API_BASE_URL | Where the browser sends API requests. Empty in production, so requests go to the same origin. |
NEXT_PUBLIC_SERVICES_PAUSED | true or false. Builds the maintenance mode, in which no API request is made. When unset, the default in frontend/lib/config.ts applies. |
NEXT_PUBLIC_EXPECTED_RETURN | Return date shown during maintenance, as YYYY-MM-DD. |
NEXT_PUBLIC_HISTORY_STARTS | Optional YYYY-MM-DD. After a restart that moved the checkpoint forward, shows when history begins until the retention window has filled. |
The defaults used in the website's copy live in frontend/lib/config.ts. Update it when the deployment configuration changes, so the docs and the interface keep matching.
Checks
These are the same checks the verification and CI pipelines run:
pnpm test pnpm --dir frontend typecheck NEXT_PUBLIC_API_BASE_URL= pnpm --dir frontend build terraform fmt -check -recursive infra terraform -chdir=infra/environments/test init -backend=false -input=false terraform -chdir=infra/environments/test validate
Deployment
The supported Terraform root is infra/environments/test. The prod root is an empty scaffold and must be completed and reviewed as an independent environment before use. Before the first apply you need:
- a Google Cloud project with billing, and a bootstrapped remote state bucket;
- a domain whose DNS you control, for the managed certificate;
- the RPC URL stored as a Secret Manager version;
- a Cloud Build connection to the repository; and
- a bootstrap image digest for the first apply.
After Terraform has created the environment, releases flow through Cloud Build. Pull requests to main run the verify pipeline, which changes nothing. Each push to main runs CI, which tests, builds the image and the static site, and publishes a release manifest. Pushing a release tag runs CD, which waits for approval and deploys that exact image digest and site archive. Operators apply infrastructure changes separately through reviewed Terraform plans.
Verification and monitoring
After each deploy, CD runs the smoke test in infra/scripts/smoke-test.sh. It checks the site, caching headers, TLS, the API, checkpoint advancement and storage policy. You can check health by hand at any time:
curl -s "https://swm.josephdara.com/api/health"
Look for "status":"ok" and a small checkpointAgeSeconds. Cloud Monitoring alerts by email on failing uptime checks, 5xx responses, persistently degraded health, high p99 latency, a stopped indexer and a stalled indexer loop.
Maintenance
Pausing takes the indexer and API offline without destroying anything. Three switches control it:
| Switch | Where |
|---|---|
services_paused local | infra/environments/test/main.tf |
Frontend pause default, or NEXT_PUBLIC_SERVICES_PAUSED | frontend/lib/config.ts |
_SERVICES_PAUSED substitution | cloudbuild/cloudbuild-cd.yaml |
To pause, set all three to true, apply Terraform, then cut a release. Terraform scales the indexer to zero, stops routing /api and disables the API and indexer alert policies. To resume, set all three to false and apply Terraform first. The indexer continues from its checkpoint and catches up before the release is cut.
If the checkpoint is moved forward before resuming, set NEXT_PUBLIC_HISTORY_STARTS so the monitor explains why older history is missing.
Rollback
Run the CD trigger against an earlier release tag and approve the build. The release manifest pins both the image digest and the site archive checksum, so they roll back together. Release artifacts expire after 14 days, which limits how far back you can go. See the runbook for the exact command.
Found a problem in this page? Open an issue in the repository.