docs: update documentation

This commit is contained in:
saravanakumardb1 2026-02-28 03:28:48 -08:00
parent e6eee35544
commit e3e332cee6

View File

@ -0,0 +1,239 @@
# Auth Cross-Product Analysis — Full Workspace Audit
> **Date:** 2026-02-28
> **Scope:** All 4 product repos + common platform
> **Question:** Do all apps share the same auth? Can a ChronoMind user sign in to NomGap? What's missing?
---
## 1. Backend Architecture (Single Source of Truth)
All products share **one** platform-service (port 4003) in `learning_ai_common_plat`.
### Auth endpoints available:
| Endpoint | Status | Notes |
| -------------------------------- | -------------- | --------------------------------------------------- |
| `POST /auth/login` | ✅ Implemented | Requires `{ email, password, productId }` |
| `POST /auth/register` | ✅ Implemented | Creates user + subscription + license |
| `POST /auth/refresh` | ✅ Implemented | Exchanges refresh token for new pair |
| `GET /auth/me` | ✅ Implemented | Returns user from Bearer token |
| `PUT /auth/profile` | ✅ Implemented | Self-service profile update |
| `POST /auth/sso` | ✅ Implemented | Microsoft/Google OAuth (find-or-create) |
| `POST /auth/verify` | ✅ Implemented | Service-to-service token check |
| `POST /auth/forgot-password` | ✅ Implemented | Generates reset token (logs it, no email sent) |
| `POST /auth/reset-password` | ✅ Implemented | Resets password with token |
| `POST /auth/verify-email` | ✅ Implemented | Verifies email with token |
| `POST /auth/resend-verification` | ✅ Implemented | Resends verification email (logs it, no email sent) |
| Admin CRUD (`/auth/users/*`) | ✅ Implemented | List, count, get, update, delete |
### Database: Single Cosmos DB
- **Container:** `users` — all users across all products
- **Partition key:** user `id`
- **Product isolation:** Every user doc has a `productId` field
- **Lookup:** `getByEmail(email, productId)` — queries by BOTH email AND productId
### JWT tokens
- **Issuer:** `bytelyst-platform`
- **Access token:** 1 hour, contains `{ sub, email, role, productId, plan }`
- **Refresh token:** 7 days, contains `{ sub, productId }`
- **Secret:** Single shared `JWT_SECRET` env var
---
## 2. The Cross-Product Sign-In Question
### Current design: Users are **per-product**
The `getByEmail()` function queries:
```sql
SELECT * FROM c WHERE c.productId = @productId AND c.email = @email
```
This means:
- **A user who registers on ChronoMind (productId: `chronomind`) is a DIFFERENT user than the same email on NomGap (productId: `nomgap`)**
- Same email can have separate accounts with different passwords on each product
- Each registration creates a separate subscription + license record per product
- JWT tokens are scoped to a productId — a ChronoMind token cannot be used for NomGap API calls
### Is this the right design?
**Yes, for now.** Here's why:
1. **Different products = different plans/subscriptions** — A user might be on Pro for ChronoMind but Free for NomGap
2. **Clean data isolation** — each product's user data doesn't leak across
3. **Independent license/device management** — device limits are per-product
4. **Simpler admin** — admin dashboard shows users per product
### Future consideration: ByteLyst Account (cross-product SSO)
If/when you want "sign in once, use all ByteLyst apps":
- Add a `byteLystAccountId` linking field to user docs
- Add a `/auth/link-account` endpoint
- This is a P3 feature, not needed now
---
## 3. Per-App Auth Inventory
### Legend
- ✅ = Implemented and working
- ⚠️ = Partially implemented (missing features)
- ❌ = Not implemented
### 3.1 LysnrAI (`learning_voice_ai_agent`)
| Surface | Login | Register | Refresh | Forgot Password | Email Verify | SSO |
| --------------------------- | ----- | --------------- | ---------------- | --------------- | ------------ | ----------------------- |
| **User Dashboard (web)** | ✅ | ✅ | ✅ (cookie) | ❌ | ❌ | ✅ (Google + Microsoft) |
| **Admin Dashboard (web)** | ✅ | ❌ (admin-only) | ✅ (cookie) | ❌ | ❌ | ❌ |
| **Tracker Dashboard (web)** | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| **iOS mobile** | ✅ | ✅ | ✅ (Keychain) | ❌ | ❌ | ✅ (Apple, Google) |
| **Android mobile** | ✅ | ✅ | ✅ (SharedPrefs) | ❌ | ❌ | ✅ (Google) |
| **Desktop (Python)** | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
**productId:** `lysnrai`
### 3.2 ChronoMind (`learning_ai_clock`)
| Surface | Login | Register | Refresh | Forgot Password | Email Verify | SSO |
| ----------- | ----- | -------- | -------------------------- | --------------- | ------------ | --- |
| **Web PWA** | ✅ | ✅ | ❌ (no auto-refresh) | ❌ | ❌ | ❌ |
| **iOS** | ✅ | ✅ | ✅ (Keychain, 45min timer) | ❌ | ❌ | ❌ |
| **Android** | ✅ | ✅ | ✅ (SharedPrefs) | ❌ | ❌ | ❌ |
**productId:** `chronomind`
### 3.3 NomGap (`learning_ai_fastgap`)
| Surface | Login | Register | Refresh | Forgot Password | Email Verify | SSO |
| ----------------------- | ---------- | ---------- | ----------------- | --------------- | ------------ | --- |
| **React Native (Expo)** | ✅ (store) | ✅ (store) | ⚠️ (hydrate only) | ❌ | ❌ | ❌ |
**productId:** `nomgap`
**Note:** Auth store actions + ProfileScreen UI are wired. `hydrateFromToken()` calls `/auth/me` but there's no proactive refresh timer. No dedicated login screen — auth is inline in ProfileScreen.
### 3.4 MindLyst (`learning_multimodal_memory_agents`)
| Surface | Login | Register | Refresh | Forgot Password | Email Verify | SSO |
| ----------------- | ----- | -------- | -------------------------- | --------------- | ------------ | --- |
| **Web (Next.js)** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **iOS** | ✅ | ✅ | ✅ (Keychain, 45min timer) | ❌ | ❌ | ❌ |
| **Android** | ✅ | ✅ | ✅ (SharedPrefs) | ❌ | ❌ | ❌ |
**productId:** `mindlyst`
**Note:** MindLyst web has NO auth at all — API routes use in-memory fallback or direct Cosmos, no platform-service integration.
### 3.5 Dashboards (common platform)
| Dashboard | Login | Register | Refresh | Forgot Password | SSO |
| ----------------------- | ----- | -------- | ------- | --------------- | --- |
| **Admin (port 3001)** | ✅ | ❌ | ✅ | ❌ | ❌ |
| **Tracker (port 3003)** | ✅ | ✅ | ✅ | ❌ | ❌ |
---
## 4. Gaps — Prioritized Action List
### P0: Critical (all users hit these)
| # | Gap | Affected | Fix |
| ------ | ------------------------------------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **G1** | **No "Forgot Password" UI anywhere** | ALL 4 products, ALL surfaces | Backend endpoints exist (`/auth/forgot-password`, `/auth/reset-password`) but ZERO clients call them. Need: forgot password form + reset password page in every app. |
| **G2** | **No email delivery for password reset / email verification** | ALL | Backend generates tokens but only LOGS them (`req.log.info`). The `TODO: Send email via delivery module` comment is still there. Need: wire delivery module (SendGrid/SES) or at minimum an SMTP transport. |
| **G3** | **MindLyst web has NO auth** | MindLyst web | Web dashboard has no login/register at all. API routes bypass platform-service entirely. Need: add auth flow matching ChronoMind web pattern. |
### P1: Important (poor UX without these)
| # | Gap | Affected | Fix |
| ------ | ----------------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **G4** | **No email verification UI** | ALL | Backend has `/auth/verify-email` + `/auth/resend-verification` but no client calls them. Users register with `emailVerified: false` and it's never checked/enforced. |
| **G5** | **ChronoMind web missing token refresh** | ChronoMind web | Web stores token in localStorage but never refreshes it. After 1 hour the token expires silently. Need: add refresh logic (like the iOS 45min timer). |
| **G6** | **NomGap missing proactive token refresh** | NomGap mobile | `hydrateFromToken()` calls `/auth/me` on startup but there's no periodic refresh. Token expires after 1 hour. Need: add refresh timer or intercept 401s. |
| **G7** | **No "Change Password" in any settings screen** | ALL | Users can only reset password via forgot-password flow (which doesn't work yet per G2). Need: `PUT /auth/profile` or new endpoint for authenticated password change. |
### P2: Consistency (works but inconsistent)
| # | Gap | Affected | Fix |
| ------- | --------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **G8** | **Password validation inconsistent across clients** | ALL | Backend requires `min(8)`. iOS/Android enforce 8+ chars, uppercase, lowercase, digit. ChronoMind web has no client-side validation. NomGap ProfileScreen has no validation. Standardize. |
| **G9** | **Token storage inconsistent** | Mixed | LysnrAI iOS/Android: Keychain/EncryptedSharedPrefs. ChronoMind: Keychain/plain SharedPrefs. MindLyst: Keychain/plain SharedPrefs. NomGap: MMKV. ChronoMind web: localStorage. Dashboards: httpOnly cookies. Consider standardizing mobile to Keychain + EncryptedSharedPrefs. |
| **G10** | **No SSO on ChronoMind, NomGap, or MindLyst** | 3 products | Only LysnrAI has Google/Microsoft/Apple SSO. Backend supports `/auth/sso`. Could add SSO to other products later. |
| **G11** | **Inconsistent `x-product-id` header** | Various | iOS `PlatformSyncManager` for ChronoMind doesn't send `x-product-id`. Some Android clients send it lowercase, some uppercase. Standardize. |
| **G12** | **No "Delete Account" in any app** | ALL | GDPR/privacy requirement. Backend has `DELETE /auth/users/:id` (admin only). Need: self-service account deletion endpoint + UI. |
### P3: Nice-to-have
| # | Gap | Affected | Fix |
| ------- | -------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------ |
| **G13** | **No cross-product ByteLyst account linking** | Future | If same user uses ChronoMind + NomGap, they have 2 separate accounts. Could add account linking later. |
| **G14** | **No rate limiting on auth endpoints from clients** | ALL | Backend has rate limiting module but clients don't handle 429 gracefully. |
| **G15** | **No biometric auth (FaceID/TouchID) on any mobile app** | iOS/Android | Could add biometric unlock after initial login. |
---
## 5. Architecture Diagram — Current State
```
┌──────────────────────────────────────────────────────────────────┐
│ platform-service (:4003) │
│ │
│ /auth/login ← email + password + productId │
│ /auth/register ← email + password + displayName + productId │
│ /auth/refresh ← refreshToken │
│ /auth/me ← Bearer token │
│ /auth/sso ← email + productId + provider │
│ /auth/forgot-password ← email + productId (⚠️ no email sent) │
│ /auth/reset-password ← token + newPassword (⚠️ no UI calls) │
│ /auth/verify-email ← token (⚠️ no UI calls) │
│ │
│ Cosmos DB: users container (partitioned by id) │
│ ┌─────────────────────────────────────────────┐ │
│ │ { id, productId, email, passwordHash, ... } │ │
│ │ │ │
│ │ productId="lysnrai" → LysnrAI users │ │
│ │ productId="chronomind" → ChronoMind users │ │
│ │ productId="nomgap" → NomGap users │ │
│ │ productId="mindlyst" → MindLyst users │ │
│ └─────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
▲ ▲ ▲ ▲ ▲
│ │ │ │ │
LysnrAI ChronoMind NomGap MindLyst Dashboards
(all 6 (web+iOS (Expo (iOS+ (admin+
surfaces) +Android) RN) Android) tracker)
```
---
## 6. Recommended Fix Order
1. **G2 — Email delivery** (unblocks G1, G4) — Wire SendGrid/SES into platform-service delivery module
2. **G1 — Forgot Password UI** — Add to all apps (once email works)
3. **G3 — MindLyst web auth** — Add auth context + login form
4. **G5 — ChronoMind web token refresh** — Add refresh logic
5. **G6 — NomGap token refresh** — Add refresh timer
6. **G4 — Email verification UI** — Add verification prompt post-register
7. **G7 — Change Password** — Add endpoint + UI in all settings screens
8. **G8 — Password validation** — Standardize client-side rules
9. **G12 — Delete Account** — Self-service endpoint + UI
10. **G9G11** — Consistency cleanup
---
## 7. Summary Answer
> **Q: Can a ChronoMind user sign in directly to NomGap?**
> **A: No.** They must register separately. Each product has its own user namespace (`productId`). Same email = different accounts on different products. This is **by design** — each product has independent plans, subscriptions, and licenses. Cross-product account linking is a future P3 feature.
> **Q: Do all apps use the same backend?**
> **A: Yes.** All products call the same platform-service `/auth/*` endpoints, storing users in the same Cosmos DB `users` container, isolated by `productId`.
> **Q: What's the biggest gap?**
> **A: Password reset doesn't work end-to-end.** The backend endpoints exist but (a) no email delivery is wired, and (b) zero client apps have forgot-password UI. This is the #1 gap to fix.