From a874a4332b7b17bf65d711f63d70906a79c5528b Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Thu, 12 Feb 2026 10:40:28 -0800 Subject: [PATCH] docs: add common platform analysis, ecosystem architecture, and drawio diagram - COMMON_PLATFORM_ANALYSIS.md: identifies 8 shared packages to extract from LysnrAI and MindLyst repos (~1,580 LOC duplication eliminated) - ECOSYSTEM_ARCHITECTURE.md: detailed post-refactor architecture with components, services, migration plan, advantages, cautions, versioning, testing, and CI/CD impact - ecosystem-after-refactor.drawio: 4-layer architecture diagram (clients, repos, common platform, Azure infra) --- docs/COMMON_PLATFORM_ANALYSIS.md | 381 +++++++++++++ docs/ECOSYSTEM_ARCHITECTURE.md | 808 +++++++++++++++++++++++++++ docs/ecosystem-after-refactor.drawio | 478 ++++++++++++++++ 3 files changed, 1667 insertions(+) create mode 100644 docs/COMMON_PLATFORM_ANALYSIS.md create mode 100644 docs/ECOSYSTEM_ARCHITECTURE.md create mode 100644 docs/ecosystem-after-refactor.drawio diff --git a/docs/COMMON_PLATFORM_ANALYSIS.md b/docs/COMMON_PLATFORM_ANALYSIS.md new file mode 100644 index 00000000..37f14f8a --- /dev/null +++ b/docs/COMMON_PLATFORM_ANALYSIS.md @@ -0,0 +1,381 @@ +# Common Platform Analysis + +> **Purpose:** Identify duplicated code across `learning_voice_ai_agent` (LysnrAI) and `learning_multimodal_memory_agents` (MindLyst) that should be extracted into `learning_ai_common_plat` as shared packages. +> +> **Date:** 2026-02-12 + +--- + +## Executive Summary + +After scanning both repos, there are **8 high-value extraction candidates** across 3 tiers (TypeScript services, Next.js dashboards, design system). The heaviest duplication is in the LysnrAI monorepo where 4 Fastify microservices each contain near-identical copies of 5 foundational files. The MindLyst repo shares the same design token values and will benefit from a shared design system package. + +--- + +## 1. Duplicated Components — TypeScript Microservices + +### 1.1 Cosmos DB Client Singleton + +**Duplication:** 4 near-identical copies across LysnrAI services + 2 in dashboards = **6 copies** + +| Location | Lines | +|----------|-------| +| `services/platform-service/src/lib/cosmos.ts` | 25 | +| `services/billing-service/src/lib/cosmos.ts` | 25 | +| `services/growth-service/src/lib/cosmos.ts` | 25 | +| `services/tracker-service/src/lib/cosmos.ts` | 25 | +| `admin-dashboard-web/src/lib/cosmos.ts` | 112 | +| `user-dashboard-web/src/lib/cosmos.ts` | 94 | + +**Pattern:** All do: lazy singleton `CosmosClient`, read `COSMOS_ENDPOINT` + `COSMOS_KEY` + `COSMOS_DATABASE` from env, expose `getContainer(name)`. Dashboard versions add container registry with partition key definitions and TTL config. + +**Proposed shared package:** `@bytelyst/cosmos` +``` +packages/cosmos/ + src/ + client.ts — getCosmosClient(), getDatabase(), getContainer() + containers.ts — container registry (names, partition keys, TTL) + types.ts — ContainerConfig interface + index.ts + package.json +``` + +--- + +### 1.2 Service Error Classes + +**Duplication:** 4 copies across LysnrAI services, each slightly different + +| Location | Error Classes | +|----------|--------------| +| `platform-service/src/lib/errors.ts` | ServiceError, NotFound, BadRequest, Unauthorized, Forbidden | +| `billing-service/src/lib/errors.ts` | ServiceError, NotFound, BadRequest, Forbidden, TooManyRequests | +| `growth-service/src/lib/errors.ts` | ServiceError, NotFound, BadRequest, Forbidden | +| `tracker-service/src/lib/errors.ts` | ServiceError, NotFound, BadRequest, Unauthorized, Forbidden, Conflict | + +**Pattern:** All share the same `ServiceError` base class with `statusCode` + `message`. Subclasses vary per service (some have Unauthorized, some have Conflict, etc.). + +**Proposed shared package:** `@bytelyst/errors` +``` +packages/errors/ + src/ + service-error.ts — base ServiceError class + http-errors.ts — NotFound, BadRequest, Unauthorized, Forbidden, Conflict, TooManyRequests + index.ts + package.json +``` + +--- + +### 1.3 JWT Auth Middleware + +**Duplication:** 3 copies in LysnrAI services + 2 in dashboards = **5 copies** + +| Location | Variant | +|----------|---------| +| `platform-service/src/modules/auth/jwt.ts` | Full: create + verify (issuer service) | +| `tracker-service/src/lib/auth.ts` | Verify-only (consumer service) | +| `billing-service` (via internal key) | Different pattern | +| `admin-dashboard-web/src/lib/auth-server.ts` | create + verify + bcrypt + authenticateUser | +| `user-dashboard-web/src/lib/auth-server.ts` | create + verify + bcrypt + authenticateUser (near-identical) | + +**Pattern:** All use `jose` library, HS256, same `getSecret()` → `TextEncoder.encode(JWT_SECRET)`. Dashboards add bcrypt password hashing and `getCurrentUser()`. + +**Proposed shared package:** `@bytelyst/auth` +``` +packages/auth/ + src/ + jwt.ts — createAccessToken, createRefreshToken, verifyToken (configurable issuer/expiry) + middleware.ts — extractAuth (Fastify), getCurrentUser (Next.js) + password.ts — hashPassword, verifyPassword (bcryptjs wrapper) + types.ts — AuthPayload, TokenPayload interfaces + index.ts + package.json +``` + +--- + +### 1.4 Fastify Server Bootstrap + +**Duplication:** 4 copies in LysnrAI services + +| Location | Lines | +|----------|-------| +| `platform-service/src/server.ts` | 87 | +| `billing-service/src/server.ts` | 101 | +| `growth-service/src/server.ts` | 79 | +| `tracker-service/src/server.ts` | 84 | + +**Pattern:** All follow the same structure: +1. Create Fastify instance with logger +2. Register CORS (parse `CORS_ORIGIN`) +3. Register Swagger (service-specific title/description) +4. Register Prometheus metrics +5. Add `x-request-id` hook (propagate or generate UUID) +6. Add `/health` endpoint (same shape: `{ status, service, version, timestamp, requestId }`) +7. Set error handler (check `instanceof ServiceError`) +8. Register route modules with `/api` prefix +9. Start listener + +**Proposed shared package:** `@bytelyst/fastify-core` +``` +packages/fastify-core/ + src/ + create-app.ts — createServiceApp({ name, version, description }) → configured Fastify instance + request-id.ts — x-request-id hook (reusable plugin) + health.ts — health check route factory + error-handler.ts — ServiceError-aware error handler + index.ts + package.json +``` + +--- + +### 1.5 Zod Config Loader + +**Duplication:** 4 copies in LysnrAI services + +| Location | Shared Fields | +|----------|--------------| +| `platform-service/src/lib/config.ts` | PORT, HOST, NODE_ENV, CORS_ORIGIN, SERVICE_NAME, COSMOS_ENDPOINT, COSMOS_KEY, COSMOS_DATABASE | +| `billing-service/src/lib/config.ts` | Same base + STRIPE_*, BILLING_* | +| `growth-service/src/lib/config.ts` | Same base + STRIPE_*, WEBHOOK_* | +| `tracker-service/src/lib/config.ts` | Same base + JWT_SECRET, DEFAULT_PRODUCT_ID | + +**Pattern:** Every service has 7 identical base fields (PORT, HOST, NODE_ENV, CORS_ORIGIN, SERVICE_NAME, COSMOS_ENDPOINT, COSMOS_KEY, COSMOS_DATABASE) and then service-specific extensions. + +**Proposed shared package:** `@bytelyst/config` +``` +packages/config/ + src/ + base-schema.ts — baseEnvSchema (Zod object with the 8 common fields) + loader.ts — loadConfig(extendedSchema?) merges base + service-specific + index.ts + package.json +``` + +--- + +### 1.6 Product Config / Identity + +**Duplication:** 4 copies in LysnrAI services + 1 JSON canonical source + +| Location | Content | +|----------|---------| +| `shared/product.json` | Canonical: `{ productId, displayName, licensePrefix, ... }` | +| `platform-service/src/lib/product-config.ts` | `PRODUCT_ID = "lysnrai"` (hardcoded) | +| `billing-service/src/lib/product-config.ts` | Same (hardcoded) | +| `growth-service/src/lib/product-config.ts` | Same (hardcoded) | +| `tracker-service/src/lib/product-config.ts` | `DEFAULT_PRODUCT_ID = env || "lysnrai"` | + +**Pattern:** Every service hardcodes or reads the same product identity. Should read from a shared source. + +**Proposed:** Include in `@bytelyst/config` — export `loadProductConfig()` that reads `shared/product.json` or env vars. Each consuming project provides its own `product.json`. + +--- + +## 2. Duplicated Components — Next.js Dashboards + +### 2.1 Auth Context (React) + +**Duplication:** 3 copies across LysnrAI dashboards + +| Location | Variant | +|----------|---------| +| `admin-dashboard-web/src/lib/auth-context.tsx` | AdminUser, localStorage keys: `admin_*` | +| `user-dashboard-web/src/lib/auth-context.tsx` | PortalUser, localStorage keys: `portal_*`, SSO cookie support | +| `tracker-dashboard-web/src/lib/` (auth context) | TrackerUser, localStorage keys: `tracker_*` | + +**Pattern:** All implement: `AuthProvider`, `useAuth()`, localStorage-backed user + token storage, login/logout. Differ only in: user type, storage key prefix, and SSO support. + +**Proposed shared package:** `@bytelyst/react-auth` +``` +packages/react-auth/ + src/ + auth-context.tsx — generic AuthProvider, configurable storage keys + login endpoint + use-auth.ts — typed useAuth() hook + types.ts — BaseUser interface, AuthConfig + index.ts + package.json +``` + +--- + +### 2.2 API Fetch Utility + +**Duplication:** 4+ copies across dashboards and service clients + +| Location | Pattern | +|----------|---------| +| `admin-dashboard-web/src/lib/api.ts` | `apiFetch(path, options)` → `{ data, error }` | +| `user-dashboard-web/src/lib/platform-client.ts` | `request(path, options)` → `T` (throws) | +| `user-dashboard-web/src/lib/billing-client.ts` | Same `request` pattern | +| `user-dashboard-web/src/lib/growth-client.ts` | Same `request` pattern | +| `tracker-dashboard-web/src/lib/tracker-client.ts` | `apiFetch` with Bearer token | + +**Pattern:** All wrap `fetch()` with: base URL, JSON headers, auth header injection, error parsing. Two variants: result-tuple `{ data, error }` vs throw-on-error. + +**Proposed shared package:** `@bytelyst/api-client` +``` +packages/api-client/ + src/ + client.ts — createApiClient({ baseUrl, getToken?, headers? }) → { fetch, safeFetch } + types.ts — ApiResult, ApiError + index.ts + package.json +``` + +--- + +### 2.3 Utility Functions + +**Duplication:** Identical `cn()` function in 2 dashboards + +| Location | +|----------| +| `admin-dashboard-web/src/lib/utils.ts` | +| `user-dashboard-web/src/lib/utils.ts` | + +**Pattern:** `cn(...inputs) → twMerge(clsx(inputs))` — standard shadcn/ui utility. + +**Proposed:** Include in `@bytelyst/ui-utils` or just in `@bytelyst/react-auth` as a peer export. + +--- + +## 3. Duplicated Components — Design System + +### 3.1 Design Tokens + +**Duplication:** Same color/spacing/typography values maintained across **5 formats** in MindLyst + referenced in LysnrAI dashboards + +| Location | Format | +|----------|--------| +| `design-system/tokens/mindlyst.tokens.json` | Canonical JSON | +| `shared/src/.../theme/MindLystTokens.kt` | KMP Kotlin object | +| `iosApp/MindLystTheme.swift` | SwiftUI structs | +| `androidApp/.../MindLystTheme.kt` | Compose theme | +| `web/src/styles/globals.css` | CSS custom properties | +| `design-system/web/mindlyst.css` | CSS custom properties (duplicate of above) | + +**Note:** LysnrAI's admin/user dashboards use TailwindCSS + shadcn/ui with a different color system currently. If both products converge on a shared design language, the token JSON can be the single source. + +**Proposed shared package:** `@bytelyst/design-tokens` +``` +packages/design-tokens/ + tokens/ + colors.json — palette, semantic dark/light, brain gradients + typography.json — font families, sizes, weights, line heights + spacing.json — 8pt grid scale + radius.json — border radius scale + motion.json — duration + easing + layout.json — breakpoints, gutter, max-width + generated/ — auto-generated from tokens JSON + tokens.css — CSS custom properties (--ml-*) + tokens.ts — TypeScript constants + tokens.kt — Kotlin object (for KMP) + tokens.swift — Swift structs (for iOS) + scripts/ + generate.ts — reads JSON, outputs all formats + package.json +``` + +--- + +## 4. Potential Future Shared Components + +These are not exact duplicates yet but represent patterns that will diverge if not unified: + +| Component | LysnrAI | MindLyst | Shared Potential | +|-----------|---------|----------|------------------| +| **OpenAI API client** | Python `src/llm/` + Azure OpenAI | KMP `api/OpenAIClient.kt` | Shared TS client for backend services | +| **Whisper/STT client** | Python `src/audio/azure_stt.py` | KMP `api/WhisperClient.kt` | Both need speech-to-text | +| **Health check aggregator** | `services/monitoring/health-check.ts` | N/A (could reuse) | Generic multi-service health poller | +| **Docker Compose patterns** | Full stack compose | Planned | Shared compose fragments | +| **CI workflow templates** | 9 GitHub Actions | 1 CI workflow | Reusable workflow templates | +| **Python Cosmos client** | `src/cloud/cosmos_client.py` | N/A | If MindLyst adds a Python backend | + +--- + +## 5. Recommended Package Structure + +``` +learning_ai_common_plat/ +├── packages/ +│ ├── cosmos/ — Azure Cosmos DB client singleton + container registry +│ ├── errors/ — Typed HTTP service errors (ServiceError hierarchy) +│ ├── auth/ — JWT create/verify + bcrypt + Fastify middleware +│ ├── fastify-core/ — Server bootstrap, request-id, health check, error handler +│ ├── config/ — Zod base env schema + product identity loader +│ ├── api-client/ — Typed fetch wrapper for dashboards/service clients +│ ├── react-auth/ — AuthProvider + useAuth() for Next.js dashboards +│ └── design-tokens/ — Canonical token JSON + generators for CSS/TS/Kotlin/Swift +├── docs/ +│ ├── COMMON_PLATFORM_ANALYSIS.md (this file) +│ └── MIGRATION_GUIDE.md (how to adopt in each repo) +├── package.json — workspace root (npm/pnpm workspaces) +├── tsconfig.base.json — shared TypeScript config +└── README.md +``` + +--- + +## 6. Migration Priority + +Ordered by **impact × ease**: + +| Priority | Package | Impact | Effort | Reason | +|----------|---------|--------|--------|--------| +| **P0** | `@bytelyst/errors` | High | Low | Drop-in, no config, 6 consumers | +| **P0** | `@bytelyst/cosmos` | High | Low | 6 identical files, most-used utility | +| **P1** | `@bytelyst/config` | High | Medium | Eliminates 4 config files + 4 product-config files | +| **P1** | `@bytelyst/auth` | High | Medium | 5 copies of JWT logic, security-critical | +| **P1** | `@bytelyst/fastify-core` | High | Medium | 4 nearly identical server.ts files (~350 lines saved) | +| **P2** | `@bytelyst/api-client` | Medium | Low | 5+ fetch wrappers in dashboards | +| **P2** | `@bytelyst/react-auth` | Medium | Medium | 3 auth contexts, saves ~400 lines | +| **P3** | `@bytelyst/design-tokens` | Medium | High | Cross-platform token generation pipeline | + +--- + +## 7. Consumption Model + +### TypeScript packages (services + dashboards) +- Publish as **npm workspace packages** or use **git submodule** + `file:` references +- Each consuming repo adds `"@bytelyst/": "file:../learning_ai_common_plat/packages/"` to `package.json` +- Alternatively, publish to a private npm registry (GitHub Packages) + +### Design tokens +- `design-tokens` package exports a CLI: `npx @bytelyst/design-tokens generate --format css,ts,kt,swift` +- Each consuming repo runs the generator as a build step or commits the generated output + +### KMP (Kotlin Multiplatform) +- MindLyst's `MindLystTokens.kt` could be auto-generated from `design-tokens/tokens/*.json` +- Add a Gradle task in `shared/build.gradle.kts` that reads the JSON and emits Kotlin + +--- + +## 8. Lines of Code Impact + +| Category | Current Duplicated LOC | After Extraction | +|----------|----------------------|------------------| +| Cosmos client (6 files) | ~306 | ~50 (one shared) | +| Error classes (4 files) | ~157 | ~45 (one shared) | +| JWT auth (5 files) | ~250 | ~60 (one shared) | +| Server bootstrap (4 files) | ~351 | ~30 (per-service config only) | +| Config loader (4 files) | ~107 | ~10 (per-service extension only) | +| Product config (4 files) | ~35 | 0 (read from shared) | +| API fetch utils (5 files) | ~200 | ~30 (one shared) | +| Auth context (3 files) | ~450 | ~50 (one shared, configured per-app) | +| **Total** | **~1,856 LOC** | **~275 LOC** | + +**Net savings: ~1,580 lines of duplicated code eliminated**, plus single-point maintenance for security-critical auth and database infrastructure. + +--- + +## 9. Next Steps + +1. Initialize `learning_ai_common_plat` as a pnpm/npm workspace monorepo +2. Start with P0 packages (`errors`, `cosmos`) — lowest risk, highest copy count +3. Add tests (port existing service tests that cover these utilities) +4. Update LysnrAI services to import from `@bytelyst/*` instead of local `./lib/*` +5. Wire MindLyst's Next.js web app to use shared design tokens +6. Set up CI to test the common platform packages independently diff --git a/docs/ECOSYSTEM_ARCHITECTURE.md b/docs/ECOSYSTEM_ARCHITECTURE.md new file mode 100644 index 00000000..f3dbdddd --- /dev/null +++ b/docs/ECOSYSTEM_ARCHITECTURE.md @@ -0,0 +1,808 @@ +# ByteLyst Ecosystem — Post-Refactor Architecture + +> **Companion diagram:** `ecosystem-after-refactor.drawio` (open in draw.io or VS Code draw.io extension) +> +> **Date:** 2026-02-12 · **Author:** Cascade + +--- + +## Table of Contents + +1. [Ecosystem Overview](#1-ecosystem-overview) +2. [Three-Repo Structure](#2-three-repo-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 ByteLyst ecosystem consists of **two product repos** and **one shared infrastructure repo**: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ CLIENT APPLICATIONS │ +│ LysnrAI Desktop · iOS · Android · Admin · User Portal · Tracker │ +│ MindLyst iOS · Android · Web │ +└───────────────────────────────┬──────────────────────────────────────────┘ + │ +┌──────────────────┐ ┌────────┴────────┐ ┌──────────────────────────────┐ +│ LysnrAI Repo │ │ Common Platform │ │ MindLyst Repo │ +│ (voice_ai_agent)│←─│ (common_plat) │─→│ (multimodal_memory_agents) │ +│ │ │ @bytelyst/* │ │ │ +│ 4 Fastify svcs │ │ 8 npm packages │ │ KMP shared module │ +│ 3 Next.js apps │ │ │ │ 3 native apps │ +│ 1 FastAPI │ │ Design tokens │ │ 1 Next.js web │ +│ 1 Desktop app │ │ (JSON → all) │ │ design-system/ │ +│ 2 Mobile apps │ │ │ │ │ +└────────┬─────────┘ └─────────────────┘ └──────────────┬───────────────┘ + │ │ +┌────────┴─────────────────────────────────────────────────┴───────────────┐ +│ AZURE CLOUD INFRASTRUCTURE │ +│ Cosmos DB · Blob Storage · Key Vault · Speech · OpenAI · Stripe │ +│ Docker Compose (Traefik · Loki · Grafana) · GitHub Actions │ +└──────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 2. Three-Repo Structure + +### 2.1 learning_voice_ai_agent (LysnrAI) + +**Purpose:** Cross-platform voice-to-text dictation platform. + +| Component | Tech | Port | Description | +|-----------|------|------|-------------| +| Desktop App | Python 3.12, tkinter | — | macOS/Windows dictation app | +| FastAPI Backend | Python 3.12 | 8000 | REST API, cloud sync | +| platform-service | Fastify + TS | 4003 | Auth, audit, flags, notifications, blob, rate limiting | +| billing-service | Fastify + TS | 4002 | Subscriptions, plans, usage, licenses, Stripe | +| growth-service | Fastify + TS | 4001 | Invitations, referrals, promo codes | +| tracker-service | Fastify + TS | 4004 | Feature requests, bugs, votes, public roadmap | +| admin-dashboard-web | Next.js 16 | 3001 | Admin panel (users, tokens, audit, themes) | +| user-dashboard-web | Next.js 16 | 3002 | User portal (profile, billing, settings, SSO) | +| tracker-dashboard-web | Next.js | 3003 | Tracker board, kanban, public roadmap | +| iOS App | Swift + SwiftUI | — | Native (no KMP) | +| Android App | Kotlin + Compose | — | Native (no KMP) | +| Monitoring | Loki + Grafana | — | Health checks, logs, metrics | + +### 2.2 learning_multimodal_memory_agents (MindLyst) + +**Purpose:** Role-based Life OS — multimodal second-brain with AI triage. + +| Component | Tech | Description | +|-----------|------|-------------| +| KMP Shared Module | Kotlin Multiplatform | Models, repositories, DI, triage pipeline, API clients | +| iOS App | SwiftUI + KMP | Native UI consuming shared Kotlin module | +| Android App | Jetpack Compose + KMP | Native UI consuming shared Kotlin module | +| Web Dashboard | Next.js 14 | Pages Router, CSS custom properties, landing + dashboard | +| design-system/ | JSON + CSS | Canonical tokens, component specs | + +### 2.3 learning_ai_common_plat (Common Platform) + +**Purpose:** Shared npm packages consumed by both product repos. + +| Package | Type | Primary Consumers | +|---------|------|-------------------| +| `@bytelyst/errors` | TypeScript | All 4 Fastify services, dashboards | +| `@bytelyst/cosmos` | TypeScript | All 4 Fastify services, 2 Next.js dashboards | +| `@bytelyst/config` | TypeScript | All 4 Fastify services | +| `@bytelyst/auth` | TypeScript | All services + dashboards with JWT | +| `@bytelyst/fastify-core` | TypeScript | All 4 Fastify services | +| `@bytelyst/api-client` | TypeScript | All 3 Next.js dashboards | +| `@bytelyst/react-auth` | TypeScript/React | All 3 Next.js dashboards | +| `@bytelyst/design-tokens` | JSON → multi-format | MindLyst (all platforms), potentially LysnrAI dashboards | + +--- + +## 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): void; +export function initializeAllContainers(): Promise; + +// 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(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; + createRefreshToken(payload: { sub: string }): Promise; + verifyToken(token: string): Promise; +}; + +// Fastify middleware +export function extractAuth(req: FastifyRequest): Promise; +export function requireRole(...roles: string[]): FastifyHook; + +// Next.js server-side +export function getCurrentUser(authHeader: string | null, getUserById: Function): Promise; + +// Password hashing +export function hashPassword(plain: string): Promise; +export function verifyPassword(plain: string, hash: string): Promise; + +// 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 { + 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; +``` + +**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; +}): { + // Throws on error (for service-to-service) + fetch(path: string, options?: RequestInit): Promise; + // Returns { data, error } tuple (for UI components) + safeFetch(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(config: { + storagePrefix: string; // "admin" | "portal" | "tracker" + loginEndpoint: string; // "/api/auth/login" + mapResponseToUser: (data: any) => TUser; + enableSSO?: boolean; +}): { + AuthProvider: React.FC<{ children: ReactNode }>; + useAuth: () => AuthContextValue; +}; + +export interface BaseUser { + id?: string; + email: string; + name: string; + role: string; +} + +export interface AuthContextValue { + user: TUser | null; + isAuthenticated: boolean; + isLoading: boolean; + login: (email: string, password: string) => Promise; + 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%** | diff --git a/docs/ecosystem-after-refactor.drawio b/docs/ecosystem-after-refactor.drawio new file mode 100644 index 00000000..63484366 --- /dev/null +++ b/docs/ecosystem-after-refactor.drawio @@ -0,0 +1,478 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +