SCANNER_URLfail-closed | URL of the separate METAQUANTICS scanner backend that powers the RECON toolkit. | The RECON features answer 503. |
SCANNER_KEYfail-closedsecret | Key for the scanner backend (must equal the backend METAQUANTICS_KEY). | The RECON features answer 503. |
CLOUDFLARE_API_TOKENfail-closedsecret | Cloudflare Radar token for the Internet Outages and Attack Origins map layers. | /api/cloudflare-radar answers 503 and both layer toggles stay hidden. |
ETHERSCAN_API_KEYsecret | Deepens chain intel with internal transactions and richer Ethereum data. | The baseline stays keyless through Blockscout. |
HELIUS_API_KEYsecret | Parsed Solana transfers for chain intel. | Solana transfer amounts and counterparties stay blank (the public RPC lists signatures only). |
FIRMS_API_KEYsecretreserved | Reserved for the per-area NASA FIRMS API. | No effect: the app uses the keyless FIRMS CSV. |
OPENSKY_CLIENT_IDsecret | OpenSky OAuth2 client id, for higher rate limits on /api/flights. | Flights use the keyless feeds. |
OPENSKY_CLIENT_SECRETsecret | OpenSky OAuth2 client secret (pairs with OPENSKY_CLIENT_ID). | Flights use the keyless feeds. |
FAA_NOTAM_CLIENT_IDsecret | Client id of the FAA NOTAM API (free signup at api.faa.gov). With the pair FAA_NOTAM_CLIENT_ID and FAA_NOTAM_CLIENT_SECRET, /api/airspace/spectrum counts GNSS-interference NOTAMs per country; sent only in a header to external-api.faa.gov and never logged. | The GNSS NOTAM column of the airspace spectrum panel reads "source not configured yet" (fontes.notam = no-key) and the FAA is never queried. |
FAA_NOTAM_CLIENT_SECRETsecret | Client secret of the FAA NOTAM API (pairs with FAA_NOTAM_CLIENT_ID); sent only in a header to external-api.faa.gov and never logged. | With either variable missing the NOTAM source stays off (no-key), without calling the FAA. |
N2YO_API_KEYsecretreserved | Reserved for satellite pass predictions. | No effect: the current code does not read it. |
AIS_API_KEYfail-closedsecret | aisstream.io key for live vessel positions (/api/maritime). | The maritime route has no AIS data and answers with a clear error. |
COMTRADE_API_KEYfail-closedsecret | UN Comtrade subscription key (annual imports by HS2 chapter for the geoeconomy engine). Sent only in the Ocp-Apim-Subscription-Key header by the seed-comtrade job. | The job fetches nothing (skipped: no-key) and every country x chapter pair stays missing; no value is ever shown as 0. |
EIA_API_KEYsecret | U.S. EIA API v2 key (free). Enables the daily spot prices of WTI, Brent and Henry Hub in /api/markets; sent only in the query string of api.eia.gov calls and never logged. | Oil and gas fall back to the monthly IMF primary commodity prices on DBnomics, labeled monthly (never presented as daily). |
DATAJUD_API_KEYfail-closedsecret | Public DataJud API key, published by the CNJ on the DataJud wiki (copy the current value; the CNJ may rotate it). Enables /api/osint/br/datajud (case header by CNJ number); sent only in the Authorization header of api-publica.datajud.cnj.jus.br calls and never logged. The API terms allow non-commercial use only. | /api/osint/br/datajud answers 200 with an empty list and motivo no-key, without calling the CNJ (also when the CNJ rejects the key). |
GEOECONOMY_ENABLEDfail-closed | Exact value 1 turns on geoeconomics: /api/geoeconomia (all pairs), /api/geoeconomia/vulnerabilidade, POST /api/geoeconomia/cenario, the v1 operation geoeconomia.vulnerabilidade and the Geoeconomics tab of the Analyst. It needs the UN Comtrade snapshot (COMTRADE_API_KEY and the seed-comtrade job). | The routes /api/geoeconomia/vulnerabilidade and /cenario answer 404 and read nothing; /api/geoeconomia answers 200 with estado unmonitored (reason flag) and no number; the v1 operation answers not monitored; the Analyst tab shows COMING SOON with the reason. |
GEMINI_API_KEY_1secret | Google Gemini key for /api/ai/analyze, /api/ai/briefing and /api/ai/overview (numbered, several are rotated). | /api/ai/analyze and /api/ai/briefing answer NO AI (deterministic synthesis of the same feeds); /api/ai/overview answers with its heuristic analyst (200, never 503). Keys sent by the browser are never accepted. |
GEMINI_API_KEY_2secret | Additional Gemini key #2, rotated with GEMINI_API_KEY_1 to spread the quota of the AI endpoints. | Optional: without it the rotation uses only the other configured keys. |
GEMINI_API_KEY_3secret | Additional Gemini key #3, rotated with GEMINI_API_KEY_1 to spread the quota of the AI endpoints. | Optional: without it the rotation uses only the other configured keys. |
GEMINI_API_KEY_4secret | Additional Gemini key #4, rotated with GEMINI_API_KEY_1 to spread the quota of the AI endpoints. | Optional: without it the rotation uses only the other configured keys. |
GEMINI_API_KEY_5secret | Additional Gemini key #5, rotated with GEMINI_API_KEY_1 to spread the quota of the AI endpoints. | Optional: without it the rotation uses only the other configured keys. |
GEMINI_API_KEY_6secret | Additional Gemini key #6, rotated with GEMINI_API_KEY_1 to spread the quota of the AI endpoints. | Optional: without it the rotation uses only the other configured keys. |
GEMINI_API_KEY_7secret | Additional Gemini key #7, rotated with GEMINI_API_KEY_1 to spread the quota of the AI endpoints. | Optional: without it the rotation uses only the other configured keys. |
GEMINI_API_KEY_8secret | Additional Gemini key #8, rotated with GEMINI_API_KEY_1 to spread the quota of the AI endpoints. | Optional: without it the rotation uses only the other configured keys. |
OLLAMA_BASE_URLreserved | Reserved: base URL of a self-hosted local model server, an owner option for sensitive data (OSINT text) that today goes to no AI provider. | No effect: the current code does not read it; sensitive data keeps answering NO AI · sensitive data. |
SDK_INGEST_KEYfail-closedsecret | Shared secret for POST /api/sdk/ingest. | The endpoint is disabled. |
GITHUB_WEBHOOK_SECRETfail-closedsecret | HMAC secret that verifies GitHub webhook payloads. | /api/github-webhook is disabled. |
GITHUB_WEBHOOK_FORWARD_URLfail-closed | URL that verified GitHub payloads are forwarded to (required together with the secret). | /api/github-webhook is disabled. |
INTEL_URL | Entity resolution backend for /api/entity/expand. | Entity expansion has no backend. |
UMAMI_URL | Base URL of the Umami analytics server (page views go to <URL>/api/send). Needs UMAMI_WEBSITE_ID too. | Analytics are simply absent (no request is made). |
SENTRY_DSNsecret | DSN that turns on Sentry error reporting (@sentry/nextjs, loaded only when set, no tracing). Also receives the consecutive-failure alerts of the seed jobs. | Sentry stays off; failure alerts go to the server log ([ops]). |
OPS_FAILURE_THRESHOLD | Number of consecutive failures of a seed job that triggers one alert (default 3). It alerts once on crossing and again only after a success resets the streak. | Default 3 is used; invalid values count as unset. |
UMAMI_WEBSITE_ID | Umami analytics site id. | Analytics are simply absent. |
METAQUANTICS_PORT | Host port the web UI is published on (the container always listens on 3000). | Port 3000. |
METAQUANTICS_TELEGRAM_CHANNELSreserved | Documented in .env.example as the channel list for the Telegram OSINT layer. | No effect: the current code does not read it. |
NODE_ENV | Runtime mode. Already set by the Docker image; it also decides production-only protections. | Next sets it by command (development or production). |
PORT | Port the server listens on inside the container (already set by the image). | 3000. |
HOSTNAME | Interface the server binds to (already set by the image). | The image default (0.0.0.0). |
MQ_DEMO | Loads synthetic demo data (src/server/demo-seed.ts) when set to 1. | The Gold store starts empty. |
MQ_DATABASE_URLsecret | Postgres connection for connector overrides, boards, health history, the durable audit trail, and the shared cache and shared rate counter across instances (migration 0009). | Overrides and boards live in the browser localStorage and there is no health history. Cache and rate counter stay in each instance's memory (they work, but are not shared). In production the admin routes answer 503 audit_store_required. |
RATE_KEY_SECRETsecret | HMAC secret that pseudonymises the client IP in the shared rate counter (Postgres): only the truncated hash reaches the database. At least 32 characters. | The shared Postgres counter is not used, even with MQ_DATABASE_URL: the rate limit applies per instance, with a random per-process salt. |
METAQUANTICS_TRUSTED_PROXYfail-closed | Declares the reverse proxy whose headers carry the client IP for rate limiting: `vercel` (x-vercel-forwarded-for, x-real-ip, rightmost X-Forwarded-For), `cloudflare` (cf-connecting-ip) or `hops:N` (the N-th X-Forwarded-For entry from the right; nginx/ALB in front of the app: `hops:1`). `none` trusts no header. | On Vercel (VERCEL=1) the Vercel profile applies; anywhere else no forwarded header is trusted and every anonymous caller shares one rate-limit bucket (stricter, never looser). Self-hosting behind nginx: set hops:1. Cloudflare in front of Vercel: set cloudflare. An invalid value counts as none and logs one warning. Outside Vercel, set none or hops:N explicitly: `vercel env pull` writes VERCEL="1" to .env.local, and a local or self-hosted run with that env would trust client-written headers. With VERCEL=1 outside a Vercel deployment (VERCEL_ENV other than production/preview), the server logs a warning. |
CONNECTORS_CRON_SECRETfail-closedsecret | Bearer secret for the health sampler POST /api/connectors/health/sample, called by pg_cron or a scheduler. | The sampler stays disabled. |
JOBS_CRON_SECRETfail-closedsecret | Bearer secret for the pre-aggregation jobs POST /api/jobs/run?job=<id> (seed-sec, seed-celestrak, housekeeping), called by pg_cron + pg_net or an external scheduler. At least 32 characters. Jobs only write with MQ_DATABASE_URL. | The jobs route answers 503 (fails closed), unless CRON_SECRET exists; a value shorter than 32 characters counts as unset. |
CRON_SECRETfail-closedsecret | Alias of JOBS_CRON_SECRET for schedulers that already use this name: applies only when JOBS_CRON_SECRET is unset. It is the secret Vercel Cron sends (Authorization: Bearer, GET /api/jobs/run, scheduled by vercel.json). | Nothing changes if JOBS_CRON_SECRET exists; without both, the jobs route answers 503. |
MQ_PROBE_ORIGIN | Origin used by the connector health probe (server configuration only, never the request Host). | Defaults to https://$VERCEL_URL on Vercel, otherwise http://127.0.0.1:$PORT. |
CONNECTORS_ADMIN_SECRETfail-closedsecret | Bearer secret (32 characters or more) for the connector admin routes: test, import, share and audit. | In production those routes answer 503. Only the development server lets them through. |
METAQUANTICS_MASTER_ADMIN_EMAILfail-closed | Email of the master admin, the app’s only password login (/login). | Without it sign-in returns 503 and the Connectors and Docs menus stay hidden for everyone. |
METAQUANTICS_MASTER_ADMIN_PASSWORD_HASHfail-closedsecret | scrypt hash of the master admin password, generated by scripts/hash-master-password.mjs (the plain password never goes into the environment). | Without it sign-in returns 503. |
METAQUANTICS_SESSION_SECRETfail-closedsecret | Secret (32 characters or more) that signs the master admin session cookie. | Without it, or with fewer than 32 characters, sign-in returns 503. |
CONNECTORS_DEV_BYPASSfail-closed | Development shortcut: lets the admin routes run without a bearer on loopback. | No shortcut. It never applies in production. |
CONNECTORS_PUBLIC_REGISTRYfail-closed | Publishes the registry and health routes (and the pages that read them) in production. | In production they answer 403 registry_private, unless an admin bearer is sent. |
METAQUANTICS_COMMERCIAL | Commercial-use lock: npm run license-gate fails on sources not cleared for commercial use, and the public API v1 and the MCP tools remove data from sources the gate would fail (registry YAML) or, without a YAML, with an undocumented license (reported in omitidos_por_licenca). | The gate only reports; sources not cleared for commercial use do not fail it, the public API v1 serves every source with its license listed in _meta, and the MCP tools list each source with its license in the result (IMF PortWatch never reaches agents). |
SEC_EDGAR_USER_AGENTfail-closed | Identifying User-Agent (name and e-mail) that the SEC requires for /api/sec-edgar. | The route answers 503 and does not query the SEC; the seed-sec job is skipped (no-key), not counted as a failure, and the SEC rejects generic User-Agents so there is no default value. |
RADAR_ENABLE_NONCOMMERCIALfail-closed | Turns on non-commercial sources (OONI, CC BY-NC-SA 4.0; EPA RadNet radiation monitors, whose commercial reuse is not confirmed; IMF PortWatch daily chokepoint transits, commercial reuse only with IMF permission). It also picks the memo variant read by the first-paint bootstrap (/api/bootstrap, chokepoints). | /api/ooni-censorship and /api/portwatch answer 200 with disabled: true and fetch nothing; the OONI signal stays out of the score. /api/radiation omits EPA RadNet (omitted: license, shown as OMITTED BY LICENSE) and keeps Safecast. The seed-portwatch job fetches nothing and the chokepoint flow component is NOT MONITORED (OMITTED BY LICENSE). |
ALERT_CHANNELS_ENABLEDfail-closed | With the exact value 1 and MQ_DATABASE_URL, turns on server-side alert channels (Web Push and webhook delivered with the tab closed; migration 0012). The server stores only the sha256 of the device token, no e-mail and no IP. | External channels stay COMING SOON: /api/alerts/channels/* and /api/alerts/publish answer 200 with disabled: true and the reason (flag-off or postgres-inactive), and nothing is stored; the alert-dispatch job evaluates and sends nothing. In-app and browser channels keep working. |
VAPID_PUBLIC_KEYfail-closed | Public VAPID key (P-256, base64url) the browser uses to subscribe to Web Push. Generated locally by the owner (node scripts/gen-vapid.mjs). | The Push channel stays COMING SOON (vapid-missing); webhook and local channels are unchanged. |
VAPID_PRIVATE_KEYfail-closedsecret | Private VAPID key that signs the ES256 JWT of every Web Push send. Secret: never leaves in a response, log or /api/status. | No push is sent; the Push channel stays COMING SOON (vapid-missing). |
VAPID_SUBJECTfail-closed | Sender contact required by push services (mailto: or the operator https URL), sent in the VAPID JWT. | No push is sent; the Push channel stays COMING SOON (vapid-missing). |
PUBLIC_API_ENABLEDfail-closed | With the exact value 1, turns on the public data API v1 (13 read-only operations, /api/v1/openapi.json and admin key issuance at /api/connectors/admin/api-keys; migration 0013). Keys are issued by the admin, stored only as sha256 and shown once; 60 requests/min per key. The five Gold routes (search, events, layers, entities/[id], entities/[id]/timeline) require the same flag and a key with scope `dados`. | Every new /api/v1 route, the OpenAPI document and key issuance answer 404 without reading any source or the database. The five Gold /api/v1 routes (search, events, layers, entities/[id] and entities/[id]/timeline) answer 404 too (Wave 10 · W0 change: they used to be anonymous). |
MCP_ENABLEDfail-closed | With the exact value 1, turns on the MCP server at POST /api/mcp (JSON-RPC 2.0, protocol 2025-06-18, no SSE): 16 read-only tools over the public API v1 operations. initialize and tools/list answer without a key; tools/call needs a public API key (or an OAuth access token when MCP_OAUTH_SECRET is set) and spends its daily quota (500 units). | /api/mcp answers 404 without reading any source, the database or the rate counter. |
MCP_OAUTH_SECRETfail-closedsecret | Secret (at least 32 bytes) that turns on OAuth 2.1 with PKCE S256 for the MCP server, without a database: it signs the client ids, codes and tokens (access mqat_ 1 h, refresh mqrt_ 30 days, rotated on every use). MCP clients then discover the flow from the 401 (WWW-Authenticate with resource_metadata). Requires METAQUANTICS_APP_URL, the OAuth origin. Changing the value revokes every token. | OAuth is off: /.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server, /api/oauth/* and /oauth/authorize answer 404, the MCP 401 carries no WWW-Authenticate and tools/call accepts only osk_ API keys. |
EMBED_ENABLEDfail-closed | With the exact value 1, turns on the read-only map embed at /embed/mapa (layers, window and bbox from the URL; no toolbar, drawing or filters). With METAQUANTICS_COMMERCIAL=1 layers from non-commercial or pending-review sources are never rendered and the footer lists them as omitted by license. | /embed/mapa answers 404 and renders nothing. |
EMBED_FRAME_ANCESTORSfail-closed | Comma-separated list of origins (https://host[:port], no wildcard, path or http:) allowed to frame the embed routes, sent as Content-Security-Policy: frame-ancestors. Only the embed routes relax X-Frame-Options; every other route stays SAMEORIGIN. Read at build time: the value goes into the headers manifest, so changing it needs a new build (or deploy). | Empty or only invalid entries: frame-ancestors is just the own origin, so no third-party site can embed the map. |
EVENT_MEMORY_ENABLEDfail-closed | With the exact value 1 and MQ_DATABASE_URL, turns on the event memory (migration 0014): the event-memory job, once a day, stores the items of 8 public feeds (earthquakes, conflicts, weather, cyber threats, health notices, tropical cyclones, tsunami bulletins and GDACS disaster alerts; never sanctions) and the coverage of each day. It keeps only a short title, source, country, point, severity, instant and link; 180-day retention. | The event-memory job answers skipped (flag or no-db) without fetching any source or storing anything; the event memory stays without coverage (never "0 events"). |
EVENT_MEMORY_EMBEDDINGSreserved | Reserved (D-3): embeddings of the events in the memory (the vector(384) column of migration 0014 stays null until there is a provider). | No effect: the current code does not read it; "similar events" uses only text, distance and country. |
FORECASTS_ENABLEDfail-closed | With the exact value 1 and MQ_DATABASE_URL, turns on the auditable forecasts (migration 0015): the forecasts job, once a day, resolves the forecasts whose deadline has passed against the same source (USGS earthquakes, CISA KEV) and publishes new ones with the base rate over 104 past weekly windows. A template with fewer than 30 windows publishes nothing; a source that does not answer never resolves a forecast as "did not happen". | The forecasts job answers skipped (flag or no-db) without fetching any source or storing anything; there are no forecasts and no score. |
NEXT_PUBLIC_METAQUANTICS_BUILD | Build version of the service worker, fixed at build time: it goes in the /sw.js query and names the worker cache, so each value starts a clean cache. | The build uses the Vercel commit, else the local git commit (plus the build time when the tree has uncommitted changes), else the build time (Docker builds have no .git: pass it as --build-arg). |
METAQUANTICS_CCTV_SNAPSHOT | Path of the camera catalogue saved on disk; off disables the snapshot. | Uses .cache/cctv-catalog.json. |
METAQUANTICS_NOMINATIM_CACHE | Path of the Nominatim geocoder cache; off disables it. | Uses .cache/nominatim.json. |
METAQUANTICS_NOMINATIM_GAP_MS | Minimum gap in ms between Nominatim requests; in production values below 1000 are raised to 1000. | 2000 ms between requests. |
METAQUANTICS_LEGACY_UNSAFEfail-closed | Set to on to re-enable the quarantined legacy modules (docs/legacy-removal.md). | The quarantined routes answer 410. |
METAQUANTICS_USER_AGENT | User-Agent used by lookups made through src/lib/stealthFetch.ts. | A built-in browser User-Agent. |
RESEND_API_KEYfail-closedsecret | Resend API key for transactional email (account approved, invite, password reset) and the daily health-report job alert to the master admin. Needs METAQUANTICS_MAIL_FROM too. | No email is sent; the master admin panel shows the invite/reset link to copy and send by other means. |
METAQUANTICS_MAIL_FROMfail-closed | Sender of the transactional emails, on a domain verified in Resend. | No email is sent (same as without RESEND_API_KEY). |
METAQUANTICS_APP_URL | Public base URL of the links sent by email (invite, password reset, approval). Also the OAuth origin of the MCP server (issuer, resource and token audience): REQUIRED when MCP_OAUTH_SECRET is set. | In development the request origin is used; in production no link is built (the request host can be forged). |
TELEGRAM_BOT_TOKENfail-closedsecret | Telegram bot token (@BotFather) that sends the Telegram channel alerts. Also needs TELEGRAM_WEBHOOK_SECRET, TELEGRAM_BOT_USERNAME and ALERT_CHANNELS_ENABLED=1. It only goes into the send URL; never into logs or responses. | The Telegram channel stays COMING SOON (telegram-missing); nothing is sent. |
TELEGRAM_WEBHOOK_SECRETfail-closedsecret | Secret ([A-Za-z0-9_-], 1 to 256 characters) that Telegram echoes in the X-Telegram-Bot-Api-Secret-Token header of the webhook; compared in constant time. | The /api/alerts/telegram/webhook endpoint answers 503 (with the flag on) and the Telegram channel stays COMING SOON. |
TELEGRAM_BOT_USERNAMEfail-closed | Bot @username (without @), used to build the t.me link that confirms the channel with /start. | The Telegram channel stays COMING SOON: without the username there is no confirmation link. |
METAQUANTICS_SECRETS_KEYfail-closedsecret | Vault key of the master admin panel (/admin/chaves): encrypts the keys and secrets set or rotated in the panel. | The Keys and secrets menu is read-only; secrets come only from the environment. |
SUPABASE_URLfail-closed | Supabase project URL (https://<ref>.supabase.co) used by the catalog Bronze: allowed raw copies in Storage, private bucket bronze. Needs SUPABASE_SERVICE_ROLE_KEY too. | The catalog-harvest job harvests the catalog as usual but keeps no raw copy in the Bronze. |
SUPABASE_SERVICE_ROLE_KEYfail-closedsecret | Supabase service_role key, used only on the server to write to the private Storage bucket bronze. Never sent to the browser or logged. | No raw copy in the Bronze (same as without SUPABASE_URL). |