Repository navigation
Expand file tree
/
Copy path.env.example
More file actions
295 lines (264 loc) Β· 20.2 KB
/
Copy path.env.example
File metadata and controls
295 lines (264 loc) Β· 20.2 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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
NODE_ENV=development
PORT=4000
DATABASE_URL=postgresql://earnproof:earnproof@localhost:5432/earnproof
REDIS_URL=redis://localhost:6379
# Target for the PostgreSQL integration suite (npm run test:integration).
# Deliberately separate from DATABASE_URL, and refused unless the database name
# contains "test": the harness creates, truncates and drops databases derived
# from this name. The named database is never itself connected to β it supplies
# the prefix for <name>_template and <name>_w<worker>.
# See docs/integration-testing.md.
TEST_DATABASE_URL=postgresql://earnproof:earnproof@localhost:5432/earnproof_test
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# APPLICATION URLS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
APP_URL=http://localhost:3000
API_URL=http://localhost:4000
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# STELLAR NETWORK
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
STELLAR_NETWORK=testnet
STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org
STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
# Ledgers behind the last verified sync checkpoint that a reorganisation may
# reach (held and re-verified on divergence). ~17280 ledgers is one day.
STELLAR_FINALITY_HISTORY_LEDGERS=17280
# Horizon pages one reconciliation read may walk (1-100).
STELLAR_FINALITY_RECONCILIATION_MAX_PAGES=10
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECRETS (REQUIRED, never logged or exposed in error messages)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Must be at least 8 characters. Used for signing session tokens.
SESSION_SECRET=replace_me
# Must be at least 8 characters. Used for verifying credential signatures.
# This is the legacy unversioned form, treated as key version 0 unless
# CREDENTIAL_SIGNING_SECRET_V0 is also set. To rotate the signing key:
# 1. Add CREDENTIAL_SIGNING_SECRET_V1=<new secret> and set
# CREDENTIAL_SIGNING_KEY_VERSION=1 so new credentials sign with it.
# 2. Keep CREDENTIAL_SIGNING_SECRET_V0 configured so credentials already
# issued under it still verify (verify-only).
# 3. Optionally bound the overlap window with an ISO-8601 deadline:
# CREDENTIAL_SIGNING_SECRET_V0_VERIFY_UNTIL=2026-12-31T00:00:00.000Z
# A version past its deadline is refused for verification even though
# it is still loaded.
# 4. To retire V0 for good, remove CREDENTIAL_SIGNING_SECRET_V0 entirely β
# credentials signed under it can no longer be verified.
CREDENTIAL_SIGNING_SECRET=replace_me
# CREDENTIAL_SIGNING_SECRET_V0=replace_me
# CREDENTIAL_SIGNING_SECRET_V1=replace_me
# CREDENTIAL_SIGNING_SECRET_V0_VERIFY_UNTIL=2026-12-31T00:00:00.000Z
# CREDENTIAL_SIGNING_KEY_VERSION=0
# Optional Ed25519 verification-key rotation overlap configuration.
CREDENTIAL_SIGNING_SECRET_PREVIOUS=
CREDENTIAL_SIGNING_KEY_ID=credential-key-0
CREDENTIAL_SIGNING_PREVIOUS_KEY_ID=
CREDENTIAL_SIGNING_KEY_OVERLAP_DAYS=30
# Payment encryption key: 32 bytes as hex (64 chars) or base64
# Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
PAYMENT_ENCRYPTION_KEY=MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# WEBHOOK DELIVERY CONFIGURATION
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Overlap window for webhook signing secret rotation (in minutes).
# When a secret is rotated, the previous secret enters OVERLAP state for this duration.
# During overlap, retries and replays can use the previous key. After expiry, the key
# transitions to RETIRED and is no longer usable.
# Default: 1440 minutes (24 hours). Must be at least 1 minute.
WEBHOOK_SECRET_OVERLAP_WINDOW_MINUTES=1440
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# AUTHENTICATION RATE LIMITING
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Configurable limits to prevent abuse of challenge creation and verification
# Limits are per hashed wallet identifier and hashed client metadata (no raw IP storage)
AUTH_RATE_LIMIT_MAX_CHALLENGE_CREATIONS=10
AUTH_RATE_LIMIT_CHALLENGE_CREATION_WINDOW_MS=900000
AUTH_RATE_LIMIT_MAX_VERIFICATIONS=5
AUTH_RATE_LIMIT_VERIFICATION_WINDOW_MS=900000
# Challenge retention: how long to keep used/expired challenges before cleanup
AUTH_CHALLENGE_RETENTION_DAYS=7
# Auth audit event retention: how long to keep auth audit events
AUTH_AUDIT_RETENTION_DAYS=90
# Cron expressions for cleanup jobs (optional, have sensible defaults)
# Sessions: midnight every day
AUTH_SESSION_CLEANUP_CRON=0 0 * * *
# Challenges: 2 AM every day
AUTH_CHALLENGE_CLEANUP_CRON=0 2 * * *
# Audit: 3 AM every day
AUTH_AUDIT_CLEANUP_CRON=0 3 * * *
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# CONTRACT ANCHORING (Optional feature)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CONTRACT_ANCHORING_ENABLED=false
CONTRACT_ANCHORING_REQUIRED=false
STELLAR_CLI_PATH=stellar
STELLAR_CLI_SOURCE=
PROOF_REGISTRY_CONTRACT_ID=
EARNPROOF_ISSUER_ADDRESS=
EARNPROOF_SCHEMA_VERSION=1
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PROOF EXPIRATION RECONCILIATION (Optional feature)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Runs every 5 minutes to transition expired proofs from ACTIVE to EXPIRED status.
# Improves query performance and dashboard accuracy. Verification logic already
# computes expiration at read time, so this is for operational visibility only.
PROOF_EXPIRATION_RECONCILIATION_ENABLED=false
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# GLOBAL API RATE LIMITING
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# "default" applies to every route not covered by a stricter tier.
# "strict" covers expensive operations (proof creation, payment sync).
# "verification" covers the public proof-verification lookup.
RATE_LIMIT_DEFAULT_TTL_MS=60000
RATE_LIMIT_DEFAULT_LIMIT=100
RATE_LIMIT_STRICT_TTL_MS=60000
RATE_LIMIT_STRICT_LIMIT=10
RATE_LIMIT_VERIFICATION_TTL_MS=60000
RATE_LIMIT_VERIFICATION_LIMIT=30
# Authenticated callers receive this multiplier across every tier above.
RATE_LIMIT_AUTHENTICATED_MULTIPLIER=3
# Proof verification abuse controls. These are separate from the shared
# throttler: unknown identifiers, repeated identifiers, and high-cardinality
# clients use privacy-safe in-memory HMAC buckets.
PROOF_VERIFICATION_ABUSE_WINDOW_MS=900000
PROOF_VERIFICATION_UNKNOWN_LIMIT=10
PROOF_VERIFICATION_REPEATED_LIMIT=60
PROOF_VERIFICATION_DISTINCT_CLIENT_LIMIT=100
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ISSUER REGISTRY (Optional feature)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ISSUER_REGISTRY_ENABLED=false
ISSUER_REGISTRY_CONTRACT_ID=
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# VERIFICATION EVENT PRIVACY CONFIGURATION
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# VERIFICATION_EVENT_RETENTION_DAYS: How long to retain privacy-safe verification events before deletion
# This controls the retention window for aggregate analytics on proof verification outcomes.
# All PII (IP, user agent, credentials) is redacted and replaced with non-identifying metadata hashes.
# Default: 90 days. Must be 1β3650 days.
VERIFICATION_EVENT_RETENTION_DAYS=90
VERIFICATION_METADATA_BUDGET_PER_PROOF=100
VERIFICATION_METADATA_BUDGET_WINDOW_MS=86400000
# Verification Event Hash Salt Rotation
# VERIFICATION_HASH_SALT_VERSION: Versioned salts for hashing verification metadata
# Salt rotates every 30 days (saltVersion = floor(daysSinceEpoch / 30))
# Different versions produce different hashes for same input, reducing long-term linkability
# This field controls which version is active; see also VERIFICATION_HASH_SALT_V* vars
VERIFICATION_HASH_SALT_VERSION=0
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DATA RETENTION (all durations in days, 1β3650 range enforced)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Retention durations in days, per record class. See docs/data-retention.md for
# the full table: purpose, owner, and disposal behaviour for each class.
#
# Every class has a safe default, so leaving these unset never means "keep
# forever". An invalid or out-of-range value causes that class to fail rather
# than silently falling back to the default.
#
# Bounds: minimum 1 day, maximum 3650 days (10 years).
RETENTION_WALLET_CHALLENGE_DAYS=7
RETENTION_AUTH_SESSION_DAYS=30
RETENTION_WEBHOOK_DELIVERY_DAYS=30
RETENTION_AUDIT_LOG_DAYS=365
RETENTION_FAILED_ANCHORING_DAYS=90
# Cleanup schedule. Retention is measured in days, so running more often adds
# database contention without shortening anything.
RETENTION_CLEANUP_CRON=0 3 * * *
# Report what would be removed without deleting anything. Enable after changing
# a retention duration, read the counts, then disable.
RETENTION_DRY_RUN=false
# Proof credentials, revocation evidence, and anchoring state are preserved and
# have no override: they are never swept automatically. See docs/data-retention.md.
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# HEALTH CHECKS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Health probe timeout in milliseconds. Must stay below orchestrator timeout (30s typical).
HEALTH_PROBE_TIMEOUT_MS=2000
# Cache TTL for health probe results (milliseconds)
HEALTH_CACHE_TTL_MS=5000
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# CLOCK SKEW MONITORING (#328) β measures only; never adjusts a clock.
# See docs/clock-skew.md.
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Defaults to true, or false under NODE_ENV=test.
CLOCK_SKEW_MONITOR_ENABLED=
CLOCK_SKEW_INTERVAL_MS=60000
CLOCK_SKEW_WARN_MS=2000
CLOCK_SKEW_CRITICAL_MS=10000
CLOCK_SKEW_SUSTAIN_FOR_MS=300000
# fail_open (default): unknown time health is reported only. fail_closed:
# unknown counts as critical β both sources are Horizon, so this ties
# readiness to Horizon availability.
CLOCK_SKEW_UNKNOWN_POLICY=fail_open
# critical: readiness fails during a sustained critical alert. none: never.
CLOCK_SKEW_READINESS_IMPACT=critical
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# OPERATIONAL METRIC ROLLUPS (#330). See docs/metrics-rollups.md.
# Retention must increase strictly from raw to minute to hour to day.
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
METRICS_ROLLUP_ENABLED=true
METRICS_ROLLUP_LATENESS_GRACE_MS=120000
METRICS_ROLLUP_SETTLE_DELAY_MS=30000
METRICS_ROLLUP_RAW_RETENTION_HOURS=6
METRICS_ROLLUP_MINUTE_RETENTION_DAYS=3
METRICS_ROLLUP_HOUR_RETENTION_DAYS=90
METRICS_ROLLUP_DAY_RETENTION_DAYS=730
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# CONFIGURATION ROLLOUTS (#329). See docs/config-rollouts.md.
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Environment slug recorded on captured snapshots (defaults to NODE_ENV).
DEPLOYMENT_ENVIRONMENT=
# Optional dedicated snapshot signing key (32+ chars). When empty, a
# purpose-bound key is derived from CREDENTIAL_SIGNING_SECRET.
CONFIG_SNAPSHOT_SIGNING_SECRET=
CONFIG_ROLLOUT_REQUIRED_GATE_CHECKS=readiness,error_rate,latency
CONFIG_ROLLOUT_MAX_GATE_EVIDENCE_AGE_MS=900000
CONFIG_ROLLOUT_GATE_VALIDITY_MS=3600000
CONFIG_ROLLOUT_DEFAULT_STAGES=5,25,100
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAYMENT ACCOUNT ROTATION (#321). See docs/payment-account-rotation.md.
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PAYMENT_ACCOUNT_ROTATION_CHALLENGE_TTL_MS=600000
PAYMENT_ACCOUNT_ROTATION_ROLLBACK_WINDOW_MS=86400000
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# RESILIENCE: CIRCUIT BREAKERS (issues #202, #203)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Per-network circuit breaker around Horizon transport calls. Consecutive
# transient failures (429/5xx/timeout/network) open the circuit; validation and
# client errors never do. While open, calls fail fast; after the cool-off a
# bounded probe decides whether to close.
HORIZON_CIRCUIT_FAILURE_THRESHOLD=5
HORIZON_CIRCUIT_OPEN_DURATION_MS=30000
HORIZON_CIRCUIT_HALF_OPEN_MAX_PROBES=1
HORIZON_CIRCUIT_SUCCESS_THRESHOLD=2
# Per-network, per-operation circuit breaker around contract invocation. When a
# circuit is open the anchoring worker stops claiming that operation's intents
# (backpressure) and resumes through a single probe once the cool-off elapses.
# Permanent contract errors are quarantined, not retried, and never open a circuit.
CONTRACT_CIRCUIT_FAILURE_THRESHOLD=5
CONTRACT_CIRCUIT_OPEN_DURATION_MS=60000
CONTRACT_CIRCUIT_HALF_OPEN_MAX_PROBES=1
CONTRACT_CIRCUIT_SUCCESS_THRESHOLD=2
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ORGANIZATION DATA EXPORTS (issue #200)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# AES-256 key (hex or base64, 32 bytes) encrypting export archives at rest.
# Absent means the export worker stays idle rather than writing plaintext.
ORGANIZATION_EXPORT_ENCRYPTION_KEY=
# Directory for staging encrypted archives. Defaults under the OS temp dir.
ORGANIZATION_EXPORT_TEMP_DIR=
# How long an export job and its artifact live before the expiry sweep removes it.
ORGANIZATION_EXPORT_JOB_TTL_HOURS=24
# How long a single-use download handoff token is valid.
ORGANIZATION_EXPORT_DOWNLOAD_TTL_MINUTES=10
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# INTEGRATION TESTING (only used by npm run test:integration)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Whether to keep test databases after tests complete (for debugging)
INTEGRATION_KEEP_DATABASES=false
# Integration test timeout in milliseconds
INTEGRATION_TEST_TIMEOUT_MS=30000
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SEEDING
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Allow demo seed data in non-production environments (used by npm run seed:demo)
ALLOW_SYNTHETIC_SEED=true