This monorepo deploys two services independently:
- Indexer (
indexer-envio/) → Envio Hosted Service - Dashboard (
ui-dashboard/) → Vercel (monitoring-dashboardproject)
Each network has a dedicated deploy branch that Envio watches:
| Network | Deploy Branch | Config File | Envio Project |
|---|---|---|---|
| Celo Mainnet | deploy/celo-mainnet |
config.celo.mainnet.yaml |
mento-v3-celo-mainnet |
| Celo Sepolia | deploy/celo-sepolia |
config.celo.sepolia.yaml |
mento-v3-celo-sepolia |
| Monad Mainnet | deploy/monad-mainnet |
config.monad.mainnet.yaml |
mento-v3-monad-mainnet |
Mainnet uses the Envio production tier with a static endpoint — the hash does not change on redeployment:
https://indexer.hyperindex.xyz/60ff18c/v1/graphql
Celo Sepolia is on the Envio dev tier. The URL hash changes on every redeploy:
https://indexer.hyperindex.xyz/<hash>/v1/graphql
After a Celo Sepolia redeploy, update NEXT_PUBLIC_HASURA_URL_CELO_SEPOLIA_HOSTED in Vercel via terraform apply.
Redeploy the mainnet indexer:
# Push main to the deploy branch (triggers Envio redeploy)
pnpm deploy:indexer celo-mainnet
# equivalent: git push origin main:deploy/celo-mainnetRedeploy Celo Sepolia:
pnpm deploy:indexer celo-sepolia
# After Envio finishes syncing, update hasura_url_celo_sepolia_hosted in
# terraform/terraform.tfvars and run: pnpm infra:applyIf Envio gets stuck or you need to retrigger without a code change:
# Empty commit trick
git commit --allow-empty -m "chore: retrigger envio deploy"
git push origin main:deploy/celo-mainnet.github/workflows/notify-envio-deploy.yml fires automatically when you push to any deploy/* branch. It posts a reminder in Discord to update the Vercel endpoint after Envio finishes syncing.
- ✅ Wait for Envio to reach 100% sync (check envio.dev/app)
- ✅ If Celo Sepolia: get the new GraphQL endpoint URL from the Envio dashboard, update
hasura_url_celo_sepolia_hostedinterraform/terraform.tfvars, runpnpm infra:apply - ✅ Trigger a Vercel redeploy (or wait for next push to
main) - ✅ Verify monitoring.mento.org loads data
Vercel's native Git integration watches main — every push that changes files under ui-dashboard/ triggers an automatic production deploy. Pushes that only touch other directories (e.g. terraform/, indexer-envio/) are skipped by the ignore command.
The project is named monitoring-dashboard and lives at monitoring.mento.org.
All Vercel and storage infrastructure is managed by Terraform in terraform/. This covers:
- Vercel project creation and configuration (
root_directory,ignore_command, Git integration) - All environment variables (Hasura URLs, Upstash Redis credentials, Blob token)
- Custom domain (
monitoring.mento.org) - Upstash Redis database (address labels storage)
State is stored remotely in GCS at gs://mento-terraform-tfstate-6ed6/monitoring-monorepo/. No local backup is needed — GCS is the source of truth and has object versioning enabled.
pnpm infra:init # first time, or after provider changes
pnpm infra:plan # preview changes
pnpm infra:apply # apply changesAll env vars are managed by Terraform (set for production and preview targets). Do not edit them manually in the Vercel dashboard.
| Variable | Source | Description |
|---|---|---|
NEXT_PUBLIC_HASURA_URL_CELO_MAINNET_HOSTED |
terraform.tfvars |
Hasura endpoint — Celo Mainnet (hosted) |
NEXT_PUBLIC_HASURA_URL_CELO_SEPOLIA_HOSTED |
terraform.tfvars |
Hasura endpoint — Celo Sepolia (hosted) |
NEXT_PUBLIC_HASURA_URL_MONAD_MAINNET_HOSTED |
terraform.tfvars |
Hasura endpoint — Monad Mainnet (hosted) |
NEXT_PUBLIC_HASURA_URL_MONAD_TESTNET_HOSTED |
terraform.tfvars |
Hasura endpoint — Monad Testnet (hosted) |
UPSTASH_REDIS_REST_URL |
Terraform output | Address labels Redis — auto-set from DB |
UPSTASH_REDIS_REST_TOKEN |
Terraform output | Address labels Redis token — auto-set |
BLOB_READ_WRITE_TOKEN |
terraform.tfvars |
Vercel Blob token for backup cron |
The dashboard includes a private address book at /address-book for labeling wallet addresses with company or entity names. Labels are stored in Upstash Redis and displayed inline throughout the UI.
A daily cron job at 03:00 UTC (defined in ui-dashboard/vercel.json) snapshots all labels to Vercel Blob storage as a backup. The Blob store (address-labels) is a team-level resource — it survives project recreation.
Run this once when setting up from scratch or recreating the Vercel project.
- Terraform ≥ 1.5
- Google Cloud SDK — authenticated with ADC (
gcloud auth application-default login). Your account needsstorage.objects.get,storage.objects.create, andstorage.objects.liston themento-terraform-tfstate-6ed6GCS bucket (role:roles/storage.objectUseron the bucket, or broader project-levelroles/storage.admin) - Vercel CLI (for blob store creation)
- Vercel API token (create at vercel.com/account/tokens)
- Upstash account + API key (console.upstash.com → Account → API Keys)
1. Provision the Blob store (one-time — not manageable via Terraform)
vercel blob create-store address-labels --scope mentolabsCopy the BLOB_READ_WRITE_TOKEN from the output (or retrieve it later from the Vercel dashboard → Storage).
2. Delete the existing Vercel project (if recreating)
vercel project rm monitoring-dashboard --scope mentolabs3. Fill in credentials
cp terraform/terraform.tfvars.example terraform/terraform.tfvars
# edit terraform/terraform.tfvars4. Init (+ one-time state migration if you have an existing local terraform.tfstate)
pnpm infra:initIf a local terraform/terraform.tfstate was present from before the GCS backend was introduced, terraform init will detect it and prompt to migrate. Enter yes to copy it to GCS. This is a one-time step — afterwards GCS is authoritative and the local file can be deleted.
5. Apply
pnpm infra:applyTerraform creates: Upstash Redis database + Vercel project + all env vars + custom domain + .vercel/project.json.
6. Trigger first deploy
Push any commit touching ui-dashboard/, or force via:
vercel deploy --prod --forcemain
├── 🚀 auto-deploys to Vercel (dashboard, when ui-dashboard/ changes)
└── feature branches → PR → main
deploy/celo-mainnet
├── 🚀 auto-deploys to Envio (indexer, mainnet)
└── updated via: pnpm deploy:indexer celo-mainnet
deploy/celo-sepolia
├── 🚀 auto-deploys to Envio (indexer, Celo Sepolia)
└── updated via: pnpm deploy:indexer celo-sepolia
Why deploy branches? Dashboard changes are frequent → auto-deploy on main push. Indexer changes are rare → manual push to deploy branch avoids unnecessary Envio redeployments (which change the endpoint hash, requiring a Terraform env var update).
Env vars were renamed for multi-chain clarity. If you have an existing terraform/terraform.tfvars, update it:
# Old (remove)
# hasura_url_mainnet_hosted = "..."
# hasura_url_sepolia_hosted = "..."
# New
hasura_url_celo_mainnet_hosted = "https://indexer.hyperindex.xyz/60ff18c/v1/graphql"
hasura_url_celo_sepolia_hosted = "https://indexer.hyperindex.xyz/fc3170d/v1/graphql"Then run pnpm infra:apply. Terraform will replace the old Vercel env vars with the new ones. Brief downtime during apply is expected.
The ignore_command (git diff HEAD^ HEAD --quiet -- ui-dashboard) cancelled the build because no ui-dashboard/ files changed. This is correct behaviour for infra-only commits. To force a deploy:
vercel deploy --prod --forceCheck build logs in the Envio dashboard → Build Logs tab. Common issues:
pnpm installfails → verifypnpm-lock.yamlis committed- Config file not found → verify
config.celo.mainnet.yamlexists inindexer-envio/ - TypeScript errors → run
pnpm indexer:celo-mainnet:codegenlocally first
The Celo Sepolia endpoint hash changed. Update hasura_url_celo_sepolia_hosted in terraform/terraform.tfvars and run pnpm infra:apply. Vercel will pick up the new env var on the next deploy.
Check Envio dashboard → Metrics tab.
- Stuck at 0% → check RPC URL in config
- RPC rate-limited → contact Envio for HyperSync support
- Start block wrong → must be ≤ first contract deployment block (
60664513for mainnet)
Delete the indexer in Envio dashboard → re-add it. This resets all state and starts from the configured start block.
State is in GCS (gs://mento-terraform-tfstate-6ed6/monitoring-monorepo/) with object versioning. To recover a previous state version, download an older object version from the GCS bucket and run terraform state push <file>.
If state is unrecoverable, import existing resources back with terraform import. Key resource addresses:
terraform import vercel_project.dashboard <project-id>
terraform import upstash_redis_database.address_labels <database-id>
terraform import vercel_project_domain.monitoring monitoring.mento.org