# LetsBe Biz — Repository Structure

**Date:** February 27, 2026
**Team:** Claude Opus 4.6 Architecture Team
**Document:** 09 of 09
**Status:** Proposal — Competing with independent team

---

## Table of Contents

1. [Decision: Monorepo](#1-decision-monorepo)
2. [Turborepo Configuration](#2-turborepo-configuration)
3. [Directory Tree](#3-directory-tree)
4. [Package Architecture](#4-package-architecture)
5. [Dependency Graph](#5-dependency-graph)
6. [Migration Plan](#6-migration-plan)
7. [Development Workflow](#7-development-workflow)
8. [Monorepo Trade-offs](#8-monorepo-trade-offs)

---

## 1. Decision: Monorepo

### Why Monorepo?

| Factor | Monorepo | Multi-Repo | Winner |
|--------|---------|-----------|--------|
| **Shared types** | Single source of truth; import directly | npm publish on every change; version drift | Monorepo |
| **Atomic changes** | Change type + all consumers in one PR | Coordinate releases across repos | Monorepo |
| **CI/CD** | One pipeline, matrix builds | Per-repo pipelines, dependency triggering | Monorepo |
| **Code discovery** | `grep` across everything | Search multiple repos separately | Monorepo |
| **Prisma schema** | One schema, shared by Hub and types | Duplicate or publish as package | Monorepo |
| **Developer onboarding** | Clone one repo, `npm install`, done | Clone 3-4 repos, configure each | Monorepo |
| **Build caching** | Turborepo caches across packages | Each repo builds independently | Monorepo |
| **Independence** | Packages are more coupled | Fully independent deploy | Multi-Repo |
| **Repo size** | Grows over time | Each repo stays lean | Multi-Repo |
| **CI isolation** | Bad test in one package blocks others | Fully isolated | Multi-Repo |

**Decision:** Monorepo with Turborepo. The shared types, Prisma schema, and tight coupling between Safety Wrapper ↔ Hub ↔ Secrets Proxy make a monorepo the clear winner. The provisioner (Bash) stays as a separate package within the monorepo but could also remain as a standalone repo if the team prefers — it has no TypeScript dependencies.

### What Stays Outside the Monorepo

| Component | Reason |
|-----------|--------|
| **OpenClaw** | Upstream dependency. Pulled as Docker image. Not forked. |
| **Tool Docker stacks** | Compose files and nginx configs live in the provisioner package. |
| **Mobile app** | React Native/Expo has different build tooling. Lives in `packages/mobile` but uses its own `metro.config.js`. |

---

## 2. Turborepo Configuration

### `turbo.json`

```json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "typecheck": {
      "dependsOn": ["^build"]
    },
    "lint": {},
    "test": {
      "dependsOn": ["^build"],
      "env": ["DATABASE_URL", "NODE_ENV"]
    },
    "test:p0": {
      "dependsOn": ["^build"],
      "cache": false
    },
    "test:p1": {
      "dependsOn": ["^build"],
      "cache": false
    },
    "test:integration": {
      "dependsOn": ["build"],
      "cache": false
    },
    "test:benchmark": {
      "dependsOn": ["build"],
      "cache": false
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "db:push": {
      "cache": false
    },
    "db:generate": {
      "outputs": ["node_modules/.prisma/**"]
    }
  }
}
```

### Root `package.json`

```json
{
  "name": "letsbe-biz",
  "private": true,
  "workspaces": [
    "packages/*"
  ],
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev --parallel",
    "test": "turbo run test",
    "test:p0": "turbo run test:p0",
    "test:integration": "turbo run test:integration",
    "lint": "turbo run lint",
    "typecheck": "turbo run typecheck",
    "format": "prettier --write \"packages/*/src/**/*.{ts,tsx}\"",
    "clean": "turbo run clean && rm -rf node_modules"
  },
  "devDependencies": {
    "turbo": "^2.3.0",
    "prettier": "^3.4.0",
    "typescript": "^5.7.0"
  },
  "engines": {
    "node": ">=22.0.0"
  }
}
```

---

## 3. Directory Tree

```
letsbe-biz/
├── .gitea/
│   └── workflows/
│       ├── ci.yml                    # Monorepo CI (lint, typecheck, test)
│       ├── safety-wrapper.yml        # SW-specific pipeline
│       ├── secrets-proxy.yml         # SP-specific pipeline
│       ├── hub.yml                   # Hub pipeline
│       ├── integration.yml           # Integration test pipeline
│       ├── deploy-staging.yml        # Auto-deploy to staging
│       ├── deploy-hub.yml            # Production Hub deploy
│       └── tenant-update.yml         # Tenant server rollout
│
├── packages/
│   ├── safety-wrapper/               # Safety Wrapper (localhost:8200)
│   │   ├── src/
│   │   │   ├── index.ts              # Entry point: HTTP server startup
│   │   │   ├── server.ts             # Express/Fastify HTTP server
│   │   │   ├── config.ts             # Configuration loading
│   │   │   ├── classification/
│   │   │   │   ├── engine.ts         # Command classification engine
│   │   │   │   ├── shell-classifier.ts   # Shell command allowlist + classification
│   │   │   │   ├── docker-classifier.ts  # Docker subcommand classification
│   │   │   │   └── rules.ts         # Classification rule definitions
│   │   │   ├── autonomy/
│   │   │   │   ├── resolver.ts       # Autonomy level resolution
│   │   │   │   ├── external-comms.ts # External Communications Gate
│   │   │   │   └── approval-queue.ts # Local approval queue (SQLite)
│   │   │   ├── executors/
│   │   │   │   ├── shell.ts          # Shell command executor (execFile)
│   │   │   │   ├── docker.ts         # Docker command executor
│   │   │   │   ├── file.ts           # File read/write executor
│   │   │   │   └── env.ts            # Env read/update executor
│   │   │   ├── secrets/
│   │   │   │   ├── registry.ts       # Encrypted SQLite secrets vault
│   │   │   │   ├── injection.ts      # SECRET_REF resolution
│   │   │   │   └── api.ts            # Secrets side-channel API
│   │   │   ├── hub/
│   │   │   │   ├── client.ts         # Hub communication (register, heartbeat, config)
│   │   │   │   └── config-sync.ts    # Config versioning and delta sync
│   │   │   ├── metering/
│   │   │   │   ├── token-tracker.ts  # Per-agent, per-model token tracking
│   │   │   │   └── bucket.ts         # Hourly bucket aggregation
│   │   │   ├── audit/
│   │   │   │   └── logger.ts         # Append-only audit log
│   │   │   └── db/
│   │   │       ├── schema.sql        # SQLite schema (secrets, approvals, audit, usage, state)
│   │   │       └── migrations/       # SQLite migration files
│   │   ├── test/
│   │   │   ├── p0/
│   │   │   │   ├── classification.test.ts  # 100+ classification tests
│   │   │   │   └── autonomy.test.ts        # Level × tier matrix tests
│   │   │   ├── p1/
│   │   │   │   ├── shell-executor.test.ts
│   │   │   │   ├── docker-executor.test.ts
│   │   │   │   └── hub-client.test.ts
│   │   │   └── integration/
│   │   │       └── openclaw-routing.test.ts
│   │   ├── Dockerfile
│   │   ├── package.json
│   │   ├── tsconfig.json
│   │   └── vitest.config.ts
│   │
│   ├── secrets-proxy/                # Secrets Proxy (localhost:8100)
│   │   ├── src/
│   │   │   ├── index.ts              # Entry point
│   │   │   ├── proxy.ts              # HTTP proxy server (transparent)
│   │   │   ├── redaction/
│   │   │   │   ├── pipeline.ts       # 4-layer pipeline orchestrator
│   │   │   │   ├── layer1-aho-corasick.ts  # Registry-based exact match
│   │   │   │   ├── layer2-regex.ts         # Pattern safety net
│   │   │   │   ├── layer3-entropy.ts       # Shannon entropy filter
│   │   │   │   └── layer4-json-keys.ts     # Sensitive key name detection
│   │   │   └── config.ts
│   │   ├── test/
│   │   │   ├── p0/
│   │   │   │   ├── redaction.test.ts       # 50+ redaction tests (TDD)
│   │   │   │   ├── false-positives.test.ts # False positive prevention
│   │   │   │   └── performance.test.ts     # <10ms latency benchmark
│   │   │   └── adversarial/
│   │   │       └── bypass-attempts.test.ts # Adversarial attack tests
│   │   ├── Dockerfile
│   │   ├── package.json
│   │   ├── tsconfig.json
│   │   └── vitest.config.ts
│   │
│   ├── hub/                          # Hub (Next.js — existing codebase, migrated)
│   │   ├── src/
│   │   │   ├── app/                  # Next.js App Router (existing structure)
│   │   │   │   ├── admin/            # Staff admin dashboard (existing)
│   │   │   │   ├── api/
│   │   │   │   │   ├── auth/         # Authentication (existing)
│   │   │   │   │   ├── v1/
│   │   │   │   │   │   ├── admin/    # Admin API (existing)
│   │   │   │   │   │   ├── tenant/   # NEW: Safety Wrapper protocol
│   │   │   │   │   │   │   ├── register/
│   │   │   │   │   │   │   ├── heartbeat/
│   │   │   │   │   │   │   ├── config/
│   │   │   │   │   │   │   ├── usage/
│   │   │   │   │   │   │   ├── approval-request/
│   │   │   │   │   │   │   └── approval-response/
│   │   │   │   │   │   ├── customer/ # NEW: Customer-facing API
│   │   │   │   │   │   │   ├── dashboard/
│   │   │   │   │   │   │   ├── agents/
│   │   │   │   │   │   │   ├── usage/
│   │   │   │   │   │   │   ├── approvals/
│   │   │   │   │   │   │   ├── billing/
│   │   │   │   │   │   │   └── tools/
│   │   │   │   │   │   ├── orchestrator/  # DEPRECATED: keep for backward compat, redirect
│   │   │   │   │   │   ├── public/    # Public API (existing)
│   │   │   │   │   │   └── webhooks/  # Stripe webhooks (existing)
│   │   │   │   │   └── cron/         # Cron endpoints (existing)
│   │   │   │   └── login/            # Login page (existing)
│   │   │   ├── lib/
│   │   │   │   ├── services/         # Business logic (existing + new)
│   │   │   │   │   ├── automation-worker.ts    # Existing
│   │   │   │   │   ├── billing-service.ts      # NEW: Token billing, Stripe Meters
│   │   │   │   │   ├── chat-relay-service.ts   # NEW: App→Hub→SW→OpenClaw
│   │   │   │   │   ├── config-generator.ts     # Existing (updated)
│   │   │   │   │   ├── push-notification.ts    # NEW: Expo Push service
│   │   │   │   │   ├── tenant-protocol.ts      # NEW: SW registration/heartbeat
│   │   │   │   │   └── ...                     # Other existing services
│   │   │   │   └── ...
│   │   │   ├── hooks/                # React Query hooks (existing)
│   │   │   └── components/           # UI components (existing)
│   │   ├── prisma/
│   │   │   ├── schema.prisma         # Shared Prisma schema (existing + new models)
│   │   │   ├── migrations/           # Prisma migrations
│   │   │   └── seed.ts               # Database seeding
│   │   ├── test/
│   │   │   ├── unit/                 # Existing unit tests (10 files)
│   │   │   ├── api/                  # NEW: API endpoint tests
│   │   │   └── integration/          # NEW: Hub↔SW protocol tests
│   │   ├── Dockerfile
│   │   ├── package.json
│   │   ├── next.config.ts
│   │   └── tsconfig.json
│   │
│   ├── website/                      # Website (letsbe.biz — separate Next.js app)
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── page.tsx          # Landing page
│   │   │   │   ├── onboarding/       # AI-powered onboarding flow
│   │   │   │   │   ├── business/     # Step 1: Business description
│   │   │   │   │   ├── tools/        # Step 2: Tool recommendation
│   │   │   │   │   ├── customize/    # Step 3: Customization
│   │   │   │   │   ├── server/       # Step 4: Server selection
│   │   │   │   │   ├── domain/       # Step 5: Domain setup
│   │   │   │   │   ├── agents/       # Step 6: Agent config (optional)
│   │   │   │   │   ├── payment/      # Step 7: Stripe checkout
│   │   │   │   │   └── status/       # Step 8: Provisioning status
│   │   │   │   ├── demo/             # Interactive demo page
│   │   │   │   └── pricing/          # Pricing page
│   │   │   └── lib/
│   │   │       ├── ai-classifier.ts  # Gemini Flash business classifier
│   │   │       └── resource-calc.ts  # Resource requirement calculator
│   │   ├── Dockerfile
│   │   ├── package.json
│   │   └── tsconfig.json
│   │
│   ├── mobile/                       # Mobile App (Expo Bare Workflow)
│   │   ├── src/
│   │   │   ├── screens/
│   │   │   │   ├── LoginScreen.tsx
│   │   │   │   ├── ChatScreen.tsx
│   │   │   │   ├── DashboardScreen.tsx
│   │   │   │   ├── ApprovalsScreen.tsx
│   │   │   │   ├── UsageScreen.tsx
│   │   │   │   ├── SettingsScreen.tsx
│   │   │   │   └── SecretsScreen.tsx
│   │   │   ├── components/
│   │   │   ├── hooks/
│   │   │   ├── stores/               # Zustand stores
│   │   │   ├── services/             # API client, push notifications
│   │   │   └── navigation/           # React Navigation
│   │   ├── app.json
│   │   ├── eas.json                  # EAS Build + Update config
│   │   ├── metro.config.js
│   │   ├── package.json
│   │   └── tsconfig.json
│   │
│   ├── shared-types/                 # Shared TypeScript types
│   │   ├── src/
│   │   │   ├── classification.ts     # Command classification types
│   │   │   ├── autonomy.ts           # Autonomy level types
│   │   │   ├── secrets.ts            # Secrets registry types
│   │   │   ├── protocol.ts           # Hub ↔ SW protocol types
│   │   │   ├── billing.ts            # Token metering types
│   │   │   ├── agents.ts             # Agent configuration types
│   │   │   └── index.ts              # Barrel export
│   │   ├── package.json
│   │   └── tsconfig.json
│   │
│   ├── shared-prisma/                # Shared Prisma client (generated)
│   │   ├── prisma/
│   │   │   └── schema.prisma         # → symlink to packages/hub/prisma/schema.prisma
│   │   ├── package.json
│   │   └── tsconfig.json
│   │
│   └── provisioner/                  # Provisioner (Bash — migrated from letsbe-ansible-runner)
│       ├── provision.sh              # Main entry point
│       ├── steps/
│       │   ├── step-01-system-update.sh
│       │   ├── step-02-docker-install.sh
│       │   ├── step-03-create-user.sh
│       │   ├── step-04-generate-secrets.sh
│       │   ├── step-05-deploy-stacks.sh
│       │   ├── step-06-nginx-configs.sh
│       │   ├── step-07-ssl-certs.sh
│       │   ├── step-08-backup-setup.sh
│       │   ├── step-09-firewall.sh
│       │   └── step-10-deploy-ai.sh      # REWRITTEN: OpenClaw + Safety Wrapper
│       ├── stacks/                   # Docker Compose files for 28+ tools
│       │   ├── chatwoot/
│       │   │   └── docker-compose.yml
│       │   ├── nextcloud/
│       │   │   └── docker-compose.yml
│       │   ├── letsbe/               # NEW: LetsBe AI stack
│       │   │   └── docker-compose.yml  # OpenClaw + Safety Wrapper + Secrets Proxy
│       │   └── ...
│       ├── nginx/                    # nginx configs for 33+ tools
│       ├── templates/                # Config templates
│       │   ├── openclaw-config.json5.tmpl
│       │   ├── safety-wrapper.json.tmpl
│       │   ├── tool-registry.json.tmpl
│       │   └── agent-templates/      # Per-business-type agent configs
│       ├── references/               # Tool cheat sheets (deployed to tenant)
│       │   ├── portainer.md
│       │   ├── nextcloud.md
│       │   ├── chatwoot.md
│       │   ├── ghost.md
│       │   ├── calcom.md
│       │   ├── stalwart.md
│       │   └── ...
│       ├── skills/                   # OpenClaw skills (deployed to tenant)
│       │   └── letsbe-tools/
│       │       └── SKILL.md          # Master tool skill
│       ├── agents/                   # Default agent configs (deployed to tenant)
│       │   ├── dispatcher/
│       │   │   └── SOUL.md
│       │   ├── it-admin/
│       │   │   └── SOUL.md
│       │   ├── marketing/
│       │   │   └── SOUL.md
│       │   ├── secretary/
│       │   │   └── SOUL.md
│       │   └── sales/
│       │       └── SOUL.md
│       ├── test/
│       │   ├── step-10.bats          # bats-core tests for step 10
│       │   ├── cleanup.bats          # n8n cleanup verification
│       │   └── full-run.bats         # Full provisioner integration test
│       ├── Dockerfile
│       └── package.json              # Minimal — just for monorepo workspace inclusion
│
├── test/                             # Cross-package integration tests
│   ├── docker-compose.integration.yml  # Full stack for integration tests
│   ├── fixtures/
│   │   ├── openclaw-config.json5
│   │   ├── safety-wrapper-config.json
│   │   ├── tool-registry.json
│   │   └── test-secrets.json
│   └── e2e/
│       ├── signup-to-chat.test.ts
│       ├── approval-flow.test.ts
│       └── secrets-never-leak.test.ts
│
├── docs/                             # Documentation (existing)
│   ├── technical/
│   ├── strategy/
│   ├── legal/
│   └── architecture-proposal/
│       └── claude/                   # This proposal
│
├── turbo.json
├── package.json                      # Root workspace config
├── tsconfig.base.json                # Shared TypeScript config
├── .gitignore
├── .eslintrc.js                      # Shared ESLint config
├── .prettierrc
└── README.md
```

---

## 4. Package Architecture

### Package Responsibilities

| Package | Language | Purpose | Depends On | Deployed As |
|---------|----------|---------|-----------|-------------|
| `safety-wrapper` | TypeScript | Command gating, tool execution, Hub comm, audit | `shared-types` | Docker container on tenant VPS |
| `secrets-proxy` | TypeScript | LLM traffic redaction (4-layer pipeline) | `shared-types` | Docker container on tenant VPS |
| `hub` | TypeScript (Next.js) | Admin dashboard, customer portal, billing, tenant protocol | `shared-types`, `shared-prisma` | Docker container on central server |
| `website` | TypeScript (Next.js) | Marketing site, onboarding flow | — | Docker container on central server |
| `mobile` | TypeScript (Expo) | Customer mobile app | `shared-types` | iOS/Android app (EAS Build) |
| `shared-types` | TypeScript | Type definitions shared across packages | — | npm workspace dependency |
| `shared-prisma` | TypeScript | Generated Prisma client | — | npm workspace dependency |
| `provisioner` | Bash | VPS provisioning scripts, tool stacks | — | Docker container (on-demand) |

### Package Size Estimates

| Package | Estimated LOC | Files | Build Output |
|---------|--------------|-------|-------------|
| `safety-wrapper` | ~3,000-4,000 | ~30 | ~200KB JS |
| `secrets-proxy` | ~1,500-2,000 | ~15 | ~100KB JS |
| `hub` | ~15,000+ (existing) + ~3,000 new | ~250+ | Next.js standalone |
| `website` | ~2,000-3,000 | ~20 | Next.js standalone |
| `mobile` | ~4,000-5,000 | ~40 | Expo bundle |
| `shared-types` | ~500-800 | ~10 | ~50KB JS |
| `provisioner` | ~5,000 (existing + new) | ~50+ | Bash scripts |

---

## 5. Dependency Graph

```
                    ┌──────────────┐
                    │ shared-types │
                    └──────┬───────┘
              ┌────────────┼────────────┬────────────┐
              │            │            │            │
     ┌────────▼──────┐ ┌──▼────────┐ ┌─▼──────┐ ┌──▼──────┐
     │safety-wrapper │ │secrets-   │ │  hub   │ │ mobile  │
     │               │ │proxy      │ │        │ │         │
     └───────────────┘ └───────────┘ └────┬───┘ └─────────┘
                                          │
                                   ┌──────▼──────┐
                                   │shared-prisma│
                                   └─────────────┘

    ┌───────────┐     ┌───────────┐
    │  website  │     │provisioner│
    │(no deps)  │     │(Bash, no  │
    │           │     │ TS deps)  │
    └───────────┘     └───────────┘
```

**Key constraints:**
- `shared-types` has ZERO dependencies. It's pure TypeScript type definitions.
- `shared-prisma` depends only on Prisma and the schema file.
- `safety-wrapper` and `secrets-proxy` never import from `hub` (no circular deps).
- `hub` never imports from `safety-wrapper` or `secrets-proxy` (communication via HTTP protocol).
- `website` is fully independent — no shared package dependencies.
- `provisioner` is Bash — no TypeScript dependencies at all.

---

## 6. Migration Plan

### Current State (5 Separate Repos)

```
letsbe-hub           → packages/hub (TypeScript, Next.js)
letsbe-ansible-runner → packages/provisioner (Bash)
letsbe-orchestrator   → DEPRECATED (capabilities → safety-wrapper)
letsbe-sysadmin-agent → DEPRECATED (capabilities → safety-wrapper)
letsbe-mcp-browser    → DEPRECATED (replaced by OpenClaw native browser)
```

### Migration Steps

#### Step 1: Create Monorepo (Week 1, Day 1-2)

```bash
# Create new repo
mkdir letsbe-biz && cd letsbe-biz
git init
npm init -y

# Install Turborepo
npm install turbo --save-dev

# Create workspace structure
mkdir -p packages/{safety-wrapper,secrets-proxy,hub,website,mobile,shared-types,shared-prisma,provisioner}

# Create turbo.json (from Section 2)
# Create root package.json (from Section 2)
# Create tsconfig.base.json
```

#### Step 2: Migrate Hub (Week 1, Day 1)

```bash
# Copy Hub source (preserve git history via subtree or fresh copy)
cp -r ../letsbe-hub/src packages/hub/src
cp -r ../letsbe-hub/prisma packages/hub/prisma
cp ../letsbe-hub/package.json packages/hub/
cp ../letsbe-hub/next.config.ts packages/hub/
cp ../letsbe-hub/tsconfig.json packages/hub/
cp ../letsbe-hub/Dockerfile packages/hub/

# Update Hub package.json:
# - name: "@letsbe/hub"
# - Add workspace dependency on shared-types, shared-prisma

# Verify Hub builds
cd packages/hub && npm install && npm run build
```

#### Step 3: Migrate Provisioner (Week 1, Day 1)

```bash
# Copy provisioner scripts
cp -r ../letsbe-ansible-runner/* packages/provisioner/

# Add minimal package.json for workspace inclusion
echo '{"name":"@letsbe/provisioner","private":true}' > packages/provisioner/package.json
```

#### Step 4: Create New Packages (Week 1, Day 2)

```bash
# shared-types — create from scratch
cd packages/shared-types
npm init -y --scope=@letsbe
# Add type definitions

# safety-wrapper — create from scratch
cd packages/safety-wrapper
npm init -y --scope=@letsbe
# Scaffold Express/Fastify server

# secrets-proxy — create from scratch
cd packages/secrets-proxy
npm init -y --scope=@letsbe
# Scaffold HTTP proxy
```

#### Step 5: Verify Everything Works (Week 1, Day 2)

```bash
# From repo root:
npm install               # Install all workspace dependencies
turbo run build            # Build all packages
turbo run typecheck        # Type check all packages
turbo run test             # Run all tests (Hub's existing 10 tests)
turbo run lint             # Lint all packages
```

#### Step 6: Archive Old Repos (Week 2)

Once the monorepo is confirmed working and the team has switched:

1. Mark `letsbe-orchestrator` as archived (deprecated)
2. Mark `letsbe-sysadmin-agent` as archived (deprecated)
3. Mark `letsbe-mcp-browser` as archived (deprecated)
4. Keep `letsbe-hub` and `letsbe-ansible-runner` read-only for reference
5. Update Gitea CI to point to new monorepo

### Git History Preservation

**Option A (Recommended): Fresh start with reference.**
- New monorepo gets a clean git history.
- Old repos remain accessible (read-only archive) for historical reference.
- This is cleaner and avoids complex git subtree merges.

**Option B: Preserve history via git subtree.**
- Use `git subtree add` to bring Hub and provisioner history into the monorepo.
- More complex but preserves `git blame` lineage.

**Recommendation:** Option A. The codebase is being substantially restructured. Historical blame on the old code is less valuable than a clean starting point. The old repos stay available for reference.

---

## 7. Development Workflow

### Daily Development

```bash
# Start all dev servers (Hub + Safety Wrapper + Secrets Proxy)
turbo run dev --parallel

# Run tests for a specific package
turbo run test --filter=safety-wrapper

# Run P0 tests only
turbo run test:p0

# Build a specific package
turbo run build --filter=secrets-proxy

# Type check everything
turbo run typecheck

# Lint everything
turbo run lint
```

### Adding a Shared Type

```bash
# 1. Add type to packages/shared-types/src/classification.ts
# 2. Export from index.ts
# 3. Import in consuming package:
#    import { CommandTier } from '@letsbe/shared-types';
# 4. Turbo automatically rebuilds shared-types before dependent packages
```

### Adding a New Package

```bash
# 1. Create directory
mkdir packages/new-package

# 2. Initialize
cd packages/new-package
npm init -y --scope=@letsbe

# 3. Add to root workspaces (already covered by packages/* glob)

# 4. Add to turbo.json pipeline if needed

# 5. Add Dockerfile if it's a deployed service
```

### Docker Development

```yaml
# docker-compose.dev.yml (root level, for local development)
services:
  postgres:
    image: postgres:16-alpine
    ports: ['5432:5432']
    environment:
      POSTGRES_DB: hub_dev
      POSTGRES_USER: hub
      POSTGRES_PASSWORD: devpass

  hub:
    build:
      context: .
      dockerfile: packages/hub/Dockerfile
    ports: ['3000:3000']
    environment:
      DATABASE_URL: postgresql://hub:devpass@postgres:5432/hub_dev
    depends_on: [postgres]

  safety-wrapper:
    build:
      context: .
      dockerfile: packages/safety-wrapper/Dockerfile
    ports: ['8200:8200']

  secrets-proxy:
    build:
      context: .
      dockerfile: packages/secrets-proxy/Dockerfile
    ports: ['8100:8100']
```

---

## 8. Monorepo Trade-offs

### Advantages Realized

| Advantage | Concrete Benefit |
|-----------|-----------------|
| **Atomic type changes** | Change `CommandTier` enum in `shared-types` → all consumers updated in same PR |
| **Turborepo caching** | Rebuild only changed packages; CI runs ~60% faster after first run |
| **Shared tooling** | One ESLint config, one Prettier config, one TypeScript base config |
| **Cross-package refactoring** | Rename a protocol field → update Safety Wrapper + Hub in one commit |
| **Single dependency tree** | No version conflicts between packages; hoisted node_modules |
| **Simplified onboarding** | Clone one repo → `npm install` → `turbo run dev` → everything running |

### Disadvantages Accepted

| Disadvantage | Mitigation |
|-------------|------------|
| **Larger repo size** | Turborepo's `--filter` flag runs only affected packages |
| **Bash in TypeScript monorepo** | Provisioner is loosely coupled — workspace inclusion is just for organization |
| **Mobile build complexity** | Expo has its own build system (EAS); it coexists but doesn't use Turbo for builds |
| **CI runs all checks** | Path-based triggers (see pipeline YAML) skip unrelated packages |
| **Single repo = single SPOF** | Gitea backup strategy; consider GitHub mirror for disaster recovery |

### When to Reconsider

The monorepo should be split if:
- The team grows beyond 8-10 engineers and package ownership boundaries become clear
- Mobile app development cadence diverges significantly from backend
- A package needs a fundamentally different build system or language (e.g., Rust Safety Wrapper rewrite)
- CI times exceed 20 minutes even with caching

None of these are likely before reaching 100 customers.

---

*End of Document — 09 Repository Structure*
