diff --git a/.github/workflows/backend-ci.yml b/.github/workflows/backend-ci.yml index 5ac9a441..a078663f 100644 --- a/.github/workflows/backend-ci.yml +++ b/.github/workflows/backend-ci.yml @@ -37,6 +37,9 @@ jobs: --health-timeout 5s --health-retries 5 + env: + DATABASE_PROVIDER: postgresql + steps: - uses: actions/checkout@v4 diff --git a/app/backend/.env.example b/app/backend/.env.example index ab1af48c..77ffe998 100644 --- a/app/backend/.env.example +++ b/app/backend/.env.example @@ -1,4 +1,9 @@ +DATABASE_PROVIDER="sqlite" # Use "sqlite" or "postgresql" DATABASE_URL="file:./prisma/dev.db" +# For PostgreSQL configuration, set: +# DATABASE_PROVIDER="postgresql" +# DATABASE_URL="postgresql://postgres:password@localhost:5432/chainforge?schema=public" +# SHADOW_DATABASE_URL="postgresql://postgres:password@localhost:5432/chainforge_shadow?schema=public" WEBHOOK_SECRET="change-me-to-a-strong-random-secret" SOROBAN_NETWORK="testnet" AID_ESCROW_CONTRACT_ID="" diff --git a/app/backend/.gitignore b/app/backend/.gitignore index 10ce9dde..b184de8b 100644 --- a/app/backend/.gitignore +++ b/app/backend/.gitignore @@ -73,3 +73,6 @@ reports/mutation/ # Keep reports directory but ignore contents reports/* !reports/.gitkeep + +# Prisma +/prisma/schema.generated.prisma diff --git a/app/backend/prisma.config.ts b/app/backend/prisma.config.ts index b2ad2efe..53b85305 100644 --- a/app/backend/prisma.config.ts +++ b/app/backend/prisma.config.ts @@ -1,7 +1,30 @@ import { defineConfig } from 'prisma/config'; +import * as fs from 'fs'; +import * as path from 'path'; + +const provider = process.env.DATABASE_PROVIDER || 'sqlite'; +const sourceSchemaPath = path.join(__dirname, 'prisma', 'schema.prisma'); +const destSchemaPath = path.join(__dirname, 'prisma', 'schema.generated.prisma'); + +if (fs.existsSync(sourceSchemaPath)) { + let content = fs.readFileSync(sourceSchemaPath, 'utf8'); + + // Replace provider in datasource block + content = content.replace( + /(datasource db\s*\{[^}]*provider\s*=\s*")[^"]*(")/g, + `$1${provider}$2` + ); + + // Remove shadowDatabaseUrl if using SQLite + if (provider === 'sqlite') { + content = content.replace(/shadowDatabaseUrl\s*=\s*env\("SHADOW_DATABASE_URL"\)/g, ''); + } + + fs.writeFileSync(destSchemaPath, content, 'utf8'); +} export default defineConfig({ - schema: 'prisma/schema.prisma', + schema: 'prisma/schema.generated.prisma', migrations: { path: 'prisma/migrations', }, diff --git a/docs/db/providers.md b/docs/db/providers.md new file mode 100644 index 00000000..27d14e28 --- /dev/null +++ b/docs/db/providers.md @@ -0,0 +1,49 @@ +# Database Providers + +ChainForge supports switching database providers dynamically using environment variables. This enables lightweight development/testing using SQLite and robust production deployments using PostgreSQL. + +## Supported Providers +- `sqlite` (Default for local development and unit/e2e testing) +- `postgresql` (Default for production) + +## Configuration + +The database provider is determined by the following environment variables: + +| Variable | Description | Example (SQLite) | Example (PostgreSQL) | +|---|---|---|---| +| `DATABASE_PROVIDER` | The Prisma database provider (`sqlite` or `postgresql`) | `sqlite` | `postgresql` | +| `DATABASE_URL` | The database connection string | `file:./prisma/dev.db` | `postgresql://user:pass@host:5432/db?schema=public` | +| `SHADOW_DATABASE_URL` | Optional shadow database URL (needed for PostgreSQL migrations if user lacks admin privileges to create new databases) | (Not used) | `postgresql://user:pass@host:5432/shadow_db?schema=public` | + +### Setting Environment Variables + +Copy `app/backend/.env.example` to `app/backend/.env` and configure: + +#### SQLite (Default) +```env +DATABASE_PROVIDER="sqlite" +DATABASE_URL="file:./prisma/dev.db" +``` + +#### PostgreSQL +```env +DATABASE_PROVIDER="postgresql" +DATABASE_URL="postgresql://postgres:password@localhost:5432/chainforge?schema=public" +SHADOW_DATABASE_URL="postgresql://postgres:password@localhost:5432/chainforge_shadow?schema=public" +``` + +--- + +## Prisma Migrations and Schema Validation + +Because migrations are provider-specific in Prisma: +1. **SQLite migrations** are committed under `app/backend/prisma/migrations`. +2. **PostgreSQL migrations** can be created/applied when using a PostgreSQL target by running: + ```bash + DATABASE_PROVIDER=postgresql DATABASE_URL="" npx prisma migrate dev --name + ``` +3. To dynamically apply migrations or initialize schema without pre-existing migration folders (e.g. for temporary test runs), use: + ```bash + DATABASE_PROVIDER=postgresql DATABASE_URL="" npx prisma db push + ```