Skip to main content

Configuration Reference

Contract Lucidity is configured via environment variables. The backend reads these through Pydantic's BaseSettings class, which supports both environment variables and a .env file at the project root.

All variables are case-insensitive (e.g., POSTGRES_USER and postgres_user are equivalent).

Database

VariableDefaultDescriptionService
POSTGRES_USERcl_userPostgreSQL usernamecl-backend, cl-worker, cl-db
POSTGRES_PASSWORDcl_password_change_mePostgreSQL passwordcl-backend, cl-worker, cl-db
POSTGRES_DBcontract_lucidityPostgreSQL database namecl-backend, cl-worker, cl-db
POSTGRES_HOSTcl-postgresPostgreSQL hostnamecl-backend, cl-worker
POSTGRES_PORT5432PostgreSQL portcl-backend, cl-worker
Change the default password

The default PostgreSQL password is cl_password_change_me. Always set a strong, unique password in production via POSTGRES_PASSWORD.

The database connection URLs are derived automatically:

  • Async (backend API): postgresql+asyncpg://{user}:{password}@{host}:{port}/{db}
  • Sync (Celery worker): postgresql+psycopg2://{user}:{password}@{host}:{port}/{db}

Redis / Celery

VariableDefaultDescriptionService
REDIS_HOSTcl-redisRedis hostnamecl-backend, cl-worker
REDIS_PORT6379Redis portcl-backend, cl-worker
REDIS_URLredis://cl-redis:6379/0Full Redis URLcl-backend, cl-worker
CELERY_BROKER_URLredis://cl-redis:6379/0Celery broker URL (Redis db 0)cl-worker
CELERY_RESULT_BACKENDredis://cl-redis:6379/1Celery result backend (Redis db 1)cl-worker

JWT / Authentication

VariableDefaultDescriptionService
JWT_SECRET_KEYchange-me-to-a-random-secret-in-productionSecret key for signing JWT tokenscl-backend
JWT_ALGORITHMHS256JWT signing algorithmcl-backend
JWT_ACCESS_TOKEN_EXPIRE_MINUTES60Access token lifetime in minutescl-backend
JWT_REFRESH_TOKEN_EXPIRE_DAYS7Refresh token lifetime in dayscl-backend
Change the JWT secret

The default JWT secret is a placeholder. In production, generate a random 64+ character secret:

openssl rand -hex 64
SSO Configuration

Single Sign-On (OIDC) is configured entirely through the admin UI (Settings > SSO), not through environment variables. SSO client secrets are encrypted at rest using a key derived from JWT_SECRET_KEY -- changing the JWT secret will invalidate any stored SSO configuration. See Single Sign-On (SSO) for setup instructions.

Application

VariableDefaultDescriptionService
APP_NAMEContract LucidityApplication display namecl-backend
APP_ENVdevelopmentEnvironment identifier (development, staging, production)cl-backend
LOG_LEVELINFOLogging level (DEBUG, INFO, WARNING, ERROR)cl-backend, cl-worker
MAX_UPLOAD_SIZE_MB100Maximum file upload size in megabytescl-backend

Storage

VariableDefaultDescriptionService
STORAGE_PATH/data/storagePath for uploaded document filescl-backend, cl-worker
CONFIG_PATH/data/configPath for application configuration filescl-backend, cl-worker

These paths correspond to Docker volumes cl-storage and cl-config. If running without Docker, ensure these directories exist and are writable.

CORS and URLs

VariableDefaultDescriptionService
CORS_ORIGINShttp://localhost:3000,https://contractlucidity.comComma-separated list of allowed CORS originscl-backend
FRONTEND_URLhttp://localhost:3000Public URL of the frontend (used for links in emails, etc.)cl-backend
BACKEND_INTERNAL_URLhttp://cl-backend:8000Internal URL for frontend-to-backend communicationcl-frontend
Adding your domain

For production, set CORS_ORIGINS to include your domain:

CORS_ORIGINS=https://contracts.yourcompany.com

The frontend uses BACKEND_INTERNAL_URL to proxy API requests within the Docker network. This should remain as the default unless you have a custom network topology.

Default Admin

