Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 68 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ Why:

| Area | Limitation |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Database | The backend uses a local **SQLite file** database by default (`DATABASE_URL=file:/.../dev.db`). Running multiple backend replicas either creates split-brain state (separate DB files/volumes) or requires sharing a single SQLite file across hosts, which is not a reliable deployment pattern. |
| Database | The backend uses **SQLite** by default. For production deployments requiring high availability, use **PostgreSQL** (`DATABASE_PROVIDER=postgresql`). SQLite still works for single-instance deployments but is not recommended for multi-replica setups. |
| Collaboration | Real-time presence state is tracked **in-memory** in the backend process, so multiple replicas will fragment presence/collaboration unless a shared Socket.IO adapter is added. |

Recommended deployment pattern:
Expand Down Expand Up @@ -336,14 +336,73 @@ docker compose -f docker-compose.oidc.yml down

Base values are documented in `backend/.env.example`. Common ones to care about:

| Variable | Default / Example | Description |
| -------------- | ------------------------- | ----------------------------------------------------------------------------------- |
| `DATABASE_URL` | `file:/app/prisma/dev.db` | SQLite file or external DB URL. |
| `FRONTEND_URL` | `http://localhost:6767` | Allowed frontend origin(s), comma-separated for multiple entries. |
| `TRUST_PROXY` | `false` | `false`, `true`, or hop count (for example `1`). |
| `JWT_SECRET` | `change-this-secret...` | Recommended in production so sessions remain stable across restarts and migrations. |
| `CSRF_SECRET` | `change-this-secret` | Recommended in production so CSRF validation remains stable across restarts. |
| `AUTH_MODE` | `local` | `local`, `hybrid`, `oidc_enforced`. |
| Variable | Default / Example | Description |
| ------------------- | ------------------------- | ----------------------------------------------------------------------------------- |
| `DATABASE_PROVIDER` | `sqlite` | Database provider: `sqlite` or `postgresql`. See [Database Provider](#database-provider) for details. |
| `DATABASE_URL` | `file:/app/prisma/dev.db` | SQLite file or external DB URL. |
| `FRONTEND_URL` | `http://localhost:6767` | Allowed frontend origin(s), comma-separated for multiple entries. |
| `TRUST_PROXY` | `false` | `false`, `true`, or hop count (for example `1`). |
| `JWT_SECRET` | `change-this-secret...` | Recommended in production so sessions remain stable across restarts and migrations. |
| `CSRF_SECRET` | `change-this-secret` | Recommended in production so CSRF validation remains stable across restarts. |
| `AUTH_MODE` | `local` | `local`, `hybrid`, `oidc_enforced`. |

</details>

<details>
<summary>Database Provider</summary>

## Database Provider

ExcaliDash supports both **SQLite** (default) and **PostgreSQL** as database providers. The provider is controlled by the `DATABASE_PROVIDER` environment variable.

### SQLite (Default)

SQLite is the default and works out of the box without additional configuration:

```yaml
# docker-compose.prod.yml
services:
backend:
environment:
- DATABASE_PROVIDER=sqlite
- DATABASE_URL=file:/app/prisma/dev.db
```

### PostgreSQL

To use PostgreSQL instead of SQLite:

1. **Set the environment variables:**

```yaml
# docker-compose.prod.yml
services:
backend:
environment:
- DATABASE_PROVIDER=postgresql
- DATABASE_URL=postgresql://user:password@host:5432/excalidash
```

2. **Generate PostgreSQL migrations:**

The repository includes SQLite migrations by default. To use PostgreSQL, you need to generate migrations for the PostgreSQL provider:

```bash
# 1. Set the provider in your local environment
export DATABASE_PROVIDER=postgresql
export DATABASE_URL="postgresql://user:password@localhost:5432/excalidash"

# 2. Remove existing SQLite migrations
rm -rf backend/prisma/migrations/postgresql

# 3. Generate initial migration for PostgreSQL
cd backend
npx prisma migrate dev --name init
```

This creates a new `backend/prisma/migrations/postgresql/` folder with PostgreSQL-specific migrations.

**Note:** When switching database providers, you cannot migrate existing data. The new database will start empty.

</details>

Expand Down
2 changes: 2 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Backend Environment Variables
PORT=8000
NODE_ENV=production
# Database provider: sqlite or postgresql
DATABASE_PROVIDER=sqlite
DATABASE_URL=file:/app/prisma/dev.db
FRONTEND_URL=http://localhost:6767
# Keep disabled unless traffic always comes through a trusted reverse proxy.
Expand Down
8 changes: 6 additions & 2 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ RUN npm ci && npm cache clean --force
# Copy prisma schema
COPY prisma ./prisma/

# Generate Prisma Client
# Set default provider for build-time Prisma generation (runtime can override via DATABASE_PROVIDER)
RUN sed -i 's/provider = env("[^"]*")/provider = "sqlite"/' prisma/schema.prisma

# Generate Prisma Client at build time (for TypeScript compilation)
# Runtime will regenerate if DATABASE_PROVIDER differs
RUN npx prisma generate

# Copy source code
Expand Down Expand Up @@ -51,7 +55,7 @@ COPY prisma ./prisma_template/
# Copy built application from builder
COPY --from=builder /app/dist ./dist

# Copy the generated Prisma Client from builder to maintain the same structure
# Copy the generated Prisma Client from builder (will be regenerated at runtime if provider changes)
COPY --from=builder /app/src/generated ./dist/generated

# Create necessary directories (ownership will be set in entrypoint)
Expand Down
44 changes: 33 additions & 11 deletions backend/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,47 @@ fi

export CSRF_SECRET

# 1. Ensure schema and migrations are present (Running as root)
# Never copy the entire prisma directory, as that can unintentionally overwrite
# persisted SQLite files or copy stray *.db artifacts into the volume.
if [ ! -f "/app/prisma/schema.prisma" ]; then
echo "Mount appears empty (missing schema.prisma). Bootstrapping schema and migrations..."
else
# Volume exists but may be missing new migrations from an upgrade.
echo "Syncing schema and migrations from template..."
# Set default DATABASE_PROVIDER if not set
if [ -z "${DATABASE_PROVIDER:-}" ]; then
echo "DATABASE_PROVIDER not set, defaulting to sqlite"
DATABASE_PROVIDER="sqlite"
fi

# Validate DATABASE_PROVIDER
if [ "${DATABASE_PROVIDER}" != "sqlite" ] && [ "${DATABASE_PROVIDER}" != "postgresql" ]; then
echo "ERROR: DATABASE_PROVIDER must be 'sqlite' or 'postgresql', got '${DATABASE_PROVIDER}'"
exit 1
fi

# Ensure migrations directory exists
mkdir -p /app/prisma/migrations

# Copy schema.prisma from template
cp /app/prisma_template/schema.prisma /app/prisma/schema.prisma
cp -R /app/prisma_template/migrations/. /app/prisma/migrations/

# Clear and copy provider-specific migrations folder
echo "Copying ${DATABASE_PROVIDER} migrations..."
rm -rf /app/prisma/migrations/*
cp -R /app/prisma_template/migrations/"${DATABASE_PROVIDER}"/. /app/prisma/migrations/

# Update schema.prisma with the runtime provider (handles both env() and static values)
echo "Configuring Prisma for provider: ${DATABASE_PROVIDER}"
sed -i 's/provider = env("[^"]*")/provider = "'"${DATABASE_PROVIDER}"'"/' /app/prisma/schema.prisma
sed -i 's/provider = "[^"]*"/provider = "'"${DATABASE_PROVIDER}"'"/' /app/prisma/schema.prisma

# Generate Prisma Client at runtime (run as root since schema is owned by root)
echo "Generating Prisma Client..."
npx prisma generate --schema=/app/prisma/schema.prisma

# Copy generated client to the expected location for the application
mkdir -p /app/dist/generated
cp -r /app/src/generated/* /app/dist/generated/

# 2. Fix permissions unconditionally (Running as root)
echo "Fixing filesystem permissions..."
chown -R nodejs:nodejs /app/uploads
chown -R nodejs:nodejs /app/prisma
chown -R nodejs:nodejs /app/uploads /app/prisma /app/dist/generated
chmod 755 /app/uploads
chmod -R 755 /app/dist/generated
chmod 600 "${JWT_SECRET_FILE}"
chmod 600 "${CSRF_SECRET_FILE}"

Expand Down
11 changes: 9 additions & 2 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 0 additions & 12 deletions backend/prisma.config.ts

This file was deleted.

Loading
Loading