-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.env.example
More file actions
152 lines (132 loc) · 8.32 KB
/
.env.example
File metadata and controls
152 lines (132 loc) · 8.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# =============================================================================
# SJMS 2.5 — Environment Variables
# Copy this file to .env and fill in the values
# =============================================================================
# ── Database (PostgreSQL) ────────────────────────────────────────────────────
# NOTE: SJMS application tables live in the `sjms_app` schema, not `public`.
# `public` is reserved for n8n + ChatHub tables; `keycloak` for the identity
# provider. Prisma migrations are applied against `sjms_app`, so the
# DATABASE_URL must pin the schema search path to it. Documented in
# docs/SESSION-HANDOFF-2026-04-10.md and docs/phase-1-verification.md.
#
# Local dev (Docker Compose Postgres):
# DATABASE_URL=postgresql://sjms:changeme@localhost:5432/sjms?schema=sjms_app
# DIRECT_URL=postgresql://sjms:changeme@localhost:5432/sjms?schema=sjms_app
#
# Vercel + Neon production: DATABASE_URL is the POOLED (PGBouncer) endpoint
# and DIRECT_URL is the UNPOOLED endpoint. The schema's `directUrl` property
# routes `prisma migrate deploy` through DIRECT_URL because PGBouncer's
# transaction mode does not carry the session state migrations need. Both
# must include `?sslmode=require&schema=sjms_app`. See docs/VERCEL-RUNBOOK.md
# §4.2 and docs/VERCEL-NEON-FIX-GUIDE.md.
DATABASE_URL=postgresql://sjms:changeme@localhost:5432/sjms?schema=sjms_app
DIRECT_URL=postgresql://sjms:changeme@localhost:5432/sjms?schema=sjms_app
DB_PASSWORD=changeme
# Forces deploy-init.ts to re-seed even when row counts indicate the
# database is populated. Useful for staging refreshes; do not set in
# production. Bool: "true" enables, anything else disables.
# FORCE_SEED=false
# Vercel public-demo bypass. When DEMO_MODE=true, every API request is
# authenticated as a synthetic `demo-admin` with all 36 roles. Required
# while Keycloak is not yet provisioned alongside the server — without
# it, every /api/v1/* call returns 401 and portals appear empty.
# DO NOT enable on an environment that holds real student/staff/financial
# data. The server logs `[DEMO_MODE] Authentication bypass enabled` at
# startup so accidental enablement is visible. See docs/VERCEL-RUNBOOK.md §2.3.
# DEMO_MODE=true
# ── Redis ────────────────────────────────────────────────────────────────────
REDIS_URL=redis://localhost:6379
# ── MinIO (Object Storage) ──────────────────────────────────────────────────
MINIO_ENDPOINT=localhost
MINIO_PORT=9000
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=changeme
MINIO_USE_SSL=false
MINIO_BUCKET=sjms-documents
# ── Keycloak (Identity & Access Management) ─────────────────────────────────
KEYCLOAK_URL=http://localhost:8080
KEYCLOAK_REALM=fhe
KEYCLOAK_CLIENT_ID=sjms-client
KEYCLOAK_CLIENT_SECRET=changeme
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=changeme
# ── n8n (Workflow Automation) ────────────────────────────────────────────────
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=changeme
N8N_HOST=localhost
N8N_PORT=5678
N8N_PROTOCOL=http
WEBHOOK_BASE_URL=http://localhost:5678
# REQUIRED in production/staging — the server throws on startup if missing
# outside development/test. Generate a secure random value, e.g.:
# node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
WEBHOOK_SECRET=changeme-generate-a-random-webhook-secret
# n8n API (used by the provisioning script: npm run provision:workflows)
N8N_API_URL=http://localhost:5678
N8N_API_KEY=changeme-n8n-api-key
# Internal service key used by n8n workflows to call back into the SJMS API.
# Must match the INTERNAL_SERVICE_KEY value set in the server section below.
WORKFLOW_INTERNAL_SECRET=changeme-must-match-INTERNAL_SERVICE_KEY
# ── Server ───────────────────────────────────────────────────────────────────
NODE_ENV=development
PORT=3001
API_BASE_URL=http://localhost:3001
JWT_SECRET=changeme-generate-a-secure-random-string
JWT_EXPIRY=1h
JWT_REFRESH_EXPIRY=7d
# Internal service key for n8n → API auth.
# REQUIRED: docker-compose.yml now fails fast if this is missing.
# Generate a fresh >=64-char value per environment, e.g.:
# node -e "console.log(require('crypto').randomBytes(48).toString('base64url'))"
# Never commit a real value; leave this as a placeholder in .env.example.
INTERNAL_SERVICE_KEY=replace-me-generate-a-64-char-random-string-before-first-run
# ── Client ───────────────────────────────────────────────────────────────────
VITE_API_URL=/api
VITE_KEYCLOAK_URL=http://localhost:8080
VITE_KEYCLOAK_REALM=fhe
VITE_KEYCLOAK_CLIENT_ID=sjms-client
# Client auth mode. Values:
# dev → skip Keycloak entirely, inject a mock admin user.
# Use this when Docker / Keycloak are not running locally.
# keycloak → real Keycloak PKCE flow via keycloak-js.
# Defaults to 'dev' if unset, so a fresh clone boots without needing Keycloak.
# The legacy VITE_AUTH_BYPASS=true is still honoured as an alias for 'dev'.
VITE_AUTH_MODE=dev
# ── UKVI Compliance ─────────────────────────────────────────────────────────
# Number of missed contact points before UKVI breach escalation (default: 3).
# Also configurable at runtime via SystemSetting key: ukvi.attendance.threshold
# UKVI_BREACH_THRESHOLD=3
# ── TLS / SSL ──────────────────────────────────────────────────────────────
# Primary domain for SJMS. Used by nginx server_name and certbot.
# DOMAIN=sjms.futurehorizons.ac.uk
# Let's Encrypt account email (receives expiry warnings).
# Only needed when using Let's Encrypt (TLS_MODE=letsencrypt).
# CERTBOT_EMAIL=it-services@futurehorizons.ac.uk
# TLS certificate mode:
# letsencrypt — automated via certbot (requires port 80 + DNS)
# institutional — manually placed cert/key in docker/nginx/certs/
# self-signed — development only (run scripts/ssl-generate-self-signed.sh)
# TLS_MODE=letsencrypt
# ── Redis (production) ──────────────────────────────────────────────────────
# Required by the production compose overlay (docker/docker-compose.prod.yml)
# REDIS_PASSWORD=changeme-generate-a-secure-password
# ── CORS ────────────────────────────────────────────────────────────────────
# Comma-separated list of allowed origins.
#
# In NODE_ENV=production this is the AUTHORITATIVE allow-list — an empty
# value rejects all CORS preflights (server/src/index.ts:61-78). Set it to
# every public Vercel/CDN domain that fronts the API. Example:
# CORS_ORIGIN=https://sjms-2-5-client.vercel.app,https://sjms.example.ac.uk
#
# Outside production the dev allow-list (Vite dev server on 5173/3001) is
# automatically prepended, so this value augments rather than replaces it.
CORS_ORIGIN=http://localhost:5173
# ── Logging ──────────────────────────────────────────────────────────────────
LOG_LEVEL=debug
LOG_FORMAT=json
# ── SMTP (Email) ─────────────────────────────────────────────────────────────
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=noreply@futurehorizons.ac.uk
SMTP_PASSWORD=changeme
SMTP_FROM=SJMS <noreply@futurehorizons.ac.uk>