fix(docs): self-audit Portal PRD + roadmap — 15 findings corrected

Review Errata (15 findings):
- F1-F2: Product count 11→10 (ByteLyst Auth has no backend)
- F3: product.json count 4→3 missing (FlowMonk, ActionTrail, LocalMemGPT)
- F4: Architecture diagram spacing fixes
- F5: Remove portalLayout from GlobalPreferences (contradicted separate Cosmos container)
- F6-F7: Widget endpoint unified to /widgets/:widgetId/data + added layout CRUD endpoints
- F8: Verified all 10 feed source endpoints against actual backend route files
- F9: Added @bytelyst/datastore to BFF tech stack
- F10: Added Cosmos containers section (portal_widget_layouts)
- F11: Global prefs dependency Phase 2→Phase 5 blocker
- F12: Removed emojis from search example
- F13: Added quick-actions task to roadmap Phase 1
- F14: Added 4 missing scaffold tasks (errors, datastore, cosmos-init, vitest)
- F15: Corrected run-local-all-services.sh location
- Updated task totals: 124→129
This commit is contained in:
saravanakumardb1 2026-03-21 20:57:28 -07:00
parent 7a4cca034c
commit edf8926d6d
2 changed files with 121 additions and 77 deletions

View File

@ -6,6 +6,30 @@
---
## Review Errata (2026-03-21 self-audit)
The following bugs/inaccuracies were found during systematic post-generation review and corrected in-place:
| # | Bug | Severity | Fix Applied |
| :-: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: | ------------------------------------------------------------------------------------------------------- |
| F1 | **Product count wrong:** Said "11 products" but ByteLyst Auth has no backend -- only 10 products have backends the portal can query | HIGH | Changed to "10 products with backends" + noted Auth as companion app |
| F2 | **ByteLyst Auth listed as product with backend** -- it's a companion app consuming platform-service, no data to aggregate | HIGH | Removed from product count, clarified in problem statement |
| F3 | **product.json count wrong:** Said "7 exist, 4 need creation" but only 3 are missing (FlowMonk, ActionTrail, LocalMemGPT) | MEDIUM | Corrected to "7 exist, 3 need creation" with specific names |
| F4 | **Architecture diagram spacing:** "ChronoMind4011" and "ActionTrail4018" missing spaces | LOW | Fixed spacing |
| F5 | **GlobalPreferences contained portalLayout:** Widget layouts were inside GlobalPreferences AND in a separate Cosmos container -- contradictory | MEDIUM | Removed `portalLayout` from GlobalPreferences; layouts stored in `portal_widget_layouts` container only |
| F6 | **Widget endpoint mismatch:** PRD API table said `/widgets/:widgetId`, roadmap said `/widgets/:widgetId/data` | MEDIUM | Unified to `/widgets/:widgetId/data` |
| F7 | **Missing widget layout endpoints in API table:** GET/PUT for layout management were in roadmap but not documented in PRD | MEDIUM | Added `GET/PUT /api/portal/widgets/layout` + `GET /api/portal/widgets/definitions` to API table |
| F8 | **Feed event source endpoints unverified:** Several assumed endpoints were wrong (ChronoMind `/timers/recent`, JarvisJr `/jarvis-sessions`, NomGap `/fasting-sessions`, PeakPulse `/sessions`) | HIGH | Verified all 10 endpoints against actual backend route files; corrected paths |
| F9 | **Missing `@bytelyst/datastore` in BFF tech stack** -- required for Cosmos container access | MEDIUM | Added to BFF tech stack row |
| F10 | **No Cosmos containers section** -- widget layouts need explicit container documentation | MEDIUM | Added section 4.6 with `portal_widget_layouts` container |
| F11 | **Dependency table: global prefs marked "Phase 2 blocker"** -- actually used in Phase 5 (Settings) | LOW | Changed to "Phase 5 blocker" |
| F12 | **Search example used emojis** -- violates "no emojis unless explicitly asked" rule | LOW | Removed emojis from search example |
| F13 | **Missing quick-actions in roadmap** -- PRD listed endpoint but no roadmap task built it | LOW | Added task 1.13 to roadmap Phase 1 |
| F14 | **Roadmap missing standard BFF scaffold files** -- `lib/errors.ts`, `lib/datastore.ts`, `lib/cosmos-init.ts`, `vitest.config.ts` not listed | MEDIUM | Added 4 tasks (0.11-0.14) to Phase 0 |
| F15 | **Roadmap task 7.19 wrong script location** -- `run-local-all-services.sh` is in `learning_voice_ai_agent/`, not common-plat | LOW | Corrected with "(in learning_voice_ai_agent repo)" note |
---
## 1. Product Identity
| Key | Value |
@ -14,7 +38,7 @@
| **Product ID** | `portal` |
| **Domain** | portal.bytelyst.com |
| **Repo** | `learning_ai_portal` (new) |
| **Ecosystem** | ByteLyst (consumes platform-service + all 11 product backends) |
| **Ecosystem** | ByteLyst (consumes platform-service + all 10 product backends) |
| **Port (web)** | 3010 |
| **Port (BFF)** | 4020 |
@ -22,7 +46,7 @@
## 2. Problem Statement
The ByteLyst ecosystem has grown to **11 products** (LysnrAI, MindLyst, ChronoMind, JarvisJr, NomGap, PeakPulse, FlowMonk, NoteLett, ActionTrail, LocalMemGPT, ByteLyst Auth), each with its own web dashboard, login, and settings. Users who use multiple products face:
The ByteLyst ecosystem has grown to **10 products with backends** (LysnrAI, MindLyst, ChronoMind, JarvisJr, NomGap, PeakPulse, FlowMonk, NoteLett, ActionTrail, LocalMemGPT) plus ByteLyst Auth (a companion app with no separate backend). Each product has its own web dashboard, login, and settings. Users who use multiple products face:
1. **Separate logins** — even though OneAuth shares identity, users still open different URLs per product
2. **No unified view** — no way to see "what's happening across all my ByteLyst apps"
@ -40,10 +64,10 @@ Meanwhile, the **admin dashboard** has grown to 43+ backend modules with 511+ en
| # | Goal | Success Metric |
| --- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| G1 | **Single login, all products** — one URL, one session, access everything | 100% of products accessible from portal |
| G1 | **Single login, all products** — one URL, one session, access everything | 100% of 10 products accessible from portal |
| G2 | **Cross-product activity feed** — timeline of recent actions across all products | Feed renders within 2s for users with 5+ products |
| G3 | **Unified search** — search notes, timers, tasks, sessions, memories from one bar | Cross-product search returns results in <1s |
| G4 | **Product launcher** — app-switcher grid (like Google's waffle menu) | All 11 products launchable with deep links |
| G4 | **Product launcher** — app-switcher grid (like Google's waffle menu) | All 10 products launchable with deep links |
| G5 | **Combined billing** — single view of all subscriptions, invoices, usage | Zero billing queries to support about "which product charges what" |
| G6 | **Global settings** — theme, timezone, notification prefs apply cross-product | Settings changes propagate to all products within 30s |
| G7 | **Cross-product widgets** — composable dashboard with pinnable product widgets | Users can customize their portal home with ≥10 widget types |
@ -100,7 +124,7 @@ Meanwhile, the **admin dashboard** has grown to 43+ backend modules with 511+ en
┌──────────┐ ┌───────────────┐ ┌───────────────┐
│ auth │ │ LysnrAI 4015 │ │ FlowMonk 4017 │
│ billing │ │ MindLyst 4014 │ │ NoteLett 4016 │
│ flags │ │ ChronoMind4011│ │ ActionTrail4018│
│ flags │ │ ChronoMind 4011│ │ ActionTrail 4018│
│ telemetry│ │ JarvisJr 4012 │ │ LocalMem 4019 │
│ usage │ │ NomGap 4013 │ │ PeakPulse 4010 │
└──────────┘ └───────────────┘ └───────────────┘
@ -138,7 +162,9 @@ interface GlobalPreferences {
inApp: boolean;
digest: 'none' | 'daily' | 'weekly';
};
portalLayout: WidgetLayout[];
// NOTE: Widget layouts are stored separately in Cosmos container
// `portal_widget_layouts` (partition: /userId), not here.
// This keeps GlobalPreferences lightweight on UserDoc.
}
```
@ -177,11 +203,14 @@ The BFF reads all `products/*/product.json` at startup to build the product regi
### 4.3 BFF API Endpoints
| Method | Path | Description | Source |
| ------ | --------------------------------- | ------------------------------------- | ----------------------------------- |
| ------ | ------------------------------------ | ------------------------------------- | ----------------------------------- |
| GET | `/api/portal/products` | List products user has access to | platform-service `/auth/me` |
| GET | `/api/portal/feed` | Cross-product activity feed (last 7d) | Fan-out to product backends |
| GET | `/api/portal/search?q=...` | Cross-product search | Fan-out to product search endpoints |
| GET | `/api/portal/widgets/:widgetId` | Fetch data for a specific widget | Product backend endpoint |
| GET | `/api/portal/widgets/definitions` | List available widget definitions | Static registry in BFF |
| GET | `/api/portal/widgets/layout` | Get user's widget layout | Cosmos `portal_widget_layouts` |
| PUT | `/api/portal/widgets/layout` | Save user's widget layout | Cosmos `portal_widget_layouts` |
| GET | `/api/portal/widgets/:widgetId/data` | Fetch data for a specific widget | Product backend endpoint |
| GET | `/api/portal/preferences` | Get global preferences | platform-service |
| PATCH | `/api/portal/preferences` | Update global preferences | platform-service |
| GET | `/api/portal/billing/summary` | Combined billing across products | platform-service subscriptions |
@ -222,12 +251,22 @@ Portal JWT adds a `scope: "portal"` claim so product backends know the request c
| Layer | Technology |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Web** | Next.js 16 (App Router), React 19, TailwindCSS v4, `@bytelyst/dashboard-shell`, Zustand, Recharts, Lucide icons |
| **BFF** | Fastify 5, TypeScript ESM, `@bytelyst/fastify-core`, `@bytelyst/api-client`, `@bytelyst/auth` |
| **BFF** | Fastify 5, TypeScript ESM, `@bytelyst/fastify-core`, `@bytelyst/api-client`, `@bytelyst/auth`, `@bytelyst/datastore` |
| **Auth** | JWT via `jose`, cookie-based session, `@bytelyst/react-auth` |
| **Shared packages** | `@bytelyst/config`, `@bytelyst/errors`, `@bytelyst/logger`, `@bytelyst/design-tokens`, `@bytelyst/telemetry-client`, `@bytelyst/feature-flag-client`, `@bytelyst/kill-switch-client` |
| **Database** | Azure Cosmos DB (`productId: "portal"`) for portal-specific data (widget layouts, preferences) |
| **Tests** | Vitest (BFF), Playwright (E2E) |
### 4.6 Cosmos Containers
Portal-specific data stored in Azure Cosmos DB with `productId: "portal"`:
| Container | Partition Key | Purpose |
| ----------------------- | ------------- | ------------------------------- |
| `portal_widget_layouts` | `/userId` | User widget grid configurations |
Global user preferences (`GlobalPreferences`) are stored on the existing `UserDoc` in platform-service's `users` container -- no new container needed for preferences.
---
## 5. Pages & UI
@ -277,18 +316,18 @@ The home page has three zones:
Global search bar in the top bar (Cmd+K). Results grouped by product:
```
🔍 "meeting notes"
"meeting notes"
📝 NoteLett (3 results)
- Meeting Notes Project Alpha (2h ago)
NoteLett (3 results)
- Meeting Notes -- Project Alpha (2h ago)
- Weekly Standup Notes (yesterday)
- Client Meeting Follow-up (3d ago)
🎤 LysnrAI (2 results)
- Meeting transcript 03/21 (today)
- Meeting transcript 03/18
LysnrAI (2 results)
- Meeting transcript -- 03/21 (today)
- Meeting transcript -- 03/18
🧠 MindLyst (1 result)
MindLyst (1 result)
- Memory: "Meeting with design team" in Work brain
```
@ -344,18 +383,18 @@ interface FeedEvent {
### 6.2 Event Sources per Product
| Product | Event Types | Source |
| ----------- | ------------------------------------------------------ | ------------------------------------ |
| Product | Event Types | Verified Backend Endpoint |
| ----------- | ------------------------------------------------------ | ----------------------------------------- |
| LysnrAI | `transcript.created`, `session.completed` | `GET /api/transcripts?limit=10` |
| MindLyst | `capture.created`, `triage.completed` | `GET /api/memory-items?limit=10` |
| ChronoMind | `timer.completed`, `routine.finished`, `pomodoro.done` | `GET /api/timers/recent` |
| JarvisJr | `session.completed`, `memory.created` | `GET /api/jarvis-sessions?limit=10` |
| NomGap | `fast.started`, `fast.completed`, `milestone.reached` | `GET /api/fasting-sessions?limit=10` |
| PeakPulse | `session.recorded`, `goal.achieved`, `badge.unlocked` | `GET /api/sessions?limit=10` |
| ChronoMind | `timer.completed`, `routine.finished`, `pomodoro.done` | `GET /api/timers?limit=10&sort=updatedAt` |
| JarvisJr | `session.completed`, `memory.created` | `GET /api/jarvis/sessions?limit=10` |
| NomGap | `fast.started`, `fast.completed`, `milestone.reached` | `GET /api/fasting/sessions?limit=10` |
| PeakPulse | `session.recorded`, `goal.achieved`, `badge.unlocked` | `GET /api/peak/sessions?limit=10` |
| FlowMonk | `task.completed`, `schedule.generated`, `entry.done` | `GET /api/schedule-entries?limit=10` |
| NoteLett | `note.created`, `note.updated`, `task.extracted` | `GET /api/notes?limit=10` |
| ActionTrail | `action.ingested`, `alert.fired`, `approval.decided` | `GET /api/actions?limit=10` |
| LocalMemGPT | `conversation.created`, `document.uploaded` | `GET /api/conversations?limit=10` |
| LocalMemGPT | `conversation.created`, `document.uploaded` | `GET /api/conversations` (no limit param) |
### 6.3 Aggregation Strategy
@ -462,15 +501,15 @@ The portal BFF can provide admin-web with:
## 11. Dependencies
| Dependency | Status | Blocker? |
| ------------------------------------------------------- | ------------------------------------- | ----------------------------------- |
| ------------------------------------------------------- | ---------------------------------------------------------------- | ----------------------------------- |
| OneAuth `memberships[]` on UserDoc | ✅ Implemented | No |
| `/auth/me` returns product list | ✅ Implemented | No |
| `@bytelyst/dashboard-shell` | ✅ Published | No |
| `@bytelyst/react-auth` | ✅ Published | No |
| Product backends expose recent-items APIs | ⚠️ Partial — most have list endpoints | Non-blocking (graceful degradation) |
| `product.json` files for all 11 products | ✅ 7 exist, 4 need creation | Non-blocking |
| `product.json` files for all 10 products | ✅ 7 exist, 3 need creation (FlowMonk, ActionTrail, LocalMemGPT) | Non-blocking |
| Service-to-service auth (portal BFF → product backends) | ❌ Needs implementation | Phase 1 blocker |
| Global preferences on UserDoc | ❌ Needs implementation | Phase 2 blocker |
| Global preferences on UserDoc | ❌ Needs implementation | Phase 5 blocker |
---

View File

@ -1,7 +1,7 @@
# Unified ByteLyst Portal — Roadmap & Task List
> **Date:** 2026-03-21 · **Companion to:** [`UNIFIED_BYTELYST_PORTAL_PRD.md`](UNIFIED_BYTELYST_PORTAL_PRD.md)
> **Estimated total:** 8 phases · ~124 tasks · 6-8 weeks
> **Estimated total:** 8 phases · ~129 tasks · 6-8 weeks
---
@ -10,7 +10,7 @@
> **Goal:** Repo exists, builds, deploys to dev. BFF starts and returns health check. Web renders shell.
| # | Task | Type | Est | Notes |
| ---- | ----------------------------------------------------------------------------------------- | ------- | --- | --------------------------------------------------------- |
| ---- | ------------------------------------------------------------------------------------------- | ------- | --- | --------------------------------------------------------- |
| 0.1 | Create `learning_ai_portal` repo with standard structure | infra | 1h | `backend/`, `web/`, `shared/`, `docs/`, `AGENTS.md` |
| 0.2 | Create `shared/product.json` (id: `portal`, port: 4020/3010) | config | 15m | Follow existing product.json pattern |
| 0.3 | Create `products/portal/product.json` in common-plat | config | 15m | Register portal in product registry |
@ -21,17 +21,21 @@
| 0.8 | Add `lib/request-context.ts` -- `getUserId(req)`, `getUserMemberships(req)` | backend | 30m | |
| 0.9 | Add `lib/product-registry.ts` -- load all product.json files, build registry | backend | 1h | Read from `../../products/*/product.json` or env-injected |
| 0.10 | Add `lib/product-client.ts` -- service-to-service HTTP client for product backends | backend | 1h | Timeout, circuit breaker, x-user-id header |
| 0.11 | Scaffold web with Next.js 16 + `@bytelyst/dashboard-shell` (port 3010) | web | 1h | App Router, TailwindCSS v4, `--portal-*` CSS props |
| 0.12 | Add `web/src/lib/product-config.ts` -- product identity + API URLs | web | 15m | |
| 0.13 | Add `web/src/lib/auth.ts` -- `@bytelyst/react-auth` provider | web | 30m | Cookie-based auth |
| 0.14 | Add `web/src/lib/api.ts` -- typed fetch client for BFF | web | 30m | |
| 0.15 | Add `web/src/app/layout.tsx` + `providers.tsx` -- shell + auth + telemetry | web | 30m | |
| 0.16 | Create `AGENTS.md` with project conventions | docs | 30m | |
| 0.17 | Create `.github/workflows/ci.yml` -- typecheck + test for backend + web | infra | 30m | |
| 0.18 | Verify: `cd backend && npm test && npm run typecheck` passes | test | 15m | |
| 0.19 | Verify: `cd web && npm run typecheck && npm run build` passes | test | 15m | |
| 0.11 | Add `lib/errors.ts` -- re-export from `@bytelyst/errors` | backend | 10m | Standard pattern across all product backends |
| 0.12 | Add `lib/datastore.ts` -- `@bytelyst/datastore` provider (Cosmos or memory via DB_PROVIDER) | backend | 30m | Required for widget layout persistence |
| 0.13 | Add `lib/cosmos-init.ts` -- register `portal_widget_layouts` container on startup | backend | 30m | Partition: `/userId` |
| 0.14 | Add `vitest.config.ts` + `test-helpers.ts` -- Vitest config + `buildTestApp()` helper | backend | 30m | Standard test scaffold |
| 0.15 | Scaffold web with Next.js 16 + `@bytelyst/dashboard-shell` (port 3010) | web | 1h | App Router, TailwindCSS v4, `--portal-*` CSS props |
| 0.16 | Add `web/src/lib/product-config.ts` -- product identity + API URLs | web | 15m | |
| 0.17 | Add `web/src/lib/auth.ts` -- `@bytelyst/react-auth` provider | web | 30m | Cookie-based auth |
| 0.18 | Add `web/src/lib/api.ts` -- typed fetch client for BFF | web | 30m | |
| 0.19 | Add `web/src/app/layout.tsx` + `providers.tsx` -- shell + auth + telemetry | web | 30m | |
| 0.20 | Create `AGENTS.md` with project conventions | docs | 30m | |
| 0.21 | Create `.github/workflows/ci.yml` -- typecheck + test for backend + web | infra | 30m | |
| 0.22 | Verify: `cd backend && npm test && npm run typecheck` passes | test | 15m | |
| 0.23 | Verify: `cd web && npm run typecheck && npm run build` passes | test | 15m | |
**Phase 0 deliverable:** Repo builds, BFF returns `GET /health`, web renders empty shell with sidebar.
**Phase 0 deliverable:** Repo builds, BFF returns `GET /health`, web renders empty shell with sidebar. (23 tasks)
---
@ -53,7 +57,8 @@
| 1.10 | Web: product launch handler -- opens product dashboard in new tab with session context | web | 1h | Deep link: `https://{domain}/?portal=true` |
| 1.11 | Web: show "Get Started" CTA for products user hasn't signed up for | web | 1h | Links to product landing page |
| 1.12 | Test: BFF products endpoint returns correct memberships | test | 1h | Vitest |
| 1.13 | Test: Login flow to product grid to launch works E2E | test | 1h | Playwright |
| 1.13 | BFF: `GET /api/portal/quick-actions` -- available quick actions per product from product registrations | backend | 1h | Static config in product.json + optional dynamic from backends |
| 1.14 | Test: Login flow to product grid to launch works E2E | test | 1h | Playwright |
**Phase 1 deliverable:** User logs in, sees grid of their products with status, can open any product in a new tab.
@ -200,7 +205,7 @@
| 7.16 | Docker: `Dockerfile` for BFF + web | infra | 1h | |
| 7.17 | Docker: Add to `docker-compose.yml` in common-plat | infra | 30m | |
| 7.18 | CI: Playwright E2E test suite (10 core flows) | test | 3h | |
| 7.19 | CI: Add portal to `run-local-all-services.sh` | infra | 15m | |
| 7.19 | CI: Add portal to `run-local-all-services.sh` (in learning_voice_ai_agent repo) | infra | 15m | |
| 7.20 | Final: Typecheck + test + build green across BFF + web | test | 1h | |
**Phase 7 deliverable:** Production-ready portal. All tests pass. Docker-deployable. Telemetry wired.
@ -230,8 +235,8 @@
| Phase | Name | Duration | Tasks | Key Deliverable |
| ----- | ------------------------------- | ------------ | ------- | ----------------------------------- |
| **0** | Repo Scaffold and Foundations | 2 days | 19 | Repo builds, shell renders |
| **1** | Product Launcher and Auth | 3 days | 13 | Login, product grid, launch |
| **0** | Repo Scaffold and Foundations | 2 days | 23 | Repo builds, shell renders |
| **1** | Product Launcher and Auth | 3 days | 14 | Login, product grid, launch |
| **2** | Activity Feed and Notifications | 3 days | 13 | Cross-product activity timeline |
| **3** | Widget Dashboard | 4 days | 17 | Customizable widget grid |
| **4** | Cross-Product Search | 2 days | 10 | Cmd+K global search |
@ -239,7 +244,7 @@
| **6** | Security and Profile | 2 days | 10 | Full SmartAuth security from portal |
| **7** | Polish and Launch | 3 days | 20 | Production-ready, Docker, E2E |
| **8** | Post-Launch | Ongoing | 10 | Drag-drop, SSE, quick actions |
| | **Total** | **~21 days** | **124** | |
| | **Total** | **~21 days** | **129** | |
---