Full-stack Starknet governance application with backend services and frontend UI.
This repository contains the complete governance stack:
- db: PostgreSQL database for governance data (proposals, votes, delegates)
- indexer: Apibara-based indexer for OpenZeppelin Governor events
- api: Express REST API serving governance data
- ui: React + Vite frontend for interacting with the governance system
This monorepo structure provides:
- Cohesion: All governance components in one place for easier development
- Version Control: Frontend and backend changes can be coordinated in single commits
- Local Development: Full stack runs together with docker-compose
- Independent Deployment: Services can still be deployed separately to different platforms
- Docker and Docker Compose installed
- Apibara DNA token (get from https://app.apibara.com/)
- Your Starknet contract addresses
-
Create environment file:
cp .env.example .env
-
Edit
.envwith your values:DNA_TOKEN=dna_your_actual_token_here GOVERNOR_ADDRESS=0x... VOTES_TOKEN_ADDRESS=0x...
-
Start backend services with docker-compose:
docker-compose up -d
-
Start the UI (in a separate terminal):
cd ui npm install npm run dev -
View logs:
docker-compose logs -f
-
Services will be running at:
- UI: http://localhost:5173 (Vite dev server)
- API: http://localhost:4000
- Database: localhost:5432
# Stop all services
docker-compose down
# Fresh start (removes all data)
docker-compose down -v
# Rebuild after code changes
docker-compose up -d --build
# View specific service logs
docker-compose logs -f indexer
docker-compose logs -f apiThis repository contains both backend and frontend, deployed to different platforms:
Deploy these 3 backend services:
- PostgreSQL database (managed database service)
- indexer (from
./indexerdirectory) - api (from
./apidirectory)
For detailed deployment instructions, see DEPLOYMENT.md.
Deploy the UI from the ./ui directory:
- Platform: Vercel, Netlify, or any static host
- Build command:
npm run build - Output directory:
dist - Environment variable:
VITE_API_URL=https://your-api-domain.railway.app
Update the API's CORS_ORIGIN environment variable to allow your UI domain:
CORS_ORIGIN=https://your-ui-domain.vercel.app
The governance API provides the following endpoints:
GET /api/governance/proposals- List all proposalsGET /api/governance/proposals/:id- Get proposal detailsGET /api/governance/proposals/:id/votes- Get votes for a proposalGET /api/governance/proposals/:id/calls- Get proposal actionsGET /api/governance/proposals/:id/queued- Get queued status and ETA for a proposalGET /api/governance/proposals/:id/executed- Get execution status for a proposalGET /api/governance/proposals/:id/canceled- Get cancellation status for a proposalGET /api/governance/delegates- List all delegatesGET /api/governance/delegates/:address- Get delegate infoGET /api/governance/delegations/:address- Get delegation infoGET /api/governance/stats/total-votes- Get total voting powerGET /api/governance/votes/address/:address- Get votes by voter address
See api/README.md for detailed API documentation.
See .env.example for a complete list of environment variables. Key variables include:
DNA_TOKEN: Apibara authentication tokenAPIBARA_URL: Apibara DNA stream URL (default: mainnet.starknet.a5a.ch)
GOVERNOR_ADDRESS: Governor contract addressVOTES_TOKEN_ADDRESS: ERC20Votes token address
STARTING_CURSOR_BLOCK_NUMBER: Block to start indexing from (0 = genesis)NO_BLOCKS_TIMEOUT_MS: Timeout for block streaming (0 = disabled)LOG_LEVEL: Log level (debug/info/warn/error)
PORT: API server port (default: 4000)CORS_ORIGIN: Allowed CORS origin- Cache TTLs for different data types
VITE_API_URL: API server URL (default: http://localhost:4000)
governance/
├── indexer/ # Governance events indexer
│ ├── src/
│ ├── Dockerfile
│ └── package.json
├── api/ # Custom Express REST API (governance only)
│ ├── src/
│ │ ├── routes/
│ │ │ └── governance.ts # Governance endpoints
│ │ ├── db/
│ │ │ └── governance.ts # Governance DB pool
│ │ └── index.ts
│ ├── Dockerfile
│ └── package.json
├── ui/ # React + Vite frontend
│ ├── src/
│ ├── public/
│ ├── vite.config.ts
│ └── package.json
├── docker-compose.yml # Local development setup (backend services)
├── .env.example # Environment variables template
├── DEPLOYMENT.md # Comprehensive deployment guide
└── README.md
Note: swaps-indexer, swaps-api, and swaps-db are maintained in a separate repository.
# Health check
curl http://localhost:4000/health
# Get all proposals
curl http://localhost:4000/api/governance/proposals | jq
# Get specific proposal
curl http://localhost:4000/api/governance/proposals/1 | jq
# Get votes for a proposal
curl http://localhost:4000/api/governance/proposals/1/votes | jq
# Get all delegates
curl http://localhost:4000/api/governance/delegates | jq
# Get total voting power
curl http://localhost:4000/api/governance/stats/total-votes | jqEach service can be developed and tested independently:
API:
cd api
npm install
npm run dev # Runs on port 4000Indexer:
cd indexer
npm install
npm run devUI:
cd ui
npm install
npm run dev # Runs on port 5173Connect to local governance database:
# Governance database
psql postgresql://postgres:postgres@localhost:5432/mainnetSymptoms: No data appearing in database, indexer logs show errors
Solutions:
- Check
DNA_TOKENis valid and not expired - Verify contract addresses are correct
- Ensure
STARTING_CURSOR_BLOCK_NUMBERis valid - Check Apibara service status
docker-compose logs indexerSymptoms: UI can't fetch data, API returns 500 errors
Solutions:
- Verify governance database is running and healthy
- Check
GOVERNANCE_DB_URLis correct - Ensure governance indexer has populated the governance database
docker-compose ps # Check service status
docker-compose logs apiSymptoms: Governance indexer taking a long time to catch up
Solutions:
- This is expected if starting from genesis
- Consider setting
STARTING_CURSOR_BLOCK_NUMBERto a more recent block (e.g., when your governor was deployed) - Check database disk space and performance
- Verify the indexer isn't being rate-limited by Apibara
If you need to completely reset and start over:
# Stop all services and remove volumes
docker-compose down -v
# Edit .env if needed
nano .env
# Start fresh
docker-compose up -dWhen contributing:
- Test locally with docker-compose
- Ensure all services start successfully
- Verify API endpoints return expected data
- Check UI displays data correctly
- Update documentation for any new features
[Your License Here]