Followup to single-source-of-truth migration. Active docs that taught or described the old 8-file agent-config pattern are updated to reflect the new architecture. - docs/ECOSYSTEM_CONSISTENCY_AUDIT.md: update §7 Agent Documentation, resolve F19 (ActionTrail missing CLAUDE.md) and F20 (Auth App missing agent docs) — both eliminated by the migration. Update §9 consistency checklist with new file inventory (AGENTS.md + canonical pointer, thin copilot pointer, legacy files removed across all 17 active repos). - docs/learning_ai_common_plat_INVENTORY.md: replace deleted AI.dev/SKILLS/update-agent-docs.md with agent-behavior-guidelines.md and agent-onboarding.md entries. Add check-agent-docs-drift.sh to the scripts table. - docs/guides/PLATFORM_PLAYBOOK.md: update new-product scaffold tree to show the 4 canonical files (AGENTS.md + 3 auto-generated derivatives), drop CLAUDE.md/.cursorrules/.windsurfrules. - docs/guides/PLATFORM_ACCELERATION_IDEAS.md: update create-app CLI description to reference the canonical pointer + derived files. - docs/guides/WORKFLOW_SYNC.md: clarify what /repo_update-agent-docs does. Historical/completed roadmaps in docs/roadmaps/completed/ are left as-is — they accurately describe state at the time and editing them would rewrite history.
861 lines
40 KiB
Markdown
861 lines
40 KiB
Markdown
# 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_<codename>
|
||
cd learning_ai_<codename>
|
||
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_<codename>/
|
||
├── docs/
|
||
│ ├── PRD.md # Product requirements
|
||
│ └── roadmap.md # Implementation roadmap
|
||
├── scripts/
|
||
│ └── docker-prep.sh # Copy from any existing product repo
|
||
├── AGENTS.md # AI agent instructions (hand-maintained; canonical pointer auto-prepended)
|
||
├── .github/
|
||
│ └── copilot-instructions.md # Thin pointer (auto-generated by update-agent-docs.sh)
|
||
├── .aider.conf.yml # Aider config (auto-generated)
|
||
├── .editorconfig # Editor config (auto-generated)
|
||
├── .gitignore
|
||
├── .env.example
|
||
└── README.md
|
||
```
|
||
|
||
### Day 0: Register Product in Platform (30 minutes)
|
||
|
||
1. **Add product to platform-service products module:**
|
||
|
||
```
|
||
POST /products
|
||
{
|
||
"id": "<PRODUCT_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/
|
||
│ │ └── <your-module>/
|
||
│ │ ├── types.ts # Zod schemas + TypeScript interfaces
|
||
│ │ ├── repository.ts # Cosmos DB CRUD
|
||
│ │ ├── routes.ts # Fastify REST endpoints
|
||
│ │ └── <module>.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)
|
||
│ └── <App>/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 <jwt> → 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/<module>/<module>.test.ts
|
||
|
||
# Web engine tests (Vitest)
|
||
web/src/lib/<module>.test.ts
|
||
|
||
# Native tests
|
||
ios/<Project>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_<codename>
|
||
□ 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
|
||
```
|