You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/architecture.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -66,6 +66,8 @@ Routing policy:
66
66
67
67
- Greetings and other social turns normally resolve directly.
68
68
- Weak or empty RAG context does not automatically trigger web search.
69
+
- Missing pre-retrieved RAG context does not mean resources are absent; explicit requests about uploaded documents route to `answer_from_rag`, then retrieval runs.
70
+
- Custom-agent routing receives the agent name, description, and linked/attached resource counts so short domain questions can still select `answer_from_rag` and retain citations.
69
71
- Web search is selected for external, fresh, or otherwise web-dependent information.
70
72
- A URL in the message or history is available context, not an automatic fetch instruction.
71
73
- Direct URL fetching happens only when inspecting the resource is necessary.
Copy file name to clipboardExpand all lines: docs/billing.md
+6-2Lines changed: 6 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ Cortex uses Stripe Hosted Checkout, signed webhooks, and the customer portal for
4
4
5
5
## Configuration
6
6
7
-
Required variables:
7
+
Required local-development variables:
8
8
9
9
-`STRIPE_SECRET_KEY`
10
10
-`STRIPE_WEBHOOK_SECRET`
@@ -13,6 +13,11 @@ Required variables:
13
13
-`STRIPE_CANCEL_URL`
14
14
-`STRIPE_PORTAL_RETURN_URL`
15
15
16
+
In production, Cloud Run uses one `BILLING_CONFIG_JSON` Secret Manager value containing
17
+
`stripe_secret_key`, `stripe_webhook_secret`, and `stripe_pro_price_id`; the three redirect
18
+
URLs remain ordinary environment variables. This keeps the Stripe credentials within one
19
+
active secret version.
20
+
16
21
Store production secret values in Google Secret Manager. See [Production configuration](env-vars-production.md).
17
22
18
23
## Webhook setup
@@ -46,4 +51,3 @@ flowchart LR
46
51
```
47
52
48
53
Webhook events are the authoritative source for subscription state. The backend verifies the Stripe signature before updating `user_subscriptions`; research and chat quota guards then read the synchronized subscription and usage state.
Copy file name to clipboardExpand all lines: docs/deployment.md
+13-1Lines changed: 13 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -116,6 +116,19 @@ Registered functions:
116
116
-`research-run` — triggered by `research/run.requested`
117
117
-`outbox-dispatcher` — scheduled every two minutes
118
118
119
+
After syncing the functions, enable the production failure and missing-dispatcher email alerts described in [Production monitoring](observability.md#inngest-alert-activation).
120
+
121
+
## Alerting activation
122
+
123
+
Provision or refresh the Cloud Monitoring baseline after the backend service exists:
The script configures the `/health` uptime check, 5xx burst policy, runtime/probe log alert, and email notification channel. Verify the email channel and send a test notification before treating the alarms as operational.
131
+
119
132
## Supabase migrations
120
133
121
134
The production workflow applies migrations automatically. For manual maintenance:
@@ -130,4 +143,3 @@ npx supabase db push
130
143
Every pull request and push to `main` builds the production container. CI scans the repository and image with Trivy, blocking HIGH or CRITICAL findings that have an available fix as well as serious configuration and secret findings.
131
144
132
145
CI also generates a CycloneDX container SBOM named `cortex-sbom-<commit-sha>` and retains it for 30 days. See [Testing and quality](testing-and-quality.md) for the complete release gates.
Copy file name to clipboardExpand all lines: docs/env-vars-production.md
+27-19Lines changed: 27 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,15 +8,14 @@ All secrets should be stored in **Google Secret Manager** and referenced via `va
8
8
9
9
| Env Var | Secret Manager | Notes |
10
10
|---|---|---|
11
-
|`OPENAI_API_KEY`| yes | Required when `LLM_PROVIDER=openai`|
11
+
|`PROVIDER_CONFIG_JSON`| yes |Secret JSON with provider, Redis, Langfuse, LangSmith, and Sentry settings: `openai_api_key`, `tavily_api_key`, `redis_url`, `langfuse_public_key`, `langfuse_secret_key`, `langfuse_base_url`, `langsmith_api_key`, `langsmith_project`, `langsmith_endpoint`, `langsmith_redaction_mode`, `langsmith_sampling_rate`, `langsmith_tracing`, and `sentry_dsn`. Required when `LLM_PROVIDER=openai`.|
12
12
|`OPENROUTER_API_KEY`| yes | Required when `LLM_PROVIDER=openrouter`|
13
13
|`LLM_PROVIDER`| no |`openai` or `openrouter`|
14
14
|`OPENAI_MODEL`| no | e.g. `gpt-4o-mini`|
15
15
|`ROUTER_TIMEOUT_SECONDS`| no | Maximum duration of each router LLM request; production uses `10.0`|
16
16
|`EMBEDDING_PROVIDER`| no |`openai`|
17
17
|`EMBEDDING_MODEL`| no |`text-embedding-3-small`|
18
18
|`EMBEDDING_DIMENSIONS`| no |`1536`|
19
-
|`TAVILY_API_KEY`| yes ||
20
19
|`ALPHA_VANTAGE_API_KEY`| yes | Required when `ASSET_PRICE_PROVIDER=alphavantage_mcp`|
21
20
|`ASSET_PRICE_PROVIDER`| no |`alphavantage_mcp`|
22
21
|`ALPHA_VANTAGE_MCP_URL`| no | Optional full remote MCP URL override |
@@ -32,12 +31,9 @@ All secrets should be stored in **Google Secret Manager** and referenced via `va
32
31
|`READINESS_REQUIRE_SUPABASE`| no | Set to `true` in production; `/ready` returns `503` if Supabase is missing or unavailable |
33
32
|`READINESS_REQUIRE_NEO4J`| no | Set to `true` in production; `/ready` returns `503` if Neo4j is missing or unavailable |
34
33
|`READINESS_TIMEOUT_SECONDS`| no | Per-dependency probe timeout; defaults to `2.0` seconds |
35
-
|`INNGEST_EVENT_KEY`| yes | From Inngest dashboard → Keys |
36
-
|`INNGEST_SIGNING_KEY`| yes | From Inngest dashboard → Keys. **Must not be empty in prod.**|
37
-
|`REDIS_URL`| yes | Upstash `rediss://` URL |
38
-
|`STRIPE_SECRET_KEY`| yes ||
39
-
|`STRIPE_WEBHOOK_SECRET`| yes | Update Stripe webhook URL to `https://<cloud-run-url>/api/billing/webhook` after first deploy |
40
-
|`STRIPE_PRO_PRICE_ID`| no ||
34
+
|`INNGEST_CONFIG_JSON`| yes | Secret JSON with `inngest_event_key` and `inngest_signing_key` from the Inngest dashboard. |
35
+
|`REDIS_CACHE_TTL_DB_LIST_SECONDS`| no | Cache TTL for DB-heavy list/read-all responses; production uses `30`. `REDIS_URL` is supplied through `PROVIDER_CONFIG_JSON`. |
36
+
|`BILLING_CONFIG_JSON`| yes | Secret JSON with `stripe_secret_key`, `stripe_webhook_secret`, and `stripe_pro_price_id`. This bundles Stripe credentials into one Secret Manager version. |
41
37
|`STRIPE_SUCCESS_URL`| no |`https://<frontend>/billing/success`|
42
38
|`STRIPE_CANCEL_URL`| no |`https://<frontend>/billing/cancel`|
43
39
|`STRIPE_PORTAL_RETURN_URL`| no |`https://<frontend>`|
@@ -49,12 +45,12 @@ All secrets should be stored in **Google Secret Manager** and referenced via `va
|`LANGFUSE_ENABLED`| no | Set to `true` only when both LangFuse keys are configured; otherwise feedback remains stored locally |
48
+
|`LANGFUSE_ENABLED`| no | Production sets this to `true`; Langfuse credentials and base URL are supplied through `PROVIDER_CONFIG_JSON`. |
49
+
|`LANGSMITH_*`| no | LangSmith tracing, API key, project, endpoint, redaction mode, and sampling rate are supplied through `PROVIDER_CONFIG_JSON`. |
55
50
|`LANGFUSE_ENV`| no |`prod`|
56
51
|`LANGFUSE_RELEASE`| no | Git SHA or semver, e.g. `v1.2.3`|
57
-
|`SENTRY_DSN`| yes | Error tracking; unset disables it entirely |
52
+
|`SENTRY_DSN`| no | Local/split-variable fallback. Production stores `sentry_dsn` inside `PROVIDER_CONFIG_JSON`; unset disables Sentry entirely. |
53
+
|`SENTRY_ENVIRONMENT`| no | Sentry issue environment; production deploys set this to `production`|
58
54
|`RATE_LIMIT_DEFAULT`| no | Per-IP request limit, e.g. `60/minute` (default) |
59
55
60
56
### Variables that must NOT be set in production
@@ -91,19 +87,16 @@ PROJECT=cortex-496709
91
87
REGION=your-region
92
88
93
89
secrets=(
94
-
openai-api-key
95
-
tavily-api-key
90
+
provider-config
96
91
cohere-api-key
97
92
neo4j-uri
98
93
neo4j-username
99
94
neo4j-password
100
95
supabase-secret-key
101
96
supabase-jwt-secret
102
-
inngest-event-key
103
-
inngest-signing-key
97
+
inngest-config
104
98
redis-url
105
-
stripe-secret-key
106
-
stripe-webhook-secret
99
+
billing-config
107
100
internal-dispatch-secret
108
101
langfuse-public-key
109
102
langfuse-secret-key
@@ -132,7 +125,22 @@ After the Cloud Run service is deployed:
132
125
3. Set **Serve URL** to `https://<cloud-run-url>/api/inngest`
133
126
4. Confirm **Event Key** and **Signing Key** match what was set in Cloud Run secrets
134
127
5. Click **Sync** — all three functions should appear: `rag-ingestion`, `research-run`, `outbox-dispatcher`
135
-
6. Verify `outbox-dispatcher` shows a cron trigger of `* * * * *`
128
+
6. Verify `outbox-dispatcher` shows a cron trigger of `*/2 * * * *`
129
+
130
+
Configure email alerts for terminal failures in every registered function and for no successful `outbox-dispatcher` run within six minutes. A dispatcher run returning zero events is healthy and must count as successful.
131
+
132
+
## Alerting post-deploy wiring
133
+
134
+
After creating a Sentry Python/FastAPI project, add its DSN as the `sentry_dsn` field in the existing `provider-config` JSON secret. This keeps production at six active Secret Manager versions. Then deploy and configure a Sentry email issue alert for new or regressed production issues with a 30-minute per-issue cooldown.
Verify the email channel and test notification delivery in Cloud Monitoring. The setup script is safe to rerun and updates resources with matching display names.
0 commit comments