learning_ai_common_plat/docs/ROADMAP.md
saravanakumardb1 bf22b5ee4c docs(roadmap): address 15 gaps found via codebase cross-reference
Gap Analysis added:
- G1: Route-level import rewiring (22 error files, 13 cosmos, 34 product-config)
- G2: Existing errors.test.ts files in 3 services need updating
- G3: 5th product-config copy in user-dashboard-web
- G4/G5: Admin dashboard API routes + repositories import product-config
- G6: growth-service webhooks.ts imports product-config
- G7: file: reference paths differ (services=3 levels, dashboards=2 levels)
- G8: pnpm install + lock file steps added to each integration
- G9: Rollback strategy added to Phase 0
- G10: Git branching strategy added to Phase 0
- G11: Docker file: reference solution (pre-copy script) in Phase 5
- G12: 24 auth-context consumer files need path updates (thin re-export pattern)
- G13: MindLyst Android MindLystTheme.kt added to Phase 4
- G14: @bytelyst/auth false dep on config removed (reads JWT_SECRET from env)
- G15: Dashboard repositories (8 files) importing cosmos added to Phase 1B

Revised: ~278 tasks, ~37-51 hours estimated
2026-02-12 10:55:03 -08:00

552 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Common Platform Extraction — Roadmap
> **Scope:** Extract shared infrastructure from `learning_voice_ai_agent` (LysnrAI) and `learning_multimodal_memory_agents` (MindLyst) into `learning_ai_common_plat` as reusable `@bytelyst/*` npm packages.
>
> **Companion docs:** [COMMON_PLATFORM_ANALYSIS.md](./COMMON_PLATFORM_ANALYSIS.md) · [ECOSYSTEM_ARCHITECTURE.md](./ECOSYSTEM_ARCHITECTURE.md) · [ecosystem-after-refactor.drawio](./ecosystem-after-refactor.drawio)
---
## Gap Analysis (added after codebase cross-reference)
The following gaps were identified by scanning every import in the actual codebase and are now addressed in the phases below:
| # | Gap | Impact | Resolution |
|---|-----|--------|------------|
| G1 | **Route-level import rewiring not scoped.** `errors` is imported in **22 route files**, `product-config` in **34 files**, `cosmos` in **13 repository files** — not just the `lib/*.ts` files. | High — each integration step is 510× more files than originally estimated | Added explicit "rewire all consumer imports" tasks per phase |
| G2 | **Existing `errors.test.ts` files** in 3 services (platform, growth, tracker) import from local path and will break | Medium | Added tasks to update or delete existing error test files |
| G3 | **`user-dashboard-web/src/lib/product-config.ts`** is a 5th copy of product-config (not counted originally) | Medium | Added to Phase 2A cleanup |
| G4 | **`admin-dashboard-web` API routes** (7 files) import `product-config` — needs rewiring | Medium | Added to Phase 2A integration |
| G5 | **`admin-dashboard-web` repositories** (users.ts, tokens.ts) import `product-config` — needs rewiring | Medium | Added to Phase 2A integration |
| G6 | **`growth-service/src/lib/webhooks.ts`** imports `PRODUCT_ID` from `product-config` — needs rewiring | Low | Added to Phase 2A integration |
| G7 | **`file:` reference paths differ** between services (3 levels: `../../../`) and dashboards (2 levels: `../../`) | Medium — wrong paths = broken installs | Added explicit path table in Phase 0 |
| G8 | **`pnpm install` + lock file regeneration** not mentioned after adding `file:` deps | Medium | Added to each integration step |
| G9 | **No rollback plan** if a migration breaks a service mid-phase | High | Added rollback strategy section |
| G10 | **No git branching strategy** — unclear if work happens on main or feature branches | Medium | Added branching guidance to Phase 0 |
| G11 | **Docker builds can't resolve `file:` references** outside build context — mentioned vaguely but not solved | High — Docker builds will fail | Added concrete Docker strategy in Phase 5 |
| G12 | **`auth-context.tsx` consumer files** not counted: admin (4 files), user (12 files), tracker (8 files) = **24 files** need import path updates | Medium | Added to Phase 3B integration |
| G13 | **MindLyst Android `MindLystTheme.kt`** (Compose theme) not in Phase 4 integration steps | Low | Added to Phase 4 |
| G14 | **`@bytelyst/auth` declared dep on `@bytelyst/config`** is unnecessary — JWT code reads `JWT_SECRET` directly from `process.env`, not via config loader | Low — false dependency complicates ordering | Removed; auth is a leaf dep on `jose` + `bcryptjs` only |
| G15 | **Dashboard repositories** (admin: 5 repos, user: 3 repos) import from `../cosmos` — need rewiring in Phase 1B | Medium | Added to Phase 1B integration |
---
## Phase 0 — Repo Scaffolding & Tooling
> **Goal:** Initialize `learning_ai_common_plat` as a proper monorepo with build tooling, so packages can be developed, tested, and consumed.
### Setup
- [ ] **0.1** Initialize `package.json` at repo root (`"private": true`, `"name": "@bytelyst/root"`)
- [ ] **0.2** Add `pnpm-workspace.yaml` declaring `packages/*` as workspace members
- [ ] **0.3** Create `tsconfig.base.json` with shared compiler options (ESM, strict, target ES2022, module NodeNext)
- [ ] **0.4** Add shared `vitest.config.ts` at repo root
- [ ] **0.5** Add `.gitignore` (node_modules, dist, coverage, .DS_Store)
- [ ] **0.6** Add `.nvmrc` matching LysnrAI's Node version
- [ ] **0.7** Add `.editorconfig` matching LysnrAI conventions
- [ ] **0.8** Add `README.md` with repo purpose, package list, and quick-start
- [ ] **0.9** Add `CONTRIBUTING.md` with conventions (commit format, PR process, testing expectations)
- [ ] **0.10** Verify: `pnpm install` succeeds, `pnpm -r build` succeeds (empty packages OK)
### Branching & `file:` Reference Strategy
- [ ] **0.11** Create `feat/common-plat-extraction` branch in **all 3 repos** — all migration work happens here, merge to main per-phase
- [ ] **0.12** Document the `file:` reference path table (all repos must be cloned side-by-side under the same parent directory):
```
# From Fastify services (3 levels up):
"@bytelyst/errors": "file:../../../learning_ai_common_plat/packages/errors"
# From Next.js dashboards at repo root (2 levels up):
"@bytelyst/errors": "file:../../learning_ai_common_plat/packages/errors"
# From MindLyst web (3 levels up — inside mindlyst-native/web/):
"@bytelyst/design-tokens": "file:../../../learning_ai_common_plat/packages/design-tokens"
```
### Rollback Strategy
- [ ] **0.13** Establish rollback rule: each phase is done on a branch. If tests fail after integration, `git stash` consumer changes and revert to local `lib/` imports. The shared package stays in common-plat for the next attempt.
- [ ] **0.14** Never delete old `lib/*.ts` files until **all consumers** have been migrated and tested in the same phase
---
## Phase 1 — P0 Packages: Errors & Cosmos (Drop-in, No Config)
> **Goal:** Extract the two leaf packages with zero dependencies on other `@bytelyst/*` packages. These are the safest, highest-copy-count extractions.
### 1A — `@bytelyst/errors`
**Extract:**
- [ ] **1A.1** Create `packages/errors/package.json` (name, version 0.1.0, type module, exports)
- [ ] **1A.2** Create `packages/errors/tsconfig.json` extending `../../tsconfig.base.json`
- [ ] **1A.3** Write `packages/errors/src/service-error.ts` — base `ServiceError` class with optional `details`
- [ ] **1A.4** Write `packages/errors/src/http-errors.ts``NotFoundError`, `BadRequestError`, `UnauthorizedError`, `ForbiddenError`, `ConflictError`, `TooManyRequestsError`
- [ ] **1A.5** Write `packages/errors/src/index.ts` — barrel export
- [ ] **1A.6** Add build script (`tsc`)
**Test:**
- [ ] **1A.7** Write `packages/errors/src/__tests__/errors.test.ts` — verify statusCode, message, instanceof, details field
- [ ] **1A.8** Run `pnpm --filter @bytelyst/errors test` — all pass
**Integrate into LysnrAI** (⚠️ G1: errors is imported in **22 route files** + 4 server.ts, not just lib/):
- [ ] **1A.9** Add `"@bytelyst/errors": "file:../../../learning_ai_common_plat/packages/errors"` to `services/platform-service/package.json`
- [ ] **1A.10** Replace `from "./lib/errors.js"``from "@bytelyst/errors"` in `server.ts`
- [ ] **1A.11** Replace `from "../../lib/errors.js"``from "@bytelyst/errors"` in **all 6 route files** (auth, audit, blob, flags, notifications, ratelimit)
- [ ] **1A.12** Run `pnpm install` in platform-service (regenerates lock file)
- [ ] **1A.13** Run platform-service tests — all pass
- [ ] **1A.14** Repeat for **billing-service**`server.ts` + **5 route files** (subscriptions, usage, plans, licenses, stripe)
- [ ] **1A.15** Repeat for **growth-service**`server.ts` + **3 route files** (invitations, referrals, promos)
- [ ] **1A.16** Repeat for **tracker-service**`server.ts` + `lib/auth.ts` + **4 route files** (items, comments, votes, public)
**Clean up old code:**
- [ ] **1A.17** Delete `services/platform-service/src/lib/errors.ts`
- [ ] **1A.18** Delete `services/billing-service/src/lib/errors.ts`
- [ ] **1A.19** Delete `services/growth-service/src/lib/errors.ts`
- [ ] **1A.20** Delete `services/tracker-service/src/lib/errors.ts`
- [ ] **1A.21** ⚠️ G2: Update or delete **existing error test files** that import from local path:
- `services/platform-service/src/lib/errors.test.ts` → update import to `@bytelyst/errors` or delete (tests now in shared package)
- `services/growth-service/src/lib/errors.test.ts` → same
- `services/tracker-service/src/lib/errors.test.ts` → same
- [ ] **1A.22** Run all 4 service test suites — confirm no regressions
- [ ] **1A.23** Verify Docker builds for all 4 services still pass
**Commit:** `feat(errors): extract @bytelyst/errors shared package`
---
### 1B — `@bytelyst/cosmos`
**Extract:**
- [ ] **1B.1** Create `packages/cosmos/package.json` (peer dep: `@azure/cosmos`)
- [ ] **1B.2** Create `packages/cosmos/tsconfig.json`
- [ ] **1B.3** Write `packages/cosmos/src/client.ts``getCosmosClient()`, `getDatabase()`, `getContainer()`
- [ ] **1B.4** Write `packages/cosmos/src/containers.ts``registerContainers()`, `initializeAllContainers()`, `ContainerConfig`
- [ ] **1B.5** Write `packages/cosmos/src/types.ts``ContainerConfig` interface
- [ ] **1B.6** Write `packages/cosmos/src/index.ts` — barrel export
- [ ] **1B.7** Add build script
**Test:**
- [ ] **1B.8** Write `packages/cosmos/src/__tests__/client.test.ts` — mock `@azure/cosmos`, verify singleton, env var reading
- [ ] **1B.9** Write `packages/cosmos/src/__tests__/containers.test.ts` — verify registry, partition key config
- [ ] **1B.10** Run `pnpm --filter @bytelyst/cosmos test` — all pass
**Integrate into LysnrAI services** (⚠️ G1: cosmos is imported in **13 repository files**, not just lib/):
- [ ] **1B.11** Add `"@bytelyst/cosmos": "file:../../../learning_ai_common_plat/packages/cosmos"` to **platform-service** `package.json` + `pnpm install`
- [ ] **1B.12** Replace `from "../../lib/cosmos.js"``from "@bytelyst/cosmos"` in **4 repository files** (auth, audit, flags, notifications)
- [ ] **1B.13** Run platform-service tests — all pass
- [ ] **1B.14** Repeat for **billing-service****4 repository files** (subscriptions, usage, plans, licenses)
- [ ] **1B.15** Repeat for **growth-service****2 repository files** (invitations, referrals)
- [ ] **1B.16** Repeat for **tracker-service****3 repository files** (items, comments, votes)
**Integrate into LysnrAI dashboards** (⚠️ G15: dashboard repositories also import cosmos):
- [ ] **1B.17** Add `"@bytelyst/cosmos": "file:../../learning_ai_common_plat/packages/cosmos"` to **admin-dashboard-web** `package.json` (⚠️ G7: 2 levels, not 3)
- [ ] **1B.18** Refactor `admin-dashboard-web/src/lib/cosmos.ts` — keep container definitions as `registerContainers()` call using `@bytelyst/cosmos`
- [ ] **1B.19** Rewire **5 admin repositories** that import `../cosmos`: `users.ts`, `tokens.ts`, `audit.ts`, `usage.ts`, `theme.ts`
- [ ] **1B.20** Run `pnpm install` + `next build` for admin-dashboard — passes
- [ ] **1B.21** Add dep to **user-dashboard-web** `package.json` (2 levels: `file:../../...`)
- [ ] **1B.22** Refactor `user-dashboard-web/src/lib/cosmos.ts` — same pattern
- [ ] **1B.23** Rewire **3 user repositories** that import `../cosmos`: `users.ts`, `settings.ts`, `transcripts.ts`
- [ ] **1B.24** Rewire **2 user API routes** that import cosmos: `api/health/route.ts`, `api/seed/route.ts`
- [ ] **1B.25** Run `pnpm install` + `next build` for user-dashboard — passes
**Clean up old code:**
- [ ] **1B.26** Delete `services/platform-service/src/lib/cosmos.ts`
- [ ] **1B.27** Delete `services/billing-service/src/lib/cosmos.ts`
- [ ] **1B.28** Delete `services/growth-service/src/lib/cosmos.ts`
- [ ] **1B.29** Delete `services/tracker-service/src/lib/cosmos.ts`
- [ ] **1B.30** Reduce `admin-dashboard-web/src/lib/cosmos.ts` to just container registry config (no client code)
- [ ] **1B.31** Reduce `user-dashboard-web/src/lib/cosmos.ts` to just container registry config (no client code)
- [ ] **1B.32** Run all service tests + `next build` for both dashboards — no regressions
- [ ] **1B.33** Verify Docker builds pass
**Commit:** `feat(cosmos): extract @bytelyst/cosmos shared package`
---
## Phase 2 — P1 Packages: Config, Auth, Fastify Core
> **Goal:** Extract the three packages that depend on Phase 1 packages. These have higher impact but require more care due to inter-package dependencies.
### 2A — `@bytelyst/config`
**Extract:**
- [ ] **2A.1** Create `packages/config/package.json` (peer dep: `zod`)
- [ ] **2A.2** Write `packages/config/src/base-schema.ts``baseEnvSchema` (PORT, HOST, NODE_ENV, CORS_ORIGIN, SERVICE_NAME, COSMOS_ENDPOINT, COSMOS_KEY, COSMOS_DATABASE)
- [ ] **2A.3** Write `packages/config/src/loader.ts``loadConfig(extension?)` function
- [ ] **2A.4** Write `packages/config/src/product-identity.ts``loadProductIdentity()` reads `product.json` or env vars
- [ ] **2A.5** Write `packages/config/src/index.ts`
- [ ] **2A.6** Add build script
**Test:**
- [ ] **2A.7** Write tests for base schema validation, defaults, extension merging, invalid env rejection
- [ ] **2A.8** Write tests for product identity loading (file + env fallback)
- [ ] **2A.9** Run `pnpm --filter @bytelyst/config test` — all pass
**Integrate into LysnrAI services** (⚠️ G1: `product-config` is imported in **34 files** across services + dashboards):
- [ ] **2A.10** Refactor **platform-service** `config.ts` → import `loadConfig()` + extend with service-specific fields only
- [ ] **2A.11** Replace `from "../../lib/product-config.js"``from "@bytelyst/config"` in **7 files** (auth routes, audit routes, flags routes, notifications routes, ratelimit routes, auth repository, auth jwt.ts)
- [ ] **2A.12** Run `pnpm install` + platform-service tests — all pass
- [ ] **2A.13** Repeat for **billing-service** — extend config with STRIPE_*, BILLING_*; rewire **10 files** (5 routes + 5 repositories) that import `product-config`
- [ ] **2A.14** Repeat for **growth-service** — extend config with STRIPE_*, WEBHOOK_*; rewire **4 files** (3 routes + `lib/webhooks.ts`) (⚠️ G6)
- [ ] **2A.15** Repeat for **tracker-service** — extend config with JWT_SECRET, DEFAULT_PRODUCT_ID; rewire **2 files** (items routes, public routes)
**Integrate into LysnrAI dashboards** (⚠️ G4/G5):
- [ ] **2A.16** Add `@bytelyst/config` dep to **admin-dashboard-web** (2-level `file:` path)
- [ ] **2A.17** Rewire **7 admin API route files** that import `product-config`: seed, users, tokens, kill-switch, analytics/retention, invitations, referrals (they use `PRODUCT_ID`)
- [ ] **2A.18** Rewire **2 admin repository files** that import `product-config`: `users.ts`, `tokens.ts`
- [ ] **2A.19** Run `pnpm install` + `next build` for admin-dashboard — passes
- [ ] **2A.20** ⚠️ G3: Add dep to **user-dashboard-web** — this is the **5th copy** of `product-config.ts` (15 lines)
- [ ] **2A.21** Run `pnpm install` + `next build` for user-dashboard — passes
**Clean up old code:**
- [ ] **2A.22** Delete **5×** `product-config.ts` (4 services + user-dashboard)
- [ ] **2A.23** Reduce 4× service `config.ts` to thin extension schemas (~5 lines each)
- [ ] **2A.24** Run all service tests + both dashboard builds — no regressions
- [ ] **2A.25** Verify Docker builds
**Commit:** `feat(config): extract @bytelyst/config shared package`
---
### 2B — `@bytelyst/auth`
**Extract:**
- [ ] **2B.1** Create `packages/auth/package.json` (peer deps: `jose`, `bcryptjs`) (⚠️ G14: NO dep on `@bytelyst/config` — JWT reads `JWT_SECRET` directly from `process.env`)
- [ ] **2B.2** Write `packages/auth/src/jwt.ts``createJwtUtils({ issuer, accessTokenExpiry, refreshTokenExpiry })`
- [ ] **2B.3** Write `packages/auth/src/middleware.ts``extractAuth()` Fastify hook, `requireRole()` guard
- [ ] **2B.4** Write `packages/auth/src/server-auth.ts``getCurrentUser()` for Next.js API routes
- [ ] **2B.5** Write `packages/auth/src/password.ts``hashPassword()`, `verifyPassword()`
- [ ] **2B.6** Write `packages/auth/src/types.ts``AuthPayload`, `TokenPayload` interfaces
- [ ] **2B.7** Write `packages/auth/src/index.ts`
- [ ] **2B.8** Add build script
**Test:**
- [ ] **2B.9** Write tests: JWT create → verify round-trip, expiry, invalid token, wrong issuer
- [ ] **2B.10** Write tests: bcrypt hash → verify round-trip, wrong password rejection
- [ ] **2B.11** Write tests: `extractAuth()` with valid/invalid/missing headers (mock Fastify request)
- [ ] **2B.12** Run `pnpm --filter @bytelyst/auth test` — all pass
**Integrate into LysnrAI services:**
- [ ] **2B.13** Refactor **platform-service** `modules/auth/jwt.ts` → use `createJwtUtils({ issuer: "lysnrai" })`
- [ ] **2B.14** Run platform-service auth tests — all pass
- [ ] **2B.15** Refactor **tracker-service** `lib/auth.ts` → use `extractAuth()` + `requireRole()`
- [ ] **2B.16** Run tracker-service tests — all pass
**Integrate into LysnrAI dashboards** (⚠️ `auth-server.ts` is imported by **20 admin API routes** and **multiple user API routes**):
- [ ] **2B.17** Add `@bytelyst/auth` dep to **admin-dashboard-web** (2-level `file:` path) + `pnpm install`
- [ ] **2B.18** Refactor **admin-dashboard-web** `lib/auth-server.ts` → use `createJwtUtils()` + `hashPassword()` + `getCurrentUser()`
- [ ] **2B.19** Verify all **20 admin API route files** that `import { ... } from "@/lib/auth-server"` still compile (import path stays same, only internals change)
- [ ] **2B.20** Run admin-dashboard `next build` — passes
- [ ] **2B.21** Add dep to **user-dashboard-web** + `pnpm install`
- [ ] **2B.22** Refactor **user-dashboard-web** `lib/auth-server.ts` → same as above with different issuer
- [ ] **2B.23** Run user-dashboard `next build` — passes
**Clean up old code:**
- [ ] **2B.24** Delete/reduce `platform-service/src/modules/auth/jwt.ts` (keep only route handlers, not JWT logic)
- [ ] **2B.25** Delete `tracker-service/src/lib/auth.ts`
- [ ] **2B.26** Reduce `admin-dashboard-web/src/lib/auth-server.ts` to thin wrapper calling `@bytelyst/auth`
- [ ] **2B.27** Reduce `user-dashboard-web/src/lib/auth-server.ts` to thin wrapper calling `@bytelyst/auth`
- [ ] **2B.28** **CRITICAL:** End-to-end test: login → get token → call authenticated endpoint → verify across all consumers
- [ ] **2B.29** Verify Docker builds
**Commit:** `feat(auth): extract @bytelyst/auth shared package`
---
### 2C — `@bytelyst/fastify-core`
**Extract:**
- [ ] **2C.1** Create `packages/fastify-core/package.json` (peer deps: `fastify`, `@fastify/cors`, `@fastify/swagger`, `fastify-metrics`; deps: `@bytelyst/errors`, `@bytelyst/config`)
- [ ] **2C.2** Write `packages/fastify-core/src/create-app.ts``createServiceApp({ name, version, description })` factory
- [ ] **2C.3** Write `packages/fastify-core/src/request-id.ts` — x-request-id propagation hook
- [ ] **2C.4** Write `packages/fastify-core/src/health.ts` — health check route factory `healthHandler(name, version)`
- [ ] **2C.5** Write `packages/fastify-core/src/error-handler.ts``ServiceError`-aware error handler
- [ ] **2C.6** Write `packages/fastify-core/src/start.ts``startService(app, port, host?)` helper
- [ ] **2C.7** Write `packages/fastify-core/src/index.ts`
- [ ] **2C.8** Add build script
**Test:**
- [ ] **2C.9** Write tests: `createServiceApp()` returns Fastify instance with CORS, Swagger, metrics
- [ ] **2C.10** Write tests: health endpoint returns correct shape `{ status, service, version, timestamp, requestId }`
- [ ] **2C.11** Write tests: error handler maps ServiceError → correct HTTP response
- [ ] **2C.12** Write tests: x-request-id is propagated or generated
- [ ] **2C.13** Run `pnpm --filter @bytelyst/fastify-core test` — all pass
**Integrate into LysnrAI:**
- [ ] **2C.14** Refactor **platform-service** `server.ts``createServiceApp()` + register routes + `startService()`
- [ ] **2C.15** Run platform-service tests — all pass
- [ ] **2C.16** Verify `/health` endpoint returns expected shape
- [ ] **2C.17** Repeat for **billing-service** (keep internal key auth hook as service-specific)
- [ ] **2C.18** Repeat for **growth-service**
- [ ] **2C.19** Repeat for **tracker-service**
**Clean up old code:**
- [ ] **2C.20** Each `server.ts` should now be ~15 lines (import factory → register routes → start)
- [ ] **2C.21** Run all 4 service test suites — no regressions
- [ ] **2C.22** Verify `services/monitoring/health-check.ts` still works with refactored health endpoints
- [ ] **2C.23** Verify Docker builds for all 4 services
- [ ] **2C.24** Verify `docker-compose up` starts all services correctly
**Commit:** `feat(fastify-core): extract @bytelyst/fastify-core shared package`
---
## Phase 3 — P2 Packages: API Client & React Auth
> **Goal:** Extract dashboard-side libraries. These affect the Next.js apps and require browser-context testing.
### 3A — `@bytelyst/api-client`
**Extract:**
- [ ] **3A.1** Create `packages/api-client/package.json` (no runtime deps)
- [ ] **3A.2** Write `packages/api-client/src/client.ts``createApiClient({ baseUrl, getToken?, defaultHeaders? })``{ fetch, safeFetch }`
- [ ] **3A.3** Write `packages/api-client/src/types.ts``ApiResult<T>`, `ApiError`, `ApiClientConfig`
- [ ] **3A.4** Write `packages/api-client/src/index.ts`
- [ ] **3A.5** Add build script
**Test:**
- [ ] **3A.6** Write tests: `fetch<T>()` calls correct URL, passes headers, throws on error
- [ ] **3A.7** Write tests: `safeFetch<T>()` returns `{ data, error }` tuple, never throws
- [ ] **3A.8** Write tests: auth token injection via `getToken()` callback
- [ ] **3A.9** Run `pnpm --filter @bytelyst/api-client test` — all pass
**Integrate into LysnrAI dashboards:**
- [ ] **3A.10** Refactor **admin-dashboard-web** `src/lib/api.ts` — use `createApiClient()`, keep domain methods (apiLogin, apiListUsers, etc.)
- [ ] **3A.11** Run admin-dashboard `next build` — passes
- [ ] **3A.12** Refactor **user-dashboard-web** client files (`platform-client.ts`, `billing-client.ts`, `growth-client.ts`)
- [ ] **3A.13** Run user-dashboard `next build` — passes
- [ ] **3A.14** Refactor **tracker-dashboard-web** `src/lib/tracker-client.ts`
- [ ] **3A.15** Run tracker-dashboard `next build` — passes
**Clean up old code:**
- [ ] **3A.16** Remove duplicated `apiFetch` / `request` base functions from each dashboard (domain methods stay)
- [ ] **3A.17** Run all 3 dashboard builds — no regressions
**Commit:** `feat(api-client): extract @bytelyst/api-client shared package`
---
### 3B — `@bytelyst/react-auth`
**Extract:**
- [ ] **3B.1** Create `packages/react-auth/package.json` (peer deps: `react`, dep: `@bytelyst/api-client`)
- [ ] **3B.2** Write `packages/react-auth/src/auth-context.tsx``createAuthProvider<TUser>({ storagePrefix, loginEndpoint, ... })`
- [ ] **3B.3** Write `packages/react-auth/src/use-auth.ts` — typed `useAuth()` hook
- [ ] **3B.4** Write `packages/react-auth/src/types.ts``BaseUser`, `AuthContextValue<TUser>`, `AuthConfig`
- [ ] **3B.5** Write `packages/react-auth/src/index.ts`
- [ ] **3B.6** Add build script
**Test:**
- [ ] **3B.7** Write tests: AuthProvider renders children, login/logout flows, localStorage persistence
- [ ] **3B.8** Write tests: useAuth() returns correct state after login/logout
- [ ] **3B.9** Run `pnpm --filter @bytelyst/react-auth test` — all pass
**Integrate into LysnrAI dashboards** (⚠️ G12: auth-context is imported by **24 component/page files** total):
- [ ] **3B.10** Add `@bytelyst/react-auth` dep to **admin-dashboard-web** (2-level `file:` path) + `pnpm install`
- [ ] **3B.11** Refactor **admin-dashboard-web** `src/lib/auth-context.tsx``createAuthProvider<AdminUser>({ storagePrefix: "admin", ... })`
- [ ] **3B.12** Verify **4 admin consumer files** still compile: `login/page.tsx`, `providers.tsx`, `auth-guard.tsx`, `sidebar-nav.tsx` (import path `@/lib/auth-context` stays same if file is kept as re-export; or update all 4)
- [ ] **3B.13** Run admin-dashboard `next build` — passes
- [ ] **3B.14** Test login/logout flow manually in admin dashboard
- [ ] **3B.15** Add dep to **user-dashboard-web** + `pnpm install`
- [ ] **3B.16** Refactor **user-dashboard-web** `src/lib/auth-context.tsx``createAuthProvider<PortalUser>({ storagePrefix: "portal", enableSSO: true, ... })`
- [ ] **3B.17** Verify **12 user consumer files** still compile: `login/page.tsx`, `providers.tsx`, `auth-guard.tsx`, `sidebar-nav.tsx`, + **8 portal page files** (profile, payments, referrals, settings, subscription, transcripts, notifications, portal/page)
- [ ] **3B.18** Run user-dashboard `next build` — passes
- [ ] **3B.19** Test login/logout + SSO flow manually in user dashboard
- [ ] **3B.20** Add dep to **tracker-dashboard-web** + `pnpm install`
- [ ] **3B.21** Refactor **tracker-dashboard-web** auth context → `createAuthProvider<TrackerUser>({ storagePrefix: "tracker", ... })`
- [ ] **3B.22** Verify **8 tracker consumer files** still compile: `login/page.tsx`, `providers.tsx`, `page.tsx`, `dashboard/layout.tsx`, `dashboard/page.tsx`, `dashboard/items/page.tsx`, `dashboard/items/[id]/page.tsx`, `dashboard/board/page.tsx`
- [ ] **3B.23** Run tracker-dashboard build — passes
**Clean up old code:**
- [ ] **3B.24** Replace `admin-dashboard-web/src/lib/auth-context.tsx` with thin re-export from `@bytelyst/react-auth` (keeps `@/lib/auth-context` import path stable for all 4 consumers)
- [ ] **3B.25** Replace `user-dashboard-web/src/lib/auth-context.tsx` with thin re-export (keeps path stable for 12 consumers)
- [ ] **3B.26** Replace `tracker-dashboard-web/src/lib/auth-context.tsx` with thin re-export (keeps path stable for 8 consumers)
- [ ] **3B.27** Run all 3 dashboard builds — no regressions
- [ ] **3B.28** **CRITICAL:** Test all login flows end-to-end across all 3 dashboards
**Commit:** `feat(react-auth): extract @bytelyst/react-auth shared package`
---
## Phase 4 — P3 Package: Design Tokens
> **Goal:** Create a cross-platform design token pipeline that generates CSS, TypeScript, Kotlin, and Swift from a single JSON source.
**Extract:**
- [ ] **4.1** Create `packages/design-tokens/package.json`
- [ ] **4.2** Migrate `mindlyst.tokens.json``packages/design-tokens/tokens/bytelyst.tokens.json` as canonical source
- [ ] **4.3** Write `packages/design-tokens/scripts/generate.ts` — reads JSON, outputs 4 formats
- [ ] **4.4** Generate `packages/design-tokens/generated/tokens.css` (CSS custom properties `--ml-*`)
- [ ] **4.5** Generate `packages/design-tokens/generated/tokens.ts` (TypeScript constants)
- [ ] **4.6** Generate `packages/design-tokens/generated/MindLystTokens.kt` (Kotlin object)
- [ ] **4.7** Generate `packages/design-tokens/generated/MindLystTheme.swift` (Swift structs)
- [ ] **4.8** Add `generate` script to package.json: `tsx scripts/generate.ts`
**Test:**
- [ ] **4.9** Write tests: generated CSS contains all expected `--ml-*` properties
- [ ] **4.10** Write tests: generated TS exports match JSON keys
- [ ] **4.11** Write tests: generated Kotlin compiles (syntax check)
- [ ] **4.12** Write tests: generated Swift compiles (syntax check)
- [ ] **4.13** Run `pnpm --filter @bytelyst/design-tokens test` — all pass
**Integrate into MindLyst:**
- [ ] **4.14** Replace `mindlyst-native/shared/src/commonMain/.../theme/MindLystTokens.kt` with generated version
- [ ] **4.15** Verify KMP build: `./gradlew :shared:compileKotlinIosSimulatorArm64`
- [ ] **4.16** ⚠️ G13: Update `androidApp/src/main/java/.../ui/theme/MindLystTheme.kt` (Compose theme) to consume generated tokens — this file was missing from original plan
- [ ] **4.17** Verify Android Compose theme still references correct token values (color names may change)
- [ ] **4.18** Replace `iosApp/MindLystTheme.swift` with generated version
- [ ] **4.19** Replace `web/src/styles/globals.css` token section with import of generated CSS
- [ ] **4.20** Replace `design-system/web/mindlyst.css` with generated CSS
- [ ] **4.21** Run `cd web && npx next build` — passes
**Clean up old code:**
- [ ] **4.22** Remove manually-maintained token values from MindLyst (now auto-generated)
- [ ] **4.23** Update MindLyst `CONTRIBUTING.md` with token update workflow (edit JSON → run generate → commit)
- [ ] **4.24** Verify visual consistency: spot-check colors in iOS preview, Android preview, and web dev server
**Commit:** `feat(design-tokens): extract @bytelyst/design-tokens with cross-platform generation`
---
## Phase 5 — CI/CD & Docker
> **Goal:** Ensure the shared packages work correctly in CI, Docker builds, and deployment pipelines.
### CI Setup
- [ ] **5.1** Create `.github/workflows/ci-common-plat.yml` — test all 8 packages on push
- [ ] **5.2** Add matrix strategy: Node 18 + Node 20
- [ ] **5.3** Add type-check step (`pnpm -r exec tsc --noEmit`)
- [ ] **5.4** Add lint step (if eslint/biome is added)
### Docker Build Compatibility (⚠️ G11: `file:` references break Docker builds)
**Problem:** `file:../../../learning_ai_common_plat/...` paths are outside the Docker build context. Docker can't COPY files outside the context root.
**Solution — Pre-copy script approach** (recommended for `file:` references):
- [ ] **5.5** Create `scripts/docker-prep.sh` that copies `@bytelyst/*` package `dist/` + `package.json` into a `.docker-deps/` folder inside each consumer
- [ ] **5.6** Add `.docker-deps/` to `.gitignore` in LysnrAI repo
- [ ] **5.7** Update each Dockerfile to COPY from `.docker-deps/@bytelyst/*` instead of the `file:` path:
```dockerfile
# Before npm install, copy pre-built shared packages
COPY .docker-deps/@bytelyst /tmp/bytelyst-packages
# Rewrite package.json file: references to point to /tmp/bytelyst-packages/*
```
- [ ] **5.8** Update **platform-service** `Dockerfile` with pre-copy pattern
- [ ] **5.9** Update **billing-service** `Dockerfile`
- [ ] **5.10** Update **growth-service** `Dockerfile`
- [ ] **5.11** Update **tracker-service** `Dockerfile`
- [ ] **5.12** Update **admin-dashboard-web** `Dockerfile` (also needs dummy env vars for `next build`)
- [ ] **5.13** Update **user-dashboard-web** `Dockerfile`
- [ ] **5.14** Update **tracker-dashboard-web** `Dockerfile` (if exists)
- [ ] **5.15** Update `docker-compose.yml` — add `scripts/docker-prep.sh` as a pre-build step or use a Makefile target
- [ ] **5.16** Run `docker compose build` — all images build successfully
- [ ] **5.17** Run `docker compose up -d` — all services start and pass health checks
**Alternative (if team grows):** Publish to GitHub Packages first (Phase 7.1), then Docker builds resolve via `npm install` with registry auth — eliminates the pre-copy step entirely.
### Consumer CI Updates
- [ ] **5.18** Update `ci-platform-service.yml` — checkout common-plat repo + install deps before test
- [ ] **5.19** Update `ci-billing-service.yml`
- [ ] **5.20** Update `ci-growth-service.yml`
- [ ] **5.21** Update `ci-tracker-service.yml`
- [ ] **5.22** Update dashboard CI workflows (if they exist)
- [ ] **5.23** Add cross-repo CI trigger: changes to `learning_ai_common_plat` trigger consumer test suites
**Commit:** `chore(ci): add common-plat CI and update consumer Docker builds`
---
## Phase 6 — Final Verification & Documentation
> **Goal:** Comprehensive end-to-end validation, documentation update, and cleanup.
### Full Regression Test
- [ ] **6.1** Run all Python tests: `python -m pytest tests/ backend/tests/ -v --tb=short`
- [ ] **6.2** Run all platform-service tests: `cd services/platform-service && npm test`
- [ ] **6.3** Run all billing-service tests: `cd services/billing-service && npm test`
- [ ] **6.4** Run all growth-service tests: `cd services/growth-service && npm test`
- [ ] **6.5** Run all tracker-service tests: `cd services/tracker-service && npm test`
- [ ] **6.6** Build admin-dashboard: `cd admin-dashboard-web && npx next build`
- [ ] **6.7** Build user-dashboard: `cd user-dashboard-web && npx next build`
- [ ] **6.8** Build tracker-dashboard: `cd tracker-dashboard-web && npx next build`
- [ ] **6.9** Build MindLyst KMP: `./gradlew :shared:compileKotlinIosSimulatorArm64`
- [ ] **6.10** Build MindLyst web: `cd web && npx next build`
- [ ] **6.11** Run common-plat tests: `pnpm -r test`
- [ ] **6.12** Docker compose full stack: `docker compose up -d` → all healthy
### End-to-End Flow Tests
- [ ] **6.13** Test: Admin login → create user → view user list
- [ ] **6.14** Test: User login → view profile → update settings
- [ ] **6.15** Test: Tracker login → create item → add comment → vote
- [ ] **6.16** Test: Public roadmap page → vote → submit idea
- [ ] **6.17** Test: Service health checks via monitoring script
### Documentation Updates
- [ ] **6.18** Update LysnrAI `AGENTS.md` — add `@bytelyst/*` packages to file ownership map
- [ ] **6.19** Update LysnrAI `README_MONO_REPO.md` — document common-plat dependency
- [ ] **6.20** Update LysnrAI `docs/API_REFERENCE.md` — note shared auth/errors
- [ ] **6.21** Update MindLyst `AGENTS.md` — reference design-tokens package
- [ ] **6.22** Update common-plat `README.md` — package API reference, usage examples
- [ ] **6.23** Write `docs/MIGRATION_GUIDE.md` — step-by-step for adopting `@bytelyst/*` in a new project
- [ ] **6.24** Update this `ROADMAP.md` — mark all tasks as complete
### Code Cleanup
- [ ] **6.25** Search LysnrAI for any remaining duplicated `cosmos.ts` / `errors.ts` / `auth.ts` files
- [ ] **6.26** Remove any dead imports or unused dependencies from service `package.json` files
- [ ] **6.27** Run `pnpm -r exec depcheck` to find unused deps (if depcheck installed)
- [ ] **6.28** Final git status check: all repos clean, no untracked artifacts
**Commit:** `docs: update all documentation for common platform integration`
---
## Phase 7 — Future Enhancements (Post-MVP)
> **Goal:** Deferred improvements that add value but aren't required for initial extraction.
- [ ] **7.1** Publish `@bytelyst/*` packages to GitHub Packages (private npm registry)
- [ ] **7.2** Add Changesets for automated version management and changelogs
- [ ] **7.3** Create reusable GitHub Actions workflow templates for service CI
- [ ] **7.4** Add `@bytelyst/blob` package (extract blob storage client + SAS generation)
- [ ] **7.5** Add `@bytelyst/monitoring` package (health check aggregator)
- [ ] **7.6** Add `@bytelyst/testing` package (shared test utilities, mock factories)
- [ ] **7.7** Evaluate Python shared package for `cosmos_client.py` + `blob_client.py` if MindLyst adds Python backend
- [ ] **7.8** Integrate `@bytelyst/design-tokens` into LysnrAI dashboards (unified design language)
- [ ] **7.9** Add pre-commit hooks to auto-run token generation when JSON changes
- [ ] **7.10** Set up Renovate/Dependabot for common-plat dependency updates
---
## Summary
| Phase | Packages | Tasks | Est. Effort | Risk Level |
|-------|----------|-------|-------------|------------|
| **0** | Repo scaffolding + branching + rollback strategy | 14 | 23 hours | None |
| **1A** | `@bytelyst/errors` | 23 | 34 hours | Low |
| **1B** | `@bytelyst/cosmos` | 33 | 45 hours | Low |
| **2A** | `@bytelyst/config` (34 files to rewire) | 25 | 45 hours | Medium |
| **2B** | `@bytelyst/auth` (20+ admin routes affected) | 29 | 46 hours | Medium-High |
| **2C** | `@bytelyst/fastify-core` | 24 | 34 hours | Medium |
| **3A** | `@bytelyst/api-client` | 17 | 23 hours | Low |
| **3B** | `@bytelyst/react-auth` (24 consumer files) | 28 | 45 hours | Medium |
| **4** | `@bytelyst/design-tokens` (4 platforms) | 24 | 46 hours | Low |
| **5** | CI/CD + Docker (pre-copy strategy) | 23 | 46 hours | Medium-High |
| **6** | Verification + docs + cleanup | 28 | 34 hours | Low |
| **7** | Future enhancements | 10 | Ongoing | — |
| **Total** | **8 packages** | **~278** | **~3751 hours** | |
### Execution Order
```
Phase 0 → Phase 1A → Phase 1B → Phase 2A → Phase 2B → Phase 2C → Phase 3A → Phase 3B → Phase 4 → Phase 5 → Phase 6
↑ ↑
depends on 1A/1B depends on 2A
(G14: auth does NOT depend on config)
```
**Rule:** Never start a phase until the previous phase's tests and Docker builds pass. Each phase ends with a commit and all-green test suite.
**Key risk areas (from Gap Analysis):**
- **Phase 1 (22+ route files):** More files to rewire than initially scoped; use IDE find-and-replace
- **Phase 2A (34 product-config imports):** Highest file count — rewire carefully, test after each service
- **Phase 2B (auth):** Security-critical — mandatory E2E login test before merging
- **Phase 3B (24 auth-context consumers):** Use thin re-export pattern to keep import paths stable
- **Phase 5 (Docker):** `file:` references break Docker builds — pre-copy script is mandatory until registry publish