Skip to content

Configuration and Environment

overthelex edited this page May 17, 2026 · 3 revisions

Configuration & Environment

The SecondLayer project uses environment variables (.env files), Docker Compose orchestration, and Nginx reverse proxying to manage service connectivity, security credentials, and MCP integrations across local and production environments. There is no staging environment -- only local and prod.

Compose files have no env_file: directives. Secrets are injected via shell env substitution, so you must always pass --env-file explicitly:

# Local
docker compose -f docker-compose.local.yml --env-file .env.local up -d

# Prod
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d

Environment Architecture

flowchart TD
    subgraph Local_Env [Local Development]
        A[Nginx :443] --> B[Backend API :3000]
        A --> V[Vite Frontend :5173]
        B --> C[(PostgreSQL :5432)]
        B --> D[(Redis :6379)]
        B --> E[(Qdrant :6333)]
        B --> F[RADA MCP :3001]
        B --> G[OpenReyestr MCP :3004]
        B --> H[Document Service :3002]
        B --> M[MinIO :9000]
    end

    subgraph Prod_Env [Production]
        N[Nginx :443] --> O[Backend :3000 via PgBouncer]
        N --> P[Frontend static]
        O --> Q[(PostgreSQL :5432)]
        O --> R[(Redis :6379)]
        O --> S[(Qdrant :6333)]
        O --> T[RADA MCP :3001]
        O --> U[OpenReyestr :3005]
        O --> W[Document Service :3002]
    end
Loading

Environment Comparison

Feature Local Prod
URL https://local.legal.org.ua https://legal.org.ua
Backend Port 3000 3000 (behind Nginx)
Database secondlayer_local secondlayer_prod
Connection Pooler Direct PgBouncer (transaction mode)
LLM Strategy bedrock-first bedrock-first
Unified Gateway Yes Yes
Blue-Green Deploy No Yes (via .active-colors)

Port Allocation

Service Local Port Prod Internal Protocol
mcp_backend 3000 3000 HTTP
mcp_rada 3001 3001 HTTP
Document Service 3002 3002 HTTP
mcp_openreyestr 3004 3005 HTTP
Frontend (Vite) 5173 N/A (static) HTTP
PostgreSQL (main) 5432 5438 (host), 5432 (internal) TCP
PostgreSQL (OpenReyestr) 5437 5440 (host), 5432 (internal) TCP
PgBouncer N/A 5439 (host), 5432 (internal) TCP
Redis 6379 6383 (host), 6379 (internal) TCP
Qdrant HTTP 6333 6339 (host), 6333 (internal) HTTP
Qdrant gRPC 6334 6340 (host), 6334 (internal) gRPC
MinIO S3 API 9000 9006 (host), 9000 (internal) HTTP
MinIO Console 9001 9007 (host), 9001 (internal) HTTP
Prometheus 9090 9090 HTTP
Grafana 3100 3100 HTTP
Nextcloud 8888 8890 HTTP

Service-Level Environment Variables

mcp_backend (Primary Backend)

Source: mcp_backend/.env.example

