diff --git a/docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md b/docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md index 5c176169..c09b5dd3 100644 --- a/docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md +++ b/docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md @@ -1,14 +1,14 @@ -# BytelystAI — Azure Key Vault & Secrets Rotation +# ByteLyst — Azure Key Vault & Secrets Rotation > **Purpose:** Centralize all secrets in Azure Key Vault and establish a repeatable rotation process. -> **Vault:** `kv-mywisprai` in `rg-mywisprai` (East US) -> **Last updated:** 2026-02-15 +> **Vault:** `kv-mywisprai` in `rg-mywisprai` (East US) — _legacy resource names, not yet renamed_ +> **Last updated:** 2026-03-21 --- ## Overview -All ByteLyst products (LysnrAI, MindLyst, legacy MyWisprAI) share a **single Key Vault**: `kv-mywisprai`. Secrets are prefixed by product. +All ByteLyst products share a **single Key Vault**: `kv-mywisprai` (legacy name). Secrets are prefixed by product (e.g., `lysnr-*`, `mindlyst-*`). ### Goals @@ -25,31 +25,32 @@ All ByteLyst products (LysnrAI, MindLyst, legacy MyWisprAI) share a **single Key ## Current State -| Product | Prefix | Secrets in KV | Status | -|---------|--------|---------------|--------| -| **MindLyst** | `mindlyst-*` | 12 | Fully populated | -| **MyWisprAI** (legacy) | `wispr-*` | 5 | Legacy desktop secrets | -| **LysnrAI** | `lysnr-*` | 13 | ✅ Seeded (2026-02-15) | +| Product | Prefix | Secrets in KV | Status | +| -------------------- | ------------ | ------------- | ------------------------------------------------------------- | +| **LysnrAI** | `lysnr-*` | 13 | ✅ Seeded (2026-02-15) | +| **MindLyst** | `mindlyst-*` | 12 | Fully populated | +| **LysnrAI (legacy)** | `wispr-*` | 5 | Legacy desktop secrets (pre-rebrand, superseded by `lysnr-*`) | -**Total secrets:** 30 (12 MindLyst + 5 MyWisprAI + 13 LysnrAI) +**Total secrets:** 30 (13 LysnrAI + 12 MindLyst + 5 legacy) ### Code Integration Status All components have AKV resolution implemented: -| Component | Integration | File | -|-----------|------------|------| -| platform-service | `resolveKeyVaultSecrets()` at startup | `services/platform-service/src/server.ts` | -| extraction-service | `resolveKeyVaultSecrets()` at startup | `services/extraction-service/src/server.ts` | -| Admin dashboard | Next.js `instrumentation.ts` hook | `admin-dashboard-web/src/instrumentation.ts` | -| User dashboard | Next.js `instrumentation.ts` hook | `user-dashboard-web/src/instrumentation.ts` | -| Tracker dashboard | Next.js `instrumentation.ts` hook | `tracker-dashboard-web/src/instrumentation.ts` | -| Python backend | `SecretResolver` + pydantic `model_validator` | `backend/src/secrets/keyvault.py` | -| Desktop app | `SecretResolver` + pydantic `model_validator` | `src/secrets/keyvault.py` | +| Component | Integration | File | +| ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | +| platform-service | `resolveKeyVaultSecrets()` at startup | `services/platform-service/src/server.ts` | +| extraction-service | `resolveKeyVaultSecrets()` at startup | `services/extraction-service/src/server.ts` | +| Admin dashboard | Next.js `instrumentation.ts` hook | `dashboards/admin-web/src/instrumentation.ts` | +| User dashboard | Next.js `instrumentation.ts` hook | `user-dashboard-web/src/instrumentation.ts` (in LysnrAI repo) | +| Tracker dashboard | Next.js `instrumentation.ts` hook | `dashboards/tracker-web/src/instrumentation.ts` | +| Python backend (LysnrAI) | `SecretResolver` + pydantic `model_validator` | `backend-python/src/secrets/keyvault.py` (in LysnrAI repo) | +| Desktop app (LysnrAI) | `SecretResolver` + pydantic `model_validator` | `src/secrets/keyvault.py` (in LysnrAI repo) | ### Admin Secrets Manager The admin dashboard at **`/ops/secrets`** provides live CRUD access to Key Vault: + - List all secrets with metadata (status, expiry, last updated) - Read secret values (masked, with copy-to-clipboard) - Create new secrets @@ -63,48 +64,38 @@ The admin dashboard at **`/ops/secrets`** provides live CRUD access to Key Vault ### LysnrAI — `lysnr-*` (13 secrets, code in `packages/config/src/keyvault.ts`) -| KV Secret Name | Env Var | Used By | Priority | -|----------------|---------|---------|----------| -| `lysnr-cosmos-key` | `COSMOS_KEY` | All services, dashboards | Critical | -| `lysnr-cosmos-endpoint` | `COSMOS_ENDPOINT` | All services, dashboards | Critical | -| `lysnr-jwt-secret` | `JWT_SECRET` | All services, dashboards | Critical | -| `lysnr-stripe-secret-key` | `STRIPE_SECRET_KEY` | platform-service | Critical | -| `lysnr-stripe-webhook-secret` | `STRIPE_WEBHOOK_SECRET` | platform-service | Critical | -| `lysnr-billing-internal-key` | `BILLING_INTERNAL_KEY` | platform-service | High | -| `lysnr-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | platform-service | Critical | -| `lysnr-blob-account-key` | `AZURE_BLOB_ACCOUNT_KEY` | platform-service | Critical | -| `lysnr-gemini-api-key` | `GEMINI_API_KEY` | extraction-service | Critical | -| `lysnr-seed-secret` | `SEED_SECRET` | admin dashboard | Medium | -| `lysnr-azure-speech-key` | `AZURE_SPEECH_KEY` | desktop, backend | High | -| `lysnr-azure-openai-key` | `AZURE_OPENAI_KEY` | extraction-service | High | -| `lysnr-azure-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | extraction-service | High | +| KV Secret Name | Env Var | Used By | Priority | +| ------------------------------ | ------------------------------ | ------------------------ | -------- | +| `lysnr-cosmos-key` | `COSMOS_KEY` | All services, dashboards | Critical | +| `lysnr-cosmos-endpoint` | `COSMOS_ENDPOINT` | All services, dashboards | Critical | +| `lysnr-jwt-secret` | `JWT_SECRET` | All services, dashboards | Critical | +| `lysnr-stripe-secret-key` | `STRIPE_SECRET_KEY` | platform-service | Critical | +| `lysnr-stripe-webhook-secret` | `STRIPE_WEBHOOK_SECRET` | platform-service | Critical | +| `lysnr-billing-internal-key` | `BILLING_INTERNAL_KEY` | platform-service | High | +| `lysnr-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | platform-service | Critical | +| `lysnr-blob-account-key` | `AZURE_BLOB_ACCOUNT_KEY` | platform-service | Critical | +| `lysnr-gemini-api-key` | `GEMINI_API_KEY` | extraction-service | Critical | +| `lysnr-seed-secret` | `SEED_SECRET` | admin dashboard | Medium | +| `lysnr-azure-speech-key` | `AZURE_SPEECH_KEY` | desktop, backend | High | +| `lysnr-azure-openai-key` | `AZURE_OPENAI_KEY` | extraction-service | High | +| `lysnr-azure-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | extraction-service | High | ### MindLyst — `mindlyst-*` (12 secrets, all populated) -| KV Secret Name | Env Var | Notes | -|----------------|---------|-------| -| `mindlyst-cosmos-endpoint` | `COSMOS_ENDPOINT` | Config | -| `mindlyst-cosmos-key` | `COSMOS_KEY` | Rotate via key1/key2 | -| `mindlyst-cosmos-database` | `COSMOS_DATABASE` | Config (`mindlyst`) | -| `mindlyst-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | Config | -| `mindlyst-openai-key` | `AZURE_OPENAI_KEY` | Rotate via key1/key2 | -| `mindlyst-openai-deployment` | `AZURE_OPENAI_DEPLOYMENT` | Config | -| `mindlyst-openai-api-version` | `AZURE_OPENAI_API_VERSION` | Config | -| `mindlyst-speech-key` | `AZURE_SPEECH_KEY` | Rotate via key1/key2 | -| `mindlyst-speech-region` | `AZURE_SPEECH_REGION` | Config | -| `mindlyst-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | Rotate via key1/key2 | -| `mindlyst-notification-hub-connection-string` | `ANH_CONNECTION_STRING` | Rotate SAS keys | -| `mindlyst-appinsights-connection-string` | `APPLICATIONINSIGHTS_CONNECTION_STRING` | Treat as sensitive | - -### MyWisprAI (legacy) — `wispr-*` (5 secrets) - -| KV Secret Name | Env Var | -|----------------|---------| -| `wispr-azure-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | -| `wispr-azure-openai-key` | `AZURE_OPENAI_KEY` | -| `wispr-azure-openai-deployment` | `AZURE_OPENAI_DEPLOYMENT` | -| `wispr-azure-speech-key` | `AZURE_SPEECH_KEY` | -| `wispr-azure-speech-region` | `AZURE_SPEECH_REGION` | +| KV Secret Name | Env Var | Notes | +| --------------------------------------------- | --------------------------------------- | -------------------- | +| `mindlyst-cosmos-endpoint` | `COSMOS_ENDPOINT` | Config | +| `mindlyst-cosmos-key` | `COSMOS_KEY` | Rotate via key1/key2 | +| `mindlyst-cosmos-database` | `COSMOS_DATABASE` | Config (`mindlyst`) | +| `mindlyst-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | Config | +| `mindlyst-openai-key` | `AZURE_OPENAI_KEY` | Rotate via key1/key2 | +| `mindlyst-openai-deployment` | `AZURE_OPENAI_DEPLOYMENT` | Config | +| `mindlyst-openai-api-version` | `AZURE_OPENAI_API_VERSION` | Config | +| `mindlyst-speech-key` | `AZURE_SPEECH_KEY` | Rotate via key1/key2 | +| `mindlyst-speech-region` | `AZURE_SPEECH_REGION` | Config | +| `mindlyst-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | Rotate via key1/key2 | +| `mindlyst-notification-hub-connection-string` | `ANH_CONNECTION_STRING` | Rotate SAS keys | +| `mindlyst-appinsights-connection-string` | `APPLICATIONINSIGHTS_CONNECTION_STRING` | Treat as sensitive | --- @@ -112,7 +103,7 @@ The admin dashboard at **`/ops/secrets`** provides live CRUD access to Key Vault ### 1. Seed LysnrAI Secrets (BLOCKING) -All 13 `lysnr-*` secrets must be added to `kv-mywisprai`: +All 13 `lysnr-*` secrets must be added to the Key Vault: ```bash # Option A: Use the seed script (reads from .env) @@ -123,17 +114,17 @@ cp .env.example .env # fill in real values # Navigate to /ops/secrets → Add Secret for each # Option C: Use az cli directly -az keyvault secret set --vault-name kv-mywisprai --name lysnr-cosmos-key --value "" -o none +az keyvault secret set --vault-name kv-mywisprai --name lysnr-cosmos-key --value "" -o none # vault name is legacy ``` ### 2. Rotate Leaked Keys (DEFERRED) Secrets have appeared in git history. Rotate after seeding: -- [ ] Cosmos DB keys (`cosmos-mywisprai`) → update `mindlyst-cosmos-key` + `lysnr-cosmos-key` +- [ ] Cosmos DB keys (`cosmos-mywisprai` — legacy name) → update `lysnr-cosmos-key` + `mindlyst-cosmos-key` - [ ] Storage account keys (`bytelystblobs`) → update blob connection strings -- [ ] Azure OpenAI keys (`mywisprai-openai-sweden`) → update OpenAI key secrets -- [ ] Speech keys (`mywisprai-speech`) → update speech key secrets +- [ ] Azure OpenAI keys (`mywisprai-openai-sweden` — legacy name) → update OpenAI key secrets +- [ ] Speech keys (`mywisprai-speech` — legacy name) → update speech key secrets - [ ] Notification Hub SAS keys → update `mindlyst-notification-hub-connection-string` ### 3. Enable KV Diagnostics @@ -200,13 +191,13 @@ Supports key1/key2. ### Recommended Rotation Schedule -| Secret Type | Frequency | Method | -|-------------|-----------|--------| -| Cosmos DB keys | Quarterly | Azure Portal → rotate → update KV | -| JWT secret | Quarterly | Generate new → update KV → rolling deploy | -| Stripe keys | Annually or on breach | Stripe Dashboard → update KV | -| API keys (Gemini, OpenAI) | Annually or on breach | Provider portal → update KV | -| Blob storage keys | Quarterly | Azure Portal → rotate → update KV | +| Secret Type | Frequency | Method | +| ------------------------- | --------------------- | ----------------------------------------- | +| Cosmos DB keys | Quarterly | Azure Portal → rotate → update KV | +| JWT secret | Quarterly | Generate new → update KV → rolling deploy | +| Stripe keys | Annually or on breach | Stripe Dashboard → update KV | +| API keys (Gemini, OpenAI) | Annually or on breach | Provider portal → update KV | +| Blob storage keys | Quarterly | Azure Portal → rotate → update KV | --- @@ -227,13 +218,13 @@ Supports key1/key2. ## Related Files -| File | Purpose | -|------|---------| -| `packages/config/src/keyvault.ts` | `resolveKeyVaultSecrets()` + `LYSNR_SECRETS` constant | -| `scripts/seed-keyvault.sh` | Seed KV from `.env` values | -| `docs/devops/AZURE_RESOURCE_INVENTORY.md` | Complete Azure resource inventory | -| `docs/devops/AZURE_PORTAL_SETUP.md` | Step-by-step provisioning guide | -| `docs/devops/ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md` | Full env var + KV gap analysis | +| File | Purpose | +| --------------------------------------------------------- | ----------------------------------------------------- | +| `packages/config/src/keyvault.ts` | `resolveKeyVaultSecrets()` + `LYSNR_SECRETS` constant | +| `scripts/seed-keyvault.sh` | Seed KV from `.env` values | +| `docs/devops/AZURE_RESOURCE_INVENTORY.md` | Complete Azure resource inventory | +| `docs/devops/AZURE_PORTAL_SETUP.md` | Step-by-step provisioning guide | +| `docs/devops/ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md` | Full env var + KV gap analysis | --- diff --git a/docs/devops/AZURE_PORTAL_SETUP.md b/docs/devops/AZURE_PORTAL_SETUP.md index 9a18be58..158e75a6 100644 --- a/docs/devops/AZURE_PORTAL_SETUP.md +++ b/docs/devops/AZURE_PORTAL_SETUP.md @@ -1,12 +1,14 @@ -# BytelystAI — Azure Portal Setup Guide (Shared Infrastructure) +# ByteLyst — Azure Portal Setup Guide (Shared Infrastructure) > **Purpose:** Step-by-step instructions to provision and manage Azure infrastructure shared between **LysnrAI** and **MindLyst** under a single resource group. > **Architecture:** Single RG, shared stateless services, separate databases. > **Time estimate:** ~20 minutes (most resources already exist from LysnrAI) > **Prerequisites:** An Azure account with an active subscription -> **Last updated:** 2026-02-14 +> **Last updated:** 2026-03-21 > -> **Security note (staging):** This document does **not** include secret values. Store secrets in Azure Key Vault (`kv-mywisprai`) and reference them by name (see **MindLyst Environment Variables** and **Key Vault** sections). Rotation is deferred; see `docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md`. +> **Security note (staging):** This document does **not** include secret values. Store secrets in Azure Key Vault (`kv-mywisprai` — legacy resource name) and reference them by name (see **MindLyst Environment Variables** and **Key Vault** sections). Rotation is deferred; see `docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md`. +> +> **Note on Azure resource names:** Many resources below still carry `mywisprai` in their names (e.g., `cosmos-mywisprai`, `kv-mywisprai`). Azure resources **cannot be renamed** after creation. The old names are purely cosmetic and work correctly. --- @@ -40,8 +42,8 @@ Both LysnrAI and MindLyst share a **single Azure resource group** with shared st rg-mywisprai/ (1 resource group) │ ├── cosmos-mywisprai (1 Cosmos DB account — already exists) -│ ├── mywisprai (database: 10 containers — existing) -│ └── mindlyst (database: 12 containers — MindLyst) +│ ├── mywisprai (database: LysnrAI — legacy name, 10 containers) +│ └── mindlyst (database: MindLyst, 12 containers) │ ├── bytelystblobs (1 Storage account — already exists) │ ├── mindlyst-voice ← NEW @@ -54,8 +56,9 @@ rg-mywisprai/ (1 resource group) ├── mywisprai-speech (1 Speech Service — shared, eastus) │ ├── kv-mywisprai (1 Key Vault — shared) -│ ├── wispr-* (existing secrets) -│ └── mindlyst-* (MindLyst secrets) ← NEW +│ ├── lysnr-* (LysnrAI secrets) +│ ├── wispr-* (LysnrAI legacy secrets, pre-rebrand) +│ └── mindlyst-* (MindLyst secrets) │ ├── lysnnai (1 Notification Hub namespace) │ ├── notificationhub (existing hub) @@ -68,21 +71,21 @@ rg-mywisprai/ (1 resource group) ### Why Share? -| Concern | Answer | -|---------|--------| -| **Cost** | Cosmos DB Serverless charges per-RU, not per-account. One account = one endpoint, one key pair, simpler rotation | -| **Management** | 1 RG to monitor, 1 cost dashboard, 1 health check | -| **Data isolation** | Separate databases within Cosmos = full container-level isolation. Queries can't cross databases | -| **Teardown safety** | Delete the `mindlyst` database → LysnrAI data untouched | -| **Stateless services** | OpenAI & Speech are stateless — same key serves both apps, no data leakage | +| Concern | Answer | +| ---------------------- | ---------------------------------------------------------------------------------------------------------------- | +| **Cost** | Cosmos DB Serverless charges per-RU, not per-account. One account = one endpoint, one key pair, simpler rotation | +| **Management** | 1 RG to monitor, 1 cost dashboard, 1 health check | +| **Data isolation** | Separate databases within Cosmos = full container-level isolation. Queries can't cross databases | +| **Teardown safety** | Delete the `mindlyst` database → LysnrAI data untouched | +| **Stateless services** | OpenAI & Speech are stateless — same key serves both apps, no data leakage | ### What Must Stay Separate -| Resource | Why | -|----------|-----| -| **Notification Hub hubs** | Each app has its own APNs certificate and FCM server key | -| **Stripe accounts** | Different products, pricing tiers, and webhook endpoints (external, not Azure) | -| **Cosmos databases** | Each app gets its own database with its own set of containers | +| Resource | Why | +| ------------------------- | ------------------------------------------------------------------------------ | +| **Notification Hub hubs** | Each app has its own APNs certificate and FCM server key | +| **Stripe accounts** | Different products, pricing tiers, and webhook endpoints (external, not Azure) | +| **Cosmos databases** | Each app gets its own database with its own set of containers | --- @@ -90,20 +93,20 @@ rg-mywisprai/ (1 resource group) These resources are **already provisioned** and will be reused by MindLyst: -| Resource | Azure Name | Region | SKU | Status | -|----------|-----------|--------|-----|--------| -| **Resource Group** | `rg-mywisprai` | `eastus` | — | Exists | -| **Cosmos DB** | `cosmos-mywisprai` | `westus2` | Serverless, NoSQL | Exists — DBs: `mywisprai` (10 containers), `mindlyst` (12 containers) | -| **Blob Storage** | `bytelystblobs` | `westus2` | StorageV2, RAGRS | Exists | -| **Azure OpenAI** | `mywisprai-openai-sweden` | `swedencentral` | S0 | Exists — deployment: `gpt-4o-mini` | -| **Speech Service** | `mywisprai-speech` | `eastus` | F0 | Exists | -| **Key Vault** | `kv-mywisprai` | `eastus` | Standard | Exists | -| **Notification Hub (namespace)** | `lysnnai` | `eastus` | Free | Exists (hubs: `notificationhub`, `mindlyst-hub`) | -| **Application Insights** | `bytelyst-appinsights` | `eastus` | Classic | Exists | +| Resource | Azure Name | Region | SKU | Status | +| -------------------------------- | ------------------------- | --------------- | ----------------- | ------------------------------------------------------------------------------ | +| **Resource Group** | `rg-mywisprai` | `eastus` | — | Exists | +| **Cosmos DB** | `cosmos-mywisprai` | `westus2` | Serverless, NoSQL | Exists — DBs: `mywisprai` (LysnrAI, 10 containers), `mindlyst` (12 containers) | +| **Blob Storage** | `bytelystblobs` | `westus2` | StorageV2, RAGRS | Exists | +| **Azure OpenAI** | `mywisprai-openai-sweden` | `swedencentral` | S0 | Exists — deployment: `gpt-4o-mini` | +| **Speech Service** | `mywisprai-speech` | `eastus` | F0 | Exists | +| **Key Vault** | `kv-mywisprai` | `eastus` | Standard | Exists | +| **Notification Hub (namespace)** | `lysnnai` | `eastus` | Free | Exists (hubs: `notificationhub`, `mindlyst-hub`) | +| **Application Insights** | `bytelyst-appinsights` | `eastus` | Classic | Exists | ### Cosmos DB: Existing LysnrAI database containers (staging) -Database: `mywisprai` (existing) +Database: `mywisprai` (legacy name — this is the LysnrAI database) - `api_tokens` - `audit_log` @@ -137,7 +140,7 @@ MindLyst secrets (canonical): - `mindlyst-notification-hub-connection-string` - `mindlyst-appinsights-connection-string` -LysnrAI secrets (existing): +LysnrAI secrets (legacy `wispr-*` prefix, pre-rebrand — superseded by `lysnr-*`): - `wispr-azure-openai-deployment` - `wispr-azure-openai-endpoint` @@ -157,14 +160,14 @@ az keyvault secret list --vault-name kv-mywisprai --query "[].name" -o tsv Only these additions are needed — no new accounts to create: -| Action | Where | What | -|--------|-------|------| -| **Rename RG (optional)** | Resource Group | Keep `rg-mywisprai` for now. Only move resources if you want a cleaner name. | -| **Add database** | Cosmos DB (`cosmos-mywisprai`) | New database `mindlyst` with 12 containers | -| **Add blob containers** | Blob Storage (`bytelystblobs`) | 3 new containers: `mindlyst-voice`, `mindlyst-images`, `mindlyst-exports` | -| **Add secrets** | Key Vault (`kv-mywisprai`) | 12 secrets with `mindlyst-` prefix (keys + config) | -| **Add hub** | Notification Hub namespace (`lysnnai`) | New hub `mindlyst-hub` | -| **Create App Insights** | New resource | `bytelyst-appinsights` (shared telemetry) | +| Action | Where | What | +| ------------------------ | -------------------------------------- | ---------------------------------------------------------------------------- | +| **Rename RG (optional)** | Resource Group | Keep `rg-mywisprai` for now. Only move resources if you want a cleaner name. | +| **Add database** | Cosmos DB (`cosmos-mywisprai`) | New database `mindlyst` with 12 containers | +| **Add blob containers** | Blob Storage (`bytelystblobs`) | 3 new containers: `mindlyst-voice`, `mindlyst-images`, `mindlyst-exports` | +| **Add secrets** | Key Vault (`kv-mywisprai`) | 12 secrets with `mindlyst-` prefix (keys + config) | +| **Add hub** | Notification Hub namespace (`lysnnai`) | New hub `mindlyst-hub` | +| **Create App Insights** | New resource | `bytelyst-appinsights` (shared telemetry) | ### Current Staging State (Completed) @@ -221,22 +224,23 @@ You should now see both `mywisprai` and `mindlyst` databases in the tree. For each container below, right-click the **`mindlyst`** database (or click the `…` menu) → **New Container**: -| # | Container Name | Partition Key | Purpose | -|---|----------------|--------------|---------| -| 1 | `users` | `/id` | User accounts and profiles | -| 2 | `brains` | `/userId` | User brain configurations (War Room, Home Base, Money Guard, etc.) | -| 3 | `brain_templates` | `/id` | Brain Pack gallery templates | -| 4 | `memory_items` | `/userId` | All captured memories (text, voice, image, link, email) | -| 5 | `actions` | `/memoryItemId` | AI-suggested actions from triage | -| 6 | `entities` | `/memoryItemId` | Extracted entities (people, dates, places, amounts) | -| 7 | `reflections` | `/userId` | Weekly reflection reports and insights | -| 8 | `share_cards` | `/userId` | Generated share cards for social sharing | -| 9 | `daily_briefs` | `/userId` | Morning and evening brief content | -| 10 | `streaks` | `/userId` | Capture streak tracking and gamification | -| 11 | `notification_log` | `/userId` | Push notification delivery log and scheduling | -| 12 | `brain_insights` | `/userId` | Cross-brain insight discoveries | +| # | Container Name | Partition Key | Purpose | +| --- | ------------------ | --------------- | ------------------------------------------------------------------ | +| 1 | `users` | `/id` | User accounts and profiles | +| 2 | `brains` | `/userId` | User brain configurations (War Room, Home Base, Money Guard, etc.) | +| 3 | `brain_templates` | `/id` | Brain Pack gallery templates | +| 4 | `memory_items` | `/userId` | All captured memories (text, voice, image, link, email) | +| 5 | `actions` | `/memoryItemId` | AI-suggested actions from triage | +| 6 | `entities` | `/memoryItemId` | Extracted entities (people, dates, places, amounts) | +| 7 | `reflections` | `/userId` | Weekly reflection reports and insights | +| 8 | `share_cards` | `/userId` | Generated share cards for social sharing | +| 9 | `daily_briefs` | `/userId` | Morning and evening brief content | +| 10 | `streaks` | `/userId` | Capture streak tracking and gamification | +| 11 | `notification_log` | `/userId` | Push notification delivery log and scheduling | +| 12 | `brain_insights` | `/userId` | Cross-brain insight discoveries | **For each container:** + 1. Click **New Container** 2. **Existing Database:** select `mindlyst` (do NOT create a new database) 3. Enter the **Container id** from the table @@ -268,13 +272,14 @@ Cosmos connection details are stored in Key Vault: 2. Go to **Data storage** → **Containers** (left sidebar) 3. Click **+ Container** for each: -| Container Name | Access Level | Purpose | -|----------------|-------------|---------| -| `mindlyst-voice` | **Private** | Voice capture recordings (WAV/PCM from STT pipeline) | -| `mindlyst-images` | **Private** | Captured photos, screenshots, and OCR source images | -| `mindlyst-exports` | **Private** | User data exports (JSON), weekly reflection PDFs | +| Container Name | Access Level | Purpose | +| ------------------ | ------------ | ---------------------------------------------------- | +| `mindlyst-voice` | **Private** | Voice capture recordings (WAV/PCM from STT pipeline) | +| `mindlyst-images` | **Private** | Captured photos, screenshots, and OCR source images | +| `mindlyst-exports` | **Private** | User data exports (JSON), weekly reflection PDFs | For each: + 1. Click **+ Container** 2. Enter the **Name** (must be lowercase, no underscores — use hyphens) 3. **Anonymous access level:** leave as **Private (no anonymous access)** @@ -284,10 +289,10 @@ For each: You should now see these MindLyst containers in `bytelystblobs` (plus any other app containers you already had): -| Container | App | -|-----------|-----| -| `mindlyst-voice` | MindLyst | -| `mindlyst-images` | MindLyst | +| Container | App | +| ------------------ | -------- | +| `mindlyst-voice` | MindLyst | +| `mindlyst-images` | MindLyst | | `mindlyst-exports` | MindLyst | ### Connection details (from Key Vault) @@ -345,20 +350,20 @@ Speech connection details are stored in Key Vault: MindLyst secrets (canonical): -| Key Vault secret name | Env var | Notes | -|---|---|---| -| `mindlyst-cosmos-endpoint` | `COSMOS_ENDPOINT` | Config (ok to store) | -| `mindlyst-cosmos-key` | `COSMOS_KEY` | Secret | -| `mindlyst-cosmos-database` | `COSMOS_DATABASE` | Config (`mindlyst`) | -| `mindlyst-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | Config | -| `mindlyst-openai-key` | `AZURE_OPENAI_KEY` | Secret | -| `mindlyst-openai-deployment` | `AZURE_OPENAI_DEPLOYMENT` | Config | -| `mindlyst-openai-api-version` | `AZURE_OPENAI_API_VERSION` | Config | -| `mindlyst-speech-key` | `AZURE_SPEECH_KEY` | Secret | -| `mindlyst-speech-region` | `AZURE_SPEECH_REGION` | Config | -| `mindlyst-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | Secret (prefer SAS later) | -| `mindlyst-notification-hub-connection-string` | `ANH_CONNECTION_STRING` | Secret | -| `mindlyst-appinsights-connection-string` | `APPLICATIONINSIGHTS_CONNECTION_STRING` | Treat as sensitive | +| Key Vault secret name | Env var | Notes | +| --------------------------------------------- | --------------------------------------- | ------------------------- | +| `mindlyst-cosmos-endpoint` | `COSMOS_ENDPOINT` | Config (ok to store) | +| `mindlyst-cosmos-key` | `COSMOS_KEY` | Secret | +| `mindlyst-cosmos-database` | `COSMOS_DATABASE` | Config (`mindlyst`) | +| `mindlyst-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | Config | +| `mindlyst-openai-key` | `AZURE_OPENAI_KEY` | Secret | +| `mindlyst-openai-deployment` | `AZURE_OPENAI_DEPLOYMENT` | Config | +| `mindlyst-openai-api-version` | `AZURE_OPENAI_API_VERSION` | Config | +| `mindlyst-speech-key` | `AZURE_SPEECH_KEY` | Secret | +| `mindlyst-speech-region` | `AZURE_SPEECH_REGION` | Config | +| `mindlyst-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | Secret (prefer SAS later) | +| `mindlyst-notification-hub-connection-string` | `ANH_CONNECTION_STRING` | Secret | +| `mindlyst-appinsights-connection-string` | `APPLICATIONINSIGHTS_CONNECTION_STRING` | Treat as sensitive | List what’s currently in the vault: @@ -368,13 +373,13 @@ az keyvault secret list --vault-name kv-mywisprai --query "[].name" -o tsv ### Existing LysnrAI secrets (for reference) -| Secret Name | Notes | -|-------------|-------| -| `wispr-azure-openai-deployment` | Existing OpenAI deployment name | -| `wispr-azure-openai-endpoint` | Existing OpenAI endpoint | -| `wispr-azure-openai-key` | Existing OpenAI key | -| `wispr-azure-speech-key` | Existing Speech key | -| `wispr-azure-speech-region` | Existing Speech region | +| Secret Name | Notes | +| ------------------------------- | ---------------------------------------------- | +| `wispr-azure-openai-deployment` | Legacy (pre-rebrand) — superseded by `lysnr-*` | +| `wispr-azure-openai-endpoint` | Legacy (pre-rebrand) | +| `wispr-azure-openai-key` | Legacy (pre-rebrand) | +| `wispr-azure-speech-key` | Legacy (pre-rebrand) | +| `wispr-azure-speech-region` | Legacy (pre-rebrand) | --- @@ -435,6 +440,7 @@ Non-secret config: ### Create (if not exists) Option A: Workspace-based (recommended) + 1. Search **"Application Insights"** → click **Create** 2. Fill in: - **Resource group:** `rg-mywisprai` @@ -460,10 +466,10 @@ In your application code, add a custom property to every trace: ```typescript // MindLyst -telemetryClient.context.tags["ai.cloud.role"] = "mindlyst-web"; +telemetryClient.context.tags['ai.cloud.role'] = 'mindlyst-web'; // LysnrAI -telemetryClient.context.tags["ai.cloud.role"] = "mywisprai-admin"; +telemetryClient.context.tags['ai.cloud.role'] = 'lysnrai-admin'; ``` Then filter in the Azure Portal: **Application Insights → Logs → `where cloud_RoleName == "mindlyst-web"`** @@ -549,16 +555,16 @@ EOF After completing all steps, verify: -| # | Check | How | -|---|-------|-----| -| 1 | **Cosmos DB: `mindlyst` database** | Data Explorer → expand `cosmos-mywisprai` → `mindlyst` → 12 containers visible | -| 2 | **Cosmos DB: `mywisprai` untouched** | Data Explorer → `mywisprai` database still has its existing containers | -| 3 | **Blob: 3 new containers** | Storage → `bytelystblobs` → Containers → `mindlyst-voice`, `mindlyst-images`, `mindlyst-exports` | -| 4 | **Blob: other containers intact (if any)** | Same page → any pre-existing containers should still be present | -| 5 | **OpenAI deployment** | Azure OpenAI Studio → Deployments → `gpt-4o-mini` listed | -| 6 | **Speech Service keys** | Speech resource → Keys and Endpoint → keys visible | -| 7 | **Key Vault: MindLyst secrets** | Key Vault → Secrets → `mindlyst-*` entries visible | -| 8 | **MindLyst web connects** | Run `cd mindlyst-native/web && npm run dev` → triage/brain-chat should use Azure OpenAI (not mock) | +| # | Check | How | +| --- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------- | +| 1 | **Cosmos DB: `mindlyst` database** | Data Explorer → expand `cosmos-mywisprai` → `mindlyst` → 12 containers visible | +| 2 | **Cosmos DB: `mywisprai` (LysnrAI) untouched** | Data Explorer → `mywisprai` database still has its existing containers | +| 3 | **Blob: 3 new containers** | Storage → `bytelystblobs` → Containers → `mindlyst-voice`, `mindlyst-images`, `mindlyst-exports` | +| 4 | **Blob: other containers intact (if any)** | Same page → any pre-existing containers should still be present | +| 5 | **OpenAI deployment** | Azure OpenAI Studio → Deployments → `gpt-4o-mini` listed | +| 6 | **Speech Service keys** | Speech resource → Keys and Endpoint → keys visible | +| 7 | **Key Vault: MindLyst secrets** | Key Vault → Secrets → `mindlyst-*` entries visible | +| 8 | **MindLyst web connects** | Run `cd mindlyst-native/web && npm run dev` → triage/brain-chat should use Azure OpenAI (not mock) | --- @@ -566,16 +572,16 @@ After completing all steps, verify: ### Combined Cost (LysnrAI + MindLyst, MVP / Low Usage) -| Service | Pricing | LysnrAI | MindLyst | Combined | -|---------|---------|---------|----------|----------| -| Cosmos DB (Serverless) | $0.25/M RU + $0.25/GB | ~$2 | ~$2 | ~$4 | -| Blob Storage (LRS) | $0.018/GB | ~$0.10 | ~$0.10 | ~$0.20 | -| Azure OpenAI (GPT-4o-mini) | $0.15/M input + $0.60/M output | ~$5 | ~$5 | ~$10 | -| Speech (F0 free) | 5h STT free | $0 | $0 | $0 | -| Key Vault | $0.03/10K ops | ~$0.03 | ~$0.03 | ~$0.06 | -| App Insights | 5GB/month free | $0 | $0 | $0 | -| Notification Hub (Free) | 1M pushes/month free | $0 | $0 | $0 | -| **Total** | | | | **~$5–15/month** | +| Service | Pricing | LysnrAI | MindLyst | Combined | +| -------------------------- | ------------------------------ | ------- | -------- | ---------------- | +| Cosmos DB (Serverless) | $0.25/M RU + $0.25/GB | ~$2 | ~$2 | ~$4 | +| Blob Storage (LRS) | $0.018/GB | ~$0.10 | ~$0.10 | ~$0.20 | +| Azure OpenAI (GPT-4o-mini) | $0.15/M input + $0.60/M output | ~$5 | ~$5 | ~$10 | +| Speech (F0 free) | 5h STT free | $0 | $0 | $0 | +| Key Vault | $0.03/10K ops | ~$0.03 | ~$0.03 | ~$0.06 | +| App Insights | 5GB/month free | $0 | $0 | $0 | +| Notification Hub (Free) | 1M pushes/month free | $0 | $0 | $0 | +| **Total** | | | | **~$5–15/month** | ### Cost Savings from Sharing @@ -589,16 +595,16 @@ After completing all steps, verify: ## Resource Naming Convention -| Azure Resource | Current Name | Ideal Name | Notes | -|---------------|-------------|------------|-------| -| Resource Group | `rg-mywisprai` | `rg-bytelyst` | Move resources to new RG (Step 1) | -| Cosmos DB Account | `cosmos-mywisprai` | `cosmos-bytelyst` | Can't rename — keep as-is | -| Blob Storage | `bytelystblobs` | `bytelystblobs` | Already brand-neutral | -| Azure OpenAI | `mywisprai-openai-sweden` | — | Can't rename — keep as-is | -| Speech Service | `mywisprai-speech` | — | Can't rename — keep as-is | -| Key Vault | `kv-mywisprai` | `kv-bytelyst` | Can't rename — keep as-is | -| Notification Hub NS | `lysnnai` | `bytelyst-hub-ns` | Consider creating new NS later if desired | -| App Insights | `bytelyst-appinsights` | — | Can recreate if you want workspace-based mode | +| Azure Resource | Current Name | Ideal Name | Notes | +| ------------------- | ------------------------- | ----------------- | --------------------------------------------- | +| Resource Group | `rg-mywisprai` | `rg-bytelyst` | Move resources to new RG (Step 1) | +| Cosmos DB Account | `cosmos-mywisprai` | `cosmos-bytelyst` | Can't rename — keep as-is | +| Blob Storage | `bytelystblobs` | `bytelystblobs` | Already brand-neutral | +| Azure OpenAI | `mywisprai-openai-sweden` | — | Can't rename — keep as-is | +| Speech Service | `mywisprai-speech` | — | Can't rename — keep as-is | +| Key Vault | `kv-mywisprai` | `kv-bytelyst` | Can't rename — keep as-is | +| Notification Hub NS | `lysnnai` | `bytelyst-hub-ns` | Consider creating new NS later if desired | +| App Insights | `bytelyst-appinsights` | — | Can recreate if you want workspace-based mode | > **Azure resources cannot be renamed after creation.** The old names (`cosmos-mywisprai`, `mywisprai-*`, etc.) still work perfectly — they're just cosmetic. Only the RG can be "renamed" by moving resources to a new one. @@ -614,7 +620,7 @@ After completing all steps, verify: set -euo pipefail # ───────────────────────────────────────────────────────────── -# BytelystAI — Azure Resource Setup Script +# ByteLyst — Azure Resource Setup Script # Creates MindLyst deltas inside an existing shared resource group # ───────────────────────────────────────────────────────────── @@ -860,19 +866,19 @@ az deployment sub create \ Use this mapping to understand how the current staging resource names relate to Bicep params. In a **different account**, you must choose new globally-unique names for most of these. -| Bicep parameter | Current staging value | Notes | -|---|---|---| -| `resourceGroupName` | `rg-mywisprai` | In a new subscription, choose a new RG name (example: `rg-bytelyst-staging`) | -| `cosmosAccountName` | `cosmos-mywisprai` | Globally unique; must change in another subscription | -| `storageAccountName` | `bytelystblobs` | Globally unique; must change in another subscription | -| `openAiAccountName` | `mywisprai-openai-sweden` | Globally unique; must change in another subscription | -| `speechAccountName` | `mywisprai-speech` | Globally unique; must change in another subscription | -| `keyVaultName` | `kv-mywisprai` | Globally unique; must change in another subscription | -| `notificationHubNamespaceName` | `lysnnai` | Globally unique; must change in another subscription | -| `mindlystHubName` | `mindlyst-hub` | Not globally unique (scoped to the namespace) | -| `appInsightsName` | `bytelyst-appinsights` | Must be unique within the RG | -| `createMywispraiDatabase` | N/A | Creates an empty `mywisprai` database placeholder (no containers) | -| `deployerObjectId` | N/A | If set, Bicep also creates Key Vault secrets (`mindlyst-*`) | +| Bicep parameter | Current staging value | Notes | +| ------------------------------ | ------------------------- | ---------------------------------------------------------------------------- | +| `resourceGroupName` | `rg-mywisprai` | In a new subscription, choose a new RG name (example: `rg-bytelyst-staging`) | +| `cosmosAccountName` | `cosmos-mywisprai` | Globally unique; must change in another subscription | +| `storageAccountName` | `bytelystblobs` | Globally unique; must change in another subscription | +| `openAiAccountName` | `mywisprai-openai-sweden` | Globally unique; must change in another subscription | +| `speechAccountName` | `mywisprai-speech` | Globally unique; must change in another subscription | +| `keyVaultName` | `kv-mywisprai` | Globally unique; must change in another subscription | +| `notificationHubNamespaceName` | `lysnnai` | Globally unique; must change in another subscription | +| `mindlystHubName` | `mindlyst-hub` | Not globally unique (scoped to the namespace) | +| `appInsightsName` | `bytelyst-appinsights` | Must be unique within the RG | +| `createMywispraiDatabase` | N/A | Creates an empty `mywisprai` database placeholder (LysnrAI, no containers) | +| `deployerObjectId` | N/A | If set, Bicep also creates Key Vault secrets (`mindlyst-*`) | --- @@ -892,6 +898,7 @@ Phase 0.3 (Azure Infrastructure): ``` **Next steps after provisioning:** + 1. (Done) MindLyst web: Enable Azure OpenAI triage + brain-chat (`OPENAI_PROVIDER=azure` + `AZURE_OPENAI_*`) 2. (Done) MindLyst web: Cosmos persistence for `/api/memory` and `/api/brains` (`COSMOS_*`) 3. Wire additional MindLyst API routes to Cosmos as needed (reflections, briefs, notifications, etc.) @@ -903,14 +910,14 @@ Phase 0.3 (Azure Infrastructure): ## Quick Reference: Portal URLs -| Resource | Direct Link | -|----------|-------------| -| Resource Group | `portal.azure.com → Resource groups → rg-mywisprai` | -| Cosmos DB Data Explorer | `portal.azure.com → cosmos-mywisprai → Data Explorer` | -| Blob Containers | `portal.azure.com → bytelystblobs → Containers` | -| OpenAI Studio | `oai.azure.com` → select `mywisprai-openai-sweden` | -| Speech Keys | `portal.azure.com → mywisprai-speech → Keys and Endpoint` | -| Key Vault Secrets | `portal.azure.com → kv-mywisprai → Secrets` | +| Resource | Direct Link | +| ----------------------- | --------------------------------------------------------- | +| Resource Group | `portal.azure.com → Resource groups → rg-mywisprai` | +| Cosmos DB Data Explorer | `portal.azure.com → cosmos-mywisprai → Data Explorer` | +| Blob Containers | `portal.azure.com → bytelystblobs → Containers` | +| OpenAI Studio | `oai.azure.com` → select `mywisprai-openai-sweden` | +| Speech Keys | `portal.azure.com → mywisprai-speech → Keys and Endpoint` | +| Key Vault Secrets | `portal.azure.com → kv-mywisprai → Secrets` | --- diff --git a/docs/devops/AZURE_RESOURCE_INVENTORY.md b/docs/devops/AZURE_RESOURCE_INVENTORY.md index b8155e27..3ed623aa 100644 --- a/docs/devops/AZURE_RESOURCE_INVENTORY.md +++ b/docs/devops/AZURE_RESOURCE_INVENTORY.md @@ -1,31 +1,33 @@ # Azure Resource Inventory -> **Last Updated:** 2026-02-14 -> **Purpose:** Complete inventory of Azure resources for ByteLyst AI products +> **Last Updated:** 2026-03-21 +> **Purpose:** Complete inventory of Azure resources for ByteLyst products +> +> **Note:** Many resources carry `mywisprai` in their names (pre-rebrand). Azure resources cannot be renamed after creation. These names are cosmetic and work correctly. --- ## 📋 Subscription Details -| Property | Value | -|----------|-------| -| **Subscription Name** | Azure subscription 1 | -| **Subscription ID** | `0e0ceaea-2677-4097-9401-1102707db826` | -| **Tenant** | eScube | -| **Tenant Domain** | saravanakumardblive.onmicrosoft.com | -| **Tenant ID** | `ab33246e-c9c9-4cb9-9a87-3616bb4920f0` | -| **Account** | saravanakumardb@live.com | -| **Environment** | AzureCloud | -| **State** | Enabled | +| Property | Value | +| --------------------- | -------------------------------------- | +| **Subscription Name** | Azure subscription 1 | +| **Subscription ID** | `0e0ceaea-2677-4097-9401-1102707db826` | +| **Tenant** | eScube | +| **Tenant Domain** | saravanakumardblive.onmicrosoft.com | +| **Tenant ID** | `ab33246e-c9c9-4cb9-9a87-3616bb4920f0` | +| **Account** | saravanakumardb@live.com | +| **Environment** | AzureCloud | +| **State** | Enabled | --- ## 🗂️ Resource Groups -| Resource Group | Location | Status | Managed By | Type | -|---------------|----------|---------|------------|------| -| **rg-mywisprai** | East US | Succeeded | - | Primary resource group | -| **ai_bytelyst-appinsights_533a81a0-d1e6-4b01-935a-67dd49a218da_managed** | East US | Succeeded | Application Insights | Auto-managed | +| Resource Group | Location | Status | Managed By | Type | +| ------------------------------------------------------------------------ | -------- | --------- | -------------------- | ---------------------- | +| **rg-mywisprai** | East US | Succeeded | - | Primary resource group | +| **ai_bytelyst-appinsights_533a81a0-d1e6-4b01-935a-67dd49a218da_managed** | East US | Succeeded | Application Insights | Auto-managed | --- @@ -36,26 +38,28 @@ #### Resource Group: `rg-mywisprai` (East US) ##### 🗄️ **Cosmos DB** - Database Account -| Property | Value | -|----------|-------| -| **Name** | cosmos-mywisprai | -| **Type** | Microsoft.DocumentDb/databaseAccounts | -| **Location** | West US 2 | -| **Kind** | GlobalDocumentDB (SQL API) | -| **Status** | Succeeded | -| **Created** | 2026-02-09 | -| **Workload Type** | Development/Testing | -| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.DocumentDb/databaseAccounts/cosmos-mywisprai` | + +| Property | Value | +| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Name** | cosmos-mywisprai | +| **Type** | Microsoft.DocumentDb/databaseAccounts | +| **Location** | West US 2 | +| **Kind** | GlobalDocumentDB (SQL API) | +| **Status** | Succeeded | +| **Created** | 2026-02-09 | +| **Workload Type** | Development/Testing | +| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.DocumentDb/databaseAccounts/cosmos-mywisprai` | **📦 Databases & Containers:** -| Database | Containers | Purpose | -|----------|-----------|---------| -| **mindlyst** | • streaks
• users
• brain_insights
• brain_templates
• daily_briefs
• memory_items
• notification_log
• brains
• actions
• entities
• share_cards
• reflections | MindLyst product data | -| **lysnrai** | • subscriptions
• notification_prefs
• licenses
• tracker_votes
• feature_flags
• payments
• tracker_items
• audit_log
• invitation_codes
• devices
• usage_daily
• tracker_comments
• referrals
• plans
• users | LysnrAI product + platform services | -| **mywisprai** | • licenses
• api_tokens
• transcripts
• audit_log
• subscriptions
• usage_daily
• users
• settings
• payments
• devices | MyWisprAI product data | +| Database | Containers | Purpose | +| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | +| **mindlyst** | • streaks
• users
• brain_insights
• brain_templates
• daily_briefs
• memory_items
• notification_log
• brains
• actions
• entities
• share_cards
• reflections | MindLyst product data | +| **lysnrai** | • subscriptions
• notification_prefs
• licenses
• tracker_votes
• feature_flags
• payments
• tracker_items
• audit_log
• invitation_codes
• devices
• usage_daily
• tracker_comments
• referrals
• plans
• users | LysnrAI product + platform services | +| **mywisprai** | • licenses
• api_tokens
• transcripts
• audit_log
• subscriptions
• usage_daily
• users
• settings
• payments
• devices | LysnrAI legacy data (pre-rebrand database name) | **🔑 Key Environment Variables:** + ```bash COSMOS_ENDPOINT=https://cosmos-mywisprai.documents.azure.com:443/ COSMOS_DATABASE=lysnrai # or mindlyst/mywisprai depending on product @@ -64,20 +68,22 @@ COSMOS_DATABASE=lysnrai # or mindlyst/mywisprai depending on product --- ##### 💾 **Storage Account** - Blob Storage -| Property | Value | -|----------|-------| -| **Name** | bytelystblobs | -| **Type** | Microsoft.Storage/storageAccounts | -| **Location** | West US 2 (Primary) | -| **Secondary Location** | West Central US | -| **Kind** | StorageV2 | -| **SKU** | Standard_RAGRS (Geo-redundant) | -| **Access Tier** | Cool | -| **Status** | Succeeded | -| **Created** | 2026-02-12 | -| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.Storage/storageAccounts/bytelystblobs` | + +| Property | Value | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| **Name** | bytelystblobs | +| **Type** | Microsoft.Storage/storageAccounts | +| **Location** | West US 2 (Primary) | +| **Secondary Location** | West Central US | +| **Kind** | StorageV2 | +| **SKU** | Standard_RAGRS (Geo-redundant) | +| **Access Tier** | Cool | +| **Status** | Succeeded | +| **Created** | 2026-02-12 | +| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.Storage/storageAccounts/bytelystblobs` | **🔑 Key Environment Variables:** + ```bash AZURE_BLOB_ACCOUNT_NAME=bytelystblobs AZURE_BLOB_CONNECTION_STRING= @@ -86,45 +92,50 @@ AZURE_BLOB_CONNECTION_STRING= --- ##### 🔐 **Key Vault** -| Property | Value | -|----------|-------| -| **Name** | kv-mywisprai | -| **Type** | Microsoft.KeyVault/vaults | -| **Location** | East US | -| **Status** | Succeeded | -| **Created** | 2026-02-07 | + +| Property | Value | +| --------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| **Name** | kv-mywisprai | +| **Type** | Microsoft.KeyVault/vaults | +| **Location** | East US | +| **Status** | Succeeded | +| **Created** | 2026-02-07 | | **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.KeyVault/vaults/kv-mywisprai` | **🔑 Key Environment Variables:** + ```bash AZURE_KEYVAULT_URL=https://kv-mywisprai.vault.azure.net/ ``` **📝 Usage in Code:** + - See: `packages/config/src/keyvault.ts` - See: `scripts/seed-keyvault.sh` --- ##### 🧠 **Azure OpenAI Service** -| Property | Value | -|----------|-------| -| **Name** | mywisprai-openai-sweden | -| **Type** | Microsoft.CognitiveServices/accounts | -| **Kind** | OpenAI | -| **Location** | Sweden Central | -| **SKU** | S0 (Standard) | -| **Status** | Succeeded | -| **Created** | 2026-02-07 | + +| Property | Value | +| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Name** | mywisprai-openai-sweden | +| **Type** | Microsoft.CognitiveServices/accounts | +| **Kind** | OpenAI | +| **Location** | Sweden Central | +| **SKU** | S0 (Standard) | +| **Status** | Succeeded | +| **Created** | 2026-02-07 | | **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.CognitiveServices/accounts/mywisprai-openai-sweden` | **🚀 Model Deployments:** -| Deployment Name | Model | Version | Capacity | -|----------------|-------|---------|----------| -| gpt-4o-mini | gpt-4o-mini | 2024-07-18 | 1 TPM | +| Deployment Name | Model | Version | Capacity | +| --------------- | ----------- | ---------- | -------- | +| gpt-4o-mini | gpt-4o-mini | 2024-07-18 | 1 TPM | **🔑 Key Environment Variables:** + ```bash AZURE_OPENAI_ENDPOINT=https://mywisprai-openai-sweden.openai.azure.com/ AZURE_OPENAI_API_KEY= @@ -134,18 +145,20 @@ AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o-mini --- ##### 🎤 **Speech Services** -| Property | Value | -|----------|-------| -| **Name** | mywisprai-speech | -| **Type** | Microsoft.CognitiveServices/accounts | -| **Kind** | SpeechServices | -| **Location** | East US | -| **SKU** | F0 (Free Tier) | -| **Status** | Succeeded | -| **Created** | 2026-02-07 | + +| Property | Value | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Name** | mywisprai-speech | +| **Type** | Microsoft.CognitiveServices/accounts | +| **Kind** | SpeechServices | +| **Location** | East US | +| **SKU** | F0 (Free Tier) | +| **Status** | Succeeded | +| **Created** | 2026-02-07 | | **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.CognitiveServices/accounts/mywisprai-speech` | **🔑 Key Environment Variables:** + ```bash AZURE_SPEECH_KEY= AZURE_SPEECH_REGION=eastus @@ -154,24 +167,26 @@ AZURE_SPEECH_REGION=eastus --- ##### 🔔 **Notification Hubs** - Push Notification Service -| Property | Value | -|----------|-------| -| **Namespace** | lysnnai | -| **Type** | Microsoft.NotificationHubs/namespaces | -| **Location** | East US | -| **SKU** | Free | -| **Status** | Succeeded | -| **Created** | 2026-02-12 | + +| Property | Value | +| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| **Namespace** | lysnnai | +| **Type** | Microsoft.NotificationHubs/namespaces | +| **Location** | East US | +| **SKU** | Free | +| **Status** | Succeeded | +| **Created** | 2026-02-12 | | **Namespace ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.NotificationHubs/namespaces/lysnnai` | **📱 Notification Hubs:** -| Hub Name | Purpose | Created | -|----------|---------|---------| -| **notificationhub** | General notifications | 2026-02-12 | -| **mindlyst-hub** | MindLyst product notifications | 2026-02-13 | +| Hub Name | Purpose | Created | +| ------------------- | ------------------------------ | ---------- | +| **notificationhub** | General notifications | 2026-02-12 | +| **mindlyst-hub** | MindLyst product notifications | 2026-02-13 | **🔑 Key Environment Variables:** + ```bash AZURE_NH_CONNECTION_STRING= AZURE_NH_HUB_NAME=mindlyst-hub # or notificationhub @@ -180,20 +195,23 @@ AZURE_NH_HUB_NAME=mindlyst-hub # or notificationhub --- ##### 📊 **Application Insights** - Monitoring & Telemetry -| Property | Value | -|----------|-------| -| **Name** | bytelyst-appinsights | -| **Type** | Microsoft.Insights/components | -| **Kind** | web | -| **Location** | East US | -| **Status** | Succeeded | -| **Created** | 2026-02-13 | + +| Property | Value | +| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| **Name** | bytelyst-appinsights | +| **Type** | Microsoft.Insights/components | +| **Kind** | web | +| **Location** | East US | +| **Status** | Succeeded | +| **Created** | 2026-02-13 | | **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.Insights/components/bytelyst-appinsights` | **🔔 Action Groups:** + - **Application Insights Smart Detection** (Global) **🔑 Key Environment Variables:** + ```bash APPLICATIONINSIGHTS_CONNECTION_STRING= APPINSIGHTS_INSTRUMENTATIONKEY= @@ -203,18 +221,18 @@ APPINSIGHTS_INSTRUMENTATIONKEY= ## 📦 Resource Summary by Type -| Resource Type | Count | Names | -|--------------|-------|-------| -| **Cosmos DB Accounts** | 1 | cosmos-mywisprai | -| **Cosmos DB Databases** | 3 | mindlyst, lysnrai, mywisprai | -| **Storage Accounts** | 1 | bytelystblobs | -| **Key Vaults** | 1 | kv-mywisprai | -| **Cognitive Services (OpenAI)** | 1 | mywisprai-openai-sweden | -| **Cognitive Services (Speech)** | 1 | mywisprai-speech | -| **Notification Hub Namespaces** | 1 | lysnnai | -| **Notification Hubs** | 2 | notificationhub, mindlyst-hub | -| **Application Insights** | 1 | bytelyst-appinsights | -| **Action Groups** | 1 | Application Insights Smart Detection | +| Resource Type | Count | Names | +| ------------------------------- | ----- | ------------------------------------- | +| **Cosmos DB Accounts** | 1 | cosmos-mywisprai | +| **Cosmos DB Databases** | 3 | mindlyst, lysnrai, mywisprai (legacy) | +| **Storage Accounts** | 1 | bytelystblobs | +| **Key Vaults** | 1 | kv-mywisprai | +| **Cognitive Services (OpenAI)** | 1 | mywisprai-openai-sweden | +| **Cognitive Services (Speech)** | 1 | mywisprai-speech | +| **Notification Hub Namespaces** | 1 | lysnnai | +| **Notification Hubs** | 2 | notificationhub, mindlyst-hub | +| **Application Insights** | 1 | bytelyst-appinsights | +| **Action Groups** | 1 | Application Insights Smart Detection | **Total Resources:** 13 (excluding auto-managed resource groups) @@ -223,6 +241,7 @@ APPINSIGHTS_INSTRUMENTATIONKEY= ## 🔑 Critical Environment Variables Summary ### Required Across All Services: + ```bash # Cosmos DB COSMOS_ENDPOINT=https://cosmos-mywisprai.documents.azure.com:443/ @@ -259,29 +278,32 @@ APPINSIGHTS_INSTRUMENTATIONKEY= ## 📍 Geographic Distribution -| Region | Resources | -|--------|-----------| -| **East US** | Speech Services, Key Vault, Notification Hubs, Application Insights | -| **West US 2** | Cosmos DB (primary), Blob Storage (primary) | -| **Sweden Central** | Azure OpenAI | -| **West Central US** | Blob Storage (secondary/geo-redundant) | -| **Global** | Action Groups | +| Region | Resources | +| ------------------- | ------------------------------------------------------------------- | +| **East US** | Speech Services, Key Vault, Notification Hubs, Application Insights | +| **West US 2** | Cosmos DB (primary), Blob Storage (primary) | +| **Sweden Central** | Azure OpenAI | +| **West Central US** | Blob Storage (secondary/geo-redundant) | +| **Global** | Action Groups | --- ## 💰 Cost Optimization Notes ### Free Tier Resources: + - ✅ Speech Services (F0) - ✅ Notification Hubs (Free) ### Paid Resources: + - 💵 Cosmos DB (Development/Testing workload) - 💵 Blob Storage (Standard_RAGRS, Cool tier) - 💵 Azure OpenAI (S0 - pay per use) - 💵 Application Insights (pay per GB ingested) ### Recommendations: + 1. Monitor Cosmos DB RU consumption (Development/Testing mode has limits) 2. Blob Storage is on Cool tier (good for infrequent access) 3. Geo-redundant storage (RAGRS) adds cost but provides disaster recovery @@ -291,47 +313,53 @@ APPINSIGHTS_INSTRUMENTATIONKEY= ## 🔗 Related Documentation -| Document | Location | -|----------|----------| -| Azure Portal Setup | `docs/devops/AZURE_PORTAL_SETUP.md` | -| Key Vault & Secrets Rotation | `docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md` | -| Environment & KV Audit | `docs/devops/ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md` | -| Cosmos DB Package | `packages/cosmos/` | -| Environment Variables Template | `.env.example` | -| Key Vault Integration | `packages/config/src/keyvault.ts` | -| Admin Secrets Manager | Admin dashboard → `/ops/secrets` (live CRUD for KV) | +| Document | Location | +| ------------------------------ | --------------------------------------------------------- | +| Azure Portal Setup | `docs/devops/AZURE_PORTAL_SETUP.md` | +| Key Vault & Secrets Rotation | `docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md` | +| Environment & KV Audit | `docs/devops/ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md` | +| Cosmos DB Package | `packages/cosmos/` | +| Environment Variables Template | `.env.example` | +| Key Vault Integration | `packages/config/src/keyvault.ts` | +| Admin Secrets Manager | Admin dashboard → `/ops/secrets` (live CRUD for KV) | --- ## 🚀 Quick Commands ### List all resources: + ```bash az resource list --output table ``` ### Get Cosmos DB connection string: + ```bash az cosmosdb keys list --name cosmos-mywisprai --resource-group rg-mywisprai --type connection-strings ``` ### Get Storage Account keys: + ```bash az storage account keys list --account-name bytelystblobs --resource-group rg-mywisprai ``` ### Get Key Vault secrets: + ```bash az keyvault secret list --vault-name kv-mywisprai --output table ``` ### Get OpenAI endpoint and keys: + ```bash az cognitiveservices account show --name mywisprai-openai-sweden --resource-group rg-mywisprai az cognitiveservices account keys list --name mywisprai-openai-sweden --resource-group rg-mywisprai ``` ### List OpenAI deployments: + ```bash az cognitiveservices account deployment list --name mywisprai-openai-sweden --resource-group rg-mywisprai --output table ``` diff --git a/docs/devops/END_TO_END_ENCRYPTION_ROADMAP.md b/docs/devops/END_TO_END_ENCRYPTION_ROADMAP.md index bee6f89a..04203d49 100644 --- a/docs/devops/END_TO_END_ENCRYPTION_ROADMAP.md +++ b/docs/devops/END_TO_END_ENCRYPTION_ROADMAP.md @@ -43,7 +43,7 @@ Week 1-2 Week 3-4 Week 5-6 Week 7-8 Week 9-10 Week 11-14 #### 1.1 Azure Key Vault Infrastructure -- [ ] **1.1.1** Enable RBAC mode on `kv-mywisprai` vault (`enableRbacAuthorization=true`) +- [ ] **1.1.1** Enable RBAC mode on `kv-mywisprai` vault (legacy name) (`enableRbacAuthorization=true`) - Assign `Key Vault Crypto Officer` to deployer user - Assign `Key Vault Crypto User` to service managed identities (when deployed) - **File:** Azure Portal / `az keyvault update` @@ -64,7 +64,7 @@ Week 1-2 Week 3-4 Week 5-6 Week 7-8 Week 9-10 Week 11-14 - [ ] **1.1.3** Add new env vars to `.env.example` and AKV secrets doc ``` - AZURE_KEYVAULT_URL=https://kv-mywisprai.vault.azure.net + AZURE_KEYVAULT_URL=https://kv-mywisprai.vault.azure.net # legacy vault name FIELD_ENCRYPT_KEY_PROVIDER=akv # 'akv' | 'env' | 'memory' FIELD_ENCRYPT_MEK_NAME=lysnr-mek # product-specific ``` @@ -461,7 +461,7 @@ Week 1-2 Week 3-4 Week 5-6 Week 7-8 Week 9-10 Week 11-14 - [ ] **6.1.1** Create `bytelyst-blob-mek` RSA key in AKV - [ ] **6.1.2** Configure `bytelystblobs` storage account to use CMK from AKV - Azure Portal → Storage account → Encryption → Customer-managed keys - - Select `bytelyst-blob-mek` from `kv-mywisprai` + - Select `bytelyst-blob-mek` from `kv-mywisprai` (legacy vault name) - [ ] **6.1.3** Verify all blob operations still work (upload, download, SAS tokens) - [ ] **6.1.4** Update `AZURE_RESOURCE_INVENTORY.md` diff --git a/docs/devops/ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md b/docs/devops/ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md index e1fe3cf7..1c397fd4 100644 --- a/docs/devops/ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md +++ b/docs/devops/ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md @@ -1,16 +1,19 @@ # Environment Variables & Azure Key Vault Audit -> **Last Updated:** 2026-02-15 +> **Last Updated:** 2026-03-21 > **Purpose:** Complete audit of environment variables, Azure Key Vault secrets, and gap analysis +> +> **Note:** Azure resource names like `kv-mywisprai` are legacy (pre-rebrand). They cannot be renamed. --- ## 🎯 Executive Summary ### Current Status: + 1. ✅ **All 13 LysnrAI secrets** seeded into Azure Key Vault (completed 2026-02-15) 2. ✅ **MindLyst secrets** fully populated (12 secrets) -3. ✅ **MyWisprAI secrets** populated (5 legacy `wispr-*` secrets) +3. ✅ **LysnrAI legacy secrets** populated (5 `wispr-*` secrets, pre-rebrand) 4. ⚠️ **Next action:** Rotate keys exposed in git history (see `AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md`) --- @@ -18,28 +21,29 @@ ## 📊 Key Vault Current State ### Azure Key Vault: `kv-mywisprai` + **Location:** East US **Total Secrets:** 17 -| Secret Name | Product | Purpose | Created | Status | -|-------------|---------|---------|---------|--------| -| `mindlyst-appinsights-connection-string` | MindLyst | Application Insights telemetry | 2026-02-14 | ✅ Active | -| `mindlyst-blob-connection-string` | MindLyst | Blob Storage access | 2026-02-14 | ✅ Active | -| `mindlyst-cosmos-database` | MindLyst | Cosmos DB database name | 2026-02-14 | ✅ Active | -| `mindlyst-cosmos-endpoint` | MindLyst | Cosmos DB endpoint | 2026-02-14 | ✅ Active | -| `mindlyst-cosmos-key` | MindLyst | Cosmos DB primary key | 2026-02-14 | ✅ Active | -| `mindlyst-notification-hub-connection-string` | MindLyst | Push notifications | 2026-02-14 | ✅ Active | -| `mindlyst-openai-api-version` | MindLyst | OpenAI API version | 2026-02-14 | ✅ Active | -| `mindlyst-openai-deployment` | MindLyst | OpenAI deployment name | 2026-02-14 | ✅ Active | -| `mindlyst-openai-endpoint` | MindLyst | Azure OpenAI endpoint | 2026-02-14 | ✅ Active | -| `mindlyst-openai-key` | MindLyst | Azure OpenAI key | 2026-02-14 | ✅ Active | -| `mindlyst-speech-key` | MindLyst | Azure Speech Services key | 2026-02-14 | ✅ Active | -| `mindlyst-speech-region` | MindLyst | Azure Speech region | 2026-02-14 | ✅ Active | -| `wispr-azure-openai-deployment` | MyWisprAI | OpenAI deployment name | 2026-02-07 | ✅ Active | -| `wispr-azure-openai-endpoint` | MyWisprAI | Azure OpenAI endpoint | 2026-02-07 | ✅ Active | -| `wispr-azure-openai-key` | MyWisprAI | Azure OpenAI key | 2026-02-07 | ✅ Active | -| `wispr-azure-speech-key` | MyWisprAI | Azure Speech Services key | 2026-02-07 | ✅ Active | -| `wispr-azure-speech-region` | MyWisprAI | Azure Speech region | 2026-02-07 | ✅ Active | +| Secret Name | Product | Purpose | Created | Status | +| --------------------------------------------- | ---------------- | ------------------------------ | ---------- | ----------------------------------- | +| `mindlyst-appinsights-connection-string` | MindLyst | Application Insights telemetry | 2026-02-14 | ✅ Active | +| `mindlyst-blob-connection-string` | MindLyst | Blob Storage access | 2026-02-14 | ✅ Active | +| `mindlyst-cosmos-database` | MindLyst | Cosmos DB database name | 2026-02-14 | ✅ Active | +| `mindlyst-cosmos-endpoint` | MindLyst | Cosmos DB endpoint | 2026-02-14 | ✅ Active | +| `mindlyst-cosmos-key` | MindLyst | Cosmos DB primary key | 2026-02-14 | ✅ Active | +| `mindlyst-notification-hub-connection-string` | MindLyst | Push notifications | 2026-02-14 | ✅ Active | +| `mindlyst-openai-api-version` | MindLyst | OpenAI API version | 2026-02-14 | ✅ Active | +| `mindlyst-openai-deployment` | MindLyst | OpenAI deployment name | 2026-02-14 | ✅ Active | +| `mindlyst-openai-endpoint` | MindLyst | Azure OpenAI endpoint | 2026-02-14 | ✅ Active | +| `mindlyst-openai-key` | MindLyst | Azure OpenAI key | 2026-02-14 | ✅ Active | +| `mindlyst-speech-key` | MindLyst | Azure Speech Services key | 2026-02-14 | ✅ Active | +| `mindlyst-speech-region` | MindLyst | Azure Speech region | 2026-02-14 | ✅ Active | +| `wispr-azure-openai-deployment` | LysnrAI (legacy) | OpenAI deployment name | 2026-02-07 | ✅ Active (superseded by `lysnr-*`) | +| `wispr-azure-openai-endpoint` | LysnrAI (legacy) | Azure OpenAI endpoint | 2026-02-07 | ✅ Active (superseded by `lysnr-*`) | +| `wispr-azure-openai-key` | LysnrAI (legacy) | Azure OpenAI key | 2026-02-07 | ✅ Active (superseded by `lysnr-*`) | +| `wispr-azure-speech-key` | LysnrAI (legacy) | Azure Speech Services key | 2026-02-07 | ✅ Active (superseded by `lysnr-*`) | +| `wispr-azure-speech-region` | LysnrAI (legacy) | Azure Speech region | 2026-02-07 | ✅ Active (superseded by `lysnr-*`) | --- @@ -49,21 +53,21 @@ The `LYSNR_SECRETS` constant defines these mappings: -| Key Vault Secret Name | Environment Variable | Status in KV | Priority | -|-----------------------|---------------------|--------------|----------| -| `lysnr-cosmos-key` | `COSMOS_KEY` | ✅ **Seeded** | 🔴 Critical | -| `lysnr-cosmos-endpoint` | `COSMOS_ENDPOINT` | ✅ **Seeded** | 🔴 Critical | -| `lysnr-jwt-secret` | `JWT_SECRET` | ✅ **Seeded** | 🔴 Critical | -| `lysnr-stripe-secret-key` | `STRIPE_SECRET_KEY` | ✅ **Seeded** | 🔴 Critical | -| `lysnr-stripe-webhook-secret` | `STRIPE_WEBHOOK_SECRET` | ✅ **Seeded** | 🔴 Critical | -| `lysnr-billing-internal-key` | `BILLING_INTERNAL_KEY` | ✅ **Seeded** | 🟠 High | +| Key Vault Secret Name | Environment Variable | Status in KV | Priority | +| ------------------------------ | ------------------------------ | ------------- | ----------- | +| `lysnr-cosmos-key` | `COSMOS_KEY` | ✅ **Seeded** | 🔴 Critical | +| `lysnr-cosmos-endpoint` | `COSMOS_ENDPOINT` | ✅ **Seeded** | 🔴 Critical | +| `lysnr-jwt-secret` | `JWT_SECRET` | ✅ **Seeded** | 🔴 Critical | +| `lysnr-stripe-secret-key` | `STRIPE_SECRET_KEY` | ✅ **Seeded** | 🔴 Critical | +| `lysnr-stripe-webhook-secret` | `STRIPE_WEBHOOK_SECRET` | ✅ **Seeded** | 🔴 Critical | +| `lysnr-billing-internal-key` | `BILLING_INTERNAL_KEY` | ✅ **Seeded** | 🟠 High | | `lysnr-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | ✅ **Seeded** | 🔴 Critical | -| `lysnr-blob-account-key` | `AZURE_BLOB_ACCOUNT_KEY` | ✅ **Seeded** | 🔴 Critical | -| `lysnr-gemini-api-key` | `GEMINI_API_KEY` | ✅ **Seeded** | 🔴 Critical | -| `lysnr-seed-secret` | `SEED_SECRET` | ✅ **Seeded** | 🟡 Medium | -| `lysnr-azure-speech-key` | `AZURE_SPEECH_KEY` | ✅ **Seeded** | 🟠 High | -| `lysnr-azure-openai-key` | `AZURE_OPENAI_KEY` | ✅ **Seeded** | 🟠 High | -| `lysnr-azure-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | ✅ **Seeded** | 🟠 High | +| `lysnr-blob-account-key` | `AZURE_BLOB_ACCOUNT_KEY` | ✅ **Seeded** | 🔴 Critical | +| `lysnr-gemini-api-key` | `GEMINI_API_KEY` | ✅ **Seeded** | 🔴 Critical | +| `lysnr-seed-secret` | `SEED_SECRET` | ✅ **Seeded** | 🟡 Medium | +| `lysnr-azure-speech-key` | `AZURE_SPEECH_KEY` | ✅ **Seeded** | 🟠 High | +| `lysnr-azure-openai-key` | `AZURE_OPENAI_KEY` | ✅ **Seeded** | 🟠 High | +| `lysnr-azure-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | ✅ **Seeded** | 🟠 High | **Total Expected:** 13 secrets **Total Seeded:** 13 secrets (100%) ✅ — Completed 2026-02-15 @@ -75,40 +79,44 @@ The `LYSNR_SECRETS` constant defines these mappings: ### Core Platform Variables (from `.env.example`) #### 🔐 Azure Key Vault -| Variable | Required | Default | Used By | In KV? | -|----------|----------|---------|---------|--------| -| `AZURE_KEYVAULT_URL` | Optional | - | All services | N/A | + +| Variable | Required | Default | Used By | In KV? | +| -------------------- | -------- | ------- | ------------ | ------ | +| `AZURE_KEYVAULT_URL` | Optional | - | All services | N/A | **Purpose:** Enable Key Vault secret resolution. Falls back to env vars if not set. --- #### 🗄️ Azure Cosmos DB -| Variable | Required | Default | Used By | In KV? | -|----------|----------|---------|---------|--------| -| `COSMOS_ENDPOINT` | ✅ Yes | - | All services | ❌ No (lysnr) | -| `COSMOS_KEY` | ✅ Yes | - | All services | ❌ No (lysnr) | -| `COSMOS_DATABASE` | No | `lysnrai` | All services | N/A | -**Purpose:** Database connection for all products (lysnrai, mindlyst, mywisprai databases). +| Variable | Required | Default | Used By | In KV? | +| ----------------- | -------- | --------- | ------------ | ------------- | +| `COSMOS_ENDPOINT` | ✅ Yes | - | All services | ❌ No (lysnr) | +| `COSMOS_KEY` | ✅ Yes | - | All services | ❌ No (lysnr) | +| `COSMOS_DATABASE` | No | `lysnrai` | All services | N/A | + +**Purpose:** Database connection for all products (lysnrai, mindlyst, mywisprai/legacy databases). --- #### 🔑 Authentication & Security -| Variable | Required | Default | Used By | In KV? | -|----------|----------|---------|---------|--------| -| `JWT_SECRET` | ✅ Yes | - | platform-service, extraction-service | ❌ No | + +| Variable | Required | Default | Used By | In KV? | +| ------------ | -------- | ------- | ------------------------------------ | ------ | +| `JWT_SECRET` | ✅ Yes | - | platform-service, extraction-service | ❌ No | **Purpose:** JWT token signing and verification across all services. --- #### 💾 Azure Blob Storage -| Variable | Required | Default | Used By | In KV? | -|----------|----------|---------|---------|--------| -| `AZURE_BLOB_CONNECTION_STRING` | Optional | - | platform-service | ❌ No | -| `AZURE_BLOB_ACCOUNT_NAME` | Optional | `bytelystblobs` | platform-service | N/A | -| `AZURE_BLOB_ACCOUNT_KEY` | Optional | - | platform-service | ❌ No | + +| Variable | Required | Default | Used By | In KV? | +| ------------------------------ | -------- | --------------- | ---------------- | ------ | +| `AZURE_BLOB_CONNECTION_STRING` | Optional | - | platform-service | ❌ No | +| `AZURE_BLOB_ACCOUNT_NAME` | Optional | `bytelystblobs` | platform-service | N/A | +| `AZURE_BLOB_ACCOUNT_KEY` | Optional | - | platform-service | ❌ No | **Purpose:** File uploads, avatar storage, document storage. **Note:** Only needed for platform-service blob module. @@ -116,13 +124,14 @@ The `LYSNR_SECRETS` constant defines these mappings: --- #### 💳 Stripe (Billing & Subscriptions) -| Variable | Required | Default | Used By | In KV? | -|----------|----------|---------|---------|--------| -| `STRIPE_SECRET_KEY` | Optional | - | platform-service | ❌ No | -| `STRIPE_WEBHOOK_SECRET` | Optional | - | platform-service | ❌ No | -| `STRIPE_PRICE_PRO` | Optional | - | platform-service | N/A | -| `STRIPE_PRICE_ENTERPRISE` | Optional | - | platform-service | N/A | -| `BILLING_INTERNAL_KEY` | Optional | - | platform-service | ❌ No | + +| Variable | Required | Default | Used By | In KV? | +| ------------------------- | -------- | ------- | ---------------- | ------ | +| `STRIPE_SECRET_KEY` | Optional | - | platform-service | ❌ No | +| `STRIPE_WEBHOOK_SECRET` | Optional | - | platform-service | ❌ No | +| `STRIPE_PRICE_PRO` | Optional | - | platform-service | N/A | +| `STRIPE_PRICE_ENTERPRISE` | Optional | - | platform-service | N/A | +| `BILLING_INTERNAL_KEY` | Optional | - | platform-service | ❌ No | **Purpose:** Subscription management, payment processing, webhook validation. **Status:** ❌ **Required for production but completely missing from Key Vault** @@ -130,11 +139,12 @@ The `LYSNR_SECRETS` constant defines these mappings: --- #### 🤖 AI Services - Extraction -| Variable | Required | Default | Used By | In KV? | -|----------|----------|---------|---------|--------| -| `GEMINI_API_KEY` | ✅ Yes | - | extraction-service (Python sidecar) | ❌ No | -| `PYTHON_SIDECAR_URL` | No | `http://localhost:4006` | extraction-service | N/A | -| `DEFAULT_MODEL_ID` | No | `gemini-2.5-flash` | extraction-service | N/A | + +| Variable | Required | Default | Used By | In KV? | +| -------------------- | -------- | ----------------------- | ----------------------------------- | ------ | +| `GEMINI_API_KEY` | ✅ Yes | - | extraction-service (Python sidecar) | ❌ No | +| `PYTHON_SIDECAR_URL` | No | `http://localhost:4006` | extraction-service | N/A | +| `DEFAULT_MODEL_ID` | No | `gemini-2.5-flash` | extraction-service | N/A | **Purpose:** Text extraction, content analysis, AI-powered features. **Status:** ❌ **Critical for extraction service functionality** @@ -142,11 +152,12 @@ The `LYSNR_SECRETS` constant defines these mappings: --- #### 🧠 Azure OpenAI (Optional) -| Variable | Required | Default | Used By | In KV? | -|----------|----------|---------|---------|--------| -| `AZURE_OPENAI_KEY` | Optional | - | extraction-service | ❌ No (lysnr) | -| `AZURE_OPENAI_ENDPOINT` | Optional | - | extraction-service | ❌ No (lysnr) | -| `AZURE_OPENAI_DEPLOYMENT_NAME` | Optional | - | extraction-service | N/A | + +| Variable | Required | Default | Used By | In KV? | +| ------------------------------ | -------- | ------- | ------------------ | ------------- | +| `AZURE_OPENAI_KEY` | Optional | - | extraction-service | ❌ No (lysnr) | +| `AZURE_OPENAI_ENDPOINT` | Optional | - | extraction-service | ❌ No (lysnr) | +| `AZURE_OPENAI_DEPLOYMENT_NAME` | Optional | - | extraction-service | N/A | **Purpose:** Alternative to Gemini for text extraction. **Existing:** ✅ Available for `wispr` and `mindlyst` products in Key Vault. @@ -154,10 +165,11 @@ The `LYSNR_SECRETS` constant defines these mappings: --- #### 🎤 Azure Speech Services -| Variable | Required | Default | Used By | In KV? | -|----------|----------|---------|---------|--------| -| `AZURE_SPEECH_KEY` | Optional | - | LysnrAI product | ❌ No (lysnr) | -| `AZURE_SPEECH_REGION` | Optional | `eastus` | LysnrAI product | N/A | + +| Variable | Required | Default | Used By | In KV? | +| --------------------- | -------- | -------- | --------------- | ------------- | +| `AZURE_SPEECH_KEY` | Optional | - | LysnrAI product | ❌ No (lysnr) | +| `AZURE_SPEECH_REGION` | Optional | `eastus` | LysnrAI product | N/A | **Purpose:** Speech-to-text, text-to-speech for voice AI features. **Existing:** ✅ Available for `wispr` and `mindlyst` products in Key Vault. @@ -165,24 +177,26 @@ The `LYSNR_SECRETS` constant defines these mappings: --- #### 🚀 Service Configuration -| Variable | Required | Default | Used By | In KV? | -|----------|----------|---------|---------|--------| -| `PORT` | No | varies | All services | N/A | -| `HOST` | No | `0.0.0.0` | All services | N/A | -| `NODE_ENV` | No | `development` | All services | N/A | -| `SERVICE_NAME` | No | auto | All services | N/A | -| `CORS_ORIGIN` | No | `*` (dev) | All services | N/A | -| `DEFAULT_PRODUCT_ID` | No | `lysnrai` | All services | N/A | + +| Variable | Required | Default | Used By | In KV? | +| -------------------- | -------- | ------------- | ------------ | ------ | +| `PORT` | No | varies | All services | N/A | +| `HOST` | No | `0.0.0.0` | All services | N/A | +| `NODE_ENV` | No | `development` | All services | N/A | +| `SERVICE_NAME` | No | auto | All services | N/A | +| `CORS_ORIGIN` | No | `*` (dev) | All services | N/A | +| `DEFAULT_PRODUCT_ID` | No | `lysnrai` | All services | N/A | **Purpose:** Runtime configuration, not secrets. --- #### 📊 Application Insights (Monitoring) -| Variable | Required | Default | Used By | In KV? | -|----------|----------|---------|---------|--------| -| `APPLICATIONINSIGHTS_CONNECTION_STRING` | Optional | - | All services (future) | ✅ Yes (mindlyst) | -| `APPINSIGHTS_INSTRUMENTATIONKEY` | Optional | - | All services (future) | N/A | + +| Variable | Required | Default | Used By | In KV? | +| --------------------------------------- | -------- | ------- | --------------------- | ----------------- | +| `APPLICATIONINSIGHTS_CONNECTION_STRING` | Optional | - | All services (future) | ✅ Yes (mindlyst) | +| `APPINSIGHTS_INSTRUMENTATIONKEY` | Optional | - | All services (future) | N/A | **Purpose:** Telemetry, logging, monitoring. **Note:** Only MindLyst has this configured currently. @@ -190,10 +204,11 @@ The `LYSNR_SECRETS` constant defines these mappings: --- #### 🔔 Notification Hubs (Mobile Push) -| Variable | Required | Default | Used By | In KV? | -|----------|----------|---------|---------|--------| -| `AZURE_NH_CONNECTION_STRING` | Optional | - | platform-service (future) | ✅ Yes (mindlyst) | -| `AZURE_NH_HUB_NAME` | Optional | - | platform-service (future) | N/A | + +| Variable | Required | Default | Used By | In KV? | +| ---------------------------- | -------- | ------- | ------------------------- | ----------------- | +| `AZURE_NH_CONNECTION_STRING` | Optional | - | platform-service (future) | ✅ Yes (mindlyst) | +| `AZURE_NH_HUB_NAME` | Optional | - | platform-service (future) | N/A | **Purpose:** Push notifications for mobile apps. **Note:** Only MindLyst has this configured currently. @@ -280,9 +295,11 @@ These secrets are **required** for LysnrAI services to function and are **comple ## 📦 Product-Specific Secret Patterns ### MindLyst Product (12 secrets) ✅ + **Prefix:** `mindlyst-*` **Status:** Fully populated **Secrets:** + - Cosmos DB (endpoint, key, database) - Blob Storage (connection string) - Azure OpenAI (endpoint, key, deployment, api-version) @@ -290,16 +307,19 @@ These secrets are **required** for LysnrAI services to function and are **comple - Notification Hub (connection string) - Application Insights (connection string) -### MyWisprAI Product (5 secrets) ⚠️ -**Prefix:** `wispr-*` -**Status:** Partially populated (legacy — pre-rebrand desktop app secrets) +### LysnrAI Legacy (5 secrets) ⚠️ + +**Prefix:** `wispr-*` (pre-rebrand) +**Status:** Populated but superseded by `lysnr-*` secrets **Secrets:** + - Azure OpenAI (endpoint, key, deployment) - Azure Speech (key, region) -**Note:** These are legacy secrets from the original MyWisprAI product. LysnrAI services use `lysnr-*` prefixed secrets instead. +**Note:** These are legacy secrets from before the myWisprAI → LysnrAI rebrand. Active LysnrAI services use `lysnr-*` prefixed secrets instead. ### LysnrAI Product (0 secrets) ❌ + **Prefix:** `lysnr-*` **Status:** Completely missing **Expected:** 13 secrets @@ -368,10 +388,10 @@ pnpm --filter @lysnrai/platform-service dev ### Step 4: Verify Each Service -| Service | Port | Test Endpoint | Expected Status | -|---------|------|---------------|-----------------| -| platform-service | 4003 | GET /health | 200 OK | -| extraction-service | 4005 | GET /health | 200 OK | +| Service | Port | Test Endpoint | Expected Status | +| ------------------ | ---- | ------------- | --------------- | +| platform-service | 4003 | GET /health | 200 OK | +| extraction-service | 4005 | GET /health | 200 OK | ### Step 5: Production Checklist @@ -390,15 +410,16 @@ pnpm --filter @lysnrai/platform-service dev ### Recommended Rotation Schedule: -| Secret Type | Rotation Frequency | Method | -|-------------|-------------------|--------| -| Cosmos DB keys | Quarterly | Azure Portal → rotate keys → update KV | -| JWT secret | Quarterly | Generate new → update KV → rolling deploy | -| Stripe keys | Annually or on breach | Stripe Dashboard → update KV | -| API keys (Gemini, OpenAI) | Annually or on breach | Provider portal → update KV | -| Blob storage keys | Quarterly | Azure Portal → rotate keys → update KV | +| Secret Type | Rotation Frequency | Method | +| ------------------------- | --------------------- | ----------------------------------------- | +| Cosmos DB keys | Quarterly | Azure Portal → rotate keys → update KV | +| JWT secret | Quarterly | Generate new → update KV → rolling deploy | +| Stripe keys | Annually or on breach | Stripe Dashboard → update KV | +| API keys (Gemini, OpenAI) | Annually or on breach | Provider portal → update KV | +| Blob storage keys | Quarterly | Azure Portal → rotate keys → update KV | ### Rotation Procedure: + 1. Generate new secret in Azure Portal / provider 2. Update Key Vault with new value 3. Services auto-fetch new secret on next restart (or use Key Vault rotation event) @@ -409,40 +430,43 @@ pnpm --filter @lysnrai/platform-service dev ## 🔗 Related Files & Documentation -| File | Purpose | -|------|---------| -| `packages/config/src/keyvault.ts` | Key Vault integration code (`resolveKeyVaultSecrets` + `LYSNR_SECRETS`) | -| `scripts/seed-keyvault.sh` | Script to populate Key Vault from `.env` values | -| `.env.example` | Template for required environment variables | -| `services/platform-service/src/server.ts` | Platform service — resolves KV secrets at startup | -| `services/extraction-service/src/server.ts` | Extraction service — resolves KV secrets at startup | -| `admin-dashboard-web/src/instrumentation.ts` | Admin dashboard — resolves KV secrets via Next.js hook | -| `user-dashboard-web/src/instrumentation.ts` | User dashboard — resolves KV secrets via Next.js hook | -| `tracker-dashboard-web/src/instrumentation.ts` | Tracker dashboard — resolves KV secrets via Next.js hook | -| `backend/src/secrets/keyvault.py` | Python backend SecretResolver | -| `src/secrets/keyvault.py` | Desktop app SecretResolver | -| `docs/devops/AZURE_PORTAL_SETUP.md` | Azure portal configuration guide | -| `docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md` | Key Vault setup + rotation runbooks | -| `docs/devops/AZURE_RESOURCE_INVENTORY.md` | Complete Azure resource inventory | +| File | Purpose | +| ----------------------------------------------------- | ----------------------------------------------------------------------- | +| `packages/config/src/keyvault.ts` | Key Vault integration code (`resolveKeyVaultSecrets` + `LYSNR_SECRETS`) | +| `scripts/seed-keyvault.sh` | Script to populate Key Vault from `.env` values | +| `.env.example` | Template for required environment variables | +| `services/platform-service/src/server.ts` | Platform service — resolves KV secrets at startup | +| `services/extraction-service/src/server.ts` | Extraction service — resolves KV secrets at startup | +| `admin-dashboard-web/src/instrumentation.ts` | Admin dashboard — resolves KV secrets via Next.js hook | +| `user-dashboard-web/src/instrumentation.ts` | User dashboard — resolves KV secrets via Next.js hook | +| `tracker-dashboard-web/src/instrumentation.ts` | Tracker dashboard — resolves KV secrets via Next.js hook | +| `backend/src/secrets/keyvault.py` | Python backend SecretResolver | +| `src/secrets/keyvault.py` | Desktop app SecretResolver | +| `docs/devops/AZURE_PORTAL_SETUP.md` | Azure portal configuration guide | +| `docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md` | Key Vault setup + rotation runbooks | +| `docs/devops/AZURE_RESOURCE_INVENTORY.md` | Complete Azure resource inventory | --- ## 📊 Summary Statistics ### Environment Variables: + - **Total Unique Variables:** 35+ - **Required for Core Functionality:** 6 - **Optional/Feature-Specific:** 29+ ### Key Vault Secrets: + - **Total Secrets in KV:** 30 - **MindLyst Secrets:** 12 ✅ -- **MyWisprAI Secrets:** 5 ⚠️ (legacy `wispr-*` prefix) +- **LysnrAI Legacy Secrets:** 5 ⚠️ (legacy `wispr-*` prefix, pre-rebrand) - **LysnrAI Secrets:** 13 ✅ (`lysnr-*` prefix) - **Expected LysnrAI Secrets:** 13 - **Coverage Gap:** 0% ### Priority Actions: + - ✅ All 13 `lysnr-*` secrets seeded (2026-02-15) - ⚠️ **Next:** Rotate keys that were exposed in git history (see `AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md`) @@ -465,6 +489,7 @@ ERROR: HTTPSConnection(host='kv-mywisprai.vault.azure.net', port=443): Failed to As a result, the generated `kv_azure.txt` currently contains `null` values for every `lysnr-*` secret. Once DNS/routing to the vault is available again, rerun the same command to emit the actual values and use the file as a snapshot for comparison. 📁 `kv_azure.txt` (post-run): + ``` lysnr-azure-openai-endpoint=null lysnr-azure-openai-key=null @@ -524,25 +549,26 @@ node -e "process.env.AZURE_KEYVAULT_URL && console.log('✅ KV enabled') || cons Scanned git history across `learning_voice_ai_agent` to recover actual secret values for the 13 missing `lysnr-*` secrets. -| # | KV Secret Name | Source | Status | -|---|----------------|--------|--------| -| 1 | `lysnr-cosmos-endpoint` | `.env` commits | ✅ Recovered | -| 2 | `lysnr-cosmos-key` | `.env` commits | ✅ Recovered | -| 3 | `lysnr-jwt-secret` | `.env` commits | ✅ Recovered | -| 4 | `lysnr-stripe-secret-key` | `.env` commits | ✅ Recovered (sk_test_*) | -| 5 | `lysnr-stripe-webhook-secret` | `.env` commits | ✅ Recovered (whsec_*) | -| 6 | `lysnr-billing-internal-key` | `.env` commits | ✅ Recovered | -| 7 | `lysnr-blob-connection-string` | `.env` commits | ✅ Recovered | -| 8 | `lysnr-blob-account-key` | `.env` commits | ✅ Recovered | -| 9 | `lysnr-gemini-api-key` | Provided manually | ✅ Recovered | -| 10 | `lysnr-seed-secret` | `.env` commits | ✅ Recovered | -| 11 | `lysnr-azure-speech-key` | `.env` commits | ✅ Recovered | -| 12 | `lysnr-azure-openai-key` | `.env` commits | ✅ Recovered | -| 13 | `lysnr-azure-openai-endpoint` | `.env` commits | ✅ Recovered | +| # | KV Secret Name | Source | Status | +| --- | ------------------------------ | ----------------- | ------------------------- | +| 1 | `lysnr-cosmos-endpoint` | `.env` commits | ✅ Recovered | +| 2 | `lysnr-cosmos-key` | `.env` commits | ✅ Recovered | +| 3 | `lysnr-jwt-secret` | `.env` commits | ✅ Recovered | +| 4 | `lysnr-stripe-secret-key` | `.env` commits | ✅ Recovered (sk*test*\*) | +| 5 | `lysnr-stripe-webhook-secret` | `.env` commits | ✅ Recovered (whsec\_\*) | +| 6 | `lysnr-billing-internal-key` | `.env` commits | ✅ Recovered | +| 7 | `lysnr-blob-connection-string` | `.env` commits | ✅ Recovered | +| 8 | `lysnr-blob-account-key` | `.env` commits | ✅ Recovered | +| 9 | `lysnr-gemini-api-key` | Provided manually | ✅ Recovered | +| 10 | `lysnr-seed-secret` | `.env` commits | ✅ Recovered | +| 11 | `lysnr-azure-speech-key` | `.env` commits | ✅ Recovered | +| 12 | `lysnr-azure-openai-key` | `.env` commits | ✅ Recovered | +| 13 | `lysnr-azure-openai-endpoint` | `.env` commits | ✅ Recovered | **Result:** 13/13 recovered. Seed script written to `kv.txt` (gitignored, temporary). **To seed:** + ```bash az login bash kv.txt @@ -555,5 +581,5 @@ rm kv.txt **Generated by:** Environment audit automation **Maintained by:** ByteLyst DevOps Team -**Next Audit:** After LysnrAI `lysnr-*` secrets are seeded into `kv-mywisprai` +**Next Audit:** After key rotation for secrets exposed in git history **Admin UI:** Secrets Manager at admin dashboard → `/ops/secrets`