chore: merge main, resolve biome formatting conflicts

Merge origin/main into feat/external-2fa-codes. Resolve formatting
conflicts caused by biome rollout; preserve both feature streams:
PR's external 2FA token + signing-session 2FA proof additions plus
main's RateLimit/RecipientExpired/signingReminders/date-auto-insert.

In complete-document-with-token.ts, drop the duplicate early
field-fetching block introduced when main moved that logic later
with date auto-insert support; keep the EXTERNAL_TWO_FACTOR_AUTH
check using derivedRecipientActionAuth.
This commit is contained in:
ephraimduncan
2026-05-12 11:46:11 +00:00
parent 9194884fbe
commit 138d663c25
1959 changed files with 93488 additions and 47038 deletions
@@ -0,0 +1,490 @@
---
title: Database Configuration
description: Configure PostgreSQL connection strings, pooling, SSL, migrations, and performance tuning for your Documenso deployment.
---
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
import { Callout } from 'fumadocs-ui/components/callout';
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
## Supported Databases
Documenso requires **PostgreSQL 14 or later**. No other databases are supported.
PostgreSQL provides the reliability, performance, and feature set required for document signing workflows, including:
- ACID compliance for transaction integrity
- JSON support for flexible metadata storage
- Full-text search capabilities
- Robust backup and replication options
## Connection String Format
PostgreSQL connection strings follow this format:
```
postgresql://[user]:[password]@[host]:[port]/[database]?[parameters]
```
### Components
| Component | Description | Example |
| ------------ | ------------------------------- | ----------------- |
| `user` | Database username | `documenso` |
| `password` | Database password (URL-encoded) | `secretpass` |
| `host` | Database server hostname or IP | `localhost` |
| `port` | Database port | `5432` |
| `database` | Database name | `documenso` |
| `parameters` | Additional connection options | `sslmode=require` |
### Examples
**Local development:**
```
postgresql://documenso:password@localhost:5432/documenso
```
**Remote server with SSL:**
```
postgresql://documenso:password@db.example.com:5432/documenso?sslmode=require
```
**With special characters in password:**
URL-encode special characters in passwords. For example, `p@ss#word` becomes `p%40ss%23word`:
```
postgresql://documenso:p%40ss%23word@localhost:5432/documenso
```
## Environment Variables
Documenso uses two database connection variables:
| Variable | Purpose |
| ---------------------------------- | --------------------------------------------------- |
| `NEXT_PRIVATE_DATABASE_URL` | Primary connection for application queries |
| `NEXT_PRIVATE_DIRECT_DATABASE_URL` | Direct connection for migrations and schema changes |
### Basic Configuration
When not using a connection pooler, set both variables to the same value:
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://user:password@host:5432/documenso
NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://user:password@host:5432/documenso
```
### Automatic Detection
Documenso automatically detects common database environment variable formats used by hosting providers:
| Provider Variable | Maps To |
| -------------------------- | ---------------------------------- |
| `DATABASE_URL` | `NEXT_PRIVATE_DATABASE_URL` |
| `POSTGRES_URL` | `NEXT_PRIVATE_DATABASE_URL` |
| `POSTGRES_PRISMA_URL` | `NEXT_PRIVATE_DATABASE_URL` |
| `DATABASE_URL_UNPOOLED` | `NEXT_PRIVATE_DIRECT_DATABASE_URL` |
| `POSTGRES_URL_NON_POOLING` | `NEXT_PRIVATE_DIRECT_DATABASE_URL` |
If your hosting provider sets these variables, Documenso will use them automatically.
## Connection Pooling
Connection pooling improves performance by reusing database connections instead of creating new ones for each request.
### When to Use Pooling
Use connection pooling when:
- Running multiple application instances
- Deploying to serverless environments
- Handling high concurrent request volumes
- Your database has connection limits
### PgBouncer Configuration
When using PgBouncer or similar poolers, configure two connection strings:
1. **Pooled connection** for application queries
2. **Direct connection** for migrations (bypasses the pooler)
```bash
# Pooled connection (through PgBouncer)
NEXT_PRIVATE_DATABASE_URL=postgresql://user:password@pooler-host:6432/documenso?pgbouncer=true
# Direct connection (bypasses PgBouncer)
NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://user:password@db-host:5432/documenso
```
<Callout type="warn">
Migrations must use a direct connection. Running migrations through a connection pooler will fail.
</Callout>
### Prisma Connection Pool
Documenso uses Prisma, which maintains its own connection pool. Configure pool size with connection string parameters:
```
postgresql://user:password@host:5432/documenso?connection_limit=10&pool_timeout=30
```
| Parameter | Description | Default |
| ------------------ | ---------------------------------------- | ------- |
| `connection_limit` | Maximum connections in the pool | 10 |
| `pool_timeout` | Seconds to wait for available connection | 10 |
## SSL/TLS Connections
### Enabling SSL
Add SSL parameters to your connection string:
```
postgresql://user:password@host:5432/documenso?sslmode=require
```
### SSL Modes
| Mode | Description |
| ------------- | --------------------------------------------------- |
| `disable` | No SSL (not recommended for production) |
| `allow` | Try non-SSL first, fall back to SSL |
| `prefer` | Try SSL first, fall back to non-SSL |
| `require` | Require SSL, but don't verify certificate |
| `verify-ca` | Require SSL and verify server certificate |
| `verify-full` | Require SSL, verify certificate, and check hostname |
For production, use `require` at minimum. Use `verify-full` when your CA certificate is available.
### Custom Certificates
When connecting to databases with self-signed or private CA certificates:
```
postgresql://user:password@host:5432/documenso?sslmode=verify-full&sslrootcert=/path/to/ca.crt
```
For Docker deployments, mount the certificate file:
```bash
docker run -d \
-v /path/to/ca.crt:/etc/ssl/certs/db-ca.crt:ro \
-e NEXT_PRIVATE_DATABASE_URL="postgresql://user:password@host:5432/documenso?sslmode=verify-full&sslrootcert=/etc/ssl/certs/db-ca.crt" \
documenso/documenso:latest
```
## Running Migrations
Database migrations update your schema when upgrading Documenso.
### Automatic Migrations
When running Documenso via Docker, migrations run automatically on container startup. No manual intervention is required.
### Manual Migrations
For manual deployments or troubleshooting:
```bash
# Apply pending migrations
npm run prisma:migrate-deploy
# Or using npx directly
npx prisma migrate deploy
```
<Callout type="info">
Always back up your database before running migrations, especially for major version upgrades.
</Callout>
### Migration Commands
| Command | Purpose |
| ----------------------- | ----------------------------------------- |
| `prisma:migrate-deploy` | Apply pending migrations (production) |
| `prisma:migrate-dev` | Create and apply migrations (development) |
| `prisma:migrate-reset` | Reset database and apply all migrations |
### Troubleshooting Migrations
<Accordions type="multiple">
<Accordion title="Migration failed midway">
Check the `_prisma_migrations` table:
```sql
SELECT * FROM _prisma_migrations WHERE finished_at IS NULL;
```
To retry, fix the underlying issue (disk space, permissions, etc.), mark as rolled back:
```sql
UPDATE _prisma_migrations SET rolled_back_at = NOW() WHERE migration_name = 'failed_migration_name';
```
Run migrations again.
</Accordion>
<Accordion title="Connection timeout during migration">
Use the direct database URL and increase timeout:
```bash
NEXT_PRIVATE_DIRECT_DATABASE_URL="postgresql://user:password@host:5432/documenso?connect_timeout=60"
```
</Accordion>
</Accordions>
## Managed Database Services
<Accordions type="multiple">
<Accordion title="Supabase">
Supabase provides PostgreSQL with built-in connection pooling via Supavisor.
**Configuration:**
```bash
# Pooled connection (Session mode - port 5432)
NEXT_PRIVATE_DATABASE_URL=postgresql://postgres.[project-ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres
# Direct connection for migrations (port 5432, direct host)
NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://postgres:[password]@db.[project-ref].supabase.co:5432/postgres
```
Find your connection strings in the Supabase dashboard under **Settings > Database > Connection string**.
</Accordion>
<Accordion title="Neon">
Neon provides serverless PostgreSQL with automatic scaling.
**Configuration:**
```bash
# Pooled connection
NEXT_PRIVATE_DATABASE_URL=postgresql://[user]:[password]@[endpoint]-pooler.region.aws.neon.tech/documenso?sslmode=require
# Direct connection for migrations
NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://[user]:[password]@[endpoint].region.aws.neon.tech/documenso?sslmode=require
```
The pooler endpoint includes `-pooler` in the hostname.
</Accordion>
<Accordion title="AWS RDS">
**Configuration:**
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://documenso:[password]@your-instance.region.rds.amazonaws.com:5432/documenso?sslmode=require
NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://documenso:[password]@your-instance.region.rds.amazonaws.com:5432/documenso?sslmode=require
```
**Recommended settings:**
- Instance class: `db.t3.medium` or larger for production
- Storage: General Purpose SSD (gp3), minimum 20GB
- Enable automated backups with 7+ day retention
- Enable Multi-AZ for high availability
</Accordion>
<Accordion title="Google Cloud SQL">
**Configuration:**
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://documenso:[password]@/documenso?host=/cloudsql/[project]:[region]:[instance]
```
When connecting via Cloud SQL Proxy, use Unix socket connections.
For public IP connections:
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://documenso:[password]@[public-ip]:5432/documenso?sslmode=require
```
</Accordion>
<Accordion title="Azure Database for PostgreSQL">
**Configuration:**
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://documenso@[server-name]:[password]@[server-name].postgres.database.azure.com:5432/documenso?sslmode=require
```
Note: Azure requires the username format `user@servername`.
</Accordion>
<Accordion title="DigitalOcean Managed Databases">
**Configuration:**
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://doadmin:[password]@[cluster-host]:25060/documenso?sslmode=require
```
DigitalOcean uses port 25060 by default and requires SSL.
</Accordion>
</Accordions>
## Backup Recommendations
### Backup Strategies
| Strategy | Frequency | Retention | Use Case |
| ---------------------- | ------------ | ----------- | ---------------------- |
| Automated snapshots | Daily | 7-30 days | Point-in-time recovery |
| Logical backups | Daily/Weekly | 30-90 days | Long-term retention |
| Continuous replication | Real-time | 24-72 hours | Disaster recovery |
### PostgreSQL Backup Commands
**Create a logical backup:**
```bash
pg_dump -h host -U user -d documenso -F c -f documenso_backup.dump
```
**Restore from backup:**
```bash
pg_restore -h host -U user -d documenso -c documenso_backup.dump
```
### Managed Service Backups
Most managed database services provide automated backups:
<Tabs items={['Supabase', 'Neon', 'AWS RDS', 'Google Cloud SQL', 'Azure']}>
<Tab value="Supabase">Daily backups with point-in-time recovery (Pro plan)</Tab>
<Tab value="Neon">Automatic branching for instant recovery</Tab>
<Tab value="AWS RDS">Automated backups with configurable retention</Tab>
<Tab value="Google Cloud SQL">Automated and on-demand backups</Tab>
<Tab value="Azure">Automatic backups with geo-redundancy options</Tab>
</Tabs>
<Callout type="warn">
Always test your backup restoration process. Untested backups may not work when needed.
</Callout>
## Performance Tuning
### PostgreSQL Configuration
Key parameters for Documenso workloads:
| Parameter | Recommended Value | Description |
| ---------------------- | ----------------- | ------------------------------------- |
| `shared_buffers` | 25% of RAM | Memory for caching data |
| `effective_cache_size` | 75% of RAM | Planner's estimate of available cache |
| `work_mem` | 64MB-256MB | Memory per sort/hash operation |
| `maintenance_work_mem` | 512MB-1GB | Memory for maintenance operations |
| `max_connections` | 100-200 | Maximum concurrent connections |
### Connection Limits
Calculate your connection limit:
```
max_connections = (application_instances × connection_pool_size) + admin_overhead
```
Example: 3 app instances with pool size 10 = `(3 × 10) + 10 = 40` connections minimum.
### Indexing
Documenso includes necessary indexes by default. Additional indexes may help for:
- Custom reporting queries
- High-volume document searches
- Audit log analysis
Check for slow queries:
```sql
SELECT query, calls, mean_time, total_time
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 10;
```
### Monitoring
Monitor these metrics:
| Metric | Warning Threshold | Action |
| -------------------- | ----------------- | ------------------------------- |
| Connection usage | > 80% | Increase limits or add pooling |
| Disk usage | > 80% | Add storage or archive old data |
| Cache hit ratio | < 95% | Increase `shared_buffers` |
| Long-running queries | > 30 seconds | Optimize query or add indexes |
## Troubleshooting
<Accordions type="multiple">
<Accordion title="Connection refused">
Causes:
- PostgreSQL not running
- Incorrect host or port
- Firewall blocking
Solutions:
- Verify PostgreSQL is running with `pg_isready -h host -p 5432`
- Check the connection string
- Verify firewall rules
with `pg_isready -h host -p 5432`, check the connection string, verify firewall rules.
</Accordion>
<Accordion title="Authentication failed">
Causes:
- Incorrect password
- User doesn't exist
- Password contains special characters
Solutions:
- Reset password with `ALTER USER documenso WITH PASSWORD 'newpassword';`
- Verify credentials in `pg_hba.conf`
- Verify URL-encoded special characters
</Accordion>
<Accordion title="SSL connection required">
Add SSL mode to your connection string:
```bash
postgresql://user:password@host:5432/documenso?sslmode=require
```
</Accordion>
<Accordion title="Too many connections">
Causes:
- Connection pool exhausted
- Connections not released
- Multiple instances exceeding limits
Solutions:
- Reduce `connection_limit`
- Increase `max_connections`
- Implement PgBouncer
</Accordion>
<Accordion title="Database does not exist">
Create the database:
```sql
CREATE DATABASE documenso;
GRANT ALL PRIVILEGES ON DATABASE documenso TO documenso;
```
</Accordion>
<Accordion title="Permission denied">
Grant permissions:
```sql
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO documenso;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO documenso;
```
</Accordion>
</Accordions>
---
## See Also
- [Environment Variables](/docs/self-hosting/configuration/environment) - Complete configuration reference
- [Storage Configuration](/docs/self-hosting/configuration/storage) - Set up document storage
- [Backups](/docs/self-hosting/maintenance/backups) - Backup strategies and procedures
- [Upgrades](/docs/self-hosting/maintenance/upgrades) - Upgrade procedures and migration handling