VariableDefaultDescriptionService
DEFAULT_ADMIN_EMAIL[email protected]Email for the auto-created admin accountcl-backend
DEFAULT_ADMIN_PASSWORD<your-strong-password>Initial password for the admin accountcl-backend

The default admin is created on first boot during the seed process. The account is flagged with must_change_password=True, prompting a password change on first login.

warning

Change DEFAULT_ADMIN_PASSWORD before first boot in production, or change the password immediately after first login. The seed process will not overwrite an existing admin account.

Frontend-Specific

These variables are set on the cl-frontend service in Docker Compose:

VariableDefaultDescriptionService
BACKEND_INTERNAL_URLhttp://cl-backend:8000Backend API URL used by the Next.js server-side proxycl-frontend
NEXT_PUBLIC_FRONTEND_URLhttp://localhost:3000Public-facing frontend URL (available client-side)cl-frontend
tip

NEXT_PUBLIC_ prefixed variables are embedded at build time in Next.js and available in the browser. BACKEND_INTERNAL_URL is server-side only and never exposed to the client.

Worker-Specific

VariableDefaultDescriptionService
CELERY_CONCURRENCY2Number of parallel Celery worker processescl-worker
Tuning concurrency

Each concurrency slot processes one document at a time and makes multiple AI API calls. Higher concurrency means faster throughput but more memory usage and higher AI API costs. Recommended values:

  • Development: 1-2
  • Small team: 2-4
  • Production: 4-8 (depending on available RAM and AI API rate limits)

Allow approximately 512 MB - 1 GB of RAM per concurrency slot.

Service Connectivity & Domain Configuration

Contract Lucidity consists of five services that must be able to communicate. Understanding how they connect is essential for a working deployment.

How Services Talk to Each Other