Variable Purpose Required
Database
POSTGRES_HOST PostgreSQL hostname Yes
POSTGRES_PORT PostgreSQL port (default: 5432) Yes
POSTGRES_USER Database user Yes
POSTGRES_PASSWORD Database password Yes
POSTGRES_DB Database name Yes
DATABASE_URL Full connection string (auto-constructed in Docker) No
Application
NODE_ENV development or production Yes
HTTP_PORT Server port (default: 3000) Yes
HTTP_HOST Bind address (default: 0.0.0.0) Yes
LOG_LEVEL Logging verbosity: debug, info, warn, error No
Security
JWT_SECRET Secret for session token signing Yes
SECONDARY_LAYER_KEYS Comma-separated API auth tokens Yes
AI / LLM
OPENAI_API_KEY Primary OpenAI key (embeddings, analysis) Yes
OPENAI_API_KEY2 Optional fallback OpenAI key No
OPENAI_EMBEDDING_MODEL Embedding model name (default: text-embedding-3-small) No
OPENAI_MODEL_QUICK Model for quick/cheap tasks No
OPENAI_MODEL_STANDARD Model for standard tasks No
OPENAI_MODEL_DEEP Model for complex reasoning No
ANTHROPIC_API_KEY Anthropic API key (optional) No
ANTHROPIC_MODEL_QUICK Anthropic quick-tier model No
ANTHROPIC_MODEL_STANDARD Anthropic standard-tier model No
ANTHROPIC_MODEL_DEEP Anthropic deep-tier model No
LLM_PROVIDER_STRATEGY Provider priority: bedrock-first, openai-first, anthropic-first, task-aware No
AWS Bedrock
AWS_ACCESS_KEY_ID AWS credentials for Bedrock Prod
AWS_SECRET_ACCESS_KEY AWS secret key Prod
AWS_REGION AWS region (default: eu-central-1) Prod
BEDROCK_MODEL_QUICK Bedrock quick-tier model ID Prod
BEDROCK_MODEL_STANDARD Bedrock standard-tier model ID Prod
BEDROCK_MODEL_DEEP Bedrock deep-tier model ID Prod
BEDROCK_FALLBACK_MODEL_QUICK Bedrock fallback quick model No
BEDROCK_FALLBACK_MODEL_STANDARD Bedrock fallback standard model No
BEDROCK_FALLBACK_MODEL_DEEP Bedrock fallback deep model No
Embeddings (VoyageAI)
VOYAGEAI_API_KEY VoyageAI key for multilingual embeddings No
VOYAGEAI_API_KEY_2 VoyageAI fallback key No
VOYAGEAI_EMBEDDING_MODEL VoyageAI model (default: voyage-multilingual-2) No
OAuth & WebAuthn
GOOGLE_CLIENT_ID Google OAuth client ID No
GOOGLE_CLIENT_SECRET Google OAuth client secret No
GOOGLE_CALLBACK_URL OAuth callback URL No
WEBAUTHN_RP_ID WebAuthn relying party ID (domain) No
WEBAUTHN_RP_NAME WebAuthn relying party display name No
WEBAUTHN_ORIGIN WebAuthn expected origin URL No
Diia Integration
DIIA_BASE_URL Diia API base URL No
DIIA_ACQUIRER_TOKEN Diia acquirer token No
DIIA_AUTH_ACQUIRER_TOKEN Diia auth acquirer token No
DIIA_BRANCH_ID Diia branch identifier No
DIIA_OFFER_ID Diia offer identifier No
CORS & Frontend
FRONTEND_URL Frontend origin for CORS Yes
ALLOWED_ORIGINS Comma-separated CORS origins Yes
PUBLIC_URL Public callback URL (Monobank webhooks, etc.) Yes
Redis
REDIS_HOST Redis hostname Yes
REDIS_PORT Redis port (default: 6379) Yes
REDIS_PASSWORD Redis password Prod
Qdrant
QDRANT_URL Qdrant HTTP endpoint Yes
QDRANT_API_KEY Qdrant authentication key No
QDRANT_EDRSR_URL Separate Qdrant instance for EDRSR vectors No
QDRANT_EDRSR_API_KEY Key for EDRSR Qdrant instance No
MinIO
MINIO_ENDPOINT MinIO hostname Yes
MINIO_PORT MinIO API port (default: 9000) Yes
MINIO_ACCESS_KEY MinIO access key Yes
MINIO_SECRET_KEY MinIO secret key Yes
MINIO_USE_SSL Enable TLS for MinIO No
MINIO_PUBLIC_URL Public-facing URL for file downloads No
Nextcloud
NEXTCLOUD_URL Nextcloud internal URL No
NEXTCLOUD_USER Nextcloud admin user No
NEXTCLOUD_PASSWORD Nextcloud admin password No
Service Integration
ENABLE_UNIFIED_GATEWAY Enable proxying to RADA/OpenReyestr Yes
RADA_MCP_URL Internal URL of RADA MCP service Yes
RADA_API_KEY API key for RADA service Yes
OPENREYESTR_MCP_URL Internal URL of OpenReyestr service Yes
OPENREYESTR_API_KEY API key for OpenReyestr service Yes
SNEAKYPIPER_API_URL SneakyPiper OSINT proxy URL No
SNEAKYPIPER_API_KEY SneakyPiper API key No
DOCUMENT_SERVICE_URL Document service internal URL No
TERMINAL_SERVICE_URL Terminal service WebSocket URL No
Payments
MONOBANK_API_KEY Monobank acquiring token No
MONOBANK_REDIRECT_URL Redirect after payment No
NOWPAYMENTS_API_KEY NOWPayments crypto gateway key No
NOWPAYMENTS_IPN_SECRET NOWPayments webhook secret No
NOWPAYMENTS_PUBLIC_KEY NOWPayments public key No
Email
SMTP_HOST SMTP server hostname No
SMTP_PORT SMTP port (default: 587) No
SMTP_USER SMTP username No
SMTP_PASS SMTP password No
SMTP_SECURE Enable TLS for SMTP No
EMAIL_FROM Sender email address No
EMAIL_FROM_NAME Sender display name No
Vision/OCR
VISION_CREDENTIALS_PATH Path to Google Cloud Vision credentials JSON No
GOOGLE_APPLICATION_CREDENTIALS Same as above (Google SDK expects this name) No
Bulk Scrape (Prod)
BULK_SCRAPE_SQS_QUEUE_URL AWS SQS queue for bulk scrape jobs No
BULK_SCRAPE_SQS_DLQ_URL SQS dead letter queue URL No
BULK_SCRAPE_S3_BUCKET S3 bucket for scraped documents No
WebRTC (Consultations)
TURN_SERVER_URL TURN server URL for WebRTC No
TURN_SHARED_SECRET TURN server shared secret No
STUN_SERVER_URL STUN server URL No
Monitoring
PROMETHEUS_URL Prometheus endpoint for metrics No
Legacy (deprecated)
ZAKONONLINE_API_TOKEN ZakonOnline court DB (deprecated, removal pending) No
ZAKONONLINE_API_TOKEN2 ZakonOnline fallback token No

