docs: update documentation
This commit is contained in:
parent
e6eee35544
commit
e3e332cee6
239
docs/WINDSURF/AUTH_CROSS_PRODUCT_ANALYSIS.md
Normal file
239
docs/WINDSURF/AUTH_CROSS_PRODUCT_ANALYSIS.md
Normal 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. **G9–G11** — 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.
|
||||
Loading…
Reference in New Issue
Block a user