-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy path.env.example
More file actions
222 lines (187 loc) · 11.6 KB
/
Copy path.env.example
File metadata and controls
222 lines (187 loc) · 11.6 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
# ── Agent Event Protocol — environment configuration ────────────────────────
#
# Copy this file to .env and fill in the values appropriate for your
# environment. The server reads these variables at startup; no restart is
# needed after changes if you re-run with the updated file.
#
# Sensitive values (tokens, secrets) should NEVER be committed to source
# control. Use a secrets manager or CI/CD secret injection in production.
#
# All variables are optional and have sensible defaults for local development.
# ── Server ───────────────────────────────────────────────────────────────────
# TCP port the HTTP server listens on.
# Default: 8787
PORT=8787
# Node.js environment hint. Set to "production" in deployed environments.
# Must be exactly "production" to enable production behaviour (fail-closed
# auth when DASHBOARD_TOKEN or METRICS_TOKEN is unset); any other value
# ("prod", "staging", …) is treated as development.
# Default: (not set)
NODE_ENV=production
# ── Database ─────────────────────────────────────────────────────────────────
# Which storage backend to use: "sqlite" (default) or "postgres".
# Both implement the same StorageBackend contract, so switching engines needs
# no code changes — only this variable plus the matching connection setting.
# Default: sqlite
STORAGE_BACKEND=sqlite
# [sqlite backend] Absolute or relative path to the SQLite database file.
# The directory is created automatically on first start.
# Default: <project-root>/data/aep.db
DATABASE_PATH=./data/aep.db
# [postgres backend] Postgres connection string. Only used when
# STORAGE_BACKEND=postgres. When unset, the pg driver falls back to the
# standard libpq env vars (PGHOST/PGPORT/PGUSER/PGPASSWORD/PGDATABASE).
# Example: postgres://aep:aep@localhost:5432/aep
# Default: (unset)
DATABASE_URL=
# ── Logging ──────────────────────────────────────────────────────────────────
# Pino log level. One of: trace | debug | info | warn | error | fatal
# Lower levels are more verbose. Use "info" or "warn" in production.
# Default: info
LOG_LEVEL=info
# Set to "true" to enable human-readable pretty-printed log output.
# Requires pino-pretty to be installed (npm install pino-pretty).
# Should NOT be enabled in production (breaks structured log ingestion).
# Default: false
LOG_PRETTY=false
# ── Authentication ───────────────────────────────────────────────────────────
# Token that protects GET /dashboard and all read endpoints when accessed via
# the browser dashboard. Accepted via:
# Authorization: Bearer <token> (API calls)
# ?token=<token> (browser URL — stripped after auth)
#
# If unset the dashboard and read endpoints are open (dev convenience mode) —
# EXCEPT when NODE_ENV=production, where the server fails closed instead:
# the dashboard returns 503 and unauthenticated reads return 401 (API-key
# reads keep working). MUST be set in production.
DASHBOARD_TOKEN=
# Token that protects GET /metrics/prometheus (the Prometheus scrape endpoint).
# Accepted via:
# Authorization: Bearer <token> (Prometheus `authorization` scrape config)
#
# If unset the scrape endpoint is open (dev convenience mode) — EXCEPT when
# NODE_ENV=production, where it returns 503 instead (fail closed). The payload
# is aggregate and tenant-label-free either way. MUST be set in production.
METRICS_TOKEN=
# Token that enables the /admin/* API key management endpoints.
# Accepted via:
# Authorization: Bearer <token>
#
# If unset all /admin/* routes return HTTP 503.
# MUST be set in production.
ADMIN_TOKEN=
# ── Compliance & Audit (Phase 14) ────────────────────────────────────────────
# HMAC secret used to sign and verify tamper-evident audit export bundles
# (`aep audit export` / `aep audit verify`). This is a SERVER-SIDE audit signing
# key, distinct from the per-API-key HMAC secrets used to sign individual events.
# Keep it secret and stable: rotating it invalidates the signatures on previously
# exported bundles.
#
# If unset, audit export/verify fail with a clear error (mirrors how ADMIN_TOKEN
# gates the /admin/* routes). Generate one with: openssl rand -hex 32
# REQUIRED to use the audit suite.
AUDIT_SIGNING_SECRET=
# ── API-key access logs (Phase 14 PR-E) ──────────────────────────────────────
# Opt-in API-key usage audit trail. When truthy (1/true/yes/on), every
# key-authenticated request is recorded (key id, method, path, status, time) and
# is queryable per key via GET /admin/keys/:id/access-log. OFF by default so the
# ingest hot path takes no extra per-request write; enable it for compliance.
# Note: access-log rows are not pruned by the retention job — manage growth at the
# storage layer if you enable this on a high-volume deployment.
ACCESS_LOG_ENABLED=
# ── Data residency (Phase 14 PR-G) ───────────────────────────────────────────
# Declares the region this deployment's storage ACTUALLY resides in: EU | US |
# APAC | global. A project can declare a required region (POST /admin/projects
# { region }); its `regionEnforced` flag is true only when this value satisfies
# it. When set, exported audit bundles also record `data_residency_region` in
# their signed manifest.
#
# IMPORTANT: this is a residency DECLARATION + mismatch signal, NOT storage
# routing — a single AEP deployment writes to one backend. Real multi-region
# routing (separate per-region ingest endpoints/storage) is an infrastructure
# concern outside the application. Leave unset if you don't track residency.
DATA_RESIDENCY_REGION=
# ── Webhooks (Phase 16) ──────────────────────────────────────────────────────
# Webhook TARGET allowlist for self-hosters. Webhook target URLs are SSRF-guarded:
# by default, loopback / private (RFC1918) / link-local / CGNAT / metadata-endpoint
# hosts are REJECTED at registration and re-checked at delivery time. To permit a
# specific private/internal target (e.g. an in-cluster alerting service, or a
# localhost listener in tests), list it here as a comma-separated set of `host` or
# `host:port` entries. An allowlisted host bypasses the private-range block but
# still must use http/https and still cannot carry embedded credentials.
# e.g. WEBHOOK_TARGET_ALLOWLIST=127.0.0.1:9099,alerts.svc.internal
WEBHOOK_TARGET_ALLOWLIST=
# Outbound webhook DELIVERY is OFF by default — a fresh deploy never starts POSTing
# anywhere. Registration (POST /webhooks) still works with delivery disabled; set
# this truthy (1/true/yes/on) to actually deliver matching events. Delivery is
# fire-and-forget off the ingest hot path, with bounded exponential-backoff retries.
WEBHOOKS_ENABLED=
# Delivery tuning (all bounded by hard ceilings in src/webhookDelivery.js):
# WEBHOOK_MAX_RETRIES retries after the first attempt (default 4, max 10)
# WEBHOOK_TIMEOUT_MS per-attempt request timeout (ms) (default 5000, max 30000)
# WEBHOOK_MAX_CONCURRENT max concurrent in-flight deliveries (default 10, max 100)
# WEBHOOK_BACKOFF_BASE_MS exponential backoff base (ms) (default 1000)
# WEBHOOK_BACKOFF_MAX_MS backoff ceiling per wait (ms) (default 30000)
# WEBHOOK_MAX_RETRIES=4
# WEBHOOK_TIMEOUT_MS=5000
# WEBHOOK_MAX_CONCURRENT=10
# WEBHOOK_BACKOFF_BASE_MS=1000
# WEBHOOK_BACKOFF_MAX_MS=30000
# ── Per-event signatures ─────────────────────────────────────────────────────
# The server accepts ONLY payload-covering v2 per-event signatures: a signature
# is accepted iff it carries `canon:"v2"` and verifies against the deep canonical
# form. Legacy v1 (envelope-only) signatures, unmarked signatures, and any
# non-v2 marker are rejected with 401. There is no env to configure this — the
# legacy v1 path, the REQUIRE_CANON_V2 strict-mode flag, and the
# SIGNATURE_V1_SUNSET deprecation-header date were all removed in issue #65
# Phase E. The published SDKs default to v2. See AUTH.md.
# ── Rate Limiting ────────────────────────────────────────────────────────────
# Maximum ingest requests (POST /events) per API key per 60-second window.
# Applies per API key ID; responses include X-RateLimit-* headers.
# Set to 0 to disable rate limiting entirely.
# Default: 300
RATE_LIMIT_RPM=300
# ── Projects / Tiers / Quotas (Phase 13 — Hosted SaaS) ───────────────────────
# A "project" owns ingested data and carries a subscription tier. Each project
# has an event quota (max accepted events; unlimited = no limit) enforced on
# ingest (POST /events → 429 when exceeded) and a retention_days policy (read by
# the PR-D pruning job). A 'default' project (enterprise/unlimited) is seeded so
# existing single-tenant deployments behave exactly as before.
#
# Manage projects via the admin API:
# POST /admin/projects { "tenantId": "...", "tier": "free|team|enterprise" }
# GET /admin/projects
# GET /admin/projects/:id
# Bind a key to a project: POST /admin/keys { "tenantId": "...", "projectId": "..." }
# Toggle quota enforcement. When "false", quotas are recorded but never block
# ingest (useful for staged rollout). Default: true
QUOTA_ENFORCEMENT=true
# How stale the in-memory per-project usage counter may get before a re-count
# against the database (milliseconds). Default: 10000
QUOTA_REFRESH_MS=10000
# Per-tier default event_quota / retention_days. Each value is a non-negative
# integer, or "unlimited" (mapped to no limit). Unset → built-in defaults:
# free: 100000 events, 30-day retention
# team: 5000000 events, 90-day retention
# enterprise: unlimited events, unlimited retention
# Per-project overrides are also accepted in POST /admin/projects.
#
# Retention is enforced by an operator-invoked pruning job (there is no always-on
# scheduler). It deletes events older than each project's retention_days and
# reconciles session summaries. Run it on a schedule (cron / k8s CronJob):
# npm run prune # delete expired events for all projects
# npm run prune -- --dry-run # report what WOULD be deleted, change nothing
# Projects with retention_days unlimited / 0 are kept forever (never pruned).
# It uses the same STORAGE_BACKEND / DATABASE_PATH / DATABASE_URL as the server.
#
# TIER_FREE_EVENT_QUOTA=100000
# TIER_FREE_RETENTION_DAYS=30
# TIER_TEAM_EVENT_QUOTA=5000000
# TIER_TEAM_RETENTION_DAYS=90
# TIER_ENTERPRISE_EVENT_QUOTA=unlimited
# TIER_ENTERPRISE_RETENTION_DAYS=unlimited
# ── Docker / Compose ─────────────────────────────────────────────────────────
# Host port that docker-compose maps to the container's PORT (above).
# Only used by docker-compose.yml.
# Default: 8787
HOST_PORT=8787