# ByteLyst Platform — Best Practices & New Product Playbook > **For:** Founders, engineers, and AI coding agents building products on the ByteLyst shared platform. > > **Last updated:** 2026-03-01 · **Ecosystem:** 6 products, 21 shared packages, 25 platform modules + 5 product backends, 1400+ service tests. --- ## Table of Contents 1. [Platform Philosophy](#1-platform-philosophy) 2. [What You Get for Free](#2-what-you-get-for-free) 3. [New Product Playbook — Step by Step](#3-new-product-playbook--step-by-step) 4. [Expected Velocity](#4-expected-velocity) 5. [Architecture Best Practices](#5-architecture-best-practices) 6. [Coding Conventions](#6-coding-conventions) 7. [Data & Cosmos DB Practices](#7-data--cosmos-db-practices) 8. [Auth & Security Practices](#8-auth--security-practices) 9. [Testing Practices](#9-testing-practices) 10. [Deployment & CI Practices](#10-deployment--ci-practices) 11. [AI Agent Collaboration](#11-ai-agent-collaboration) 12. [Anti-Patterns to Avoid](#12-anti-patterns-to-avoid) 13. [Real-World Examples](#13-real-world-examples) --- ## 1. Platform Philosophy The ByteLyst platform follows a **"build once, ship five"** model: - **Product-agnostic core** — every shared package and service works for any product via the `productId` field - **Thin product shells** — product repos contain only UI and product-specific logic; all infrastructure is shared - **Convention over configuration** — follow the patterns, get auth/billing/telemetry/flags/audit for free - **Offline-first** — clients work without connectivity and sync when online ### The Three Layers ``` ┌─────────────────────────────────────────────────────────────┐ │ PRODUCT REPO UI + product-specific logic only │ │ (your new app) Next.js / SwiftUI / Compose / RN │ └────────────────────────────┬────────────────────────────────┘ │ file: refs / REST API ┌────────────────────────────┴────────────────────────────────┐ │ COMMON PLATFORM @bytelyst/* packages │ │ (learning_ai_common_plat) platform-service (port 4003) │ │ extraction-service (port 4005) │ └────────────────────────────┬────────────────────────────────┘ │ ┌────────────────────────────┴────────────────────────────────┐ │ AZURE INFRASTRUCTURE Cosmos DB · Blob · Key Vault │ │ Speech · OpenAI · Stripe │ └─────────────────────────────────────────────────────────────┘ ``` --- ## 2. What You Get for Free ### 2.1 Shared Packages (21) Every package is `npm install`-able via `file:` refs to the sibling common-plat repo. **Server-side packages (Node.js / Fastify):** | Package | What It Does | You Write | | -------------------------- | ---------------------------------------------------- | ------------------------ | | **@bytelyst/auth** | JWT sign/verify, password hash, auth middleware | Nothing — just call it | | **@bytelyst/cosmos** | Cosmos DB client singleton, container registry | Register your containers | | **@bytelyst/config** | Zod env loader, product identity, Key Vault resolver | Your product's `.env` | | **@bytelyst/api-client** | Fetch wrapper with auth injection, timeout, retry | Your service URLs | | **@bytelyst/errors** | Typed HTTP errors (400–429) | Throw them | | **@bytelyst/fastify-core** | `createServiceApp()` + `startService()` factory | Your route plugins | | **@bytelyst/logger** | Pino-based structured logging | `req.log.info(...)` | | **@bytelyst/events** | Typed in-memory event bus with error isolation | Emit/subscribe | | **@bytelyst/blob** | Azure Blob Storage client + SAS token helpers | Your container names | | **@bytelyst/extraction** | AI text extraction client | Your extraction tasks | | **@bytelyst/monitoring** | Health-check utilities, Loki/Grafana helpers | Your service name | | **@bytelyst/testing** | Shared test mocks, Fastify inject helpers | Import in tests | **Client-side packages (Browser / React Native / Mobile):** | Package | What It Does | You Write | | --------------------------------- | ------------------------------------------------------------ | --------------------- | | **@bytelyst/auth-client** | Client-side auth (login, register, token refresh, SSO) | Wire to your login UI | | **@bytelyst/platform-client** | Typed fetch wrapper with auth injection, x-request-id, retry | Your base URL | | **@bytelyst/feature-flag-client** | Feature flag polling client with caching | Init + `isEnabled()` | | **@bytelyst/kill-switch-client** | Kill switch check (force-update, maintenance mode) | Init at app launch | | **@bytelyst/offline-queue** | Persistent retry queue with max retries and queue size | Storage adapter | | **@bytelyst/react-auth** | `createAuthContext()` → typed Provider + useAuth hook | Wrap your app | | **@bytelyst/telemetry-client** | Browser/RN telemetry SDK (queue, flush, beacon) | `trackEvent()` | | **@bytelyst/design-tokens** | JSON → CSS/TS/Kotlin/Swift token generator | Your color overrides | | **@bytelyst/blob-client** | SAS URL upload/download via platform-service blob endpoints | Container + file data | ### 2.2 Platform Service Modules (25 — product-agnostic) The consolidated platform-service (port 4003) provides REST endpoints for shared infrastructure: | Category | Modules | What You Get | | ----------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------- | | **Identity** | auth, sessions | JWT auth, login/register, SSO, password reset, email verification, device sessions | | **Billing** | subscriptions, plans, licenses, stripe, promos | Stripe integration, plan management, promo codes, license keys | | **Growth** | invitations, referrals | Invite links, referral tracking, reward attribution | | **Ops** | flags, maintenance, status, ip-rules, ratelimit, jobs | Feature flags with rollout %, maintenance mode, public status page, scheduled jobs | | **Data** | audit, exports, settings, notifications, delivery | Audit log, GDPR export, user preferences, email/push delivery with templates | | **Content** | items, comments, votes, public, changelog, feedback | Tracker/roadmap items, comments, voting, public roadmap, in-app feedback | | **Telemetry** | telemetry, analytics, experiments | Event ingestion, error clustering, geo distribution, A/B experiments | | **Storage** | blob, products | Blob SAS tokens, product registry/cache | | **Impersonation** | impersonation | Admin user impersonation for debugging | ### 2.3 Product-Specific Backends (NEW — migrated from platform-service) Product-specific modules now live in each product repo's `backend/` directory. This keeps domain logic close to the product code and platform-service product-agnostic. | Product | Port | Modules | Tests | | -------------- | ---- | ----------------------------------------------------------------------------------------- | ----- | | **PeakPulse** | 4010 | peak-sessions, peak-routes | 32 | | **ChronoMind** | 4011 | timers, routines, shared-timers, households, webhooks | 174 | | **JarvisJr** | 4012 | jarvis-agents, jarvis-sessions, jarvis-memory, jarvis-teams, marketplace | 198 | | **NomGap** | 4013 | fasting-sessions, fasting-protocols, body-stages, social-fasting, meal-log, push-triggers | 152 | | **MindLyst** | 4014 | brains, memory, reflections, daily-briefs, streaks | 59 | | **LysnrAI** | 8000 | _(Python FastAPI backend — kept as-is, not migrated to Fastify)_ | 53 | Each backend uses: - `@bytelyst/fastify-core` for app factory - `@bytelyst/cosmos` for Cosmos DB - `@bytelyst/auth` for JWT verification (same `JWT_SECRET` as platform-service) - `@bytelyst/errors` for typed HTTP errors - Validated env config via Zod (never read `process.env` directly for secrets) ### 2.4 Dashboards (Product-Agnostic) | Dashboard | Port | What It Does | | --------------- | ---- | ---------------------------------------------------------------------------------------------- | | **admin-web** | 3001 | User management, audit logs, feature flags, telemetry viewer, secrets manager, mission control | | **tracker-web** | 3003 | Issue tracker, public roadmap, voting, changelog | Both work for any product — they read `productId` from env and filter accordingly. ### 2.5 Infrastructure - **Azure Cosmos DB** — multi-tenant via `productId` partition - **Azure Blob Storage** — 6 containers (audio, transcripts, attachments, avatars, releases, backups) - **Azure Key Vault** — secrets resolution at startup via `@bytelyst/config` - **Docker Compose** — full stack with Traefik, Loki, Grafana - **GitHub Actions** — CI templates (lint, test, typecheck, build) - **Husky + lint-staged** — pre-commit secret scanning, linting --- ## 3. New Product Playbook — Step by Step ### Day 0: Identity & Repo Setup (1 hour) ```bash # 1. Create your product repo mkdir learning_ai_ cd learning_ai_ git init # 2. Choose your product identity PRODUCT_ID="yourapp" # lowercase, no hyphens (e.g. "nomgap", "chronomind") BUNDLE_ID="com.saravana.${PRODUCT_ID}" DOMAIN="${PRODUCT_ID}.app" ``` Create the scaffolding: ``` learning_ai_/ ├── docs/ │ ├── PRD.md # Product requirements │ └── roadmap.md # Implementation roadmap ├── scripts/ │ └── docker-prep.sh # Copy from any existing product repo ├── AGENTS.md # AI agent instructions (copy + customize template) ├── CLAUDE.md # Symlink or copy of AGENTS.md ├── .cursorrules # Symlink or copy of AGENTS.md ├── .windsurfrules # Symlink or copy of AGENTS.md ├── .gitignore ├── .env.example └── README.md ``` ### Day 0: Register Product in Platform (30 minutes) 1. **Add product to platform-service products module:** ``` POST /products { "id": "", "name": "Your App Name", "description": "One-liner", "domain": "yourapp.app", "bundleId": "com.saravana.yourapp" } ``` 2. **Seed default feature flags** — already automatic (see `flags/seed.ts`), just add your product's flags to the seed file. 3. **Add to backup/push workflows** — update `scripts/backup-main.sh` and `.windsurf/workflows/repo_*.md` to include the new repo. ### Day 1: Web App (Next.js) — 2–4 hours ```bash mkdir web && cd web npx create-next-app@latest . --app --typescript --tailwind --eslint npm install zustand zod date-fns recharts ``` Wire the shared packages: ```json // package.json — add file: refs { "dependencies": { "@bytelyst/api-client": "file:../../learning_ai_common_plat/packages/api-client", "@bytelyst/auth-client": "file:../../learning_ai_common_plat/packages/auth-client", "@bytelyst/config": "file:../../learning_ai_common_plat/packages/config", "@bytelyst/cosmos": "file:../../learning_ai_common_plat/packages/cosmos", "@bytelyst/react-auth": "file:../../learning_ai_common_plat/packages/react-auth", "@bytelyst/telemetry-client": "file:../../learning_ai_common_plat/packages/telemetry-client", "@bytelyst/errors": "file:../../learning_ai_common_plat/packages/errors" } } ``` Create the standard `src/lib/` wiring files (copy from any existing product): | File | Purpose | Source Package | | ------------------------ | ------------------------------- | ---------------------------- | | `lib/cosmos.ts` | Register Cosmos containers | `@bytelyst/cosmos` | | `lib/auth-server.ts` | JWT utils for API routes | `@bytelyst/auth` | | `lib/product-config.ts` | Product identity | `@bytelyst/config` | | `lib/platform-client.ts` | API client for platform-service | `@bytelyst/api-client` | | `lib/telemetry.ts` | Client telemetry init | `@bytelyst/telemetry-client` | | `app/providers.tsx` | AuthProvider + telemetry init | `@bytelyst/react-auth` | **What you DON'T write:** auth flows, JWT handling, token refresh, Cosmos client setup, error types, API client with retry/timeout, telemetry pipeline, feature flag polling. ### Day 1: Native App (choose your framework) — 4–8 hours | Option | Best For | Stack | | ------------------------- | --------------------------------- | ------------------------------------------ | | **Expo (React Native)** | Fast cross-platform, JS ecosystem | Expo SDK, expo-router, Zustand + MMKV | | **KMP + SwiftUI/Compose** | Maximum native performance | Shared Kotlin, native UI shells | | **Pure Native** | Single platform focus | SwiftUI (iOS) or Jetpack Compose (Android) | For any native app, use the shared platform SDKs: **iOS / macOS / watchOS — ByteLystPlatformSDK (Swift Package):** 1. Add `../learning_ai_common_plat/packages/swift-platform-sdk/` as a local SPM dependency 2. Create `Platform/` directory with thin wrappers (Config, KeychainHelper, TelemetryService, AuthService, etc.) 3. Wire `PlatformSyncManager` for cloud sync 4. Use design tokens from `@bytelyst/design-tokens` (auto-generated `*Theme.swift`) **Android — kotlin-platform-sdk (Gradle module):** 1. Add `../learning_ai_common_plat/packages/kotlin-platform-sdk` as a project dependency 2. Create a Hilt `PlatformModule` (or Koin `platformModule`) providing `BLPlatformConfig`, `BLAuthClient`, `BLTelemetryClient`, `BLFeatureFlagClient`, `BLKillSwitchClient` 3. Wire sync via `PlatformApiClient` + `SyncRepository` **React Native (Expo) — @bytelyst/\* TS packages:** 1. Wire `@bytelyst/platform-client`, `@bytelyst/auth-client`, `@bytelyst/feature-flag-client`, `@bytelyst/kill-switch-client`, `@bytelyst/offline-queue` 2. Use MMKV as storage adapter for offline queue 3. Use design tokens from `@bytelyst/design-tokens` (auto-generated `tokens.ts`) ### Day 2: Product-Specific Backend (2–4 hours per module) > **Key change (2026-03-01):** Product-specific modules now live in the product repo's `backend/` directory, NOT in platform-service. This keeps domain logic close to the product and platform-service product-agnostic. Scaffold the backend (copy from any existing product repo): ``` your-product/backend/ ├── src/ │ ├── lib/ │ │ ├── config.ts # Zod env schema (PORT, HOST, JWT_SECRET, COSMOS_*) │ │ ├── cosmos.ts # Re-export from @bytelyst/cosmos │ │ ├── cosmos-init.ts # Register + initialize Cosmos containers │ │ ├── auth.ts # Re-export from @bytelyst/auth │ │ ├── errors.ts # Re-export from @bytelyst/errors │ │ └── request-context.ts # productId validation from JWT/headers │ ├── modules/ │ │ └── / │ │ ├── types.ts # Zod schemas + TypeScript interfaces │ │ ├── repository.ts # Cosmos DB CRUD │ │ ├── routes.ts # Fastify REST endpoints │ │ └── .test.ts # Vitest tests │ └── server.ts # Entry point ├── package.json # file: refs to @bytelyst/* packages ├── tsconfig.json ├── vitest.config.ts └── .env.example ``` **Template (server.ts):** ```typescript import { createServiceApp, startService } from '@bytelyst/fastify-core'; import { jwtVerify } from 'jose'; import { yourRoutes } from './modules/your-module/routes.js'; import { initCosmosIfNeeded } from './lib/cosmos-init.js'; import { config } from './lib/config.js'; // ⚠️ Always use validated config — never process.env directly for secrets const jwtSecret = new TextEncoder().encode(config.JWT_SECRET); await initCosmosIfNeeded(); const app = await createServiceApp({ name: 'yourapp-backend', version: '0.1.0' }); app.addHook('onRequest', async req => { const auth = req.headers.authorization; if (!auth?.startsWith('Bearer ')) return; try { const { payload } = await jwtVerify(auth.slice(7), jwtSecret, { issuer: 'bytelyst-platform' }); req.jwtPayload = payload; } catch { /* token invalid — leave undefined */ } }); await app.register(yourRoutes, { prefix: '/api' }); await startService(app, { port: config.PORT, host: config.HOST }); ``` **Template (routes.ts):** ```typescript import type { FastifyInstance } from 'fastify'; import { extractAuth } from '../../lib/auth.js'; import { BadRequestError, NotFoundError } from '../../lib/errors.js'; import * as repo from './repository.js'; import { CreateYourDocSchema } from './types.js'; const PRODUCT_ID = 'yourapp'; export async function yourRoutes(app: FastifyInstance) { app.get('/your-resource', async req => { const auth = await extractAuth(req); return { items: await repo.list(auth.sub, PRODUCT_ID) }; }); // ... POST, PUT, DELETE } ``` ### Day 3: User Dashboard (optional) — 4–6 hours If your product needs a user-facing web portal, create a Next.js app in your product repo: ``` your-product/ └── user-dashboard-web/ ├── src/ │ ├── app/ # App Router pages │ ├── lib/ # Standard wiring files (copy pattern) │ └── components/ # shadcn/ui + custom ├── package.json # file: refs to @bytelyst/* └── .env.example ``` The admin dashboard and tracker dashboard are **already built and product-agnostic** — just point them at your productId. --- ## 4. Expected Velocity ### What Took Months, Now Takes Days Based on actual delivery across 6 products (LysnrAI, MindLyst, ChronoMind, NomGap, JarvisJr, PeakPulse): | Capability | Without Platform | With Platform | Savings | | ------------------------------------------------ | ---------------- | --------------------------- | ------- | | Auth (JWT, login, register, SSO, password reset) | 2–3 weeks | 0 days (already built) | 100% | | Billing (Stripe, plans, subscriptions) | 2–3 weeks | 0 days | 100% | | Feature flags with rollout | 1 week | 0 days | 100% | | Telemetry pipeline | 1–2 weeks | 1 hour (wire client) | 95% | | Admin dashboard | 3–4 weeks | 0 days (shared) | 100% | | Audit logging | 3–5 days | 0 days | 100% | | GDPR data export | 3–5 days | 0 days | 100% | | Email delivery (templates, SendGrid) | 1 week | 0 days | 100% | | Rate limiting + IP rules | 3–5 days | 0 days | 100% | | Blob storage (uploads, SAS tokens) | 1 week | 0 days | 100% | | Public roadmap + issue tracker | 2 weeks | 0 days | 100% | | Client offline sync queue | 1 week | 2 hours (copy pattern) | 90% | | Design system (tokens across platforms) | 1–2 weeks | 1 hour (add product colors) | 90% | | **New product-specific CRUD module** | — | **2–4 hours** | — | | **Full MVP (web + mobile shell)** | 6–10 weeks | **3–5 days** | ~85% | ### Realistic Timeline for a New Product | Day | Milestone | | --------- | --------------------------------------------------------------------- | | **Day 0** | Repo created, product registered, AGENTS.md written | | **Day 1** | Web app scaffolded with auth, telemetry, feature flags wired | | **Day 2** | 2–3 product-specific backend modules, Cosmos containers registered | | **Day 3** | Core UI screens built, offline sync queue, user dashboard (if needed) | | **Day 4** | Native app shells (iOS/Android) with auth + sync wired | | **Day 5** | Polish, tests, CI, first deploy | **By Day 5 you have:** a fully authenticated, multi-platform app with billing, telemetry, feature flags, admin dashboard, audit logging, GDPR export, public roadmap, and offline sync — all production-grade. --- ## 5. Architecture Best Practices ### 5.1 Product Repo Structure ``` your-product/ ├── web/ # Next.js (App Router) or Expo │ ├── src/ │ │ ├── app/ # Pages + API routes │ │ ├── components/ # UI components │ │ └── lib/ # Engine logic (pure TS, no framework imports) │ └── package.json # file: refs to @bytelyst/* ├── backend/ # Product-specific Fastify backend (NEW) │ ├── src/ │ │ ├── lib/ # config, cosmos, auth, errors re-exports │ │ ├── modules/ # Domain modules (types, repo, routes, tests) │ │ └── server.ts # Entry point │ └── package.json # file: refs to @bytelyst/* server packages ├── ios/ # SwiftUI (if native) │ └── /Platform/ # Thin wrappers over ByteLystPlatformSDK ├── android/ # Jetpack Compose (if native) │ └── app/.../platform/ # Hilt/Koin module for kotlin-platform-sdk ├── docs/ # PRD, roadmap, research ├── scripts/ # Build/deploy scripts ├── AGENTS.md # AI agent instructions └── .env.example ``` ### 5.2 Engine Logic Separation **Critical rule:** Keep business logic in pure TypeScript/Kotlin/Swift files with zero framework dependencies. ``` ✅ web/src/lib/fasting-timer.ts → pure TS, testable without DOM ✅ web/src/lib/body-stages.ts → pure TS, imported by components ❌ web/src/components/Timer.tsx → business logic mixed with React ❌ web/src/lib/timer.ts → imports from 'react' ``` This enables: - Unit testing without mocking React/RN - Sharing logic between web and native (via ports) - AI agents can modify engine logic confidently ### 5.3 Sync Architecture Every client follows the same offline-first pattern: ``` Local Store (Zustand/MMKV/UserDefaults) │ ├── Immediate: update local state ├── Fire-and-forget: POST/PUT to platform-service └── On failure: enqueue to offline queue │ └── On next online: flush queue → pull remote → merge ``` **Shared packages for sync:** - `@bytelyst/offline-queue` — persistent retry queue with max retries and queue size (TS/RN) - `@bytelyst/platform-client` — typed fetch wrapper with auth injection, x-request-id, auto-retry on 401 (TS/RN) - `ByteLystPlatformSDK.BLSyncEngine` — offline-first sync engine (Swift/iOS) - `kotlin-platform-sdk` — platform API client + secure store (Kotlin/Android) **Reference implementations:** - `PlatformSyncManager.swift` (ChronoMind) — bidirectional sync with conflict detection, offline queue - `PlatformSyncManager.swift` (PeakPulse) — BLSyncEngine-based upload/download - `src/api/client.ts` (NomGap) — `@bytelyst/platform-client` wrapper with auth token injection --- ## 6. Coding Conventions ### Must Follow | Rule | Why | | ---------------------------------------------- | --------------------------------------- | | Every Cosmos document includes `productId` | Multi-tenant isolation | | Every REST endpoint validates with Zod schemas | Type safety + auto documentation | | Every service propagates `x-request-id` | Distributed tracing | | Use `req.log` / `app.log` in Fastify | Structured logging with request context | | Use `structlog` in Python | Same — never `print()` | | Use theme tokens, never hardcode colors | Cross-platform consistency | | Commit messages: `type(scope): description` | Changelog generation | | Imports always at top of file | Code style consistency | ### Must Not Do | Anti-Pattern | Do Instead | | -------------------------------- | -------------------------------------- | | `console.log` in production | `req.log.info(...)` or analytics stub | | `any` type in TypeScript | Zod inference or explicit types | | Hardcode secrets | `@bytelyst/config` + Key Vault | | Hardcode API URLs | Environment variables | | `Math.random()` for IDs in loops | `crypto.randomUUID()` or include index | | Modify tests to make them pass | Fix the actual code | | `npm` in common-plat | `pnpm` (workspace) | --- ## 7. Data & Cosmos DB Practices ### Container Naming ``` ✅ fasting_sessions (snake_case, plural) ✅ feature_flags ❌ FastingSessions (no PascalCase) ❌ fasting-session (no hyphens, no singular) ``` ### Document Shape Every document must include: ```typescript { id: string; // Unique ID (e.g. "session_1709234567890") productId: string; // ALWAYS — multi-tenant key // ... your fields createdAt: string; // ISO 8601 updatedAt: string; // ISO 8601 } ``` ### Partition Key Strategy - Use `productId` as partition key for shared collections - Use `id` as partition key for product-specific collections with low cross-product queries - For high-volume telemetry: composite key like `productId:yyyyMM:platform` ### Query Patterns ```typescript // ✅ Always filter by productId first 'SELECT * FROM c WHERE c.productId = @pid AND c.userId = @uid ORDER BY c.createdAt DESC'; // ❌ Full scan — never do this 'SELECT * FROM c'; ``` --- ## 8. Auth & Security Practices ### JWT Flow ``` Client → POST /auth/login → platform-service → JWT (access + refresh) Client → Authorization: Bearer → platform-service validates Client → 401 → silent refresh via refresh token → retry ``` ### Server-Side (Next.js API Routes) ```typescript // lib/auth-server.ts — copy from existing product import { createJwtUtils } from '@bytelyst/auth'; // ⚠️ For product backends (Fastify): use validated Zod config, never process.env directly // For Next.js API routes: process.env is acceptable since Next.js validates at build time export const { verifyToken, signToken, hashPassword, verifyPassword } = createJwtUtils({ secret: process.env.JWT_SECRET!, }); ``` ### Client-Side ```typescript // lib/auth-client.ts — copy from existing product import { createAuthClient } from '@bytelyst/auth-client'; export const authClient = createAuthClient({ baseUrl: process.env.NEXT_PUBLIC_PLATFORM_URL!, storage: { getItem, setItem, removeItem }, // localStorage or MMKV }); ``` ### Security Checklist - [ ] Husky pre-commit: secret scan (`scripts/secret-scan-staged.sh`) - [ ] Husky pre-push: full repo scan (`scripts/secret-scan-repo.sh`) - [ ] No secrets in `.env.example` — only placeholder keys - [ ] All real secrets in Azure Key Vault - [ ] `@bytelyst/config` resolves secrets at startup - [ ] Rate limiting on all public endpoints - [ ] Edge middleware blocks unauthenticated API requests --- ## 9. Testing Practices ### Test Structure ``` # Service tests (Vitest) services/platform-service/src/modules//.test.ts # Web engine tests (Vitest) web/src/lib/.test.ts # Native tests ios/Tests/ # XCTest android/app/src/test/ # JUnit5 # E2E tests (Playwright) web/e2e/ ``` ### Testing Rules 1. **Engine logic gets unit tests** — pure functions, no mocking needed 2. **API routes get integration tests** — use `@bytelyst/testing` Fastify inject helpers 3. **Never modify tests to make them pass** — fix the code 4. **Test the module pattern** — `types.ts` (schema validation), `repository.ts` (CRUD), `routes.ts` (HTTP) 5. **Mock external services** — Cosmos, Stripe, SendGrid 6. **Run all tests before pushing:** ```bash # Common platform cd learning_ai_common_plat && pnpm test # Your product web cd your-product/web && npm test # Typecheck cd your-product/web && npx tsc --noEmit ``` ### Current Test Counts (for reference) **Platform (common-plat):** | Repo | Tests | Test Files | | ---------------- | ----- | ---------- | | Platform-service | 766 | 66 | | Shared packages | ~120 | 21 | **Product backends (Fastify):** | Repo | Tests | Port | | ------------------ | ----- | ---- | | JarvisJr backend | 198 | 4012 | | ChronoMind backend | 174 | 4011 | | NomGap backend | 152 | 4013 | | MindLyst backend | 59 | 4014 | | PeakPulse backend | 32 | 4010 | | LysnrAI backend | 53 | 8000 | **Product frontends:** | Repo | Tests | Framework | | ------------------ | ----- | --------- | | NomGap (RN) | 430 | Vitest | | ChronoMind web | 394 | Vitest | | JarvisJr web | 32 | Vitest | | ChronoMind iOS | 129 | XCTest | | ChronoMind Android | 30 | JUnit5 | --- ## 10. Deployment & CI Practices ### Local Development ```bash # Start platform-service (required for all products) cd learning_ai_common_plat/services/platform-service npm run dev # port 4003 # Start your product cd your-product/web npm run dev # port 3000 (or custom) ``` ### Docker / CI Builds Product repos use `file:` refs to `@bytelyst/*` packages. These break in Docker/CI where the sibling repo isn't available. Use the tarball prep workflow: ```bash # 1. Build packages cd learning_ai_common_plat && pnpm build # 2. Pack tarballs + rewrite package.json ./scripts/docker-prep.sh # 3. Now Docker build works (no sibling repo needed) docker build your-product/web/ # 4. Restore original package.json ./scripts/docker-prep.sh --restore ``` ### Environment Variables ```bash # Required for every product COSMOS_ENDPOINT=https://your-cosmos.documents.azure.com:443 COSMOS_KEY=... JWT_SECRET=... PRODUCT_ID=yourapp # Platform-service URL (for client API calls) PLATFORM_SERVICE_URL=http://localhost:4003 NEXT_PUBLIC_PLATFORM_URL=http://localhost:4003 # Optional but recommended AZURE_BLOB_CONNECTION_STRING=... STRIPE_SECRET_KEY=... ``` --- ## 11. AI Agent Collaboration ### AGENTS.md Is Your Contract Every product repo MUST have an `AGENTS.md` at root. This is the onboarding doc for all AI coding agents (Claude, Cursor, Copilot, Windsurf, Codex). Include: 1. **Project identity** — product name, ID, bundle ID, repo name 2. **Repo layout** — directory tree with descriptions 3. **Tech stack** — frameworks, versions, patterns 4. **Coding conventions** — must-follow and must-not-do rules 5. **File ownership map** — which files to touch for which domain 6. **Build & test commands** — copy-pastable verification steps 7. **Common pitfalls** — things agents frequently get wrong ### Windsurf Workflows Create `.windsurf/workflows/` for repeatable multi-step tasks: ```yaml --- description: Build and deploy the app --- 1. Run tests // turbo 2. Build the app // turbo 3. Deploy to staging ``` ### Key Agent Rules - Agents should **read AGENTS.md first** before making any changes - Agents should **never modify tests to make them pass** - Agents should **use `req.log` not `console.log`** - Agents should **always include `productId`** in Cosmos documents - Agents should **run typecheck + tests** after making changes --- ## 12. Anti-Patterns to Avoid ### Architecture Anti-Patterns | Don't | Do Instead | | --------------------------------------------- | ------------------------------------------------------- | | Build a custom auth system | Use `@bytelyst/auth` + `@bytelyst/auth-client` | | Create a new microservice for each feature | Add a module to platform-service | | Inline `fetch()` wrappers in dashboard code | Use `@bytelyst/api-client` factory | | Put business logic in React components | Pure TS in `src/lib/`, React in `src/components/` | | Create a separate Cosmos database per product | Share one database, partition by `productId` | | Write your own feature flag system | Use `flags/poll` endpoint + existing polling client | | Skip offline queue | Copy `offline-queue.ts` pattern — users will be offline | ### Code Anti-Patterns | Don't | Do Instead | | ------------------------------------------------------ | ----------------------------------------------- | | `import { something } from '../../../common_plat/...'` | `import { something } from '@bytelyst/package'` | | `const id = Math.random().toString()` | `const id = crypto.randomUUID()` | | `catch (e: any)` | `catch (e: unknown)` with type narrowing | | `if (process.env.NODE_ENV === 'production')` | Feature flags via `flags/poll` | | Copy-paste an entire module and rename | Use the module template pattern in §3 | ### Process Anti-Patterns | Don't | Do Instead | | -------------------------------------------------- | -------------------------------------------- | | Make a giant PR across 5 repos | Commit incrementally per repo, push in order | | Skip typecheck before pushing | `npx tsc --noEmit` is mandatory | | Forget to update AGENTS.md | Keep it current — it's the agent contract | | Use `npm` in common-plat | `pnpm` — workspace protocol requires it | | Forget `pnpm build` before dashboard `npm install` | Always build packages first | --- ## 13. Real-World Examples ### Example: How NomGap Was Built NomGap (fasting visualization app) was built on this platform in ~1 week: 1. **Day 0:** Created `learning_ai_fastgap`, wrote PRD, wrote AGENTS.md 2. **Day 1:** Expo (React Native) app scaffolded with: - Zustand + MMKV for state - `@bytelyst/auth-client` for auth - `@bytelyst/telemetry-client` for telemetry - Feature flag polling from platform-service 3. **Day 2:** Pure engine modules in `src/lib/` — fasting timer, body stages, autophagy meter, safety checks, gamification (283 tests) 4. **Day 3:** Platform-service modules added — `fasting-sessions`, `fasting-protocols`, `body-stages`, `social-fasting`, `meal-log` 5. **Day 4:** Offline queue, sync, native extensions (widgets, watch app stubs) 6. **Day 5:** Store assets, CI, polish **What was NOT built from scratch:** Auth, billing, telemetry, feature flags, admin dashboard, audit logging, rate limiting, email delivery — all inherited from the platform. ### Example: How ChronoMind Was Built ChronoMind (AI clock/timer) spans web (Next.js PWA), iOS (SwiftUI), Android (Compose), watchOS, macOS: 1. **Web:** Next.js 16 + Zustand + Serwist (PWA). 16 pure engine modules in `web/src/lib/`, 12 React components, 394 tests 2. **iOS:** SwiftUI with 20+ shared modules in `ios/ChronoMind/Shared/`, `Platform/` wrappers over ByteLystPlatformSDK, WidgetKit, Live Activities, Siri Shortcuts 3. **Android:** Jetpack Compose + Room + Hilt + kotlin-platform-sdk, Glance widgets, foreground service 4. **Backend:** Product-specific Fastify backend (port 4011) with 5 modules (timers, routines, shared-timers, households, webhooks) — 198 tests 5. **Sync:** Bidirectional sync with offline queue, conflict detection, Keychain-based auth token storage **Total product backend modules:** 5. Everything else (auth, billing, flags, telemetry, admin, tracker) was inherited from platform-service. --- ## Quick Reference: Copy-Paste Checklist for New Products ``` □ Create repo: learning_ai_ □ Write AGENTS.md (copy template, customize) □ Create .env.example with required vars □ Register product: POST /products to platform-service □ Add flags to services/platform-service/src/modules/flags/seed.ts □ Add design tokens to packages/design-tokens/ (optional) □ Scaffold web app with file: refs to @bytelyst/* □ Create lib/ wiring: cosmos.ts, auth-server.ts, product-config.ts, platform-client.ts □ Scaffold product backend in backend/ (copy from existing product repo) □ — lib/config.ts with Zod env validation (JWT_SECRET from config, NOT process.env) □ — lib/cosmos-init.ts to register + initialize Cosmos containers □ — 1–3 domain modules (types.ts, repository.ts, routes.ts, *.test.ts) □ Wire native SDKs: □ — iOS: ByteLystPlatformSDK → Platform/ wrappers □ — Android: kotlin-platform-sdk → Hilt/Koin module □ — RN: @bytelyst/platform-client, auth-client, feature-flag-client, kill-switch-client, offline-queue □ Wire telemetry client □ Wire feature flag polling □ Add offline queue for sync □ Write tests for engine logic □ Run typecheck + tests □ Add to backup/push workflows □ Push to origin ```