docs(devops): update stale mywisprai/MyWisprAI branding across 5 AKV docs

- BytelystAI → ByteLyst in titles
- MyWisprAI → LysnrAI (legacy) for wispr-* secret references
- Added 'legacy resource name' annotations to Azure resource names
  (kv-mywisprai, cosmos-mywisprai, etc. cannot be renamed)
- Updated dashboard paths (admin-web moved to dashboards/)
- Fixed telemetry role name: mywisprai-admin → lysnrai-admin
- Updated last-updated dates to 2026-03-21

Files: AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md,
AZURE_PORTAL_SETUP.md, AZURE_RESOURCE_INVENTORY.md,
ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md,
END_TO_END_ENCRYPTION_ROADMAP.md
This commit is contained in:
saravanakumardb1 2026-03-21 09:15:30 -07:00
parent 5b2c6f2874
commit 8af997ba0f
5 changed files with 524 additions and 472 deletions

View File

@ -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. > **Purpose:** Centralize all secrets in Azure Key Vault and establish a repeatable rotation process.
> **Vault:** `kv-mywisprai` in `rg-mywisprai` (East US) > **Vault:** `kv-mywisprai` in `rg-mywisprai` (East US) _legacy resource names, not yet renamed_
> **Last updated:** 2026-02-15 > **Last updated:** 2026-03-21
--- ---
## Overview ## 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 ### Goals
@ -25,31 +25,32 @@ All ByteLyst products (LysnrAI, MindLyst, legacy MyWisprAI) share a **single Key
## Current State ## Current State
| Product | Prefix | Secrets in KV | Status | | Product | Prefix | Secrets in KV | Status |
|---------|--------|---------------|--------| | -------------------- | ------------ | ------------- | ------------------------------------------------------------- |
| **MindLyst** | `mindlyst-*` | 12 | Fully populated | | **LysnrAI** | `lysnr-*` | 13 | ✅ Seeded (2026-02-15) |
| **MyWisprAI** (legacy) | `wispr-*` | 5 | Legacy desktop secrets | | **MindLyst** | `mindlyst-*` | 12 | Fully populated |
| **LysnrAI** | `lysnr-*` | 13 | ✅ Seeded (2026-02-15) | | **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 ### Code Integration Status
All components have AKV resolution implemented: All components have AKV resolution implemented:
| Component | Integration | File | | Component | Integration | File |
|-----------|------------|------| | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- |
| platform-service | `resolveKeyVaultSecrets()` at startup | `services/platform-service/src/server.ts` | | platform-service | `resolveKeyVaultSecrets()` at startup | `services/platform-service/src/server.ts` |
| extraction-service | `resolveKeyVaultSecrets()` at startup | `services/extraction-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` | | 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` | | User dashboard | Next.js `instrumentation.ts` hook | `user-dashboard-web/src/instrumentation.ts` (in LysnrAI repo) |
| Tracker dashboard | Next.js `instrumentation.ts` hook | `tracker-dashboard-web/src/instrumentation.ts` | | Tracker dashboard | Next.js `instrumentation.ts` hook | `dashboards/tracker-web/src/instrumentation.ts` |
| Python backend | `SecretResolver` + pydantic `model_validator` | `backend/src/secrets/keyvault.py` | | Python backend (LysnrAI) | `SecretResolver` + pydantic `model_validator` | `backend-python/src/secrets/keyvault.py` (in LysnrAI repo) |
| Desktop app | `SecretResolver` + pydantic `model_validator` | `src/secrets/keyvault.py` | | Desktop app (LysnrAI) | `SecretResolver` + pydantic `model_validator` | `src/secrets/keyvault.py` (in LysnrAI repo) |
### Admin Secrets Manager ### Admin Secrets Manager
The admin dashboard at **`/ops/secrets`** provides live CRUD access to Key Vault: The admin dashboard at **`/ops/secrets`** provides live CRUD access to Key Vault:
- List all secrets with metadata (status, expiry, last updated) - List all secrets with metadata (status, expiry, last updated)
- Read secret values (masked, with copy-to-clipboard) - Read secret values (masked, with copy-to-clipboard)
- Create new secrets - 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`) ### LysnrAI — `lysnr-*` (13 secrets, code in `packages/config/src/keyvault.ts`)
| KV Secret Name | Env Var | Used By | Priority | | KV Secret Name | Env Var | Used By | Priority |
|----------------|---------|---------|----------| | ------------------------------ | ------------------------------ | ------------------------ | -------- |
| `lysnr-cosmos-key` | `COSMOS_KEY` | All services, dashboards | Critical | | `lysnr-cosmos-key` | `COSMOS_KEY` | All services, dashboards | Critical |
| `lysnr-cosmos-endpoint` | `COSMOS_ENDPOINT` | All services, dashboards | Critical | | `lysnr-cosmos-endpoint` | `COSMOS_ENDPOINT` | All services, dashboards | Critical |
| `lysnr-jwt-secret` | `JWT_SECRET` | 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-secret-key` | `STRIPE_SECRET_KEY` | platform-service | Critical |
| `lysnr-stripe-webhook-secret` | `STRIPE_WEBHOOK_SECRET` | platform-service | Critical | | `lysnr-stripe-webhook-secret` | `STRIPE_WEBHOOK_SECRET` | platform-service | Critical |
| `lysnr-billing-internal-key` | `BILLING_INTERNAL_KEY` | platform-service | High | | `lysnr-billing-internal-key` | `BILLING_INTERNAL_KEY` | platform-service | High |
| `lysnr-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | platform-service | Critical | | `lysnr-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | platform-service | Critical |
| `lysnr-blob-account-key` | `AZURE_BLOB_ACCOUNT_KEY` | 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-gemini-api-key` | `GEMINI_API_KEY` | extraction-service | Critical |
| `lysnr-seed-secret` | `SEED_SECRET` | admin dashboard | Medium | | `lysnr-seed-secret` | `SEED_SECRET` | admin dashboard | Medium |
| `lysnr-azure-speech-key` | `AZURE_SPEECH_KEY` | desktop, backend | High | | `lysnr-azure-speech-key` | `AZURE_SPEECH_KEY` | desktop, backend | High |
| `lysnr-azure-openai-key` | `AZURE_OPENAI_KEY` | extraction-service | High | | `lysnr-azure-openai-key` | `AZURE_OPENAI_KEY` | extraction-service | High |
| `lysnr-azure-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | extraction-service | High | | `lysnr-azure-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | extraction-service | High |
### MindLyst — `mindlyst-*` (12 secrets, all populated) ### MindLyst — `mindlyst-*` (12 secrets, all populated)
| KV Secret Name | Env Var | Notes | | KV Secret Name | Env Var | Notes |
|----------------|---------|-------| | --------------------------------------------- | --------------------------------------- | -------------------- |
| `mindlyst-cosmos-endpoint` | `COSMOS_ENDPOINT` | Config | | `mindlyst-cosmos-endpoint` | `COSMOS_ENDPOINT` | Config |
| `mindlyst-cosmos-key` | `COSMOS_KEY` | Rotate via key1/key2 | | `mindlyst-cosmos-key` | `COSMOS_KEY` | Rotate via key1/key2 |
| `mindlyst-cosmos-database` | `COSMOS_DATABASE` | Config (`mindlyst`) | | `mindlyst-cosmos-database` | `COSMOS_DATABASE` | Config (`mindlyst`) |
| `mindlyst-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | Config | | `mindlyst-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | Config |
| `mindlyst-openai-key` | `AZURE_OPENAI_KEY` | Rotate via key1/key2 | | `mindlyst-openai-key` | `AZURE_OPENAI_KEY` | Rotate via key1/key2 |
| `mindlyst-openai-deployment` | `AZURE_OPENAI_DEPLOYMENT` | Config | | `mindlyst-openai-deployment` | `AZURE_OPENAI_DEPLOYMENT` | Config |
| `mindlyst-openai-api-version` | `AZURE_OPENAI_API_VERSION` | Config | | `mindlyst-openai-api-version` | `AZURE_OPENAI_API_VERSION` | Config |
| `mindlyst-speech-key` | `AZURE_SPEECH_KEY` | Rotate via key1/key2 | | `mindlyst-speech-key` | `AZURE_SPEECH_KEY` | Rotate via key1/key2 |
| `mindlyst-speech-region` | `AZURE_SPEECH_REGION` | Config | | `mindlyst-speech-region` | `AZURE_SPEECH_REGION` | Config |
| `mindlyst-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | Rotate via key1/key2 | | `mindlyst-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | Rotate via key1/key2 |
| `mindlyst-notification-hub-connection-string` | `ANH_CONNECTION_STRING` | Rotate SAS keys | | `mindlyst-notification-hub-connection-string` | `ANH_CONNECTION_STRING` | Rotate SAS keys |
| `mindlyst-appinsights-connection-string` | `APPLICATIONINSIGHTS_CONNECTION_STRING` | Treat as sensitive | | `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` |
--- ---
@ -112,7 +103,7 @@ The admin dashboard at **`/ops/secrets`** provides live CRUD access to Key Vault
### 1. Seed LysnrAI Secrets (BLOCKING) ### 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 ```bash
# Option A: Use the seed script (reads from .env) # 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 # Navigate to /ops/secrets → Add Secret for each
# Option C: Use az cli directly # Option C: Use az cli directly
az keyvault secret set --vault-name kv-mywisprai --name lysnr-cosmos-key --value "<value>" -o none az keyvault secret set --vault-name kv-mywisprai --name lysnr-cosmos-key --value "<value>" -o none # vault name is legacy
``` ```
### 2. Rotate Leaked Keys (DEFERRED) ### 2. Rotate Leaked Keys (DEFERRED)
Secrets have appeared in git history. Rotate after seeding: 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 - [ ] Storage account keys (`bytelystblobs`) → update blob connection strings
- [ ] Azure OpenAI keys (`mywisprai-openai-sweden`) → update OpenAI key secrets - [ ] Azure OpenAI keys (`mywisprai-openai-sweden` — legacy name) → update OpenAI key secrets
- [ ] Speech keys (`mywisprai-speech`) → update speech key secrets - [ ] Speech keys (`mywisprai-speech` — legacy name) → update speech key secrets
- [ ] Notification Hub SAS keys → update `mindlyst-notification-hub-connection-string` - [ ] Notification Hub SAS keys → update `mindlyst-notification-hub-connection-string`
### 3. Enable KV Diagnostics ### 3. Enable KV Diagnostics
@ -200,13 +191,13 @@ Supports key1/key2.
### Recommended Rotation Schedule ### Recommended Rotation Schedule
| Secret Type | Frequency | Method | | Secret Type | Frequency | Method |
|-------------|-----------|--------| | ------------------------- | --------------------- | ----------------------------------------- |
| Cosmos DB keys | Quarterly | Azure Portal → rotate → update KV | | Cosmos DB keys | Quarterly | Azure Portal → rotate → update KV |
| JWT secret | Quarterly | Generate new → update KV → rolling deploy | | JWT secret | Quarterly | Generate new → update KV → rolling deploy |
| Stripe keys | Annually or on breach | Stripe Dashboard → update KV | | Stripe keys | Annually or on breach | Stripe Dashboard → update KV |
| API keys (Gemini, OpenAI) | Annually or on breach | Provider portal → update KV | | API keys (Gemini, OpenAI) | Annually or on breach | Provider portal → update KV |
| Blob storage keys | Quarterly | Azure Portal → rotate → update KV | | Blob storage keys | Quarterly | Azure Portal → rotate → update KV |
--- ---
@ -227,13 +218,13 @@ Supports key1/key2.
## Related Files ## Related Files
| File | Purpose | | File | Purpose |
|------|---------| | --------------------------------------------------------- | ----------------------------------------------------- |
| `packages/config/src/keyvault.ts` | `resolveKeyVaultSecrets()` + `LYSNR_SECRETS` constant | | `packages/config/src/keyvault.ts` | `resolveKeyVaultSecrets()` + `LYSNR_SECRETS` constant |
| `scripts/seed-keyvault.sh` | Seed KV from `.env` values | | `scripts/seed-keyvault.sh` | Seed KV from `.env` values |
| `docs/devops/AZURE_RESOURCE_INVENTORY.md` | Complete Azure resource inventory | | `docs/devops/AZURE_RESOURCE_INVENTORY.md` | Complete Azure resource inventory |
| `docs/devops/AZURE_PORTAL_SETUP.md` | Step-by-step provisioning guide | | `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 | | `docs/devops/ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md` | Full env var + KV gap analysis |
--- ---

View File

@ -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. > **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. > **Architecture:** Single RG, shared stateless services, separate databases.
> **Time estimate:** ~20 minutes (most resources already exist from LysnrAI) > **Time estimate:** ~20 minutes (most resources already exist from LysnrAI)
> **Prerequisites:** An Azure account with an active subscription > **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) rg-mywisprai/ (1 resource group)
├── cosmos-mywisprai (1 Cosmos DB account — already exists) ├── cosmos-mywisprai (1 Cosmos DB account — already exists)
│ ├── mywisprai (database: 10 containers — existing) │ ├── mywisprai (database: LysnrAI — legacy name, 10 containers)
│ └── mindlyst (database: 12 containers — MindLyst) │ └── mindlyst (database: MindLyst, 12 containers)
├── bytelystblobs (1 Storage account — already exists) ├── bytelystblobs (1 Storage account — already exists)
│ ├── mindlyst-voice ← NEW │ ├── mindlyst-voice ← NEW
@ -54,8 +56,9 @@ rg-mywisprai/ (1 resource group)
├── mywisprai-speech (1 Speech Service — shared, eastus) ├── mywisprai-speech (1 Speech Service — shared, eastus)
├── kv-mywisprai (1 Key Vault — shared) ├── kv-mywisprai (1 Key Vault — shared)
│ ├── wispr-* (existing secrets) │ ├── lysnr-* (LysnrAI secrets)
│ └── mindlyst-* (MindLyst secrets) ← NEW │ ├── wispr-* (LysnrAI legacy secrets, pre-rebrand)
│ └── mindlyst-* (MindLyst secrets)
├── lysnnai (1 Notification Hub namespace) ├── lysnnai (1 Notification Hub namespace)
│ ├── notificationhub (existing hub) │ ├── notificationhub (existing hub)
@ -68,21 +71,21 @@ rg-mywisprai/ (1 resource group)
### Why Share? ### Why Share?
| Concern | Answer | | Concern | Answer |
|---------|--------| | ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| **Cost** | Cosmos DB Serverless charges per-RU, not per-account. One account = one endpoint, one key pair, simpler rotation | | **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 | | **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 | | **Data isolation** | Separate databases within Cosmos = full container-level isolation. Queries can't cross databases |
| **Teardown safety** | Delete the `mindlyst` database → LysnrAI data untouched | | **Teardown safety** | Delete the `mindlyst` database → LysnrAI data untouched |
| **Stateless services** | OpenAI & Speech are stateless — same key serves both apps, no data leakage | | **Stateless services** | OpenAI & Speech are stateless — same key serves both apps, no data leakage |
### What Must Stay Separate ### What Must Stay Separate
| Resource | Why | | Resource | Why |
|----------|-----| | ------------------------- | ------------------------------------------------------------------------------ |
| **Notification Hub hubs** | Each app has its own APNs certificate and FCM server key | | **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) | | **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 | | **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: These resources are **already provisioned** and will be reused by MindLyst:
| Resource | Azure Name | Region | SKU | Status | | Resource | Azure Name | Region | SKU | Status |
|----------|-----------|--------|-----|--------| | -------------------------------- | ------------------------- | --------------- | ----------------- | ------------------------------------------------------------------------------ |
| **Resource Group** | `rg-mywisprai` | `eastus` | — | Exists | | **Resource Group** | `rg-mywisprai` | `eastus` | — | Exists |
| **Cosmos DB** | `cosmos-mywisprai` | `westus2` | Serverless, NoSQL | Exists — DBs: `mywisprai` (10 containers), `mindlyst` (12 containers) | | **Cosmos DB** | `cosmos-mywisprai` | `westus2` | Serverless, NoSQL | Exists — DBs: `mywisprai` (LysnrAI, 10 containers), `mindlyst` (12 containers) |
| **Blob Storage** | `bytelystblobs` | `westus2` | StorageV2, RAGRS | Exists | | **Blob Storage** | `bytelystblobs` | `westus2` | StorageV2, RAGRS | Exists |
| **Azure OpenAI** | `mywisprai-openai-sweden` | `swedencentral` | S0 | Exists — deployment: `gpt-4o-mini` | | **Azure OpenAI** | `mywisprai-openai-sweden` | `swedencentral` | S0 | Exists — deployment: `gpt-4o-mini` |
| **Speech Service** | `mywisprai-speech` | `eastus` | F0 | Exists | | **Speech Service** | `mywisprai-speech` | `eastus` | F0 | Exists |
| **Key Vault** | `kv-mywisprai` | `eastus` | Standard | Exists | | **Key Vault** | `kv-mywisprai` | `eastus` | Standard | Exists |
| **Notification Hub (namespace)** | `lysnnai` | `eastus` | Free | Exists (hubs: `notificationhub`, `mindlyst-hub`) | | **Notification Hub (namespace)** | `lysnnai` | `eastus` | Free | Exists (hubs: `notificationhub`, `mindlyst-hub`) |
| **Application Insights** | `bytelyst-appinsights` | `eastus` | Classic | Exists | | **Application Insights** | `bytelyst-appinsights` | `eastus` | Classic | Exists |
### Cosmos DB: Existing LysnrAI database containers (staging) ### Cosmos DB: Existing LysnrAI database containers (staging)
Database: `mywisprai` (existing) Database: `mywisprai` (legacy name — this is the LysnrAI database)
- `api_tokens` - `api_tokens`
- `audit_log` - `audit_log`
@ -137,7 +140,7 @@ MindLyst secrets (canonical):
- `mindlyst-notification-hub-connection-string` - `mindlyst-notification-hub-connection-string`
- `mindlyst-appinsights-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-deployment`
- `wispr-azure-openai-endpoint` - `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: Only these additions are needed — no new accounts to create:
| Action | Where | What | | Action | Where | What |
|--------|-------|------| | ------------------------ | -------------------------------------- | ---------------------------------------------------------------------------- |
| **Rename RG (optional)** | Resource Group | Keep `rg-mywisprai` for now. Only move resources if you want a cleaner name. | | **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 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 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 secrets** | Key Vault (`kv-mywisprai`) | 12 secrets with `mindlyst-` prefix (keys + config) |
| **Add hub** | Notification Hub namespace (`lysnnai`) | New hub `mindlyst-hub` | | **Add hub** | Notification Hub namespace (`lysnnai`) | New hub `mindlyst-hub` |
| **Create App Insights** | New resource | `bytelyst-appinsights` (shared telemetry) | | **Create App Insights** | New resource | `bytelyst-appinsights` (shared telemetry) |
### Current Staging State (Completed) ### 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**: For each container below, right-click the **`mindlyst`** database (or click the `…` menu) → **New Container**:
| # | Container Name | Partition Key | Purpose | | # | Container Name | Partition Key | Purpose |
|---|----------------|--------------|---------| | --- | ------------------ | --------------- | ------------------------------------------------------------------ |
| 1 | `users` | `/id` | User accounts and profiles | | 1 | `users` | `/id` | User accounts and profiles |
| 2 | `brains` | `/userId` | User brain configurations (War Room, Home Base, Money Guard, etc.) | | 2 | `brains` | `/userId` | User brain configurations (War Room, Home Base, Money Guard, etc.) |
| 3 | `brain_templates` | `/id` | Brain Pack gallery templates | | 3 | `brain_templates` | `/id` | Brain Pack gallery templates |
| 4 | `memory_items` | `/userId` | All captured memories (text, voice, image, link, email) | | 4 | `memory_items` | `/userId` | All captured memories (text, voice, image, link, email) |
| 5 | `actions` | `/memoryItemId` | AI-suggested actions from triage | | 5 | `actions` | `/memoryItemId` | AI-suggested actions from triage |
| 6 | `entities` | `/memoryItemId` | Extracted entities (people, dates, places, amounts) | | 6 | `entities` | `/memoryItemId` | Extracted entities (people, dates, places, amounts) |
| 7 | `reflections` | `/userId` | Weekly reflection reports and insights | | 7 | `reflections` | `/userId` | Weekly reflection reports and insights |
| 8 | `share_cards` | `/userId` | Generated share cards for social sharing | | 8 | `share_cards` | `/userId` | Generated share cards for social sharing |
| 9 | `daily_briefs` | `/userId` | Morning and evening brief content | | 9 | `daily_briefs` | `/userId` | Morning and evening brief content |
| 10 | `streaks` | `/userId` | Capture streak tracking and gamification | | 10 | `streaks` | `/userId` | Capture streak tracking and gamification |
| 11 | `notification_log` | `/userId` | Push notification delivery log and scheduling | | 11 | `notification_log` | `/userId` | Push notification delivery log and scheduling |
| 12 | `brain_insights` | `/userId` | Cross-brain insight discoveries | | 12 | `brain_insights` | `/userId` | Cross-brain insight discoveries |
**For each container:** **For each container:**
1. Click **New Container** 1. Click **New Container**
2. **Existing Database:** select `mindlyst` (do NOT create a new database) 2. **Existing Database:** select `mindlyst` (do NOT create a new database)
3. Enter the **Container id** from the table 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) 2. Go to **Data storage****Containers** (left sidebar)
3. Click **+ Container** for each: 3. Click **+ Container** for each:
| Container Name | Access Level | Purpose | | Container Name | Access Level | Purpose |
|----------------|-------------|---------| | ------------------ | ------------ | ---------------------------------------------------- |
| `mindlyst-voice` | **Private** | Voice capture recordings (WAV/PCM from STT pipeline) | | `mindlyst-voice` | **Private** | Voice capture recordings (WAV/PCM from STT pipeline) |
| `mindlyst-images` | **Private** | Captured photos, screenshots, and OCR source images | | `mindlyst-images` | **Private** | Captured photos, screenshots, and OCR source images |
| `mindlyst-exports` | **Private** | User data exports (JSON), weekly reflection PDFs | | `mindlyst-exports` | **Private** | User data exports (JSON), weekly reflection PDFs |
For each: For each:
1. Click **+ Container** 1. Click **+ Container**
2. Enter the **Name** (must be lowercase, no underscores — use hyphens) 2. Enter the **Name** (must be lowercase, no underscores — use hyphens)
3. **Anonymous access level:** leave as **Private (no anonymous access)** 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): You should now see these MindLyst containers in `bytelystblobs` (plus any other app containers you already had):
| Container | App | | Container | App |
|-----------|-----| | ------------------ | -------- |
| `mindlyst-voice` | MindLyst | | `mindlyst-voice` | MindLyst |
| `mindlyst-images` | MindLyst | | `mindlyst-images` | MindLyst |
| `mindlyst-exports` | MindLyst | | `mindlyst-exports` | MindLyst |
### Connection details (from Key Vault) ### Connection details (from Key Vault)
@ -345,20 +350,20 @@ Speech connection details are stored in Key Vault:
MindLyst secrets (canonical): MindLyst secrets (canonical):
| Key Vault secret name | Env var | Notes | | Key Vault secret name | Env var | Notes |
|---|---|---| | --------------------------------------------- | --------------------------------------- | ------------------------- |
| `mindlyst-cosmos-endpoint` | `COSMOS_ENDPOINT` | Config (ok to store) | | `mindlyst-cosmos-endpoint` | `COSMOS_ENDPOINT` | Config (ok to store) |
| `mindlyst-cosmos-key` | `COSMOS_KEY` | Secret | | `mindlyst-cosmos-key` | `COSMOS_KEY` | Secret |
| `mindlyst-cosmos-database` | `COSMOS_DATABASE` | Config (`mindlyst`) | | `mindlyst-cosmos-database` | `COSMOS_DATABASE` | Config (`mindlyst`) |
| `mindlyst-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | Config | | `mindlyst-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | Config |
| `mindlyst-openai-key` | `AZURE_OPENAI_KEY` | Secret | | `mindlyst-openai-key` | `AZURE_OPENAI_KEY` | Secret |
| `mindlyst-openai-deployment` | `AZURE_OPENAI_DEPLOYMENT` | Config | | `mindlyst-openai-deployment` | `AZURE_OPENAI_DEPLOYMENT` | Config |
| `mindlyst-openai-api-version` | `AZURE_OPENAI_API_VERSION` | Config | | `mindlyst-openai-api-version` | `AZURE_OPENAI_API_VERSION` | Config |
| `mindlyst-speech-key` | `AZURE_SPEECH_KEY` | Secret | | `mindlyst-speech-key` | `AZURE_SPEECH_KEY` | Secret |
| `mindlyst-speech-region` | `AZURE_SPEECH_REGION` | Config | | `mindlyst-speech-region` | `AZURE_SPEECH_REGION` | Config |
| `mindlyst-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | Secret (prefer SAS later) | | `mindlyst-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | Secret (prefer SAS later) |
| `mindlyst-notification-hub-connection-string` | `ANH_CONNECTION_STRING` | Secret | | `mindlyst-notification-hub-connection-string` | `ANH_CONNECTION_STRING` | Secret |
| `mindlyst-appinsights-connection-string` | `APPLICATIONINSIGHTS_CONNECTION_STRING` | Treat as sensitive | | `mindlyst-appinsights-connection-string` | `APPLICATIONINSIGHTS_CONNECTION_STRING` | Treat as sensitive |
List whats currently in the vault: List whats 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) ### Existing LysnrAI secrets (for reference)
| Secret Name | Notes | | Secret Name | Notes |
|-------------|-------| | ------------------------------- | ---------------------------------------------- |
| `wispr-azure-openai-deployment` | Existing OpenAI deployment name | | `wispr-azure-openai-deployment` | Legacy (pre-rebrand) — superseded by `lysnr-*` |
| `wispr-azure-openai-endpoint` | Existing OpenAI endpoint | | `wispr-azure-openai-endpoint` | Legacy (pre-rebrand) |
| `wispr-azure-openai-key` | Existing OpenAI key | | `wispr-azure-openai-key` | Legacy (pre-rebrand) |
| `wispr-azure-speech-key` | Existing Speech key | | `wispr-azure-speech-key` | Legacy (pre-rebrand) |
| `wispr-azure-speech-region` | Existing Speech region | | `wispr-azure-speech-region` | Legacy (pre-rebrand) |
--- ---
@ -435,6 +440,7 @@ Non-secret config:
### Create (if not exists) ### Create (if not exists)
Option A: Workspace-based (recommended) Option A: Workspace-based (recommended)
1. Search **"Application Insights"** → click **Create** 1. Search **"Application Insights"** → click **Create**
2. Fill in: 2. Fill in:
- **Resource group:** `rg-mywisprai` - **Resource group:** `rg-mywisprai`
@ -460,10 +466,10 @@ In your application code, add a custom property to every trace:
```typescript ```typescript
// MindLyst // MindLyst
telemetryClient.context.tags["ai.cloud.role"] = "mindlyst-web"; telemetryClient.context.tags['ai.cloud.role'] = 'mindlyst-web';
// LysnrAI // 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"`** Then filter in the Azure Portal: **Application Insights → Logs → `where cloud_RoleName == "mindlyst-web"`**
@ -549,16 +555,16 @@ EOF
After completing all steps, verify: After completing all steps, verify:
| # | Check | How | | # | Check | How |
|---|-------|-----| | --- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| 1 | **Cosmos DB: `mindlyst` database** | Data Explorer → expand `cosmos-mywisprai``mindlyst` → 12 containers visible | | 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 | | 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` | | 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 | | 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 | | 5 | **OpenAI deployment** | Azure OpenAI Studio → Deployments → `gpt-4o-mini` listed |
| 6 | **Speech Service keys** | Speech resource → Keys and Endpoint → keys visible | | 6 | **Speech Service keys** | Speech resource → Keys and Endpoint → keys visible |
| 7 | **Key Vault: MindLyst secrets** | Key Vault → Secrets → `mindlyst-*` entries 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) | | 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) ### Combined Cost (LysnrAI + MindLyst, MVP / Low Usage)
| Service | Pricing | LysnrAI | MindLyst | Combined | | Service | Pricing | LysnrAI | MindLyst | Combined |
|---------|---------|---------|----------|----------| | -------------------------- | ------------------------------ | ------- | -------- | ---------------- |
| Cosmos DB (Serverless) | $0.25/M RU + $0.25/GB | ~$2 | ~$2 | ~$4 | | 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 | | 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 | | 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 | | Speech (F0 free) | 5h STT free | $0 | $0 | $0 |
| Key Vault | $0.03/10K ops | ~$0.03 | ~$0.03 | ~$0.06 | | Key Vault | $0.03/10K ops | ~$0.03 | ~$0.03 | ~$0.06 |
| App Insights | 5GB/month free | $0 | $0 | $0 | | App Insights | 5GB/month free | $0 | $0 | $0 |
| Notification Hub (Free) | 1M pushes/month free | $0 | $0 | $0 | | Notification Hub (Free) | 1M pushes/month free | $0 | $0 | $0 |
| **Total** | | | | **~$515/month** | | **Total** | | | | **~$515/month** |
### Cost Savings from Sharing ### Cost Savings from Sharing
@ -589,16 +595,16 @@ After completing all steps, verify:
## Resource Naming Convention ## Resource Naming Convention
| Azure Resource | Current Name | Ideal Name | Notes | | Azure Resource | Current Name | Ideal Name | Notes |
|---------------|-------------|------------|-------| | ------------------- | ------------------------- | ----------------- | --------------------------------------------- |
| Resource Group | `rg-mywisprai` | `rg-bytelyst` | Move resources to new RG (Step 1) | | 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 | | Cosmos DB Account | `cosmos-mywisprai` | `cosmos-bytelyst` | Can't rename — keep as-is |
| Blob Storage | `bytelystblobs` | `bytelystblobs` | Already brand-neutral | | Blob Storage | `bytelystblobs` | `bytelystblobs` | Already brand-neutral |
| Azure OpenAI | `mywisprai-openai-sweden` | — | Can't rename — keep as-is | | Azure OpenAI | `mywisprai-openai-sweden` | — | Can't rename — keep as-is |
| Speech Service | `mywisprai-speech` | — | 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 | | 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 | | 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 | | 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. > **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 set -euo pipefail
# ───────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────
# BytelystAI — Azure Resource Setup Script # ByteLyst — Azure Resource Setup Script
# Creates MindLyst deltas inside an existing shared resource group # 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. 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 | | Bicep parameter | Current staging value | Notes |
|---|---|---| | ------------------------------ | ------------------------- | ---------------------------------------------------------------------------- |
| `resourceGroupName` | `rg-mywisprai` | In a new subscription, choose a new RG name (example: `rg-bytelyst-staging`) | | `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 | | `cosmosAccountName` | `cosmos-mywisprai` | Globally unique; must change in another subscription |
| `storageAccountName` | `bytelystblobs` | 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 | | `openAiAccountName` | `mywisprai-openai-sweden` | Globally unique; must change in another subscription |
| `speechAccountName` | `mywisprai-speech` | 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 | | `keyVaultName` | `kv-mywisprai` | Globally unique; must change in another subscription |
| `notificationHubNamespaceName` | `lysnnai` | 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) | | `mindlystHubName` | `mindlyst-hub` | Not globally unique (scoped to the namespace) |
| `appInsightsName` | `bytelyst-appinsights` | Must be unique within the RG | | `appInsightsName` | `bytelyst-appinsights` | Must be unique within the RG |
| `createMywispraiDatabase` | N/A | Creates an empty `mywisprai` database placeholder (no containers) | | `createMywispraiDatabase` | N/A | Creates an empty `mywisprai` database placeholder (LysnrAI, no containers) |
| `deployerObjectId` | N/A | If set, Bicep also creates Key Vault secrets (`mindlyst-*`) | | `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:** **Next steps after provisioning:**
1. (Done) MindLyst web: Enable Azure OpenAI triage + brain-chat (`OPENAI_PROVIDER=azure` + `AZURE_OPENAI_*`) 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_*`) 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.) 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 ## Quick Reference: Portal URLs
| Resource | Direct Link | | Resource | Direct Link |
|----------|-------------| | ----------------------- | --------------------------------------------------------- |
| Resource Group | `portal.azure.com → Resource groups → rg-mywisprai` | | Resource Group | `portal.azure.com → Resource groups → rg-mywisprai` |
| Cosmos DB Data Explorer | `portal.azure.com → cosmos-mywisprai → Data Explorer` | | Cosmos DB Data Explorer | `portal.azure.com → cosmos-mywisprai → Data Explorer` |
| Blob Containers | `portal.azure.com → bytelystblobs → Containers` | | Blob Containers | `portal.azure.com → bytelystblobs → Containers` |
| OpenAI Studio | `oai.azure.com` → select `mywisprai-openai-sweden` | | OpenAI Studio | `oai.azure.com` → select `mywisprai-openai-sweden` |
| Speech Keys | `portal.azure.com → mywisprai-speech → Keys and Endpoint` | | Speech Keys | `portal.azure.com → mywisprai-speech → Keys and Endpoint` |
| Key Vault Secrets | `portal.azure.com → kv-mywisprai → Secrets` | | Key Vault Secrets | `portal.azure.com → kv-mywisprai → Secrets` |
--- ---

