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

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.
> **Architecture:** Single RG, shared stateless services, separate databases.
> **Time estimate:** ~20 minutes (most resources already exist from LysnrAI)
> **Prerequisites:** An Azure account with an active subscription
> **Last updated:** 2026-02-14
> **Last updated:** 2026-03-21
>
> **Security note (staging):** This document does **not** include secret values. Store secrets in Azure Key Vault (`kv-mywisprai`) and reference them by name (see **MindLyst Environment Variables** and **Key Vault** sections). Rotation is deferred; see `docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md`.
> **Security note (staging):** This document does **not** include secret values. Store secrets in Azure Key Vault (`kv-mywisprai` — legacy resource name) and reference them by name (see **MindLyst Environment Variables** and **Key Vault** sections). Rotation is deferred; see `docs/devops/AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md`.
>
> **Note on Azure resource names:** Many resources below still carry `mywisprai` in their names (e.g., `cosmos-mywisprai`, `kv-mywisprai`). Azure resources **cannot be renamed** after creation. The old names are purely cosmetic and work correctly.
---
@ -40,8 +42,8 @@ Both LysnrAI and MindLyst share a **single Azure resource group** with shared st
rg-mywisprai/ (1 resource group)
├── cosmos-mywisprai (1 Cosmos DB account — already exists)
│ ├── mywisprai (database: 10 containers — existing)
│ └── mindlyst (database: 12 containers — MindLyst)
│ ├── mywisprai (database: LysnrAI — legacy name, 10 containers)
│ └── mindlyst (database: MindLyst, 12 containers)
├── bytelystblobs (1 Storage account — already exists)
│ ├── mindlyst-voice ← NEW
@ -54,8 +56,9 @@ rg-mywisprai/ (1 resource group)
├── mywisprai-speech (1 Speech Service — shared, eastus)
├── kv-mywisprai (1 Key Vault — shared)
│ ├── wispr-* (existing secrets)
│ └── mindlyst-* (MindLyst secrets) ← NEW
│ ├── lysnr-* (LysnrAI secrets)
│ ├── wispr-* (LysnrAI legacy secrets, pre-rebrand)
│ └── mindlyst-* (MindLyst secrets)
├── lysnnai (1 Notification Hub namespace)
│ ├── notificationhub (existing hub)
@ -68,21 +71,21 @@ rg-mywisprai/ (1 resource group)
### Why Share?
| Concern | Answer |
|---------|--------|
| **Cost** | Cosmos DB Serverless charges per-RU, not per-account. One account = one endpoint, one key pair, simpler rotation |
| **Management** | 1 RG to monitor, 1 cost dashboard, 1 health check |
| **Data isolation** | Separate databases within Cosmos = full container-level isolation. Queries can't cross databases |
| **Teardown safety** | Delete the `mindlyst` database → LysnrAI data untouched |
| **Stateless services** | OpenAI & Speech are stateless — same key serves both apps, no data leakage |
| Concern | Answer |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| **Cost** | Cosmos DB Serverless charges per-RU, not per-account. One account = one endpoint, one key pair, simpler rotation |
| **Management** | 1 RG to monitor, 1 cost dashboard, 1 health check |
| **Data isolation** | Separate databases within Cosmos = full container-level isolation. Queries can't cross databases |
| **Teardown safety** | Delete the `mindlyst` database → LysnrAI data untouched |
| **Stateless services** | OpenAI & Speech are stateless — same key serves both apps, no data leakage |
### What Must Stay Separate
| Resource | Why |
|----------|-----|
| **Notification Hub hubs** | Each app has its own APNs certificate and FCM server key |
| **Stripe accounts** | Different products, pricing tiers, and webhook endpoints (external, not Azure) |
| **Cosmos databases** | Each app gets its own database with its own set of containers |
| Resource | Why |
| ------------------------- | ------------------------------------------------------------------------------ |
| **Notification Hub hubs** | Each app has its own APNs certificate and FCM server key |
| **Stripe accounts** | Different products, pricing tiers, and webhook endpoints (external, not Azure) |
| **Cosmos databases** | Each app gets its own database with its own set of containers |
---
@ -90,20 +93,20 @@ rg-mywisprai/ (1 resource group)
These resources are **already provisioned** and will be reused by MindLyst:
| Resource | Azure Name | Region | SKU | Status |
|----------|-----------|--------|-----|--------|
| **Resource Group** | `rg-mywisprai` | `eastus` | — | Exists |
| **Cosmos DB** | `cosmos-mywisprai` | `westus2` | Serverless, NoSQL | Exists — DBs: `mywisprai` (10 containers), `mindlyst` (12 containers) |
| **Blob Storage** | `bytelystblobs` | `westus2` | StorageV2, RAGRS | Exists |
| **Azure OpenAI** | `mywisprai-openai-sweden` | `swedencentral` | S0 | Exists — deployment: `gpt-4o-mini` |
| **Speech Service** | `mywisprai-speech` | `eastus` | F0 | Exists |
| **Key Vault** | `kv-mywisprai` | `eastus` | Standard | Exists |
| **Notification Hub (namespace)** | `lysnnai` | `eastus` | Free | Exists (hubs: `notificationhub`, `mindlyst-hub`) |
| **Application Insights** | `bytelyst-appinsights` | `eastus` | Classic | Exists |
| Resource | Azure Name | Region | SKU | Status |
| -------------------------------- | ------------------------- | --------------- | ----------------- | ------------------------------------------------------------------------------ |
| **Resource Group** | `rg-mywisprai` | `eastus` | — | Exists |
| **Cosmos DB** | `cosmos-mywisprai` | `westus2` | Serverless, NoSQL | Exists — DBs: `mywisprai` (LysnrAI, 10 containers), `mindlyst` (12 containers) |
| **Blob Storage** | `bytelystblobs` | `westus2` | StorageV2, RAGRS | Exists |
| **Azure OpenAI** | `mywisprai-openai-sweden` | `swedencentral` | S0 | Exists — deployment: `gpt-4o-mini` |
| **Speech Service** | `mywisprai-speech` | `eastus` | F0 | Exists |
| **Key Vault** | `kv-mywisprai` | `eastus` | Standard | Exists |
| **Notification Hub (namespace)** | `lysnnai` | `eastus` | Free | Exists (hubs: `notificationhub`, `mindlyst-hub`) |
| **Application Insights** | `bytelyst-appinsights` | `eastus` | Classic | Exists |
### Cosmos DB: Existing LysnrAI database containers (staging)
Database: `mywisprai` (existing)
Database: `mywisprai` (legacy name — this is the LysnrAI database)
- `api_tokens`
- `audit_log`
@ -137,7 +140,7 @@ MindLyst secrets (canonical):
- `mindlyst-notification-hub-connection-string`
- `mindlyst-appinsights-connection-string`
LysnrAI secrets (existing):
LysnrAI secrets (legacy `wispr-*` prefix, pre-rebrand — superseded by `lysnr-*`):
- `wispr-azure-openai-deployment`
- `wispr-azure-openai-endpoint`
@ -157,14 +160,14 @@ az keyvault secret list --vault-name kv-mywisprai --query "[].name" -o tsv
Only these additions are needed — no new accounts to create:
| Action | Where | What |
|--------|-------|------|
| **Rename RG (optional)** | Resource Group | Keep `rg-mywisprai` for now. Only move resources if you want a cleaner name. |
| **Add database** | Cosmos DB (`cosmos-mywisprai`) | New database `mindlyst` with 12 containers |
| **Add blob containers** | Blob Storage (`bytelystblobs`) | 3 new containers: `mindlyst-voice`, `mindlyst-images`, `mindlyst-exports` |
| **Add secrets** | Key Vault (`kv-mywisprai`) | 12 secrets with `mindlyst-` prefix (keys + config) |
| **Add hub** | Notification Hub namespace (`lysnnai`) | New hub `mindlyst-hub` |
| **Create App Insights** | New resource | `bytelyst-appinsights` (shared telemetry) |
| Action | Where | What |
| ------------------------ | -------------------------------------- | ---------------------------------------------------------------------------- |
| **Rename RG (optional)** | Resource Group | Keep `rg-mywisprai` for now. Only move resources if you want a cleaner name. |
| **Add database** | Cosmos DB (`cosmos-mywisprai`) | New database `mindlyst` with 12 containers |
| **Add blob containers** | Blob Storage (`bytelystblobs`) | 3 new containers: `mindlyst-voice`, `mindlyst-images`, `mindlyst-exports` |
| **Add secrets** | Key Vault (`kv-mywisprai`) | 12 secrets with `mindlyst-` prefix (keys + config) |
| **Add hub** | Notification Hub namespace (`lysnnai`) | New hub `mindlyst-hub` |
| **Create App Insights** | New resource | `bytelyst-appinsights` (shared telemetry) |
### Current Staging State (Completed)
@ -221,22 +224,23 @@ You should now see both `mywisprai` and `mindlyst` databases in the tree.
For each container below, right-click the **`mindlyst`** database (or click the `…` menu) → **New Container**:
| # | Container Name | Partition Key | Purpose |
|---|----------------|--------------|---------|
| 1 | `users` | `/id` | User accounts and profiles |
| 2 | `brains` | `/userId` | User brain configurations (War Room, Home Base, Money Guard, etc.) |
| 3 | `brain_templates` | `/id` | Brain Pack gallery templates |
| 4 | `memory_items` | `/userId` | All captured memories (text, voice, image, link, email) |
| 5 | `actions` | `/memoryItemId` | AI-suggested actions from triage |
| 6 | `entities` | `/memoryItemId` | Extracted entities (people, dates, places, amounts) |
| 7 | `reflections` | `/userId` | Weekly reflection reports and insights |
| 8 | `share_cards` | `/userId` | Generated share cards for social sharing |
| 9 | `daily_briefs` | `/userId` | Morning and evening brief content |
| 10 | `streaks` | `/userId` | Capture streak tracking and gamification |
| 11 | `notification_log` | `/userId` | Push notification delivery log and scheduling |
| 12 | `brain_insights` | `/userId` | Cross-brain insight discoveries |
| # | Container Name | Partition Key | Purpose |
| --- | ------------------ | --------------- | ------------------------------------------------------------------ |
| 1 | `users` | `/id` | User accounts and profiles |
| 2 | `brains` | `/userId` | User brain configurations (War Room, Home Base, Money Guard, etc.) |
| 3 | `brain_templates` | `/id` | Brain Pack gallery templates |
| 4 | `memory_items` | `/userId` | All captured memories (text, voice, image, link, email) |
| 5 | `actions` | `/memoryItemId` | AI-suggested actions from triage |
| 6 | `entities` | `/memoryItemId` | Extracted entities (people, dates, places, amounts) |
| 7 | `reflections` | `/userId` | Weekly reflection reports and insights |
| 8 | `share_cards` | `/userId` | Generated share cards for social sharing |
| 9 | `daily_briefs` | `/userId` | Morning and evening brief content |
| 10 | `streaks` | `/userId` | Capture streak tracking and gamification |
| 11 | `notification_log` | `/userId` | Push notification delivery log and scheduling |
| 12 | `brain_insights` | `/userId` | Cross-brain insight discoveries |
**For each container:**
1. Click **New Container**
2. **Existing Database:** select `mindlyst` (do NOT create a new database)
3. Enter the **Container id** from the table
@ -268,13 +272,14 @@ Cosmos connection details are stored in Key Vault:
2. Go to **Data storage****Containers** (left sidebar)
3. Click **+ Container** for each:
| Container Name | Access Level | Purpose |
|----------------|-------------|---------|
| `mindlyst-voice` | **Private** | Voice capture recordings (WAV/PCM from STT pipeline) |
| `mindlyst-images` | **Private** | Captured photos, screenshots, and OCR source images |
| `mindlyst-exports` | **Private** | User data exports (JSON), weekly reflection PDFs |
| Container Name | Access Level | Purpose |
| ------------------ | ------------ | ---------------------------------------------------- |
| `mindlyst-voice` | **Private** | Voice capture recordings (WAV/PCM from STT pipeline) |
| `mindlyst-images` | **Private** | Captured photos, screenshots, and OCR source images |
| `mindlyst-exports` | **Private** | User data exports (JSON), weekly reflection PDFs |
For each:
1. Click **+ Container**
2. Enter the **Name** (must be lowercase, no underscores — use hyphens)
3. **Anonymous access level:** leave as **Private (no anonymous access)**
@ -284,10 +289,10 @@ For each:
You should now see these MindLyst containers in `bytelystblobs` (plus any other app containers you already had):
| Container | App |
|-----------|-----|
| `mindlyst-voice` | MindLyst |
| `mindlyst-images` | MindLyst |
| Container | App |
| ------------------ | -------- |
| `mindlyst-voice` | MindLyst |
| `mindlyst-images` | MindLyst |
| `mindlyst-exports` | MindLyst |
### Connection details (from Key Vault)
@ -345,20 +350,20 @@ Speech connection details are stored in Key Vault:
MindLyst secrets (canonical):
| Key Vault secret name | Env var | Notes |
|---|---|---|
| `mindlyst-cosmos-endpoint` | `COSMOS_ENDPOINT` | Config (ok to store) |
| `mindlyst-cosmos-key` | `COSMOS_KEY` | Secret |
| `mindlyst-cosmos-database` | `COSMOS_DATABASE` | Config (`mindlyst`) |
| `mindlyst-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | Config |
| `mindlyst-openai-key` | `AZURE_OPENAI_KEY` | Secret |
| `mindlyst-openai-deployment` | `AZURE_OPENAI_DEPLOYMENT` | Config |
| `mindlyst-openai-api-version` | `AZURE_OPENAI_API_VERSION` | Config |
| `mindlyst-speech-key` | `AZURE_SPEECH_KEY` | Secret |
| `mindlyst-speech-region` | `AZURE_SPEECH_REGION` | Config |
| `mindlyst-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | Secret (prefer SAS later) |
| `mindlyst-notification-hub-connection-string` | `ANH_CONNECTION_STRING` | Secret |
| `mindlyst-appinsights-connection-string` | `APPLICATIONINSIGHTS_CONNECTION_STRING` | Treat as sensitive |
| Key Vault secret name | Env var | Notes |
| --------------------------------------------- | --------------------------------------- | ------------------------- |
| `mindlyst-cosmos-endpoint` | `COSMOS_ENDPOINT` | Config (ok to store) |
| `mindlyst-cosmos-key` | `COSMOS_KEY` | Secret |
| `mindlyst-cosmos-database` | `COSMOS_DATABASE` | Config (`mindlyst`) |
| `mindlyst-openai-endpoint` | `AZURE_OPENAI_ENDPOINT` | Config |
| `mindlyst-openai-key` | `AZURE_OPENAI_KEY` | Secret |
| `mindlyst-openai-deployment` | `AZURE_OPENAI_DEPLOYMENT` | Config |
| `mindlyst-openai-api-version` | `AZURE_OPENAI_API_VERSION` | Config |
| `mindlyst-speech-key` | `AZURE_SPEECH_KEY` | Secret |
| `mindlyst-speech-region` | `AZURE_SPEECH_REGION` | Config |
| `mindlyst-blob-connection-string` | `AZURE_BLOB_CONNECTION_STRING` | Secret (prefer SAS later) |
| `mindlyst-notification-hub-connection-string` | `ANH_CONNECTION_STRING` | Secret |
| `mindlyst-appinsights-connection-string` | `APPLICATIONINSIGHTS_CONNECTION_STRING` | Treat as sensitive |
List 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)
| Secret Name | Notes |
|-------------|-------|
| `wispr-azure-openai-deployment` | Existing OpenAI deployment name |
| `wispr-azure-openai-endpoint` | Existing OpenAI endpoint |
| `wispr-azure-openai-key` | Existing OpenAI key |
| `wispr-azure-speech-key` | Existing Speech key |
| `wispr-azure-speech-region` | Existing Speech region |
| Secret Name | Notes |
| ------------------------------- | ---------------------------------------------- |
| `wispr-azure-openai-deployment` | Legacy (pre-rebrand) — superseded by `lysnr-*` |
| `wispr-azure-openai-endpoint` | Legacy (pre-rebrand) |
| `wispr-azure-openai-key` | Legacy (pre-rebrand) |
| `wispr-azure-speech-key` | Legacy (pre-rebrand) |
| `wispr-azure-speech-region` | Legacy (pre-rebrand) |
---
@ -435,6 +440,7 @@ Non-secret config:
### Create (if not exists)
Option A: Workspace-based (recommended)
1. Search **"Application Insights"** → click **Create**
2. Fill in:
- **Resource group:** `rg-mywisprai`
@ -460,10 +466,10 @@ In your application code, add a custom property to every trace:
```typescript
// MindLyst
telemetryClient.context.tags["ai.cloud.role"] = "mindlyst-web";
telemetryClient.context.tags['ai.cloud.role'] = 'mindlyst-web';
// LysnrAI
telemetryClient.context.tags["ai.cloud.role"] = "mywisprai-admin";
telemetryClient.context.tags['ai.cloud.role'] = 'lysnrai-admin';
```
Then filter in the Azure Portal: **Application Insights → Logs → `where cloud_RoleName == "mindlyst-web"`**
@ -549,16 +555,16 @@ EOF
After completing all steps, verify:
| # | Check | How |
|---|-------|-----|
| 1 | **Cosmos DB: `mindlyst` database** | Data Explorer → expand `cosmos-mywisprai``mindlyst` → 12 containers visible |
| 2 | **Cosmos DB: `mywisprai` untouched** | Data Explorer → `mywisprai` database still has its existing containers |
| 3 | **Blob: 3 new containers** | Storage → `bytelystblobs` → Containers → `mindlyst-voice`, `mindlyst-images`, `mindlyst-exports` |
| 4 | **Blob: other containers intact (if any)** | Same page → any pre-existing containers should still be present |
| 5 | **OpenAI deployment** | Azure OpenAI Studio → Deployments → `gpt-4o-mini` listed |
| 6 | **Speech Service keys** | Speech resource → Keys and Endpoint → keys visible |
| 7 | **Key Vault: MindLyst secrets** | Key Vault → Secrets → `mindlyst-*` entries visible |
| 8 | **MindLyst web connects** | Run `cd mindlyst-native/web && npm run dev` → triage/brain-chat should use Azure OpenAI (not mock) |
| # | Check | How |
| --- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| 1 | **Cosmos DB: `mindlyst` database** | Data Explorer → expand `cosmos-mywisprai``mindlyst` → 12 containers visible |
| 2 | **Cosmos DB: `mywisprai` (LysnrAI) untouched** | Data Explorer → `mywisprai` database still has its existing containers |
| 3 | **Blob: 3 new containers** | Storage → `bytelystblobs` → Containers → `mindlyst-voice`, `mindlyst-images`, `mindlyst-exports` |
| 4 | **Blob: other containers intact (if any)** | Same page → any pre-existing containers should still be present |
| 5 | **OpenAI deployment** | Azure OpenAI Studio → Deployments → `gpt-4o-mini` listed |
| 6 | **Speech Service keys** | Speech resource → Keys and Endpoint → keys visible |
| 7 | **Key Vault: MindLyst secrets** | Key Vault → Secrets → `mindlyst-*` entries visible |
| 8 | **MindLyst web connects** | Run `cd mindlyst-native/web && npm run dev` → triage/brain-chat should use Azure OpenAI (not mock) |
---
@ -566,16 +572,16 @@ After completing all steps, verify:
### Combined Cost (LysnrAI + MindLyst, MVP / Low Usage)
| Service | Pricing | LysnrAI | MindLyst | Combined |
|---------|---------|---------|----------|----------|
| Cosmos DB (Serverless) | $0.25/M RU + $0.25/GB | ~$2 | ~$2 | ~$4 |
| Blob Storage (LRS) | $0.018/GB | ~$0.10 | ~$0.10 | ~$0.20 |
| Azure OpenAI (GPT-4o-mini) | $0.15/M input + $0.60/M output | ~$5 | ~$5 | ~$10 |
| Speech (F0 free) | 5h STT free | $0 | $0 | $0 |
| Key Vault | $0.03/10K ops | ~$0.03 | ~$0.03 | ~$0.06 |
| App Insights | 5GB/month free | $0 | $0 | $0 |
| Notification Hub (Free) | 1M pushes/month free | $0 | $0 | $0 |
| **Total** | | | | **~$515/month** |
| Service | Pricing | LysnrAI | MindLyst | Combined |
| -------------------------- | ------------------------------ | ------- | -------- | ---------------- |
| Cosmos DB (Serverless) | $0.25/M RU + $0.25/GB | ~$2 | ~$2 | ~$4 |
| Blob Storage (LRS) | $0.018/GB | ~$0.10 | ~$0.10 | ~$0.20 |
| Azure OpenAI (GPT-4o-mini) | $0.15/M input + $0.60/M output | ~$5 | ~$5 | ~$10 |
| Speech (F0 free) | 5h STT free | $0 | $0 | $0 |
| Key Vault | $0.03/10K ops | ~$0.03 | ~$0.03 | ~$0.06 |
| App Insights | 5GB/month free | $0 | $0 | $0 |
| Notification Hub (Free) | 1M pushes/month free | $0 | $0 | $0 |
| **Total** | | | | **~$515/month** |
### Cost Savings from Sharing
@ -589,16 +595,16 @@ After completing all steps, verify:
## Resource Naming Convention
| Azure Resource | Current Name | Ideal Name | Notes |
|---------------|-------------|------------|-------|
| Resource Group | `rg-mywisprai` | `rg-bytelyst` | Move resources to new RG (Step 1) |
| Cosmos DB Account | `cosmos-mywisprai` | `cosmos-bytelyst` | Can't rename — keep as-is |
| Blob Storage | `bytelystblobs` | `bytelystblobs` | Already brand-neutral |
| Azure OpenAI | `mywisprai-openai-sweden` | — | Can't rename — keep as-is |
| Speech Service | `mywisprai-speech` | — | Can't rename — keep as-is |
| Key Vault | `kv-mywisprai` | `kv-bytelyst` | Can't rename — keep as-is |
| Notification Hub NS | `lysnnai` | `bytelyst-hub-ns` | Consider creating new NS later if desired |
| App Insights | `bytelyst-appinsights` | — | Can recreate if you want workspace-based mode |
| Azure Resource | Current Name | Ideal Name | Notes |
| ------------------- | ------------------------- | ----------------- | --------------------------------------------- |
| Resource Group | `rg-mywisprai` | `rg-bytelyst` | Move resources to new RG (Step 1) |
| Cosmos DB Account | `cosmos-mywisprai` | `cosmos-bytelyst` | Can't rename — keep as-is |
| Blob Storage | `bytelystblobs` | `bytelystblobs` | Already brand-neutral |
| Azure OpenAI | `mywisprai-openai-sweden` | — | Can't rename — keep as-is |
| Speech Service | `mywisprai-speech` | — | Can't rename — keep as-is |
| Key Vault | `kv-mywisprai` | `kv-bytelyst` | Can't rename — keep as-is |
| Notification Hub NS | `lysnnai` | `bytelyst-hub-ns` | Consider creating new NS later if desired |
| App Insights | `bytelyst-appinsights` | — | Can recreate if you want workspace-based mode |
> **Azure resources cannot be renamed after creation.** The old names (`cosmos-mywisprai`, `mywisprai-*`, etc.) still work perfectly — they're just cosmetic. Only the RG can be "renamed" by moving resources to a new one.
@ -614,7 +620,7 @@ After completing all steps, verify:
set -euo pipefail
# ─────────────────────────────────────────────────────────────
# BytelystAI — Azure Resource Setup Script
# ByteLyst — Azure Resource Setup Script
# Creates MindLyst deltas inside an existing shared resource group
# ─────────────────────────────────────────────────────────────
@ -860,19 +866,19 @@ az deployment sub create \
Use this mapping to understand how the current staging resource names relate to Bicep params. In a **different account**, you must choose new globally-unique names for most of these.
| Bicep parameter | Current staging value | Notes |
|---|---|---|
| `resourceGroupName` | `rg-mywisprai` | In a new subscription, choose a new RG name (example: `rg-bytelyst-staging`) |
| `cosmosAccountName` | `cosmos-mywisprai` | Globally unique; must change in another subscription |
| `storageAccountName` | `bytelystblobs` | Globally unique; must change in another subscription |
| `openAiAccountName` | `mywisprai-openai-sweden` | Globally unique; must change in another subscription |
| `speechAccountName` | `mywisprai-speech` | Globally unique; must change in another subscription |
| `keyVaultName` | `kv-mywisprai` | Globally unique; must change in another subscription |
| `notificationHubNamespaceName` | `lysnnai` | Globally unique; must change in another subscription |
| `mindlystHubName` | `mindlyst-hub` | Not globally unique (scoped to the namespace) |
| `appInsightsName` | `bytelyst-appinsights` | Must be unique within the RG |
| `createMywispraiDatabase` | N/A | Creates an empty `mywisprai` database placeholder (no containers) |
| `deployerObjectId` | N/A | If set, Bicep also creates Key Vault secrets (`mindlyst-*`) |
| Bicep parameter | Current staging value | Notes |
| ------------------------------ | ------------------------- | ---------------------------------------------------------------------------- |
| `resourceGroupName` | `rg-mywisprai` | In a new subscription, choose a new RG name (example: `rg-bytelyst-staging`) |
| `cosmosAccountName` | `cosmos-mywisprai` | Globally unique; must change in another subscription |
| `storageAccountName` | `bytelystblobs` | Globally unique; must change in another subscription |
| `openAiAccountName` | `mywisprai-openai-sweden` | Globally unique; must change in another subscription |
| `speechAccountName` | `mywisprai-speech` | Globally unique; must change in another subscription |
| `keyVaultName` | `kv-mywisprai` | Globally unique; must change in another subscription |
| `notificationHubNamespaceName` | `lysnnai` | Globally unique; must change in another subscription |
| `mindlystHubName` | `mindlyst-hub` | Not globally unique (scoped to the namespace) |
| `appInsightsName` | `bytelyst-appinsights` | Must be unique within the RG |
| `createMywispraiDatabase` | N/A | Creates an empty `mywisprai` database placeholder (LysnrAI, no containers) |
| `deployerObjectId` | N/A | If set, Bicep also creates Key Vault secrets (`mindlyst-*`) |
---
@ -892,6 +898,7 @@ Phase 0.3 (Azure Infrastructure):
```
**Next steps after provisioning:**
1. (Done) MindLyst web: Enable Azure OpenAI triage + brain-chat (`OPENAI_PROVIDER=azure` + `AZURE_OPENAI_*`)
2. (Done) MindLyst web: Cosmos persistence for `/api/memory` and `/api/brains` (`COSMOS_*`)
3. Wire additional MindLyst API routes to Cosmos as needed (reflections, briefs, notifications, etc.)
@ -903,14 +910,14 @@ Phase 0.3 (Azure Infrastructure):
## Quick Reference: Portal URLs
| Resource | Direct Link |
|----------|-------------|
| Resource Group | `portal.azure.com → Resource groups → rg-mywisprai` |
| Cosmos DB Data Explorer | `portal.azure.com → cosmos-mywisprai → Data Explorer` |
| Blob Containers | `portal.azure.com → bytelystblobs → Containers` |
| OpenAI Studio | `oai.azure.com` → select `mywisprai-openai-sweden` |
| Speech Keys | `portal.azure.com → mywisprai-speech → Keys and Endpoint` |
| Key Vault Secrets | `portal.azure.com → kv-mywisprai → Secrets` |
| Resource | Direct Link |
| ----------------------- | --------------------------------------------------------- |
| Resource Group | `portal.azure.com → Resource groups → rg-mywisprai` |
| Cosmos DB Data Explorer | `portal.azure.com → cosmos-mywisprai → Data Explorer` |
| Blob Containers | `portal.azure.com → bytelystblobs → Containers` |
| OpenAI Studio | `oai.azure.com` → select `mywisprai-openai-sweden` |
| Speech Keys | `portal.azure.com → mywisprai-speech → Keys and Endpoint` |
| Key Vault Secrets | `portal.azure.com → kv-mywisprai → Secrets` |
---

View File

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

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.1** Enable RBAC mode on `kv-mywisprai` vault (`enableRbacAuthorization=true`)
- [ ] **1.1.1** Enable RBAC mode on `kv-mywisprai` vault (legacy name) (`enableRbacAuthorization=true`)
- Assign `Key Vault Crypto Officer` to deployer user
- Assign `Key Vault Crypto User` to service managed identities (when deployed)
- **File:** Azure Portal / `az keyvault update`
@ -64,7 +64,7 @@ Week 1-2 Week 3-4 Week 5-6 Week 7-8 Week 9-10 Week 11-14
- [ ] **1.1.3** Add new env vars to `.env.example` and AKV secrets doc
```
AZURE_KEYVAULT_URL=https://kv-mywisprai.vault.azure.net
AZURE_KEYVAULT_URL=https://kv-mywisprai.vault.azure.net # legacy vault name
FIELD_ENCRYPT_KEY_PROVIDER=akv # 'akv' | 'env' | 'memory'
FIELD_ENCRYPT_MEK_NAME=lysnr-mek # product-specific
```
@ -461,7 +461,7 @@ Week 1-2 Week 3-4 Week 5-6 Week 7-8 Week 9-10 Week 11-14
- [ ] **6.1.1** Create `bytelyst-blob-mek` RSA key in AKV
- [ ] **6.1.2** Configure `bytelystblobs` storage account to use CMK from AKV
- Azure Portal → Storage account → Encryption → Customer-managed keys
- Select `bytelyst-blob-mek` from `kv-mywisprai`
- Select `bytelyst-blob-mek` from `kv-mywisprai` (legacy vault name)
- [ ] **6.1.3** Verify all blob operations still work (upload, download, SAS tokens)
- [ ] **6.1.4** Update `AZURE_RESOURCE_INVENTORY.md`

View File

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