mcp_rada (Parliament Data Server)

Source: mcp_rada/.env.example

Variable Purpose Required
POSTGRES_HOST PostgreSQL host Yes
POSTGRES_PORT PostgreSQL port (default: 5433 standalone / 5432 in Docker) Yes
POSTGRES_USER DB user (default: rada_mcp) Yes
POSTGRES_PASSWORD DB password Yes
POSTGRES_DB DB name Yes
POSTGRES_SCHEMA Schema within shared DB (default: rada) Yes
DATABASE_URL Full connection string No
REDIS_HOST Redis host Yes
REDIS_PORT Redis port (default: 6380 standalone / 6379 in Docker) Yes
REDIS_PASSWORD Redis password Prod
OPENAI_API_KEY OpenAI key for AI analysis Yes
OPENAI_API_KEY2 Fallback key No
OPENAI_MODEL_QUICK Quick-tier model No
OPENAI_MODEL_STANDARD Standard-tier model No
OPENAI_MODEL_DEEP Deep-tier model No
ANTHROPIC_API_KEY Anthropic key (optional) No
LLM_PROVIDER_STRATEGY Provider priority strategy No
SECONDLAYER_URL Backend URL for cross-referencing No
SECONDLAYER_API_KEY Backend API key No
RADA_API_KEYS Comma-separated API auth keys Yes
HTTP_PORT Server port (default: 3001) Yes
HTTP_HOST Bind address Yes
LOG_LEVEL Logging level No
NODE_ENV Environment mode Yes
CACHE_TTL_DEPUTIES Deputy cache TTL in seconds (default: 604800 = 7d) No
CACHE_TTL_BILLS Bill cache TTL (default: 86400 = 1d) No
CACHE_TTL_LAWS Law cache TTL (default: 2592000 = 30d) No
CACHE_TTL_VOTING Voting cache TTL (default: 259200 = 3d) No

mcp_openreyestr (State Register Server)

Source: mcp_openreyestr/.env.example

Variable Purpose Required
POSTGRES_HOST PostgreSQL host Yes
POSTGRES_PORT PostgreSQL port (default: 5435 standalone / 5432 in Docker) Yes
POSTGRES_USER DB user (default: openreyestr) Yes
POSTGRES_PASSWORD DB password Yes
POSTGRES_DB DB name (default: openreyestr) Yes
DATABASE_URL Full connection string No
REDIS_HOST Redis host No
REDIS_PORT Redis port (default: 6382 standalone) No
REDIS_PASSWORD Redis password No
HTTP_PORT Server port (default: 3004 standalone / 3005 prod) Yes
HTTP_HOST Bind address Yes
NODE_ENV Environment mode Yes
OPENAI_API_KEY OpenAI key for AI search No
OPENAI_EMBEDDING_MODEL Embedding model No
OPENAI_MODEL_QUICK Quick model No
OPENAI_MODEL_STANDARD Standard model No
OPENAI_MODEL_DEEP Deep model No
ANTHROPIC_API_KEY Anthropic key No
OPENREYESTR_API_KEYS Comma-separated auth keys Yes
SECONDARY_LAYER_KEYS Legacy auth keys (will be deprecated) No
JWT_SECRET JWT signing secret No
SECONDLAYER_URL Backend URL for cross-referencing No
SECONDLAYER_API_KEY Backend API key No
LOG_LEVEL Logging level No

