-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy path.env.example
More file actions
147 lines (128 loc) · 9.28 KB
/
Copy path.env.example
File metadata and controls
147 lines (128 loc) · 9.28 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
# Copy to .env and fill in for a real deployment: cp .env.example .env
# docker compose reads .env automatically. NEVER commit a real .env.
# Dev defaults (in docker-compose.yml) work without any of these set.
# --- Database (Postgres) ---
POSTGRES_USER=bim
POSTGRES_PASSWORD=change-me-strong-password # REQUIRED in prod
POSTGRES_DB=bim
# --- Object storage (MinIO / S3) ---
S3_ACCESS_KEY=change-me # REQUIRED in prod (also the MinIO root user)
S3_SECRET_KEY=change-me-strong-secret # REQUIRED in prod
S3_BUCKET=aec-bim
# --- Auth / access control ---
AEC_RBAC=1 # 1 = enforce project roles (set 1 in prod; default 0 is open)
AEC_API_KEY=change-me-long-random-token # bearer token treated as admin; set a strong value in prod
# Generate a strong secret, e.g.: openssl rand -hex 32 (or: python -c "import secrets;print(secrets.token_hex(32))")
AEC_AUTH_SECRET=change-me-long-random-secret # signs login bearer tokens; REQUIRED in prod (else tokens are forgeable)
AEC_REQUIRE_SECRET=1 # refuse to start if AEC_AUTH_SECRET is unset (fail-closed)
AEC_ADMIN_EMAILS= # comma-separated platform admins (Settings/audit/user mgmt)
# --- Transport / browser hardening (set when served over HTTPS, e.g. behind the Caddy overlay) ---
AEC_HSTS=1 # emit Strict-Transport-Security (HTTPS only)
AEC_COOKIE_SECURE=1 # force Secure flag on the auth cookie (auto-on over HTTPS)
AEC_CSP=1 # 1 = strict resource Content-Security-Policy (or supply a full policy)
AEC_SIGNED_URL_TTL=3600 # lifetime (s) of signed model.frag / attachment download URLs
# AEC_METRICS_AUTH=1 # require the AEC_API_KEY bearer on /metrics — set this when the
# # Prometheus scrape endpoint is reachable from an untrusted network.
# # Default OFF = /metrics stays open (unchanged for existing scrapers).
# --- Abuse limits ---
AEC_MAX_UPLOAD_MB=1024 # reject request bodies larger than this (-> 413)
AEC_RATE_LIMIT_RPM=600 # per-IP requests/min (0 = off); needs AEC_REDIS_URL for multi-worker
AEC_LOGIN_MAX_FAILS=8 # lock a username out after this many failed logins...
AEC_LOGIN_WINDOW_SEC=300 # ...within this sliding window (-> 429)
# AEC_TRUST_XUSER stays UNSET in prod — the X-User header is a dev-only impersonation shim.
# --- Container resource limits (opt-in) — feed the commented-out `deploy.resources.limits` blocks in
# docker-compose.yml / docker-compose.prod.yml. OFF by default: a hard memory cap that is too low will
# OOM-kill a legitimate large-IFC conversion mid-run. Uncomment the matching compose block AND set a
# value here that is sized for YOUR host, then leave generous headroom.
# - Converter is the memory-hungry one: IFC→Fragments holds the whole model in RAM, so size it well
# above your largest model. If you run conversions in parallel, multiply by AEC_PUBLISH_WORKERS
# (PR #70) — each concurrent job holds its own model.
# - The API also does in-process reconverts and runs UVICORN_WORKERS (default 4); keep it generous.
# AEC_API_MEM_LIMIT=4g # api container memory cap
# AEC_API_CPUS=2 # api container CPU cap (cores)
# AEC_CONVERTER_MEM_LIMIT=8g # converter cap — >= largest model * concurrent jobs (AEC_PUBLISH_WORKERS)
# AEC_CONVERTER_CPUS=4 # converter CPU cap (cores)
# AEC_PG_MEM_LIMIT=2g # postgres cap
# AEC_MINIO_MEM_LIMIT=1g # minio cap
# AEC_WEB_MEM_LIMIT=256m # web (nginx static) cap
# --- Redis (optional, for multi-worker) — shares rate-limit + login-lockout counters across workers ---
# AEC_REDIS_URL=redis://redis:6379/0
# --- Outbound webhooks (optional) — POST a JSON event to these URLs on module transitions
# (Power Automate / Zapier / Teams / a custom listener). Comma-separated; fail-open (a broken
# endpoint never blocks the transition). Also settable in Settings.
# AEC_WEBHOOK_URLS=https://prod-00.westus.logic.azure.com/workflows/...
# Sign each delivery: X-Massing-Signature: sha256=HMAC(secret, "<X-Massing-Event-Timestamp>." + body).
# Set a strong random value so a receiver can verify authenticity + reject replays.
# AEC_WEBHOOK_SECRET=
# Delivery is retried with exponential backoff: AEC_WEBHOOK_RETRIES (default 3),
# AEC_WEBHOOK_RETRY_BASE seconds (default 0.5). Recent attempts: GET /webhooks/deliveries (admin).
# --- AI assists (optional) — plain-English "Ask the model", Draft RFI, BOQ from text.
# Without a key these degrade gracefully (Ask returns the model data snapshot).
# ANTHROPIC_API_KEY=sk-ant-...
# --- Email digests (optional) ---
# Unset AEC_SMTP_HOST → digests are a logged no-op. Set these to send per-member work-queue
# digests (POST /projects/{pid}/notifications/digest). Recipients come from each user's email.
# AEC_SMTP_HOST=smtp.example.com
# AEC_SMTP_PORT=587
# AEC_SMTP_USER=
# AEC_SMTP_PASSWORD=
# AEC_SMTP_FROM=no-reply@example.com
# AEC_SMTP_TLS=1 # 1 = STARTTLS (default), 0 = plain
# --- SSO / OAuth (optional) ---
# Set a provider's CLIENT_ID + CLIENT_SECRET to show its "Continue with …" button on sign-in.
# Register the OAuth app with each provider; redirect URI = <your-host>/api/auth/oauth/<provider>/callback
# AEC_OAUTH_GOOGLE_CLIENT_ID=
# AEC_OAUTH_GOOGLE_CLIENT_SECRET=
# AEC_OAUTH_MICROSOFT_CLIENT_ID=
# AEC_OAUTH_MICROSOFT_CLIENT_SECRET=
# AEC_OAUTH_MICROSOFT_TENANT=common # or your Entra tenant id
# AEC_OAUTH_PROCORE_CLIENT_ID=
# AEC_OAUTH_PROCORE_CLIENT_SECRET=
# AEC_APP_URL=/ # where the callback redirects after sign-in
# --- SAML 2.0 SSO (optional) ---
# Set all three IdP values to enable a "Continue with SSO" button (posts to /auth/saml/login).
# Register our SP with the IdP: entityID = AEC_SAML_SP_ENTITY_ID (default "massing"),
# ACS URL = <your-host>/api/auth/saml/acs (POST binding). SP metadata: GET /api/auth/saml/metadata.
# The IdP signing cert pins verification — paste the PEM or the bare base64 body.
# AEC_SAML_IDP_ENTITY_ID=
# AEC_SAML_IDP_SSO_URL=
# AEC_SAML_IDP_CERT=
# AEC_SAML_SP_ENTITY_ID=massing
# AEC_SAML_ACS_URL= # override only if behind a proxy (else auto-derived)
# --- SCIM 2.0 provisioning (optional) ---
# Set a strong random token to enable automated user provisioning from an IdP (Okta, Azure AD/Entra,
# OneLogin, JumpCloud). Configure the IdP's SCIM connector with base URL <your-host>/api/scim/v2 and
# this value as the bearer token. Unset = the whole /scim/v2 surface returns 503 (disabled).
# AEC_SCIM_TOKEN=
# --- Error alerting (optional) — Sentry / GlitchTip ---
# The DB error_log records what broke but alarms no one. Set a DSN to page on-call on production 500s
# (dedup + release tracking). Server-side only; UNSET = no-op (nothing initializes, no network). Sentry
# and self-hosted GlitchTip both take the same DSN-style value. After setting the DSN, create alert
# rules in your Sentry/GlitchTip project. Error reporting only — tracing stays off by default.
# AEC_SENTRY_DSN=https://<key>@o0.ingest.sentry.io/0 # or your GlitchTip DSN; SENTRY_DSN also honored
# AEC_SENTRY_ENVIRONMENT=production # defaults to AEC_ENV
# AEC_SENTRY_RELEASE=massing@0.1.0 # optional; tags events with a release for regressions
# AEC_SENTRY_TRACES_SAMPLE_RATE=0 # keep 0 — performance tracing is a separate concern
# --- Distributed tracing (optional) — OpenTelemetry (traces only) ---
# Request-id + JSON logs tell you a request was slow/failed but not WHERE across API → Postgres →
# MinIO → converter. Set an OTLP/HTTP endpoint to export the end-to-end span tree. Server-side only;
# UNSET = no-op (no provider, no exporter, no network). Point it at any OTLP collector — Jaeger,
# Grafana Tempo and Datadog all accept OTLP/HTTP. Sentry (above) stays error alerting; OTel owns tracing.
# OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 # OTLP/HTTP base; traces POST to /v1/traces
# AEC_OTEL_TRACES_SAMPLE_RATE=0.1 # fraction of root traces sampled; set 1.0 to debug an incident
# AEC_OTEL_SERVICE_NAME=massing-api # span service.name; defaults to AEC_ENV, else massing-api
# --- CORS ---
# Only needed if a browser calls the API cross-origin. In the bundled stack the web
# app uses nginx's same-origin /api proxy, so this can stay at the dev default.
AEC_CORS_ORIGINS=http://localhost:5173
# --- Ports ---
WEB_PORT=8080 # host port for the web app (nginx)
# --- Optional: Autodesk APS bridge (paid) for .rvt -> .ifc conversion ---
APS_CLIENT_ID=
APS_CLIENT_SECRET=
# --- Optional: real-estate listing syndication bridge (WPRealWise / MLS) ---
# The RESO export (GET /projects/{pid}/listings/{lid}/reso) always works. Set these to PUSH a
# listing into WPRealWise (or an MLS RESO Web API) from the Disposition tab. Off unless both set.
# REALWISE_URL=https://realwise.example.com
# REALWISE_API_KEY=
# RE_SYNDICATION_TARGET=wprealwise # wprealwise (implemented) | mls