This repository contains the Fundable Backend API and the Fundable Soroban
indexer scaffold. The API lives in src/; the indexer workspace lives in
indexer/. The repository uses Bun for package management and script
execution.
- TypeScript
- Bun
- Express
- PostgreSQL and TypeORM
- Node's built-in test runner with
c8coverage - Turborepo, Vitest, and Biome for the indexer workspace
Ensure you have the following installed on your system:
- Node.js 22.x
- Bun 1.3.8
- PostgreSQL 14+
- Docker and Docker Compose for local database workflows
# 1. Copy environment config
cp .env.example .env
# 2. Start database + run migrations in one command
make setup
# or without Make:
bun run setup
# 3. Start the dev server
bun run devmake db # start database
bun run dev # start API
make db-stop # stop database when done
make db-reset # wipe all data and start fresh# Run pending migrations
make migrate
# Revert last migration
make migrate-revert
# Generate a new migration
make migration-new name=AddWalletTable
# Run migrations without local Node (uses Docker)
make migrate-dockerCopy .env.example to .env and edit values for your local environment.
The same root .env.example contains Backend API settings, Cairo/StarkNet
settings, and Soroban indexer settings.
Ensure sensitive keys are not committed to version control.
-
Start the development server:
bun run dev (This will start the API server with hot reloading enabled.)
-
To build and run for production:
bun run build && bun run start
.
├── src/ # Express Backend API
├── indexer/ # Soroban indexer workspace
│ ├── common/ # Shared indexer infrastructure
│ ├── streams/ # Payment stream indexer domain
│ └── distributions/ # Distribution indexer domain
├── .github/ # PR and issue templates
├── docs/plans/ # Design and implementation plans
├── docker-compose.yml
├── package.json
└── bun.lock
API source layout:
src/
├── __tests__/ # Test files
├── appMiddlewares/ # Main app files
├── components/ # Folder containing version folder
├── v1/ # Version 1
├── features/ # Feature files
├── featureMiddleware/ # middlewares pertaining to feature
├── featureController/ # controllers pertaining to feature
├── featureRoutes/ # routes pertaining to feature
├── featureServices/ # Business logic and services pertaining to feature
├── featureValidation/ # Validation pertaining to feature
└── routes.v1.ts # V1 routes file
├── config/ # Configuration files
├── migrations/ # Database migration files
├── scripts/ # App Scripts files
├── services/ # App Services files
├── types/ # Configuration files
├── utils/ # Utility functions
├── .env.example # environment file to duplicate
└── index.ts # Application entry point
-
Update the database configuration in
.env. -
Run migrations to set up the database schema:
bun run run-migration
-
If you need to create a new migration:
bun run generate-migration <MigrationName>
-
Create a new entity in
src/components/v1/feature/feature.entities.ts:// src/components/v1/feature/feature.entities.ts import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; @Entity('feature') export class (FeatureName) { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() email: string; }
-
Generate and run the migration for the new entity:
bun run generate-migration <MigrationName> bun run run-migration
To run tests, use the following command:
bun run testTests are located in src/__tests__ and run with Node's test runner (node --test) + coverage (c8).
The Fundable Soroban indexer lives in indexer/. It is a Bun/Turborepo
workspace with:
indexer/common: shared indexer infrastructure.indexer/streams: payment stream indexer domain.indexer/distributions: token distribution indexer domain.
Useful commands from the repository root:
bun run indexer:type-check
bun run indexer:test
bun run indexer:lintRead indexer/README.md and indexer/INDEXER_GUIDELINES.md before working on
indexer issues.
Read CONTRIBUTING.md and use the root .github issue and PR templates. They
cover both Backend API and indexer work. Keep PRs scoped to one issue, avoid
generated files, and run the verification commands listed in the PR template.
POST /api/v1/campaigns (JWT required)
Request body:
{
"campaign_ref": "ABCDE",
"target_amount": "1000",
"donation_token": "0x1"
}Notes:
- Rate limit: max 5 campaign creations per user per hour.
- Auth: send
Authorization: Bearer <JWT>and include awalletAddress(oraddress) claim in the token.
Set these env vars to enable real on-chain calls:
CAIRO_RPC_URLCAIRO_ACCOUNT_ADDRESSCAIRO_PRIVATE_KEYCAIRO_FACTORY_CONTRACT_ADDRESS
Optional:
CAMPAIGN_CREATED_EVENT_KEY(event key to extractcampaign_idfrom the tx receipt; otherwise falls back to tx hash)
For local development without a chain connection:
CAIRO_MOCK=true