lexwebapp (Frontend)

Source: lexwebapp/.env.example

All frontend variables are prefixed with VITE_ and injected at build time by Vite.

Variable Purpose Required
VITE_API_URL Backend API URL (e.g., https://legal.org.ua) Yes
VITE_API_KEY API auth key (must match SECONDARY_LAYER_KEYS) Yes
VITE_ENABLE_SSE_STREAMING Enable SSE streaming for long ops (default: true) No
VITE_MOCK_PAYMENTS Mock payment gateway for dev (default: true) No
VITE_ENABLE_ALL_MCP_TOOLS Show all MCP tools in UI No
VITE_SHOW_TOOL_SELECTOR Show tool selector in chat No
VITE_ENABLE_THINKING_STEPS Show AI thinking steps No
VITE_AUTO_EXPAND_THINKING Auto-expand thinking panel No

mobile (Flutter App)

Source: mobile/.env.example

Variable Purpose Required
API_URL Backend API URL Yes
FLAVOR Build flavor (e.g., stage, production) Yes

deployment (Docker Compose .env)

Source: deployment/.env.example

This file feeds the Docker Compose orchestration. Key additions beyond per-service vars:

Variable Purpose Required
POSTGRES_SUPERUSER Superuser for DB initialization Local only
POSTGRES_SUPERUSER_PASSWORD Superuser password Local only
RADA_POSTGRES_USER RADA DB user Yes
RADA_POSTGRES_PASSWORD RADA DB password Yes
RADA_POSTGRES_SCHEMA RADA schema name (default: rada) Yes
OPENREYESTR_POSTGRES_USER OpenReyestr DB user Yes
OPENREYESTR_POSTGRES_PASSWORD OpenReyestr DB password Yes
OPENREYESTR_POSTGRES_DB OpenReyestr DB name Yes
GRAFANA_ADMIN_PASSWORD Grafana admin password No
ADMIN_EMAIL Grafana admin email No
ADMIN_USER_EMAIL Seeded admin user email (local) Local only
ADMIN_USER_PASSWORD Seeded admin user password (local) Local only
VITE_API_URL Frontend build-time API URL Yes
HUDOC_POSTGRES_USER HUDOC bulk data DB user No
HUDOC_POSTGRES_PASSWORD HUDOC DB password No
HUDOC_POSTGRES_DB HUDOC DB name No
HUDOC_DATA_PATH Host path for HUDOC PostgreSQL data No
NEXTCLOUD_DB_NAME Nextcloud DB name No
NEXTCLOUD_DB_USER Nextcloud DB user No
NEXTCLOUD_DB_PASSWORD Nextcloud DB password No
QDRANT_API_KEY Qdrant authentication key No
REDIS_PASSWORD Redis authentication password Prod
ADMIN_USERS Comma-separated admin emails (prod seed) No

LLM Provider Strategy

The system uses a tiered model selection approach (ModelSelector in @secondlayer/shared):

Tier Use Case Example Models
quick Simple classification, short answers Claude Haiku, GPT-5-nano, Nova Micro
standard Standard analysis, search queries Claude Sonnet, GPT-5-mini, Nova Pro
deep Complex reasoning, multi-step analysis Claude Sonnet 4.6, GPT-5.1

Provider strategies (set via LLM_PROVIDER_STRATEGY):

  • bedrock-first -- Use AWS Bedrock as primary, fallback to OpenAI/Anthropic direct APIs
  • openai-first -- Use OpenAI API as primary
  • anthropic-first -- Use Anthropic API as primary
  • task-aware -- Dynamic selection based on task type

Production currently uses bedrock-first with Anthropic Claude models on AWS Bedrock (eu-central-1), with OpenAI as embedding provider.

Database Architecture

Shared PostgreSQL Instance (Local & Prod)

The main PostgreSQL instance hosts multiple schemas:

  • Default schema -- secondlayer user, main application tables (users, sessions, documents, billing, etc.)
  • rada schema -- rada_mcp user, parliament data (deputies, bills, laws, voting)

Separate PostgreSQL Instance

  • OpenReyestr -- openreyestr user, state register data (legal entities, beneficiaries, debtors)
  • HUDOC (local only) -- hudoc user, European Court of Human Rights bulk data

Connection Pooling (Prod)

Production uses PgBouncer in transaction mode between the application and PostgreSQL:

  • MAX_CLIENT_CONN=500
  • DEFAULT_POOL_SIZE=50
  • Auth: scram-sha-256

The backend connects to pgbouncer-prod:5432, which proxies to postgres-prod:5432.

Redis Configuration

Redis is used for caching, session storage, and rate limiting. Production enforces authentication and disables dangerous commands (CONFIG, DEBUG, FLUSHDB, FLUSHALL, SLAVEOF, REPLICAOF).

  • Local: maxmemory 512mb, volatile-lru eviction
  • Prod: maxmemory 2048mb, volatile-lru eviction

Credential Management

File Organization

File Environment Git-tracked
mcp_backend/.env.example Template Yes
mcp_rada/.env.example Template Yes
mcp_openreyestr/.env.example Template Yes
lexwebapp/.env.example Template Yes
deployment/.env.example Template Yes
deployment/.env.local Local dev No
deployment/.env.prod Production No
vision-ocr-credentials.json Google Cloud Vision No

Security Rules

  • .env files are excluded from version control via .gitignore
  • API keys use comma-separated lists for multi-key rotation
  • JWT secrets must be changed from defaults in production
  • Redis and Qdrant require authentication in production
  • Google Cloud Vision credentials are bind-mounted into containers

Docker Network Topology

Local Network (secondlayer-local)

All services communicate over a single bridge network. Service discovery uses Docker container names:

Service Container Name Internal Hostname
PostgreSQL (main) secondlayer-postgres-local postgres-local
PostgreSQL (OpenReyestr) openreyestr-postgres-local postgres-openreyestr-local
Redis secondlayer-redis-local redis-local
Qdrant secondlayer-qdrant-local qdrant-local
Backend secondlayer-app-local app-local
RADA MCP rada-mcp-app-local rada-mcp-app-local
OpenReyestr openreyestr-app-local openreyestr-app-local
Document Service document-service-local document-service-local
MinIO minio-local minio-local
Nextcloud nextcloud-local nextcloud-local
Terminal Service terminal-service-local terminal-service-local
Nginx nginx-local nginx-local

Production Network (secondlayer-prod-network)

Same pattern with -prod suffix. Blue-green deployment uses alternate container names (e.g., secondlayer-app-blue, secondlayer-app-green), tracked via deployment/.active-colors.

Monitoring Stack

Service Port Purpose
Prometheus 9090 Metrics collection & alerting rules
Grafana 3100 (maps to 3000 internal) Dashboards & visualization
cAdvisor Internal only Container resource metrics
Redis Exporter 9121 Redis metrics for Prometheus

Feature Flags

Flag Service Purpose
ENABLE_UNIFIED_GATEWAY Backend Proxy RADA/OpenReyestr tools through backend
VITE_ENABLE_SSE_STREAMING Frontend Enable real-time streaming for tool execution
VITE_MOCK_PAYMENTS Frontend Bypass real payment gateway in dev
VITE_ENABLE_ALL_MCP_TOOLS Frontend Show all available MCP tools
VITE_SHOW_TOOL_SELECTOR Frontend Show manual tool selection UI
VITE_ENABLE_THINKING_STEPS Frontend Display AI reasoning steps
MOCK_PAYMENTS Backend (Prod) Set to "false" in production

Quick Start Checklist

To get the local environment running, you need at minimum:

  1. Copy deployment/.env.example to deployment/.env.local
  2. Set OPENAI_API_KEY (required for embeddings and analysis)
  3. Set POSTGRES_PASSWORD (or use the default local_dev_password)
  4. Optionally set VOYAGEAI_API_KEY for multilingual embeddings
  5. Optionally set AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY for Bedrock LLM
  6. Run:
    cd deployment
    docker compose -f docker-compose.local.yml --env-file .env.local up -d

For production, additionally configure:

  • AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY (Bedrock)
  • REDIS_PASSWORD (strong password)
  • QDRANT_API_KEY
  • JWT_SECRET (cryptographically random, 64+ chars)
  • MONOBANK_API_KEY (live payments)
  • SMTP_USER / SMTP_PASS (email delivery)
  • GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET (OAuth)
  • DIIA_ACQUIRER_TOKEN / DIIA_AUTH_ACQUIRER_TOKEN (Diia auth)

Clone this wiki locally