-
Notifications
You must be signed in to change notification settings - Fork 1
Configuration and 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 -dflowchart 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
| 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) |
| 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 |
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 |
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 |
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 |
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 |
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 |
Source: mobile/.env.example
| Variable | Purpose | Required |
|---|---|---|
API_URL |
Backend API URL | Yes |
FLAVOR |
Build flavor (e.g., stage, production) |
Yes |
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 |
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.
The main PostgreSQL instance hosts multiple schemas:
-
Default schema --
secondlayeruser, main application tables (users, sessions, documents, billing, etc.) -
radaschema --rada_mcpuser, parliament data (deputies, bills, laws, voting)
-
OpenReyestr --
openreyestruser, state register data (legal entities, beneficiaries, debtors) -
HUDOC (local only) --
hudocuser, European Court of Human Rights bulk data
Production uses PgBouncer in transaction mode between the application and PostgreSQL:
MAX_CLIENT_CONN=500DEFAULT_POOL_SIZE=50- Auth:
scram-sha-256
The backend connects to pgbouncer-prod:5432, which proxies to postgres-prod:5432.
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-lrueviction - Prod:
maxmemory 2048mb,volatile-lrueviction
| 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 |
-
.envfiles 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
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 |
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.
| 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 |
| 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 |
To get the local environment running, you need at minimum:
- Copy
deployment/.env.exampletodeployment/.env.local - Set
OPENAI_API_KEY(required for embeddings and analysis) - Set
POSTGRES_PASSWORD(or use the defaultlocal_dev_password) - Optionally set
VOYAGEAI_API_KEYfor multilingual embeddings - Optionally set
AWS_ACCESS_KEY_ID+AWS_SECRET_ACCESS_KEYfor Bedrock LLM - 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)