View File

@ -1,31 +1,33 @@
# Azure Resource Inventory # Azure Resource Inventory
> **Last Updated:** 2026-02-14 > **Last Updated:** 2026-03-21
> **Purpose:** Complete inventory of Azure resources for ByteLyst AI products > **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 ## 📋 Subscription Details
| Property | Value | | Property | Value |
|----------|-------| | --------------------- | -------------------------------------- |
| **Subscription Name** | Azure subscription 1 | | **Subscription Name** | Azure subscription 1 |
| **Subscription ID** | `0e0ceaea-2677-4097-9401-1102707db826` | | **Subscription ID** | `0e0ceaea-2677-4097-9401-1102707db826` |
| **Tenant** | eScube | | **Tenant** | eScube |
| **Tenant Domain** | saravanakumardblive.onmicrosoft.com | | **Tenant Domain** | saravanakumardblive.onmicrosoft.com |
| **Tenant ID** | `ab33246e-c9c9-4cb9-9a87-3616bb4920f0` | | **Tenant ID** | `ab33246e-c9c9-4cb9-9a87-3616bb4920f0` |
| **Account** | saravanakumardb@live.com | | **Account** | saravanakumardb@live.com |
| **Environment** | AzureCloud | | **Environment** | AzureCloud |
| **State** | Enabled | | **State** | Enabled |
--- ---
## 🗂️ Resource Groups ## 🗂️ Resource Groups
| Resource Group | Location | Status | Managed By | Type | | Resource Group | Location | Status | Managed By | Type |
|---------------|----------|---------|------------|------| | ------------------------------------------------------------------------ | -------- | --------- | -------------------- | ---------------------- |
| **rg-mywisprai** | East US | Succeeded | - | Primary resource group | | **rg-mywisprai** | East US | Succeeded | - | Primary resource group |
| **ai_bytelyst-appinsights_533a81a0-d1e6-4b01-935a-67dd49a218da_managed** | East US | Succeeded | Application Insights | Auto-managed | | **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) #### Resource Group: `rg-mywisprai` (East US)
##### 🗄️ **Cosmos DB** - Database Account ##### 🗄️ **Cosmos DB** - Database Account
| Property | Value |
|----------|-------| | Property | Value |
| **Name** | cosmos-mywisprai | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Type** | Microsoft.DocumentDb/databaseAccounts | | **Name** | cosmos-mywisprai |
| **Location** | West US 2 | | **Type** | Microsoft.DocumentDb/databaseAccounts |
| **Kind** | GlobalDocumentDB (SQL API) | | **Location** | West US 2 |
| **Status** | Succeeded | | **Kind** | GlobalDocumentDB (SQL API) |
| **Created** | 2026-02-09 | | **Status** | Succeeded |
| **Workload Type** | Development/Testing | | **Created** | 2026-02-09 |
| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.DocumentDb/databaseAccounts/cosmos-mywisprai` | | **Workload Type** | Development/Testing |
| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.DocumentDb/databaseAccounts/cosmos-mywisprai` |
**📦 Databases & Containers:** **📦 Databases & Containers:**
| Database | Containers | Purpose | | Database | Containers | Purpose |
|----------|-----------|---------| | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| **mindlyst** | • streaks<br>• users<br>• brain_insights<br>• brain_templates<br>• daily_briefs<br>• memory_items<br>• notification_log<br>• brains<br>• actions<br>• entities<br>• share_cards<br>• reflections | MindLyst product data | | **mindlyst** | • streaks<br>• users<br>• brain_insights<br>• brain_templates<br>• daily_briefs<br>• memory_items<br>• notification_log<br>• brains<br>• actions<br>• entities<br>• share_cards<br>• reflections | MindLyst product data |
| **lysnrai** | • subscriptions<br>• notification_prefs<br>• licenses<br>• tracker_votes<br>• feature_flags<br>• payments<br>• tracker_items<br>• audit_log<br>• invitation_codes<br>• devices<br>• usage_daily<br>• tracker_comments<br>• referrals<br>• plans<br>• users | LysnrAI product + platform services | | **lysnrai** | • subscriptions<br>• notification_prefs<br>• licenses<br>• tracker_votes<br>• feature_flags<br>• payments<br>• tracker_items<br>• audit_log<br>• invitation_codes<br>• devices<br>• usage_daily<br>• tracker_comments<br>• referrals<br>• plans<br>• users | LysnrAI product + platform services |
| **mywisprai** | • licenses<br>• api_tokens<br>• transcripts<br>• audit_log<br>• subscriptions<br>• usage_daily<br>• users<br>• settings<br>• payments<br>• devices | MyWisprAI product data | | **mywisprai** | • licenses<br>• api_tokens<br>• transcripts<br>• audit_log<br>• subscriptions<br>• usage_daily<br>• users<br>• settings<br>• payments<br>• devices | LysnrAI legacy data (pre-rebrand database name) |
**🔑 Key Environment Variables:** **🔑 Key Environment Variables:**
```bash ```bash
COSMOS_ENDPOINT=https://cosmos-mywisprai.documents.azure.com:443/ COSMOS_ENDPOINT=https://cosmos-mywisprai.documents.azure.com:443/
COSMOS_DATABASE=lysnrai # or mindlyst/mywisprai depending on product 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 ##### 💾 **Storage Account** - Blob Storage
| Property | Value |
|----------|-------| | Property | Value |
| **Name** | bytelystblobs | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| **Type** | Microsoft.Storage/storageAccounts | | **Name** | bytelystblobs |
| **Location** | West US 2 (Primary) | | **Type** | Microsoft.Storage/storageAccounts |
| **Secondary Location** | West Central US | | **Location** | West US 2 (Primary) |
| **Kind** | StorageV2 | | **Secondary Location** | West Central US |
| **SKU** | Standard_RAGRS (Geo-redundant) | | **Kind** | StorageV2 |
| **Access Tier** | Cool | | **SKU** | Standard_RAGRS (Geo-redundant) |
| **Status** | Succeeded | | **Access Tier** | Cool |
| **Created** | 2026-02-12 | | **Status** | Succeeded |
| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.Storage/storageAccounts/bytelystblobs` | | **Created** | 2026-02-12 |
| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.Storage/storageAccounts/bytelystblobs` |
**🔑 Key Environment Variables:** **🔑 Key Environment Variables:**
```bash ```bash
AZURE_BLOB_ACCOUNT_NAME=bytelystblobs AZURE_BLOB_ACCOUNT_NAME=bytelystblobs
AZURE_BLOB_CONNECTION_STRING=<from-portal> AZURE_BLOB_CONNECTION_STRING=<from-portal>
@ -86,45 +92,50 @@ AZURE_BLOB_CONNECTION_STRING=<from-portal>
--- ---
##### 🔐 **Key Vault** ##### 🔐 **Key Vault**
| Property | Value |
|----------|-------| | Property | Value |
| **Name** | kv-mywisprai | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| **Type** | Microsoft.KeyVault/vaults | | **Name** | kv-mywisprai |
| **Location** | East US | | **Type** | Microsoft.KeyVault/vaults |
| **Status** | Succeeded | | **Location** | East US |
| **Created** | 2026-02-07 | | **Status** | Succeeded |
| **Created** | 2026-02-07 |
| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.KeyVault/vaults/kv-mywisprai` | | **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.KeyVault/vaults/kv-mywisprai` |
**🔑 Key Environment Variables:** **🔑 Key Environment Variables:**
```bash ```bash
AZURE_KEYVAULT_URL=https://kv-mywisprai.vault.azure.net/ AZURE_KEYVAULT_URL=https://kv-mywisprai.vault.azure.net/
``` ```
**📝 Usage in Code:** **📝 Usage in Code:**
- See: `packages/config/src/keyvault.ts` - See: `packages/config/src/keyvault.ts`
- See: `scripts/seed-keyvault.sh` - See: `scripts/seed-keyvault.sh`
--- ---
##### 🧠 **Azure OpenAI Service** ##### 🧠 **Azure OpenAI Service**
| Property | Value |
|----------|-------| | Property | Value |
| **Name** | mywisprai-openai-sweden | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Type** | Microsoft.CognitiveServices/accounts | | **Name** | mywisprai-openai-sweden |
| **Kind** | OpenAI | | **Type** | Microsoft.CognitiveServices/accounts |
| **Location** | Sweden Central | | **Kind** | OpenAI |
| **SKU** | S0 (Standard) | | **Location** | Sweden Central |
| **Status** | Succeeded | | **SKU** | S0 (Standard) |
| **Created** | 2026-02-07 | | **Status** | Succeeded |
| **Created** | 2026-02-07 |
| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.CognitiveServices/accounts/mywisprai-openai-sweden` | | **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.CognitiveServices/accounts/mywisprai-openai-sweden` |
**🚀 Model Deployments:** **🚀 Model Deployments:**
| Deployment Name | Model | Version | Capacity | | Deployment Name | Model | Version | Capacity |
|----------------|-------|---------|----------| | --------------- | ----------- | ---------- | -------- |
| gpt-4o-mini | gpt-4o-mini | 2024-07-18 | 1 TPM | | gpt-4o-mini | gpt-4o-mini | 2024-07-18 | 1 TPM |
**🔑 Key Environment Variables:** **🔑 Key Environment Variables:**
```bash ```bash
AZURE_OPENAI_ENDPOINT=https://mywisprai-openai-sweden.openai.azure.com/ AZURE_OPENAI_ENDPOINT=https://mywisprai-openai-sweden.openai.azure.com/
AZURE_OPENAI_API_KEY=<from-keyvault-or-portal> AZURE_OPENAI_API_KEY=<from-keyvault-or-portal>
@ -134,18 +145,20 @@ AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o-mini
--- ---
##### 🎤 **Speech Services** ##### 🎤 **Speech Services**
| Property | Value |
|----------|-------| | Property | Value |
| **Name** | mywisprai-speech | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Type** | Microsoft.CognitiveServices/accounts | | **Name** | mywisprai-speech |
| **Kind** | SpeechServices | | **Type** | Microsoft.CognitiveServices/accounts |
| **Location** | East US | | **Kind** | SpeechServices |
| **SKU** | F0 (Free Tier) | | **Location** | East US |
| **Status** | Succeeded | | **SKU** | F0 (Free Tier) |
| **Created** | 2026-02-07 | | **Status** | Succeeded |
| **Created** | 2026-02-07 |
| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.CognitiveServices/accounts/mywisprai-speech` | | **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.CognitiveServices/accounts/mywisprai-speech` |
**🔑 Key Environment Variables:** **🔑 Key Environment Variables:**
```bash ```bash
AZURE_SPEECH_KEY=<from-portal> AZURE_SPEECH_KEY=<from-portal>
AZURE_SPEECH_REGION=eastus AZURE_SPEECH_REGION=eastus
@ -154,24 +167,26 @@ AZURE_SPEECH_REGION=eastus
--- ---
##### 🔔 **Notification Hubs** - Push Notification Service ##### 🔔 **Notification Hubs** - Push Notification Service
| Property | Value |
|----------|-------| | Property | Value |
| **Namespace** | lysnnai | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **Type** | Microsoft.NotificationHubs/namespaces | | **Namespace** | lysnnai |
| **Location** | East US | | **Type** | Microsoft.NotificationHubs/namespaces |
| **SKU** | Free | | **Location** | East US |
| **Status** | Succeeded | | **SKU** | Free |
| **Created** | 2026-02-12 | | **Status** | Succeeded |
| **Created** | 2026-02-12 |
| **Namespace ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.NotificationHubs/namespaces/lysnnai` | | **Namespace ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.NotificationHubs/namespaces/lysnnai` |
**📱 Notification Hubs:** **📱 Notification Hubs:**
| Hub Name | Purpose | Created | | Hub Name | Purpose | Created |
|----------|---------|---------| | ------------------- | ------------------------------ | ---------- |
| **notificationhub** | General notifications | 2026-02-12 | | **notificationhub** | General notifications | 2026-02-12 |
| **mindlyst-hub** | MindLyst product notifications | 2026-02-13 | | **mindlyst-hub** | MindLyst product notifications | 2026-02-13 |
**🔑 Key Environment Variables:** **🔑 Key Environment Variables:**
```bash ```bash
AZURE_NH_CONNECTION_STRING=<from-portal> AZURE_NH_CONNECTION_STRING=<from-portal>
AZURE_NH_HUB_NAME=mindlyst-hub # or notificationhub AZURE_NH_HUB_NAME=mindlyst-hub # or notificationhub
@ -180,20 +195,23 @@ AZURE_NH_HUB_NAME=mindlyst-hub # or notificationhub
--- ---
##### 📊 **Application Insights** - Monitoring & Telemetry ##### 📊 **Application Insights** - Monitoring & Telemetry
| Property | Value |
|----------|-------| | Property | Value |
| **Name** | bytelyst-appinsights | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| **Type** | Microsoft.Insights/components | | **Name** | bytelyst-appinsights |
| **Kind** | web | | **Type** | Microsoft.Insights/components |
| **Location** | East US | | **Kind** | web |
| **Status** | Succeeded | | **Location** | East US |
| **Created** | 2026-02-13 | | **Status** | Succeeded |
| **Created** | 2026-02-13 |
| **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.Insights/components/bytelyst-appinsights` | | **Resource ID** | `/subscriptions/0e0ceaea-2677-4097-9401-1102707db826/resourceGroups/rg-mywisprai/providers/Microsoft.Insights/components/bytelyst-appinsights` |
**🔔 Action Groups:** **🔔 Action Groups:**
- **Application Insights Smart Detection** (Global) - **Application Insights Smart Detection** (Global)
**🔑 Key Environment Variables:** **🔑 Key Environment Variables:**
```bash ```bash
APPLICATIONINSIGHTS_CONNECTION_STRING=<from-portal> APPLICATIONINSIGHTS_CONNECTION_STRING=<from-portal>
APPINSIGHTS_INSTRUMENTATIONKEY=<from-portal> APPINSIGHTS_INSTRUMENTATIONKEY=<from-portal>
@ -203,18 +221,18 @@ APPINSIGHTS_INSTRUMENTATIONKEY=<from-portal>
## 📦 Resource Summary by Type ## 📦 Resource Summary by Type
| Resource Type | Count | Names | | Resource Type | Count | Names |
|--------------|-------|-------| | ------------------------------- | ----- | ------------------------------------- |
| **Cosmos DB Accounts** | 1 | cosmos-mywisprai | | **Cosmos DB Accounts** | 1 | cosmos-mywisprai |
| **Cosmos DB Databases** | 3 | mindlyst, lysnrai, mywisprai | | **Cosmos DB Databases** | 3 | mindlyst, lysnrai, mywisprai (legacy) |
| **Storage Accounts** | 1 | bytelystblobs | | **Storage Accounts** | 1 | bytelystblobs |
| **Key Vaults** | 1 | kv-mywisprai | | **Key Vaults** | 1 | kv-mywisprai |
| **Cognitive Services (OpenAI)** | 1 | mywisprai-openai-sweden | | **Cognitive Services (OpenAI)** | 1 | mywisprai-openai-sweden |
| **Cognitive Services (Speech)** | 1 | mywisprai-speech | | **Cognitive Services (Speech)** | 1 | mywisprai-speech |
| **Notification Hub Namespaces** | 1 | lysnnai | | **Notification Hub Namespaces** | 1 | lysnnai |
| **Notification Hubs** | 2 | notificationhub, mindlyst-hub | | **Notification Hubs** | 2 | notificationhub, mindlyst-hub |
| **Application Insights** | 1 | bytelyst-appinsights | | **Application Insights** | 1 | bytelyst-appinsights |
| **Action Groups** | 1 | Application Insights Smart Detection | | **Action Groups** | 1 | Application Insights Smart Detection |
**Total Resources:** 13 (excluding auto-managed resource groups) **Total Resources:** 13 (excluding auto-managed resource groups)
@ -223,6 +241,7 @@ APPINSIGHTS_INSTRUMENTATIONKEY=<from-portal>
## 🔑 Critical Environment Variables Summary ## 🔑 Critical Environment Variables Summary
### Required Across All Services: ### Required Across All Services:
```bash ```bash
# Cosmos DB # Cosmos DB
COSMOS_ENDPOINT=https://cosmos-mywisprai.documents.azure.com:443/ COSMOS_ENDPOINT=https://cosmos-mywisprai.documents.azure.com:443/
@ -259,29 +278,32 @@ APPINSIGHTS_INSTRUMENTATIONKEY=<from-portal>
## 📍 Geographic Distribution ## 📍 Geographic Distribution
| Region | Resources | | Region | Resources |
|--------|-----------| | ------------------- | ------------------------------------------------------------------- |
| **East US** | Speech Services, Key Vault, Notification Hubs, Application Insights | | **East US** | Speech Services, Key Vault, Notification Hubs, Application Insights |
| **West US 2** | Cosmos DB (primary), Blob Storage (primary) | | **West US 2** | Cosmos DB (primary), Blob Storage (primary) |
| **Sweden Central** | Azure OpenAI | | **Sweden Central** | Azure OpenAI |
| **West Central US** | Blob Storage (secondary/geo-redundant) | | **West Central US** | Blob Storage (secondary/geo-redundant) |
| **Global** | Action Groups | | **Global** | Action Groups |
--- ---
## 💰 Cost Optimization Notes ## 💰 Cost Optimization Notes
### Free Tier Resources: ### Free Tier Resources:
- ✅ Speech Services (F0) - ✅ Speech Services (F0)
- ✅ Notification Hubs (Free) - ✅ Notification Hubs (Free)
### Paid Resources: ### Paid Resources:
- 💵 Cosmos DB (Development/Testing workload) - 💵 Cosmos DB (Development/Testing workload)
- 💵 Blob Storage (Standard_RAGRS, Cool tier) - 💵 Blob Storage (Standard_RAGRS, Cool tier)
- 💵 Azure OpenAI (S0 - pay per use) - 💵 Azure OpenAI (S0 - pay per use)
- 💵 Application Insights (pay per GB ingested) - 💵 Application Insights (pay per GB ingested)
### Recommendations: ### Recommendations:
1. Monitor Cosmos DB RU consumption (Development/Testing mode has limits) 1. Monitor Cosmos DB RU consumption (Development/Testing mode has limits)
2. Blob Storage is on Cool tier (good for infrequent access) 2. Blob Storage is on Cool tier (good for infrequent access)
3. Geo-redundant storage (RAGRS) adds cost but provides disaster recovery 3. Geo-redundant storage (RAGRS) adds cost but provides disaster recovery
@ -291,47 +313,53 @@ APPINSIGHTS_INSTRUMENTATIONKEY=<from-portal>
## 🔗 Related Documentation ## 🔗 Related Documentation
| Document | Location | | Document | Location |
|----------|----------| | ------------------------------ | --------------------------------------------------------- |
| Azure Portal Setup | `docs/devops/AZURE_PORTAL_SETUP.md` | | Azure Portal Setup | `docs/devops/AZURE_PORTAL_SETUP.md` |
| Key Vault & Secrets Rotation | `docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.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` | | Environment & KV Audit | `docs/devops/ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md` |
| Cosmos DB Package | `packages/cosmos/` | | Cosmos DB Package | `packages/cosmos/` |
| Environment Variables Template | `.env.example` | | Environment Variables Template | `.env.example` |
| Key Vault Integration | `packages/config/src/keyvault.ts` | | Key Vault Integration | `packages/config/src/keyvault.ts` |
| Admin Secrets Manager | Admin dashboard → `/ops/secrets` (live CRUD for KV) | | Admin Secrets Manager | Admin dashboard → `/ops/secrets` (live CRUD for KV) |
--- ---
## 🚀 Quick Commands ## 🚀 Quick Commands
### List all resources: ### List all resources:
```bash ```bash
az resource list --output table az resource list --output table
``` ```
### Get Cosmos DB connection string: ### Get Cosmos DB connection string:
```bash ```bash
az cosmosdb keys list --name cosmos-mywisprai --resource-group rg-mywisprai --type connection-strings az cosmosdb keys list --name cosmos-mywisprai --resource-group rg-mywisprai --type connection-strings
``` ```
### Get Storage Account keys: ### Get Storage Account keys:
```bash ```bash
az storage account keys list --account-name bytelystblobs --resource-group rg-mywisprai az storage account keys list --account-name bytelystblobs --resource-group rg-mywisprai
``` ```
### Get Key Vault secrets: ### Get Key Vault secrets:
```bash ```bash
az keyvault secret list --vault-name kv-mywisprai --output table az keyvault secret list --vault-name kv-mywisprai --output table
``` ```
### Get OpenAI endpoint and keys: ### Get OpenAI endpoint and keys:
```bash ```bash
az cognitiveservices account show --name mywisprai-openai-sweden --resource-group rg-mywisprai 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 az cognitiveservices account keys list --name mywisprai-openai-sweden --resource-group rg-mywisprai
``` ```
### List OpenAI deployments: ### List OpenAI deployments:
```bash ```bash
az cognitiveservices account deployment list --name mywisprai-openai-sweden --resource-group rg-mywisprai --output table az cognitiveservices account deployment list --name mywisprai-openai-sweden --resource-group rg-mywisprai --output table
``` ```

View File

@ -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 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 Officer` to deployer user
- Assign `Key Vault Crypto User` to service managed identities (when deployed) - Assign `Key Vault Crypto User` to service managed identities (when deployed)
- **File:** Azure Portal / `az keyvault update` - **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 - [ ] **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_KEY_PROVIDER=akv # 'akv' | 'env' | 'memory'
FIELD_ENCRYPT_MEK_NAME=lysnr-mek # product-specific 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.1** Create `bytelyst-blob-mek` RSA key in AKV
- [ ] **6.1.2** Configure `bytelystblobs` storage account to use CMK from AKV - [ ] **6.1.2** Configure `bytelystblobs` storage account to use CMK from AKV
- Azure Portal → Storage account → Encryption → Customer-managed keys - 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.3** Verify all blob operations still work (upload, download, SAS tokens)
- [ ] **6.1.4** Update `AZURE_RESOURCE_INVENTORY.md` - [ ] **6.1.4** Update `AZURE_RESOURCE_INVENTORY.md`

