# ByteLyst Ecosystem — Post-Refactor Architecture

> **Companion diagram:** `ecosystem-after-refactor.drawio` (open in draw.io or VS Code draw.io extension)
>
> **Date:** 2026-03-05 · **Author:** Cascade

---

## Table of Contents

1. [Ecosystem Overview](#1-ecosystem-overview)
2. [Workspace Structure](#2-workspace-structure)
3. [Common Platform Packages — Detailed](#3-common-platform-packages--detailed)
4. [Component & Service Inventory](#4-component--service-inventory)
5. [Dependency Graph](#5-dependency-graph)
6. [Migration Plan](#6-migration-plan)
7. [Advantages](#7-advantages)
8. [Cautions & Risks](#8-cautions--risks)
9. [Versioning Strategy](#9-versioning-strategy)
10. [Testing Strategy](#10-testing-strategy)
11. [CI/CD Impact](#11-cicd-impact)
12. [Decision Log](#12-decision-log)

---

## 1. Ecosystem Overview

The active ByteLyst workspace consists of **seven product/shared repositories** coordinated side-by-side under `~/code/mygh/`, with `learning_ai_common_plat` serving as the shared infrastructure and platform capability layer:

```
┌──────────────────────────────────────────────────────────────────────────────┐
│                           ACTIVE WORKSPACE REPOS                             │
│  learning_ai_common_plat  → shared packages, services, dashboards, MCP      │
│  learning_voice_ai_agent  → LysnrAI                                          │
│  learning_multimodal_memory_agents → MindLyst                                │
│  learning_ai_clock        → ChronoMind                                       │
│  learning_ai_fastgap      → NomGap                                           │
│  learning_ai_jarvis_jr    → JarvisJr                                         │
│  learning_ai_peakpulse    → PeakPulse                                        │
└──────────────────────────────────────┬───────────────────────────────────────┘
                                      │
┌──────────────────────────────────────┴───────────────────────────────────────┐
│                         learning_ai_common_plat                              │
│  36 @bytelyst/* packages · 4 services · 3 dashboards · MCP/A2A orchestration │
│  platform-service · extraction-service · mcp-server · monitoring             │
│  admin-web · tracker-web · ux-lab                                            │
└──────────────────────────────────────┬───────────────────────────────────────┘
                                      │
┌──────────────────────────────────────┴───────────────────────────────────────┐
│                        PRODUCT APPLICATION REPOSITORIES                      │
│  LysnrAI · MindLyst · ChronoMind · NomGap · JarvisJr · PeakPulse            │
│  Each consumes shared packages/SDKs and owns product-specific apps/backends  │
└──────────────────────────────────────┬───────────────────────────────────────┘
                                      │
┌──────────────────────────────────────┴───────────────────────────────────────┐
│                      SHARED CLOUD / LOCAL PLATFORM INFRA                     │
│  Cosmos DB · Blob Storage · Key Vault · OpenAI · Speech · Stripe            │
│  Docker Compose · Traefik · Loki · Grafana · local repo workflows           │
└──────────────────────────────────────────────────────────────────────────────┘
```

---

## 2. Workspace Structure

The canonical repo list is maintained in `.windsurf/workflows/repos.txt` and currently includes seven active repositories.

| Repository                          | Product / Role       | Primary Stack                                | Key Capabilities                                                                                                 |
| ----------------------------------- | -------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `learning_ai_common_plat`           | Shared platform repo | TypeScript, Fastify, Next.js, Swift, Kotlin  | 36 shared packages, platform-service, extraction-service, mcp-server, monitoring, admin-web, tracker-web, ux-lab |
| `learning_voice_ai_agent`           | LysnrAI              | Python 3.12, Fastify, Next.js, Swift, Kotlin | Desktop dictation, product backend, user dashboard, mobile apps                                                  |
| `learning_multimodal_memory_agents` | MindLyst             | KMP, SwiftUI, Compose, Next.js               | Shared business logic, native apps, web dashboard                                                                |
| `learning_ai_clock`                 | ChronoMind           | Next.js, SwiftUI, Kotlin, Fastify            | Timer/focus product, web + native + backend                                                                      |
| `learning_ai_fastgap`               | NomGap               | React Native, Fastify                        | Fasting app, engine modules, Expo/mobile backend                                                                 |
| `learning_ai_jarvis_jr`             | JarvisJr             | SwiftUI, Next.js, Kotlin, Fastify            | Voice-first coaching apps and backend                                                                            |
| `learning_ai_peakpulse`             | PeakPulse            | SwiftUI, Fastify                             | Sensor-driven adventure tracking app and backend                                                                 |

### 2.1 Role of `learning_ai_common_plat`

**Purpose:** Shared platform foundation for all six product repositories.

| Surface    | Current Scope                                                                                                                             |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| Packages   | 36 `@bytelyst/*` packages spanning auth, config, API clients, diagnostics, sync, storage, SDKs, design tokens, AI/extraction, and testing |
| Services   | `platform-service` (4003), `extraction-service` (4005), `mcp-server`, `monitoring`                                                        |
| Dashboards | `admin-web` (3001), `tracker-web` (3003), `ux-lab` (internal)                                                                             |
| Tooling    | MCP tool registry, A2A pipelines, repo workflows, secret scanning, backup/sync automation                                                 |

### 2.2 Product Repositories

Each product repo consumes shared packages and/or SDKs from `learning_ai_common_plat` while owning product-specific UI, engine logic, and backend APIs.

| Product    | Repo                                | Shared Platform Consumption                                                                 |
| ---------- | ----------------------------------- | ------------------------------------------------------------------------------------------- |
| LysnrAI    | `learning_voice_ai_agent`           | `@bytelyst/*` packages, shared platform-service, extraction-service, dashboards integration |
| MindLyst   | `learning_multimodal_memory_agents` | design tokens, auth/config/cosmos patterns, extraction integration, platform-service        |
| ChronoMind | `learning_ai_clock`                 | design tokens flow, platform-service, shared package patterns                               |
| NomGap     | `learning_ai_fastgap`               | React Native platform SDK and shared package integration                                    |
| JarvisJr   | `learning_ai_jarvis_jr`             | shared SDKs/packages, platform-service, marketplace patterns                                |
| PeakPulse  | `learning_ai_peakpulse`             | Swift platform SDK, platform-service wrappers, shared design/system patterns                |

### 2.3 Workspace Operating Model

The workspace is managed as a coordinated multi-repo environment:

- Common platform changes land first when shared packages or services change.
- Product repos consume `workspace:*` or `file:` references during local development.
- Cross-repo workflows (`repo_sync-repos`, `repo_backup-and-push`, `repo_commit-workspace`) use `.windsurf/workflows/repos.txt` as the canonical repo list.
- MCP/A2A capabilities in `services/mcp-server` provide orchestration and operator tooling across the workspace.

### 2.4 Historical Note

Older sections of this document may describe the earlier three-repo architecture used during the initial refactor phase. The current source of truth for active workspace topology is the seven-repo model above.

---

## 3. Common Platform Packages — Detailed

### 3.1 `@bytelyst/errors` (P0)

**What it replaces:** 4 separate `errors.ts` files across services (157 LOC total).

```typescript
// Unified error hierarchy
export class ServiceError extends Error {
  constructor(public statusCode: number, message: string) { ... }
}
export class NotFoundError extends ServiceError { /* 404 */ }
export class BadRequestError extends ServiceError { /* 400 */ }
export class UnauthorizedError extends ServiceError { /* 401 */ }
export class ForbiddenError extends ServiceError { /* 403 */ }
export class ConflictError extends ServiceError { /* 409 */ }
export class TooManyRequestsError extends ServiceError { /* 429 */ }
```

**Design decision:** Superset of all error types currently used. Services import only what they need. The `details` property (used by billing-service's TooManyRequests) is added to the base class as optional.

**Dependencies:** None (leaf package).

---

### 3.2 `@bytelyst/cosmos` (P0)

**What it replaces:** 6 separate `cosmos.ts` files (306 LOC total).

```typescript
// Core exports
export function getCosmosClient(): CosmosClient;
export function getDatabase(dbName?: string): Database;
export function getContainer(name: string): Container;

// Container registry (dashboards use this)
export function registerContainers(config: Record<string, ContainerConfig>): void;
export function initializeAllContainers(): Promise<void>;

// Types
export interface ContainerConfig {
  partitionKeyPath: string;
  defaultTtl?: number | null;
}
```

**Design decision:** The simple `getContainer(name)` used by microservices works alongside the full registry used by dashboards. Services call `getContainer()` directly; dashboards call `registerContainers()` first to set up the partition key map.

**Dependencies:** `@azure/cosmos` (peer dependency).

---

### 3.3 `@bytelyst/config` (P1)

**What it replaces:** 4 separate `config.ts` + 4 separate `product-config.ts` (142 LOC total).

```typescript
// Base env schema — every Fastify service needs these
export const baseEnvSchema = z.object({
  PORT: z.coerce.number().default(3000),
  HOST: z.string().default('0.0.0.0'),
  NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
  CORS_ORIGIN: z.string().optional(),
  SERVICE_NAME: z.string(),
  COSMOS_ENDPOINT: z.string().min(1),
  COSMOS_KEY: z.string().min(1),
  COSMOS_DATABASE: z.string().default('lysnrai'),
});

// Extend per-service
export function loadConfig<T extends z.ZodRawShape>(extension: T) {
  return baseEnvSchema.extend(extension).parse(process.env);
}

// Product identity
export function loadProductIdentity(path?: string): ProductIdentity;
export interface ProductIdentity {
  productId: string;
  displayName: string;
  licensePrefix: string;
  configDirName: string;
  envVarPrefix: string;
}
```

**Design decision:** Each service calls `loadConfig({ STRIPE_SECRET_KEY: z.string(), ... })` to extend the base. The product identity reads from `shared/product.json` or falls back to env vars, eliminating the hardcoded `product-config.ts` copies.

**Dependencies:** `zod` (peer dependency).

---

### 3.4 `@bytelyst/auth` (P1)

**What it replaces:** 5 separate JWT/auth files (250 LOC total).

```typescript
// JWT operations (configurable issuer + expiry)
export function createJwtUtils(options: {
  issuer: string;
  accessTokenExpiry?: string; // default "1h"
  refreshTokenExpiry?: string; // default "30d"
}): {
  createAccessToken(payload: TokenPayload): Promise<string>;
  createRefreshToken(payload: { sub: string }): Promise<string>;
  verifyToken(token: string): Promise<TokenPayload | null>;
};

// Fastify middleware
export function extractAuth(req: FastifyRequest): Promise<AuthPayload>;
export function requireRole(...roles: string[]): FastifyHook;

// Next.js server-side
export function getCurrentUser(
  authHeader: string | null,
  getUserById: Function
): Promise<UserDoc | null>;

// Password hashing
export function hashPassword(plain: string): Promise<string>;
export function verifyPassword(plain: string, hash: string): Promise<boolean>;

// Types
export interface AuthPayload {
  sub: string;
  email?: string;
  role?: string;
  productId?: string;
  type?: string;
}
export interface TokenPayload {
  sub: string;
  email: string;
  role: string;
  type: 'access' | 'refresh';
}
```

**Design decision:** The `createJwtUtils()` factory pattern allows each service to configure its own issuer (`lysnrai-admin`, `lysnrai-user`, `lysnrai`) while sharing all the logic. Platform-service creates tokens; other services only verify. The `requireRole()` hook is a new addition that multiple services currently implement inline.

**Dependencies:** `jose`, `bcryptjs` (peer dependencies).

---

### 3.5 `@bytelyst/fastify-core` (P1)

**What it replaces:** 4 separate `server.ts` files (351 LOC total).

```typescript
export async function createServiceApp(options: {
  name: string;
  version: string;
  description: string;
  port?: number;
  corsOrigin?: string;
}): Promise<FastifyInstance> {
  const app = Fastify({ logger: true });

  // CORS
  await app.register(cors, { origin: ... });

  // OpenAPI / Swagger
  await app.register(swagger, { openapi: { info: { title, version, description } } });

  // Prometheus metrics
  await app.register(metricsPlugin, { endpoint: "/metrics" });

  // x-request-id propagation
  app.addHook("onRequest", requestIdHook);

  // Health endpoint
  app.get("/health", healthHandler(options.name, options.version));

  // ServiceError-aware error handler
  app.setErrorHandler(serviceErrorHandler);

  return app;
}

export async function startService(app: FastifyInstance, port: number, host?: string): Promise<void>;
```

**Design decision:** After calling `createServiceApp()`, each service just registers its route modules and calls `startService()`. The server.ts in each service shrinks from ~85 lines to ~15 lines. The `healthHandler` returns the standard `{ status, service, version, timestamp, requestId }` shape that the monitoring health-check script expects.

**Dependencies:** `fastify`, `@fastify/cors`, `@fastify/swagger`, `fastify-metrics`, `@bytelyst/errors`, `@bytelyst/config` (peer dependencies).

---

### 3.6 `@bytelyst/api-client` (P2)

**What it replaces:** 5+ separate fetch wrapper implementations (200 LOC total).

```typescript
export function createApiClient(options: {
  baseUrl: string;
  getToken?: () => string | null;
  defaultHeaders?: Record<string, string>;
}): {
  // Throws on error (for service-to-service)
  fetch<T>(path: string, options?: RequestInit): Promise<T>;
  // Returns { data, error } tuple (for UI components)
  safeFetch<T>(
    path: string,
    options?: RequestInit
  ): Promise<{ data: T | null; error: string | null }>;
};
```

**Design decision:** Two fetch modes: throwing (used by server-side service clients like `billing-client.ts`, `growth-client.ts`) and safe (used by React components via `api.ts`). The `getToken()` callback handles auth header injection without coupling to any specific storage mechanism.

**Dependencies:** None (uses native `fetch`).

---

### 3.7 `@bytelyst/react-auth` (P2)

**What it replaces:** 3 separate `auth-context.tsx` files (450 LOC total).

```typescript
export function createAuthProvider<TUser extends BaseUser>(config: {
  storagePrefix: string; // "admin" | "portal" | "tracker"
  loginEndpoint: string; // "/api/auth/login"
  mapResponseToUser: (data: any) => TUser;
  enableSSO?: boolean;
}): {
  AuthProvider: React.FC<{ children: ReactNode }>;
  useAuth: () => AuthContextValue<TUser>;
};

export interface BaseUser {
  id?: string;
  email: string;
  name: string;
  role: string;
}

export interface AuthContextValue<TUser> {
  user: TUser | null;
  isAuthenticated: boolean;
  isLoading: boolean;
  login: (email: string, password: string) => Promise<boolean>;
  logout: () => void;
  getAccessToken: () => string | null;
}
```

**Design decision:** Factory pattern produces a fully-typed `AuthProvider` + `useAuth()` pair. Each dashboard provides its own `TUser` type and storage prefix. SSO cookie support (used by user-dashboard) is opt-in via `enableSSO`. Registration support (also user-dashboard only) can be added as an optional config callback.

**Dependencies:** `react` (peer dependency), `@bytelyst/api-client`.

---

### 3.8 `@bytelyst/design-tokens` (P3)

**What it replaces:** 5 manually-synced token files across MindLyst.

```
packages/design-tokens/
├── tokens/
│   └── bytelyst.tokens.json    ← SINGLE SOURCE OF TRUTH
├── generated/                   ← Auto-generated (committed or gitignored)
│   ├── tokens.css               ← CSS custom properties (--ml-*)
│   ├── tokens.ts                ← TypeScript constants
│   ├── tokens.kt                ← Kotlin object (MindLystTokens)
│   └── tokens.swift             ← Swift structs (MindLystColors/Spacing/Radius)
├── scripts/
│   └── generate.ts              ← Reads JSON, emits all formats
└── package.json
```

**Design decision:** The canonical `bytelyst.tokens.json` (migrated from MindLyst's existing `mindlyst.tokens.json`) is the single source. A generation script produces platform-specific files. Consumers either:

- **Import the generated file** directly (CSS, TS)
- **Copy the generated file** into their project as a build step (Kotlin, Swift)

This eliminates the manual sync problem where token changes require updating 5 files.

**Dependencies:** None at runtime; `typescript` for the generation script.

---

## 4. Component & Service Inventory

### 4.1 All Services (Post-Refactor)

| Service           | Repo     | Port | Shared Packages Used                       |
| ----------------- | -------- | ---- | ------------------------------------------ |
| platform-service  | LysnrAI  | 4003 | errors, cosmos, config, auth, fastify-core |
| billing-service   | LysnrAI  | 4002 | errors, cosmos, config, fastify-core       |
| growth-service    | LysnrAI  | 4001 | errors, cosmos, config, fastify-core       |
| tracker-service   | LysnrAI  | 4004 | errors, cosmos, config, auth, fastify-core |
| FastAPI Backend   | LysnrAI  | 8000 | (Python — separate concern)                |
| admin-dashboard   | LysnrAI  | 3001 | cosmos, auth, api-client, react-auth       |
| user-dashboard    | LysnrAI  | 3002 | cosmos, auth, api-client, react-auth       |
| tracker-dashboard | LysnrAI  | 3003 | api-client, react-auth                     |
| MindLyst Web      | MindLyst | 3050 | design-tokens                              |
| MindLyst iOS      | MindLyst | —    | design-tokens (generated Swift)            |
| MindLyst Android  | MindLyst | —    | design-tokens (generated Kotlin)           |

### 4.2 Azure Infrastructure

| Service      | Resource                      | Used By                            |
| ------------ | ----------------------------- | ---------------------------------- |
| Cosmos DB    | cosmos-mywisprai (Serverless) | All TS services + dashboards       |
| Blob Storage | bytelystblobs (6 containers)  | platform-service, desktop, backend |
| Key Vault    | kv-mywisprai                  | Desktop, mobile, backend           |
| Speech       | mywisprai-speech (F0)         | Desktop, LysnrAI mobile            |
| Azure OpenAI | mywisprai-openai-sweden (S0)  | Desktop, backend                   |
| OpenAI API   | api.openai.com                | MindLyst KMP (triage, Whisper)     |
| Stripe       | Payments API                  | billing-service, growth-service    |

### 4.3 DevOps Components

| Component                 | Location                     | Scope                                   |
| ------------------------- | ---------------------------- | --------------------------------------- |
| Docker Compose            | LysnrAI root                 | All services + Loki + Grafana + Traefik |
| Health Check              | services/monitoring/         | Aggregates all /health endpoints        |
| GitHub Actions            | .github/workflows/ (9 files) | Per-service CI                          |
| run-local-all-services.sh | LysnrAI root                 | Dev startup script                      |

---

## 5. Dependency Graph

```
@bytelyst/design-tokens  (standalone — no deps)
        │
        └─→ MindLyst iOS/Android/Web

@bytelyst/errors  (standalone — no deps)
        │
        ├─→ @bytelyst/fastify-core
        ├─→ All 4 Fastify services
        └─→ All 3 Next.js dashboards (via API routes)

@bytelyst/cosmos  (depends on: @azure/cosmos)
        │
        ├─→ All 4 Fastify services
        └─→ admin-dashboard, user-dashboard

@bytelyst/config  (depends on: zod)
        │
        ├─→ @bytelyst/fastify-core
        ├─→ @bytelyst/auth
        └─→ All 4 Fastify services

@bytelyst/auth  (depends on: jose, bcryptjs, @bytelyst/config)
        │
        ├─→ @bytelyst/api-client
        ├─→ platform-service (creates tokens)
        ├─→ tracker-service (verifies tokens)
        └─→ admin/user dashboards (server-side auth)

@bytelyst/fastify-core  (depends on: fastify, @bytelyst/errors, @bytelyst/config)
        │
        └─→ All 4 Fastify services

@bytelyst/api-client  (no runtime deps)
        │
        ├─→ @bytelyst/react-auth
        └─→ All 3 dashboards

@bytelyst/react-auth  (depends on: react, @bytelyst/api-client)
        │
        └─→ All 3 Next.js dashboards
```

**Key insight:** The graph is a clean DAG (directed acyclic graph) with no circular dependencies. Leaf packages (`errors`, `cosmos`, `design-tokens`) can be extracted first with zero risk.

---

## 6. Migration Plan

### Phase 1: Foundation (Week 1)

1. **Initialize `learning_ai_common_plat`** as pnpm workspace monorepo
   - `pnpm init`, `pnpm-workspace.yaml`, `tsconfig.base.json`
   - Shared `vitest` config, `ruff.toml` (for future Python packages)

2. **Extract `@bytelyst/errors`** (P0, 1 hour)
   - Copy `platform-service/src/lib/errors.ts` as starting point
   - Add `ConflictError` (from tracker) and `TooManyRequestsError` (from billing)
   - Add optional `details` field to base `ServiceError`
   - Write tests (port from service tests)
   - Update all 4 services: `import { ServiceError, ... } from "@bytelyst/errors"`

3. **Extract `@bytelyst/cosmos`** (P0, 2 hours)
   - Merge service version (simple) + dashboard version (registry + TTL)
   - Parameterize default database name
   - Write tests (mock Cosmos client)
   - Update all 6 consumers

### Phase 2: Service Infrastructure (Week 2)

4. **Extract `@bytelyst/config`** (P1, 2 hours)
   - Create `baseEnvSchema` from common fields
   - Add `loadConfig()` extension function
   - Add `loadProductIdentity()` from `shared/product.json`
   - Update all 4 services + remove 4 `product-config.ts` files

5. **Extract `@bytelyst/auth`** (P1, 3 hours)
   - Create `createJwtUtils()` factory
   - Port `extractAuth()` Fastify hook
   - Port `getCurrentUser()` for Next.js
   - Port `hashPassword()` / `verifyPassword()`
   - Critical: test all auth flows end-to-end after migration

6. **Extract `@bytelyst/fastify-core`** (P1, 3 hours)
   - Create `createServiceApp()` factory
   - Port request-id hook, health handler, error handler
   - Refactor all 4 `server.ts` files to use factory
   - Verify Docker builds still pass

### Phase 3: Dashboard Libraries (Week 3)

7. **Extract `@bytelyst/api-client`** (P2, 2 hours)
   - Create `createApiClient()` with both fetch modes
   - Update dashboard client files to use shared client
   - Service-specific methods stay in their respective client files

8. **Extract `@bytelyst/react-auth`** (P2, 3 hours)
   - Create `createAuthProvider()` factory
   - Port SSO cookie logic as opt-in
   - Update all 3 dashboard auth contexts
   - Test login/logout flows in each dashboard

### Phase 4: Design System (Week 4+)

9. **Extract `@bytelyst/design-tokens`** (P3, 4 hours)
   - Migrate `mindlyst.tokens.json` as canonical source
   - Write generation script for CSS, TS, Kotlin, Swift
   - Add to MindLyst build pipeline
   - Consider adopting for LysnrAI dashboards (future)

---

## 7. Advantages

### 7.1 Immediate Benefits

| Benefit                           | Impact                                                | Measurement                       |
| --------------------------------- | ----------------------------------------------------- | --------------------------------- |
| **~1,580 LOC eliminated**         | Less code to maintain                                 | 8 fewer files per service feature |
| **Single-point security fixes**   | JWT/auth vulnerability fixed once, applied everywhere | 1 PR instead of 5                 |
| **Consistent error handling**     | All services return identical error shapes            | 0 divergence                      |
| **Faster new service creation**   | `createServiceApp()` → 15 lines to launch             | Minutes vs hours                  |
| **Cosmos DB config in one place** | Container registry + TTL managed centrally            | 1 file vs 6                       |

### 7.2 Medium-Term Benefits

| Benefit                        | Impact                                                                           |
| ------------------------------ | -------------------------------------------------------------------------------- |
| **MindLyst backend bootstrap** | When MindLyst adds backend services, it gets Fastify infra for free              |
| **Consistent design language** | Token generation ensures iOS/Android/Web never drift                             |
| **Cross-product features**     | Tracker service already product-agnostic; shared auth enables MindLyst to use it |
| **Onboarding speed**           | New developer learns one pattern, applies to all services                        |
| **Testability**                | Shared packages have isolated tests; consumer tests focus on business logic      |

### 7.3 Architectural Benefits

| Benefit                    | Description                                                            |
| -------------------------- | ---------------------------------------------------------------------- |
| **Separation of concerns** | Infrastructure (how) separated from business logic (what)              |
| **Dependency inversion**   | Services depend on abstractions (`@bytelyst/auth`) not implementations |
| **DRY principle**          | No more copy-paste-modify cycle for new services                       |
| **Contract stability**     | Shared types ensure API contracts don't drift between services         |
| **Upgrade path**           | Update `jose` or `@azure/cosmos` in one place                          |

---

## 8. Cautions & Risks

### 8.1 HIGH RISK — Tightly Coupled Releases

| Risk                        | Description                                                              | Mitigation                                                                                               |
| --------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------- |
| **Breaking change cascade** | A breaking change in `@bytelyst/auth` breaks all services simultaneously | Semantic versioning + `file:` references pin to exact commits. Run all consumer tests before publishing. |
| **Diamond dependency**      | Two packages depend on different versions of a shared dep                | Use peer dependencies + strict version ranges. `pnpm` handles this well.                                 |
| **Deployment ordering**     | Must deploy common-plat before consuming repos can use new features      | Use git tags/releases. Consumers reference a specific version or commit.                                 |

### 8.2 MEDIUM RISK — Development Friction

| Risk                 | Description                                             | Mitigation                                                                      |
| -------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------- |
| **Cross-repo PRs**   | A feature spanning common-plat + LysnrAI requires 2 PRs | Use `file:../learning_ai_common_plat/packages/X` in dev, pin to version in CI.  |
| **Local dev setup**  | Developers need all 3 repos cloned side-by-side         | Document in README. Add a setup script. Consider git submodules as alternative. |
| **IDE navigation**   | "Go to definition" may not work across repos            | TypeScript project references or workspace-level `tsconfig.json` can help.      |
| **Over-abstraction** | Temptation to extract things that aren't truly shared   | Rule: **only extract when ≥2 consumers exist AND the code is >90% identical**.  |

### 8.3 LOW RISK — Operational

| Risk                        | Description                                                       | Mitigation                                                                                              |
| --------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| **npm registry dependency** | Publishing to GitHub Packages adds infra complexity               | Start with `file:` references (zero infra). Upgrade to registry only if team grows.                     |
| **Test isolation**          | Shared package tests may not catch consumer-specific issues       | Each consumer repo keeps integration tests. Shared packages only unit-test their own API.               |
| **Python exclusion**        | The desktop app and FastAPI backend can't use TypeScript packages | Python remains independent. If patterns emerge (e.g., Cosmos client), create a Python equivalent later. |
| **KMP exclusion**           | MindLyst's Kotlin code can't use npm packages directly            | Only `design-tokens` applies to KMP (via generated Kotlin). All other packages are TS-only.             |

### 8.4 Things to AVOID

1. **Don't extract too early** — Wait until code is stable and duplicated in ≥2 places
2. **Don't create a "utils" dumping ground** — Every package must have a clear, single responsibility
3. **Don't abstract configuration** — Each service's `config.ts` should remain in the service; only the base schema is shared
4. **Don't share React components** — UI components are product-specific; only infrastructure (auth, fetch) is shared
5. **Don't break existing imports in one big PR** — Migrate one package at a time, keep old imports working temporarily

---

## 9. Versioning Strategy

### Recommended: File References (Phase 1)

```jsonc
// In LysnrAI's services/platform-service/package.json
{
  "dependencies": {
    "@bytelyst/errors": "file:../../../learning_ai_common_plat/packages/errors",
    "@bytelyst/cosmos": "file:../../../learning_ai_common_plat/packages/cosmos",
  },
}
```

**Pros:** Zero infrastructure, works locally, `pnpm install` resolves it.
**Cons:** All repos must be cloned side-by-side. Docker builds need a multi-stage approach or volume mount.

### Future: GitHub Packages (Phase 2+)

```jsonc
{
  "dependencies": {
    "@bytelyst/errors": "^1.0.0",
    "@bytelyst/cosmos": "^1.0.0",
  },
}
```

**Pros:** True version pinning, CI-friendly, no local path dependency.
**Cons:** Requires GitHub Packages setup, publish workflow, access tokens.

### Versioning Rules

- **MAJOR** (1.0 → 2.0): Breaking change to public API (renamed export, removed function, changed return type)
- **MINOR** (1.0 → 1.1): New export, new optional parameter, new error subclass
- **PATCH** (1.0.0 → 1.0.1): Bug fix, internal refactor, dependency update

---

## 10. Testing Strategy

### Package-Level Tests

Each `@bytelyst/*` package has its own `vitest` test suite:

| Package       | Test Focus                                                              |
| ------------- | ----------------------------------------------------------------------- |
| errors        | Error class hierarchy, statusCode correctness, instanceof checks        |
| cosmos        | Client singleton behavior, container registry, env var reading (mocked) |
| config        | Zod schema validation, defaults, extension merging                      |
| auth          | JWT sign/verify round-trip, expiry, issuer validation, bcrypt hashing   |
| fastify-core  | App factory produces correct hooks/routes, health endpoint shape        |
| api-client    | Fetch wrapper behavior with mock server, error handling, auth injection |
| react-auth    | Provider renders, login/logout flows, localStorage persistence          |
| design-tokens | Generated output matches expected format for each platform              |

### Consumer-Level Tests

Each service/dashboard keeps its existing test suite. After migration:

- Service tests verify that imported shared functions work correctly **in context**
- No need to re-test JWT internals — that's the package's job
- Focus on **integration**: "Does my route handler correctly call `extractAuth()` and get the right payload?"

### CI Matrix

```
common-plat CI:
  → Run all 8 package test suites
  → Run type-check (tsc --noEmit)
  → Run lint (ruff for future Python packages)

LysnrAI CI (per-service):
  → Install common-plat packages (file: or registry)
  → Run service tests
  → Run Next.js build

MindLyst CI:
  → Build KMP shared module
  → Build Next.js web
  → Verify generated tokens match source JSON
```

---

## 11. CI/CD Impact

### Docker Build Changes

Services currently build independently. After extraction:

**Option A: Multi-stage with copy** (recommended for `file:` references)

```dockerfile
# Copy common-plat packages into build context
COPY ../learning_ai_common_plat/packages/errors /common/errors
COPY ../learning_ai_common_plat/packages/cosmos /common/cosmos
# Adjust package.json to point to /common/*
```

**Option B: Pre-publish** (recommended for registry)

```dockerfile
# Common-plat packages are already on npm registry
RUN npm install  # resolves @bytelyst/* from GitHub Packages
```

**Option C: Monorepo build context** (if repos are merged or submoduled)

```dockerfile
# Build context includes all repos
COPY . /workspace
WORKDIR /workspace/learning_voice_ai_agent/services/platform-service
RUN npm install && npm run build
```

### docker-compose.yml Changes

The existing `docker-compose.yml` may need an additional volume mount or build context adjustment:

```yaml
services:
  platform-service:
    build:
      context: . # May need to widen to parent directory
      dockerfile: services/platform-service/Dockerfile
```

### GitHub Actions Changes

- **New workflow:** `ci-common-plat.yml` — tests all shared packages on push to `learning_ai_common_plat`
- **Modified workflows:** Each service CI installs common-plat packages before running tests
- **Potential:** A "consumer test" job in `ci-common-plat.yml` that runs key consumer tests after package changes

---

## 12. Decision Log

| Decision                                               | Rationale                                                                                   | Alternatives Considered                                                                  |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **pnpm workspace monorepo** for common-plat            | Simplest multi-package management, strict dep resolution                                    | npm workspaces (less strict), Turborepo (overkill for 8 packages), Nx (too heavy)        |
| **`file:` references** initially                       | Zero infrastructure, works immediately                                                      | git submodules (complex merge), npm registry (needs setup), copy-paste (defeats purpose) |
| **Factory pattern** for fastify-core, auth, react-auth | Services need slightly different config (port, issuer, user type) but identical boilerplate | Inheritance (fragile), config objects (less type-safe), template codegen (complex)       |
| **Peer dependencies** for heavy libs                   | Prevents version conflicts (e.g., two versions of `@azure/cosmos` in one service)           | Direct deps (risk duplicate bundles), optional deps (too loose)                          |
| **TypeScript-only** packages (no Python)               | Python desktop/backend have less duplication and different patterns                         | Shared Python package (only 2 consumers, not worth the packaging complexity yet)         |
| **Design tokens as JSON → generated code**             | JSON is the universal format; generation ensures consistency                                | Manual sync (error-prone), Figma API (adds dependency), CSS-only (excludes native)       |
| **NOT extracting React UI components**                 | UI is product-specific; only infrastructure is truly shared                                 | Shared component library (premature — products have different UX)                        |
| **NOT merging repos**                                  | Three distinct products with different release cadences and teams                           | Monorepo (coupling), git submodules (merge conflicts)                                    |

---

## Appendix A: File Counts Per Service (Before vs After)

### Before Refactor

```
services/platform-service/src/lib/
  ├── config.ts           (32 lines)
  ├── cosmos.ts           (25 lines)
  ├── errors.ts           (38 lines)
  ├── product-config.ts   (9 lines)
  └── blob.ts             (service-specific, stays)

services/billing-service/src/lib/
  ├── config.ts           (34 lines)  ← DUPLICATE
  ├── cosmos.ts           (25 lines)  ← DUPLICATE
  ├── errors.ts           (41 lines)  ← DUPLICATE
  └── product-config.ts   (9 lines)   ← DUPLICATE

services/growth-service/src/lib/
  ├── config.ts           (25 lines)  ← DUPLICATE
  ├── cosmos.ts           (25 lines)  ← DUPLICATE
  ├── errors.ts           (35 lines)  ← DUPLICATE
  └── product-config.ts   (11 lines)  ← DUPLICATE

services/tracker-service/src/lib/
  ├── auth.ts             (52 lines)  ← DUPLICATE
  ├── config.ts           (24 lines)  ← DUPLICATE
  ├── cosmos.ts           (25 lines)  ← DUPLICATE
  ├── errors.ts           (44 lines)  ← DUPLICATE
  └── product-config.ts   (7 lines)   ← DUPLICATE
```

### After Refactor

```
services/platform-service/src/lib/
  ├── blob.ts             (service-specific, stays)
  └── (all others → @bytelyst/*)

services/billing-service/src/lib/
  └── (empty — all moved to @bytelyst/*)

services/growth-service/src/lib/
  └── (empty — all moved to @bytelyst/*)

services/tracker-service/src/lib/
  └── (empty — all moved to @bytelyst/*)

Each server.ts: ~85 lines → ~15 lines
Each config.ts: ~30 lines → ~5 lines (just the extension schema)
```

---

## Appendix B: Ecosystem Metrics

| Metric                                  | Before           | After              | Delta     |
| --------------------------------------- | ---------------- | ------------------ | --------- |
| Duplicated infrastructure LOC           | ~1,856           | ~275               | **-85%**  |
| Number of `errors.ts` files             | 4                | 1                  | **-75%**  |
| Number of `cosmos.ts` files             | 6                | 1                  | **-83%**  |
| Number of `auth/jwt` files              | 5                | 1                  | **-80%**  |
| Number of `server.ts` boilerplate lines | 351              | ~60                | **-83%**  |
| Time to create new Fastify service      | ~2 hours         | ~20 min            | **-83%**  |
| Time to fix a JWT vulnerability         | 5 PRs            | 1 PR               | **-80%**  |
| Design token sync effort (MindLyst)     | Manual (5 files) | Automated (1 JSON) | **-100%** |