The frontend is the only public-facing service for normal user traffic. It serves the web application and proxies all /api/* requests to the backend internally. The backend, database, Redis, and worker are never exposed to the internet for user traffic.

SCIM Endpoint Routing

If you use SCIM provisioning, the identity provider needs to reach the backend's SCIM endpoint at /scim/v2. This path is not covered by the default frontend proxy (which only forwards /api/*).

You have two options:

Option A: Add a frontend rewrite rule (recommended)

Add a rewrite for /scim/* in your next.config.ts so the frontend proxies SCIM traffic to the backend, keeping a single public URL:

next.config.ts
async rewrites() {
return [
{
source: "/api/:path*",
destination: `${process.env.BACKEND_INTERNAL_URL || "http://cl-backend:8000"}/api/:path*`,
},
{
source: "/scim/:path*",
destination: `${process.env.BACKEND_INTERNAL_URL || "http://cl-backend:8000"}/scim/:path*`,
},
];
},

With this approach, the SCIM endpoint URL you configure in your IdP is https://your-domain.com/scim/v2.

warning

Adding rewrite rules requires rebuilding the frontend container: docker compose up -d --build cl-frontend. The next.config.ts file is not volume-mounted.

Option B: Expose the backend directly for SCIM

Expose the backend on a separate public URL (e.g., https://api.your-domain.com) and configure your IdP to use https://api.your-domain.com/scim/v2. This requires additional TLS configuration and firewall rules to restrict access to the SCIM endpoints.

tip

Option A is simpler and keeps your deployment's single-URL architecture. Option B is useful if you cannot rebuild the frontend image or need to isolate SCIM traffic for security or audit reasons.

Setting Your Domain Name

Only one domain is needed — the domain pointing to your frontend service. Configure it in three places:

SettingWhere to SetExample Value
DNS recordYour DNS provider (Cloudflare, Route 53, etc.)contracts.yourfirm.com → frontend IP
FRONTEND_URLcl-backend environmenthttps://contracts.yourfirm.com
CORS_ORIGINScl-backend environmenthttps://contracts.yourfirm.com
NEXT_PUBLIC_FRONTEND_URLcl-frontend environmenthttps://contracts.yourfirm.com
TLS certificateYour reverse proxy or cloud load balancerAuto via Let's Encrypt, ACM, etc.

The BACKEND_INTERNAL_URL on cl-frontend should point to the backend's internal address (e.g., http://cl-backend:8000 on Docker, or the private IP/hostname if services run on separate machines).

SSO Callback URLs

SSO callback URLs are derived dynamically from the incoming request. When a user initiates SSO login, the backend reads request.base_url to construct the callback URL. This means SSO automatically works with whatever domain traffic arrives on -- no separate SSO URL configuration is needed beyond what your identity provider requires.

SCIM Endpoint URL

The SCIM endpoint URL also uses request.base_url for the meta.location fields in SCIM responses. If you use a frontend rewrite (Option A above), SCIM responses will reference your frontend domain. If you expose the backend directly (Option B), they will reference the backend's domain. Both approaches work correctly with identity providers.

In a standard deployment, all five services run within the same cloud network:

Deployment ModelFrontendBackend + WorkerDatabaseRedis
Docker ComposeSame hostSame hostSame hostSame host
EasyPanelSame serverSame serverManaged or same serverSame server
AWSECS / FargateECS / FargateRDS PostgreSQLElastiCache
AzureApp ServiceApp ServiceAzure Database for PostgreSQLAzure Cache for Redis
GCPCloud RunCloud RunCloud SQLMemorystore

In all cases, services communicate over the cloud provider's private network (VPC, VNet, etc.). The only public endpoint is the frontend, which sits behind a load balancer or reverse proxy that terminates TLS.

Key connectivity requirements:

  • cl-frontend must reach cl-backend on port 8000 (internal)
  • cl-backend and cl-worker must reach cl-postgres on port 5432
  • cl-backend and cl-worker must reach cl-redis on port 6379
  • cl-worker uses the same database and Redis as cl-backend
  • If using SCIM provisioning: the IdP must reach the SCIM endpoint (either via the frontend proxy or directly to the backend -- see "SCIM Endpoint Routing" above)

Cross-Cloud / Distributed Deployments

For reference only

Cross-cloud deployments are not a supported configuration. This section is provided for information only, for organizations with specific infrastructure requirements.

It is technically possible to run services across cloud providers (e.g., frontend on Vercel, backend on AWS, database on GCP). If you choose this path:

  1. The frontend still needs BACKEND_INTERNAL_URL — but it will be an external HTTPS URL instead of an internal hostname. The backend must be exposed with TLS, and CORS_ORIGINS must include the frontend domain.

  2. Database connectivity — set POSTGRES_HOST to the external database hostname. Use TLS for the connection (?sslmode=require is recommended). Ensure firewall rules allow inbound connections from the backend's IP range.

  3. Redis connectivity — set REDIS_URL to the external Redis URL with TLS (rediss://). Redis should be co-located with the backend and worker for latency reasons — document processing makes frequent Redis calls.

  4. Latency considerations — the backend and worker make many small database and Redis queries per document. Placing them in different regions from the database or Redis will significantly impact processing speed. Keep backend, worker, database, and Redis in the same region. The frontend can be in a different region with minimal impact.

  5. Network security — all cross-cloud connections should use TLS. Consider VPN tunnels or cloud interconnects (AWS Direct Connect, Azure ExpressRoute, GCP Cloud Interconnect) for production workloads.

Complete .env Example

.env
# Database
POSTGRES_USER=cl_user
POSTGRES_PASSWORD=your-strong-database-password
POSTGRES_DB=contract_lucidity

# Redis
REDIS_URL=redis://cl-redis:6379/0

# Authentication
JWT_SECRET_KEY=your-64-character-random-secret-here
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=60
JWT_REFRESH_TOKEN_EXPIRE_DAYS=7

# Application
APP_ENV=production
LOG_LEVEL=INFO
MAX_UPLOAD_SIZE_MB=100

# CORS / URLs
CORS_ORIGINS=https://contracts.yourcompany.com
FRONTEND_URL=https://contracts.yourcompany.com
BACKEND_INTERNAL_URL=http://cl-backend:8000

# Admin
DEFAULT_ADMIN_EMAIL=[email protected]
DEFAULT_ADMIN_PASSWORD=initial-strong-password

# Worker
CELERY_CONCURRENCY=4
warning

Never commit .env files to version control. Add .env to your .gitignore.