View File

@ -1,16 +1,19 @@
# Environment Variables & Azure Key Vault Audit # 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 > **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 ## 🎯 Executive Summary
### Current Status: ### Current Status:
1. ✅ **All 13 LysnrAI secrets** seeded into Azure Key Vault (completed 2026-02-15) 1. ✅ **All 13 LysnrAI secrets** seeded into Azure Key Vault (completed 2026-02-15)
2. ✅ **MindLyst secrets** fully populated (12 secrets) 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`) 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 ## 📊 Key Vault Current State
### Azure Key Vault: `kv-mywisprai` ### Azure Key Vault: `kv-mywisprai`
**Location:** East US **Location:** East US
**Total Secrets:** 17 **Total Secrets:** 17
| Secret Name | Product | Purpose | Created | Status | | Secret Name | Product | Purpose | Created | Status |
|-------------|---------|---------|---------|--------| | --------------------------------------------- | ---------------- | ------------------------------ | ---------- | ----------------------------------- |
| `mindlyst-appinsights-connection-string` | MindLyst | Application Insights telemetry | 2026-02-14 | ✅ Active | | `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-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-database` | MindLyst | Cosmos DB database name | 2026-02-14 | ✅ Active |
| `mindlyst-cosmos-endpoint` | MindLyst | Cosmos DB endpoint | 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-cosmos-key` | MindLyst | Cosmos DB primary key | 2026-02-14 | ✅ Active |
| `mindlyst-notification-hub-connection-string` | MindLyst | Push notifications | 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-api-version` | MindLyst | OpenAI API version | 2026-02-14 | ✅ Active |
| `mindlyst-openai-deployment` | MindLyst | OpenAI deployment name | 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-endpoint` | MindLyst | Azure OpenAI endpoint | 2026-02-14 | ✅ Active |
| `mindlyst-openai-key` | MindLyst | Azure OpenAI key | 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-key` | MindLyst | Azure Speech Services key | 2026-02-14 | ✅ Active |
| `mindlyst-speech-region` | MindLyst | Azure Speech region | 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-deployment` | LysnrAI (legacy) | OpenAI deployment name | 2026-02-07 | ✅ Active (superseded by `lysnr-*`) |
| `wispr-azure-openai-endpoint` | MyWisprAI | Azure OpenAI endpoint | 2026-02-07 | ✅ Active | | `wispr-azure-openai-endpoint` | LysnrAI (legacy) | Azure OpenAI endpoint | 2026-02-07 | ✅ Active (superseded by `lysnr-*`) |
| `wispr-azure-openai-key` | MyWisprAI | Azure OpenAI key | 2026-02-07 | ✅ Active | | `wispr-azure-openai-key` | LysnrAI (legacy) | Azure OpenAI key | 2026-02-07 | ✅ Active (superseded by `lysnr-*`) |
| `wispr-azure-speech-key` | MyWisprAI | Azure Speech Services key | 2026-02-07 | ✅ Active | | `wispr-azure-speech-key` | LysnrAI (legacy) | Azure Speech Services key | 2026-02-07 | ✅ Active (superseded by `lysnr-*`) |
| `wispr-azure-speech-region` | MyWisprAI | Azure Speech region | 2026-02-07 | ✅ Active | | `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: The `LYSNR_SECRETS` constant defines these mappings:
| Key Vault Secret Name | Environment Variable | Status in KV | Priority | | Key Vault Secret Name | Environment Variable | Status in KV | Priority |
|-----------------------|---------------------|--------------|----------| | ------------------------------ | ------------------------------ | ------------- | ----------- |
| `lysnr-cosmos-key` | `COSMOS_KEY` | ✅ **Seeded** | 🔴 Critical | | `lysnr-cosmos-key` | `COSMOS_KEY` | ✅ **Seeded** | 🔴 Critical |
| `lysnr-cosmos-endpoint` | `COSMOS_ENDPOINT` | ✅ **Seeded** | 🔴 Critical | | `lysnr-cosmos-endpoint` | `COSMOS_ENDPOINT` | ✅ **Seeded** | 🔴 Critical |
| `lysnr-jwt-secret` | `JWT_SECRET` | ✅ **Seeded** | 🔴 Critical | | `lysnr-jwt-secret` | `JWT_SECRET` | ✅ **Seeded** | 🔴 Critical |
| `lysnr-stripe-secret-key` | `STRIPE_SECRET_KEY` | ✅ **Seeded** | 🔴 Critical | | `lysnr-stripe-secret-key` | `STRIPE_SECRET_KEY` | ✅ **Seeded** | 🔴 Critical |
| `lysnr-stripe-webhook-secret` | `STRIPE_WEBHOOK_SECRET` | ✅ **Seeded** | 🔴 Critical | | `lysnr-stripe-webhook-secret` | `STRIPE_WEBHOOK_SECRET` | ✅ **Seeded** | 🔴 Critical |
| `lysnr-billing-internal-key` | `BILLING_INTERNAL_KEY` | ✅ **Seeded** | 🟠 High | | `lysnr-billing-internal-key` | `BILLING_INTERNAL_KEY` | ✅ **Seeded** | 🟠 High |
| `lysnr-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | ✅ **Seeded** | 🔴 Critical | | `lysnr-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | ✅ **Seeded** | 🔴 Critical |
| `lysnr-blob-account-key` | `AZURE_BLOB_ACCOUNT_KEY` | ✅ **Seeded** | 🔴 Critical | | `lysnr-blob-account-key` | `AZURE_BLOB_ACCOUNT_KEY` | ✅ **Seeded** | 🔴 Critical |
| `lysnr-gemini-api-key` | `GEMINI_API_KEY` | ✅ **Seeded** | 🔴 Critical | | `lysnr-gemini-api-key` | `GEMINI_API_KEY` | ✅ **Seeded** | 🔴 Critical |
| `lysnr-seed-secret` | `SEED_SECRET` | ✅ **Seeded** | 🟡 Medium | | `lysnr-seed-secret` | `SEED_SECRET` | ✅ **Seeded** | 🟡 Medium |
| `lysnr-azure-speech-key` | `AZURE_SPEECH_KEY` | ✅ **Seeded** | 🟠 High | | `lysnr-azure-speech-key` | `AZURE_SPEECH_KEY` | ✅ **Seeded** | 🟠 High |
| `lysnr-azure-openai-key` | `AZURE_OPENAI_KEY` | ✅ **Seeded** | 🟠 High | | `lysnr-azure-openai-key` | `AZURE_OPENAI_KEY` | ✅ **Seeded** | 🟠 High |
| `lysnr-azure-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | ✅ **Seeded** | 🟠 High | | `lysnr-azure-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | ✅ **Seeded** | 🟠 High |
**Total Expected:** 13 secrets **Total Expected:** 13 secrets
**Total Seeded:** 13 secrets (100%) ✅ — Completed 2026-02-15 **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`) ### Core Platform Variables (from `.env.example`)
#### 🔐 Azure Key Vault #### 🔐 Azure Key Vault
| Variable | Required | Default | Used By | In KV? |
|----------|----------|---------|---------|--------| | Variable | Required | Default | Used By | In KV? |
| `AZURE_KEYVAULT_URL` | Optional | - | All services | N/A | | -------------------- | -------- | ------- | ------------ | ------ |
| `AZURE_KEYVAULT_URL` | Optional | - | All services | N/A |
**Purpose:** Enable Key Vault secret resolution. Falls back to env vars if not set. **Purpose:** Enable Key Vault secret resolution. Falls back to env vars if not set.
--- ---
#### 🗄️ Azure Cosmos DB #### 🗄️ 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 #### 🔑 Authentication & Security
| Variable | Required | Default | Used By | In KV? |
|----------|----------|---------|---------|--------| | Variable | Required | Default | Used By | In KV? |
| `JWT_SECRET` | ✅ Yes | - | platform-service, extraction-service | ❌ No | | ------------ | -------- | ------- | ------------------------------------ | ------ |
| `JWT_SECRET` | ✅ Yes | - | platform-service, extraction-service | ❌ No |
**Purpose:** JWT token signing and verification across all services. **Purpose:** JWT token signing and verification across all services.
--- ---
#### 💾 Azure Blob Storage #### 💾 Azure Blob Storage
| Variable | Required | Default | Used By | In KV? |
|----------|----------|---------|---------|--------| | 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_CONNECTION_STRING` | Optional | - | platform-service | ❌ No |
| `AZURE_BLOB_ACCOUNT_KEY` | 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. **Purpose:** File uploads, avatar storage, document storage.
**Note:** Only needed for platform-service blob module. **Note:** Only needed for platform-service blob module.
@ -116,13 +124,14 @@ The `LYSNR_SECRETS` constant defines these mappings:
--- ---
#### 💳 Stripe (Billing & Subscriptions) #### 💳 Stripe (Billing & Subscriptions)
| Variable | Required | Default | Used By | In KV? |
|----------|----------|---------|---------|--------| | Variable | Required | Default | Used By | In KV? |
| `STRIPE_SECRET_KEY` | Optional | - | platform-service | ❌ No | | ------------------------- | -------- | ------- | ---------------- | ------ |
| `STRIPE_WEBHOOK_SECRET` | Optional | - | platform-service | ❌ No | | `STRIPE_SECRET_KEY` | Optional | - | platform-service | ❌ No |
| `STRIPE_PRICE_PRO` | Optional | - | platform-service | N/A | | `STRIPE_WEBHOOK_SECRET` | Optional | - | platform-service | ❌ No |
| `STRIPE_PRICE_ENTERPRISE` | Optional | - | platform-service | N/A | | `STRIPE_PRICE_PRO` | Optional | - | platform-service | N/A |
| `BILLING_INTERNAL_KEY` | Optional | - | platform-service | ❌ No | | `STRIPE_PRICE_ENTERPRISE` | Optional | - | platform-service | N/A |
| `BILLING_INTERNAL_KEY` | Optional | - | platform-service | ❌ No |
**Purpose:** Subscription management, payment processing, webhook validation. **Purpose:** Subscription management, payment processing, webhook validation.
**Status:** ❌ **Required for production but completely missing from Key Vault** **Status:** ❌ **Required for production but completely missing from Key Vault**
@ -130,11 +139,12 @@ The `LYSNR_SECRETS` constant defines these mappings:
--- ---
#### 🤖 AI Services - Extraction #### 🤖 AI Services - Extraction
| Variable | Required | Default | Used By | In KV? |
|----------|----------|---------|---------|--------| | 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 | | `GEMINI_API_KEY` | ✅ Yes | - | extraction-service (Python sidecar) | ❌ No |
| `DEFAULT_MODEL_ID` | No | `gemini-2.5-flash` | extraction-service | N/A | | `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. **Purpose:** Text extraction, content analysis, AI-powered features.
**Status:** ❌ **Critical for extraction service functionality** **Status:** ❌ **Critical for extraction service functionality**
@ -142,11 +152,12 @@ The `LYSNR_SECRETS` constant defines these mappings:
--- ---
#### 🧠 Azure OpenAI (Optional) #### 🧠 Azure OpenAI (Optional)
| Variable | Required | Default | Used By | In KV? |
|----------|----------|---------|---------|--------| | 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_KEY` | Optional | - | extraction-service | ❌ No (lysnr) |
| `AZURE_OPENAI_DEPLOYMENT_NAME` | Optional | - | extraction-service | N/A | | `AZURE_OPENAI_ENDPOINT` | Optional | - | extraction-service | ❌ No (lysnr) |
| `AZURE_OPENAI_DEPLOYMENT_NAME` | Optional | - | extraction-service | N/A |
**Purpose:** Alternative to Gemini for text extraction. **Purpose:** Alternative to Gemini for text extraction.
**Existing:** ✅ Available for `wispr` and `mindlyst` products in Key Vault. **Existing:** ✅ Available for `wispr` and `mindlyst` products in Key Vault.
@ -154,10 +165,11 @@ The `LYSNR_SECRETS` constant defines these mappings:
--- ---
#### 🎤 Azure Speech Services #### 🎤 Azure Speech Services
| Variable | Required | Default | Used By | In KV? |
|----------|----------|---------|---------|--------| | Variable | Required | Default | Used By | In KV? |
| `AZURE_SPEECH_KEY` | Optional | - | LysnrAI product | ❌ No (lysnr) | | --------------------- | -------- | -------- | --------------- | ------------- |
| `AZURE_SPEECH_REGION` | Optional | `eastus` | LysnrAI product | N/A | | `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. **Purpose:** Speech-to-text, text-to-speech for voice AI features.
**Existing:** ✅ Available for `wispr` and `mindlyst` products in Key Vault. **Existing:** ✅ Available for `wispr` and `mindlyst` products in Key Vault.
@ -165,24 +177,26 @@ The `LYSNR_SECRETS` constant defines these mappings:
--- ---
#### 🚀 Service Configuration #### 🚀 Service Configuration
| Variable | Required | Default | Used By | In KV? |
|----------|----------|---------|---------|--------| | Variable | Required | Default | Used By | In KV? |
| `PORT` | No | varies | All services | N/A | | -------------------- | -------- | ------------- | ------------ | ------ |
| `HOST` | No | `0.0.0.0` | All services | N/A | | `PORT` | No | varies | All services | N/A |
| `NODE_ENV` | No | `development` | All services | N/A | | `HOST` | No | `0.0.0.0` | All services | N/A |
| `SERVICE_NAME` | No | auto | All services | N/A | | `NODE_ENV` | No | `development` | All services | N/A |
| `CORS_ORIGIN` | No | `*` (dev) | All services | N/A | | `SERVICE_NAME` | No | auto | All services | N/A |
| `DEFAULT_PRODUCT_ID` | No | `lysnrai` | 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. **Purpose:** Runtime configuration, not secrets.
--- ---
#### 📊 Application Insights (Monitoring) #### 📊 Application Insights (Monitoring)
| Variable | Required | Default | Used By | In KV? |
|----------|----------|---------|---------|--------| | Variable | Required | Default | Used By | In KV? |
| `APPLICATIONINSIGHTS_CONNECTION_STRING` | Optional | - | All services (future) | ✅ Yes (mindlyst) | | --------------------------------------- | -------- | ------- | --------------------- | ----------------- |
| `APPINSIGHTS_INSTRUMENTATIONKEY` | Optional | - | All services (future) | N/A | | `APPLICATIONINSIGHTS_CONNECTION_STRING` | Optional | - | All services (future) | ✅ Yes (mindlyst) |
| `APPINSIGHTS_INSTRUMENTATIONKEY` | Optional | - | All services (future) | N/A |
**Purpose:** Telemetry, logging, monitoring. **Purpose:** Telemetry, logging, monitoring.
**Note:** Only MindLyst has this configured currently. **Note:** Only MindLyst has this configured currently.
@ -190,10 +204,11 @@ The `LYSNR_SECRETS` constant defines these mappings:
--- ---
#### 🔔 Notification Hubs (Mobile Push) #### 🔔 Notification Hubs (Mobile Push)
| Variable | Required | Default | Used By | In KV? |
|----------|----------|---------|---------|--------| | 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 | | `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. **Purpose:** Push notifications for mobile apps.
**Note:** Only MindLyst has this configured currently. **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 ## 📦 Product-Specific Secret Patterns
### MindLyst Product (12 secrets) ✅ ### MindLyst Product (12 secrets) ✅
**Prefix:** `mindlyst-*` **Prefix:** `mindlyst-*`
**Status:** Fully populated **Status:** Fully populated
**Secrets:** **Secrets:**
- Cosmos DB (endpoint, key, database) - Cosmos DB (endpoint, key, database)
- Blob Storage (connection string) - Blob Storage (connection string)
- Azure OpenAI (endpoint, key, deployment, api-version) - 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) - Notification Hub (connection string)
- Application Insights (connection string) - Application Insights (connection string)
### MyWisprAI Product (5 secrets) ⚠️ ### LysnrAI Legacy (5 secrets) ⚠️
**Prefix:** `wispr-*`
**Status:** Partially populated (legacy — pre-rebrand desktop app secrets) **Prefix:** `wispr-*` (pre-rebrand)
**Status:** Populated but superseded by `lysnr-*` secrets
**Secrets:** **Secrets:**
- Azure OpenAI (endpoint, key, deployment) - Azure OpenAI (endpoint, key, deployment)
- Azure Speech (key, region) - 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) ❌ ### LysnrAI Product (0 secrets) ❌
**Prefix:** `lysnr-*` **Prefix:** `lysnr-*`
**Status:** Completely missing **Status:** Completely missing
**Expected:** 13 secrets **Expected:** 13 secrets
@ -368,10 +388,10 @@ pnpm --filter @lysnrai/platform-service dev
### Step 4: Verify Each Service ### Step 4: Verify Each Service
| Service | Port | Test Endpoint | Expected Status | | Service | Port | Test Endpoint | Expected Status |
|---------|------|---------------|-----------------| | ------------------ | ---- | ------------- | --------------- |
| platform-service | 4003 | GET /health | 200 OK | | platform-service | 4003 | GET /health | 200 OK |
| extraction-service | 4005 | GET /health | 200 OK | | extraction-service | 4005 | GET /health | 200 OK |
### Step 5: Production Checklist ### Step 5: Production Checklist
@ -390,15 +410,16 @@ pnpm --filter @lysnrai/platform-service dev
### Recommended Rotation Schedule: ### Recommended Rotation Schedule:
| Secret Type | Rotation Frequency | Method | | Secret Type | Rotation Frequency | Method |
|-------------|-------------------|--------| | ------------------------- | --------------------- | ----------------------------------------- |
| Cosmos DB keys | Quarterly | Azure Portal → rotate keys → update KV | | Cosmos DB keys | Quarterly | Azure Portal → rotate keys → update KV |
| JWT secret | Quarterly | Generate new → update KV → rolling deploy | | JWT secret | Quarterly | Generate new → update KV → rolling deploy |
| Stripe keys | Annually or on breach | Stripe Dashboard → update KV | | Stripe keys | Annually or on breach | Stripe Dashboard → update KV |
| API keys (Gemini, OpenAI) | Annually or on breach | Provider portal → update KV | | API keys (Gemini, OpenAI) | Annually or on breach | Provider portal → update KV |
| Blob storage keys | Quarterly | Azure Portal → rotate keys → update KV | | Blob storage keys | Quarterly | Azure Portal → rotate keys → update KV |
### Rotation Procedure: ### Rotation Procedure:
1. Generate new secret in Azure Portal / provider 1. Generate new secret in Azure Portal / provider
2. Update Key Vault with new value 2. Update Key Vault with new value
3. Services auto-fetch new secret on next restart (or use Key Vault rotation event) 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 ## 🔗 Related Files & Documentation
| File | Purpose | | File | Purpose |
|------|---------| | ----------------------------------------------------- | ----------------------------------------------------------------------- |
| `packages/config/src/keyvault.ts` | Key Vault integration code (`resolveKeyVaultSecrets` + `LYSNR_SECRETS`) | | `packages/config/src/keyvault.ts` | Key Vault integration code (`resolveKeyVaultSecrets` + `LYSNR_SECRETS`) |
| `scripts/seed-keyvault.sh` | Script to populate Key Vault from `.env` values | | `scripts/seed-keyvault.sh` | Script to populate Key Vault from `.env` values |
| `.env.example` | Template for required environment variables | | `.env.example` | Template for required environment variables |
| `services/platform-service/src/server.ts` | Platform service — resolves KV secrets at startup | | `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 | | `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 | | `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 | | `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 | | `tracker-dashboard-web/src/instrumentation.ts` | Tracker dashboard — resolves KV secrets via Next.js hook |
| `backend/src/secrets/keyvault.py` | Python backend SecretResolver | | `backend/src/secrets/keyvault.py` | Python backend SecretResolver |
| `src/secrets/keyvault.py` | Desktop app SecretResolver | | `src/secrets/keyvault.py` | Desktop app SecretResolver |
| `docs/devops/AZURE_PORTAL_SETUP.md` | Azure portal configuration guide | | `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_KEY_VAULT_AND_SECRETS_ROTATION.md` | Key Vault setup + rotation runbooks |
| `docs/devops/AZURE_RESOURCE_INVENTORY.md` | Complete Azure resource inventory | | `docs/devops/AZURE_RESOURCE_INVENTORY.md` | Complete Azure resource inventory |
--- ---
## 📊 Summary Statistics ## 📊 Summary Statistics
### Environment Variables: ### Environment Variables:
- **Total Unique Variables:** 35+ - **Total Unique Variables:** 35+
- **Required for Core Functionality:** 6 - **Required for Core Functionality:** 6
- **Optional/Feature-Specific:** 29+ - **Optional/Feature-Specific:** 29+
### Key Vault Secrets: ### Key Vault Secrets:
- **Total Secrets in KV:** 30 - **Total Secrets in KV:** 30
- **MindLyst Secrets:** 12 ✅ - **MindLyst Secrets:** 12 ✅
- **MyWisprAI Secrets:** 5 ⚠️ (legacy `wispr-*` prefix) - **LysnrAI Legacy Secrets:** 5 ⚠️ (legacy `wispr-*` prefix, pre-rebrand)
- **LysnrAI Secrets:** 13 ✅ (`lysnr-*` prefix) - **LysnrAI Secrets:** 13 ✅ (`lysnr-*` prefix)
- **Expected LysnrAI Secrets:** 13 - **Expected LysnrAI Secrets:** 13
- **Coverage Gap:** 0% - **Coverage Gap:** 0%
### Priority Actions: ### Priority Actions:
- ✅ All 13 `lysnr-*` secrets seeded (2026-02-15) - ✅ 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`) - ⚠️ **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. 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): 📁 `kv_azure.txt` (post-run):
``` ```
lysnr-azure-openai-endpoint=null lysnr-azure-openai-endpoint=null
lysnr-azure-openai-key=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. Scanned git history across `learning_voice_ai_agent` to recover actual secret values for the 13 missing `lysnr-*` secrets.
| # | KV Secret Name | Source | Status | | # | KV Secret Name | Source | Status |
|---|----------------|--------|--------| | --- | ------------------------------ | ----------------- | ------------------------- |
| 1 | `lysnr-cosmos-endpoint` | `.env` commits | ✅ Recovered | | 1 | `lysnr-cosmos-endpoint` | `.env` commits | ✅ Recovered |
| 2 | `lysnr-cosmos-key` | `.env` commits | ✅ Recovered | | 2 | `lysnr-cosmos-key` | `.env` commits | ✅ Recovered |
| 3 | `lysnr-jwt-secret` | `.env` commits | ✅ Recovered | | 3 | `lysnr-jwt-secret` | `.env` commits | ✅ Recovered |
| 4 | `lysnr-stripe-secret-key` | `.env` commits | ✅ Recovered (sk_test_*) | | 4 | `lysnr-stripe-secret-key` | `.env` commits | ✅ Recovered (sk*test*\*) |
| 5 | `lysnr-stripe-webhook-secret` | `.env` commits | ✅ Recovered (whsec_*) | | 5 | `lysnr-stripe-webhook-secret` | `.env` commits | ✅ Recovered (whsec\_\*) |
| 6 | `lysnr-billing-internal-key` | `.env` commits | ✅ Recovered | | 6 | `lysnr-billing-internal-key` | `.env` commits | ✅ Recovered |
| 7 | `lysnr-blob-connection-string` | `.env` commits | ✅ Recovered | | 7 | `lysnr-blob-connection-string` | `.env` commits | ✅ Recovered |
| 8 | `lysnr-blob-account-key` | `.env` commits | ✅ Recovered | | 8 | `lysnr-blob-account-key` | `.env` commits | ✅ Recovered |
| 9 | `lysnr-gemini-api-key` | Provided manually | ✅ Recovered | | 9 | `lysnr-gemini-api-key` | Provided manually | ✅ Recovered |
| 10 | `lysnr-seed-secret` | `.env` commits | ✅ Recovered | | 10 | `lysnr-seed-secret` | `.env` commits | ✅ Recovered |
| 11 | `lysnr-azure-speech-key` | `.env` commits | ✅ Recovered | | 11 | `lysnr-azure-speech-key` | `.env` commits | ✅ Recovered |
| 12 | `lysnr-azure-openai-key` | `.env` commits | ✅ Recovered | | 12 | `lysnr-azure-openai-key` | `.env` commits | ✅ Recovered |
| 13 | `lysnr-azure-openai-endpoint` | `.env` commits | ✅ Recovered | | 13 | `lysnr-azure-openai-endpoint` | `.env` commits | ✅ Recovered |
**Result:** 13/13 recovered. Seed script written to `kv.txt` (gitignored, temporary). **Result:** 13/13 recovered. Seed script written to `kv.txt` (gitignored, temporary).
**To seed:** **To seed:**
```bash ```bash
az login az login
bash kv.txt bash kv.txt
@ -555,5 +581,5 @@ rm kv.txt
**Generated by:** Environment audit automation **Generated by:** Environment audit automation
**Maintained by:** ByteLyst DevOps Team **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` **Admin UI:** Secrets Manager at admin dashboard → `/ops/secrets`