-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.env.example
More file actions
151 lines (143 loc) · 8.49 KB
/
Copy path.env.example
File metadata and controls
151 lines (143 loc) · 8.49 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
# Acta Diurna - environment configuration
# Quick start: cp .env.example .env && docker compose up -d
# The defaults below boot a working local instance; change the two
# CHANGE-ME values before exposing the instance to anyone.
# --- PostgreSQL (compose-managed database) ------------------------------------
POSTGRES_USER=acta
# CHANGE-ME: database password. Any strong value; only the containers see it.
POSTGRES_PASSWORD=change-me-db-password
POSTGRES_DB=acta_diurna
# DATABASE_URL is assembled by docker-compose.yml from the POSTGRES_* values.
# Set it only when running the app outside compose (local dev, external DB):
# DATABASE_URL=postgresql://acta:change-me-db-password@localhost:5432/acta_diurna
# --- Application ---------------------------------------------------------------
# Runtime mode: development | test | production. docker-compose.yml sets this to
# production for you, so leave it UNSET on the compose path. It only matters for a
# non-compose run (`node build` directly): production refuses an http:// ORIGIN
# off loopback (cookies must be Secure) and forbids LOG_LEVEL=debug. Default
# development.
# NODE_ENV=production
# Public URL readers use to reach this instance (scheme + host [+ port]).
# Behind a reverse proxy, set it to the proxy's public URL (https://...).
ORIGIN=http://localhost:3000
# Host port the app is published on (container always listens on 3000).
PORT=3000
# CHANGE-ME: session signing secret, minimum 32 characters.
# Generate one with: openssl rand -hex 32
SESSION_SECRET=insecure-dev-only-secret-change-me-0123456789
# pino log level: fatal | error | warn | info | debug | trace
LOG_LEVEL=info
# Max connections in the PostgreSQL pool. OPTIONAL, default 10, bounded 1-100.
# The default fits a single author plus light reader traffic; raise it when the
# reader realm carries concurrent load, keeping it below the database's
# max_connections minus headroom for migrations and maintenance.
# DB_POOL_MAX=10
# Filesystem directory for uploaded data-set files. docker-compose.yml sets this
# to /data/uploads on the `uploads` named volume (persisted across restarts), so
# leave it UNSET on the compose path. Set it only for a non-compose run; it must
# point at a writable, persisted directory. OPTIONAL, default data/uploads.
# UPLOADS_DIR=/data/uploads
# Reader session lifetime in DAYS for magic-link readers. OPTIONAL: leave UNSET
# (the default) for NO reader-session expiry - the share's own expiry/revocation
# governs access, re-checked on every load. Set a number of days to force reader
# sessions to age out after that long. The author session is a fixed 7 days.
# READER_SESSION_TTL=30
# Retention grace in DAYS for an UNBOUND uploaded data set before the periodic
# purge deletes its row and its file. OPTIONAL, default 30. An unbound data set
# is a legitimate transient state (it can precede or outlive a report), so this
# window separates a fresh upload from a truly-abandoned orphan.
# DATA_SET_ORPHAN_RETENTION_DAYS=30
# Retention window in DAYS for the reader access-audit trail (who opened which of
# your reports, when - the "Access audit" view). OPTIONAL with NO default: leave
# it UNSET to KEEP the audit history indefinitely (the conservative choice). Set a
# number of days to have the purge sweep delete access records older than that
# (GDPR data minimization - bound how long reader-access history lives).
# ACCESS_RECORD_RETENTION_DAYS=365
# Period in MINUTES of the background purge sweep (spent verification tokens +
# orphaned data sets + aged access records). OPTIONAL, default 60. The sweep never
# runs under tests.
# PURGE_INTERVAL_MINUTES=60
# Max request body the app accepts, in bytes (transport cap, read by the Node
# adapter). Default 50 MB, aligned with the data-upload limit so the app's own
# 413 fires instead of a generic transport error. Raise only alongside the cap.
BODY_SIZE_LIMIT=52428800
# --- Reverse proxy (optional: docker compose --profile proxy) ------------------
# The bundled Caddy proxy terminates TLS (automatic HTTPS) and strips inbound
# X-Forwarded-For. To use it, set the three values below, then run:
# docker compose --profile proxy up -d --build
# Public hostname Caddy serves and provisions a certificate for.
# CADDY_DOMAIN=reports.example.com
# Header carrying the real client IP. Leave EMPTY for a directly-exposed app (it
# then trusts the socket peer). Set to x-forwarded-for ONLY behind a proxy that
# strips inbound XFF, like the bundled Caddy profile.
# ADDRESS_HEADER=x-forwarded-for
# When using the proxy, also set ORIGIN to the public https URL above:
# ORIGIN=https://reports.example.com
# --- SMTP (reader magic links - used from Epic 3) -----------------------------
# Authenticated relay for delivering magic links. The block is optional: the app
# boots without it so you can configure the relay later, then confirm delivery
# from Settings -> "Send test email". If you set ANY SMTP_* value, you must set
# SMTP_HOST, SMTP_PORT and SMTP_FROM (a half-configured relay fails fast at boot).
# Boot validates the shape only; an unreachable relay is reported at send time,
# never at startup.
SMTP_HOST=
# 587 for STARTTLS, 465 for implicit TLS, 25 for plaintext.
SMTP_PORT=
SMTP_USER=
# CHANGE-ME: relay password. Never logged; redacted everywhere.
SMTP_PASSWORD=
# Sender address shown to readers, e.g. reports@example.com.
SMTP_FROM=
# Optional: friendly sender name shown to recipients (e.g. "Acta Diurna").
# Unset = the bare SMTP_FROM address is used.
SMTP_FROM_NAME=
# Transport security: starttls (upgrade on 587) | tls (implicit on 465) | none.
# For a bare internal smarthost on port 25 with no credentials, set none and
# leave SMTP_USER / SMTP_PASSWORD empty (no auth, no STARTTLS is attempted).
SMTP_TLS_MODE=starttls
# --- Identity / multi-author mode (Epic 8) ------------------------------------
# The operating mode is chosen by SMTP above, an ops decision, not a web action:
# SMTP unset -> SINGLE mode: one password author (AUTHOR_PASSWORD_HASH),
# unverified consultation-token reader shares (today's
# behaviour). The two vars below are IGNORED.
# SMTP set -> MULTI mode: authors sign in by email magic link within
# AUTHOR_EMAIL_DOMAIN (the password login is disabled), and
# reader shares are verified by magic link.
# In MULTI mode the two vars below are REQUIRED and validated fail-fast at boot
# (a missing or out-of-domain value refuses to boot, so SMTP can never silently
# lock everyone out - there is no password fallback in multi mode).
# The bare email domain authors sign in with, e.g. example.com (REQUIRED when SMTP is set).
AUTHOR_EMAIL_DOMAIN=
# The email that inherits all existing reports on the first multi-mode boot; it
# MUST be within AUTHOR_EMAIL_DOMAIN, e.g. owner@example.com (REQUIRED when SMTP is set).
INITIAL_OWNER_EMAIL=
# Optional multi-mode reader allow-list: comma-separated destination domain
# patterns, e.g. *.example.com,partner.org. Empty -> any verified reader email
# may read (subject to the per-share recipient list).
READER_EMAIL_DOMAINS=
# --- AI generation (optional LLM endpoint - used from Epic 5) ------------------
# OpenAI-compatible Chat Completions endpoint for AI-assisted report generation.
# The block is optional: the app boots without it and generation simply stays
# unavailable. Point LLM_BASE_URL at any OpenAI-compatible base - the OpenAI API,
# a local runtime (Ollama, llama.cpp), or an Anthropic-compatible proxy. There is
# NO default cloud endpoint: the connector talks ONLY to the URL you set here
# (no phone-home). If you set ANY LLM_* value, you must set LLM_BASE_URL and
# LLM_MODEL (a half-configured endpoint fails fast at boot). Boot validates the
# shape only; an unreachable endpoint is reported at generation time.
LLM_BASE_URL=
# Bearer key for the endpoint. OPTIONAL - leave empty for an unauthenticated
# local endpoint. Never logged; redacted everywhere.
LLM_API_KEY=
# Model id passed to the endpoint, e.g. gpt-4o-mini or a local model name.
LLM_MODEL=
# SECOND gate, separate from the config above: configuration ALONE never enables
# an outbound call. Set this to true to consciously opt in. The connector makes a
# call only when the endpoint is configured AND this is true.
AI_GENERATION_ENABLED=false
# --- Author authentication ---------------------------------------------------
# argon2id PHC hash of the author password (never the password itself).
# Generate it with:
# pnpm auth:hash -- <your-password>
# Keep the single quotes: the hash contains `$` characters that docker compose
# would otherwise try to interpolate.
AUTHOR_PASSWORD_HASH=''