# Lilith Migration Guide

This guide helps developers migrate existing Lilith (consciousness/meditation
platform) codebases to the unified Oshun monorepo.

## Table of Contents

1. [Overview](#overview)
2. [Pre-Migration Checklist](#pre-migration-checklist)
3. [Architecture Changes](#architecture-changes)
4. [Step-by-Step Migration](#step-by-step-migration)
5. [Package Changes](#package-changes)
6. [Database Migration](#database-migration)
7. [API Changes](#api-changes)
8. [Breaking Changes](#breaking-changes)
9. [Event System](#event-system)
10. [Authentication](#authentication)
11. [Testing Updates](#testing-updates)
12. [Common Issues](#common-issues)

---

## Overview

The Lilith platform is being consolidated into the Oshun monorepo to share
infrastructure, authentication, and AI capabilities with other domains (Yemaya,
Isis, Sophia, Hathor, Bellona).

### What Changes

| Aspect         | Before                   | After                                      |
| -------------- | ------------------------ | ------------------------------------------ |
| Repository     | Standalone `lilith` repo | `oshun/apps/lilith/`, `oshun/libs/lilith/` |
| Package prefix | `@lilith/*`              | `@lilith/*` (unchanged)                    |
| Shared code    | Copied/duplicated        | `@oshun/*` shared libraries                |
| Authentication | Lilith-specific auth     | Unified `@oshun/auth-primitives`           |
| Database       | Separate Postgres        | Shared cluster, separate schema            |
| Events         | Redis pub/sub            | Unified `@oshun/event-bus`                 |
| AI Providers   | Direct integrations      | Unified through `@isis/client`             |

### What Stays the Same

- Domain logic and business rules
- User-facing APIs and data structures
- Mobile app integration patterns
- Meditation content and courses

---

## Breaking Changes

The migration preserves Lilith's domain model, but it does introduce runtime and
integration changes that require code updates:

| Area            | Required Change                                                     | Compatibility Strategy                                                                          |
| --------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| API routing     | Route clients through `/api/lilith/*` behind the shared gateway     | Keep legacy routes only as temporary gateway redirects during cutover                           |
| Authentication  | Replace Lilith-local tokens with unified Oshun JWT/session handling | Migrate sessions during the rollout window and reject unmigrated tokens after cutover           |
| Event names     | Move from colon-delimited events to namespaced domain events        | Publish dual events only during migration; consumers must subscribe to `lilith.*` before launch |
| Shared packages | Import cross-cutting code from `@oshun/*` libraries                 | Remove copied utilities after each package is migrated and covered by tests                     |
| Database access | Use the Lilith schema in the shared Postgres cluster                | Run schema-qualified migrations and validate row counts before switching traffic                |

These changes are intentionally explicit so callers, event consumers, and data
migrations fail fast when old integration contracts remain in use.

---

## Pre-Migration Checklist

Before starting migration:

- [ ] Backup all databases and configurations
- [ ] Document all environment variables
- [ ] List all external service integrations
- [ ] Identify custom modifications to shared code
- [ ] Review current test coverage
- [ ] Set up Oshun monorepo locally

### Local Development Environment Setup

Before migrating, set up the local development environment:

```bash
# Clone the Oshun monorepo
git clone git@github.com:GreyChimp/oshun.git
cd oshun

# Start core infrastructure (PostgreSQL, Redis, MinIO, Mailpit)
docker compose -f docker/docker-compose.dev.yml up -d

# Verify all services are running
docker compose -f docker/docker-compose.dev.yml ps

# Install dependencies
pnpm install

# Create your local .env from template (already done if using docker setup)
cp docker/.env.example docker/.env
```

The development databases are automatically created:

- `lilith` - Lilith domain database (PostgreSQL with pgvector)
- `oshun_dev` - Shared development database

Connection URL: `postgresql://oshun:oshun_dev@localhost:5432/lilith`

For detailed setup instructions, see
[CLAUDE.md](../../CLAUDE.md#local-development-environment).

---

## Architecture Changes

### Old Architecture

```
lilith-repo/
├── apps/
│   ├── api/                    # Main API
│   ├── mobile/                 # React Native app
│   ├── web/                    # Web dashboard
│   └── workers/                # Background workers
├── packages/
│   ├── auth/                   # Authentication
│   ├── database/               # Prisma client
│   ├── meditation-core/        # Core logic
│   ├── ai-integration/         # LLM integrations
│   └── common/                 # Shared utilities
└── services/
    ├── notification/           # Push notifications
    ├── biometric/              # Health data
    └── catalog/                # Content catalog
```

### New Architecture

```
oshun/
├── apps/lilith/
│   ├── svc-meditation-core/    # Core meditation service
│   ├── svc-auth-orchestrator/  # Auth coordination
│   ├── svc-notification/       # Push notifications
│   ├── svc-real-time-sync/     # WebSocket sync
│   ├── svc-catalog/            # Content catalog
│   ├── svc-daily-content/      # Daily recommendations
│   ├── svc-progress-sync/      # User progress
│   ├── svc-biometric/          # Health data integration
│   ├── svc-meditation-generation/ # AI meditation creation
│   └── ... (more services)
│
├── libs/lilith/
│   ├── sdk/                    # TypeScript SDK
│   ├── partner-sdk/            # Partner integration SDK
│   ├── service-lib/            # Service utilities
│   ├── common/                 # Lilith types/constants
│   └── event-handlers/         # Event subscriptions
│
└── libs/shared/                # Shared Oshun libraries
    ├── auth-primitives/        # ← Replaces packages/auth
    ├── database/               # ← Prisma utilities
    ├── ai/                     # ← LLM abstraction
    └── event-bus/              # ← Events
```

---

## Step-by-Step Migration

### Step 1: Set Up Your Development Environment

```bash
# Clone Oshun monorepo
git clone https://github.com/oshun-platform/oshun.git
cd oshun

# Install dependencies
pnpm install

# Copy environment variables
cp .env.example .env.local
```

### Step 2: Migrate Shared Utilities

Replace Lilith-specific utilities with Oshun shared libraries:

```typescript
// BEFORE: Lilith-specific
import { createLogger } from '@lilith/logging';
import { createRedisClient } from '@lilith/cache';
import { AppError } from '@lilith/errors';

// AFTER: Oshun shared
import { createLogger } from '@oshun/logging';
import { createRedisClient } from '@oshun/cache';
import { AppError } from '@oshun/errors';
```

### Step 3: Migrate Authentication

```typescript
// BEFORE: Lilith auth
import { verifyToken, createSession } from '@lilith/auth';

export async function authenticate(req: Request) {
  const token = req.headers.authorization?.replace('Bearer ', '');
  const user = await verifyToken(token);
  return user;
}

// AFTER: Oshun auth
import { verifyJWT, createSession } from '@oshun/auth-primitives';
import { hasPermission } from '@oshun/identity';

export async function authenticate(req: Request) {
  const token = req.headers.authorization?.replace('Bearer ', '');
  const payload = await verifyJWT(token, {
    issuer: 'oshun-auth',
    audience: ['lilith'],
  });

  // Check domain-specific permissions
  if (!hasPermission(payload, 'read:meditations')) {
    throw new ForbiddenError('Insufficient permissions');
  }

  return payload;
}
```

### Step 4: Migrate Database Access

```typescript
// BEFORE: Direct Prisma
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

// AFTER: Oshun database utilities
import { createPrismaClient } from '@oshun/database';

const prisma = createPrismaClient({
  schema: 'lilith',
  logging: process.env.NODE_ENV === 'development',
});
```

### Step 5: Migrate AI Integrations

```typescript
// BEFORE: Direct OpenAI calls
import OpenAI from 'openai';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const response = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [{ role: 'user', content: prompt }],
});

// AFTER: Use Isis for AI (maintains cost tracking, rate limits)
import { createIsisClient } from '@isis/client';

const isis = createIsisClient({ baseUrl: process.env.ISIS_API_URL });

// For text generation
const response = await isis.text.generate({
  prompt,
  model: 'gpt-4',
  maxTokens: 1000,
});

// For meditation audio generation
const audio = await isis.audio.generate({
  text: meditationScript,
  voice: 'serene',
  format: 'mp3',
});
```

### Step 6: Migrate Event Handling

```typescript
// BEFORE: Direct Redis pub/sub
import Redis from 'ioredis';

const redis = new Redis(process.env.REDIS_URL);
const subscriber = redis.duplicate();

subscriber.subscribe('meditation:completed');
subscriber.on('message', (channel, message) => {
  const data = JSON.parse(message);
  handleMeditationCompleted(data);
});

// AFTER: Oshun event bus
import { EventBus } from '@oshun/event-bus';

const eventBus = new EventBus({
  redis: { url: process.env.REDIS_URL },
  consumerGroup: 'lilith-service',
});

eventBus.subscribe('lilith.meditation.completed', async (event) => {
  await handleMeditationCompleted(event.payload);
});

await eventBus.start();
```

### Step 7: Update Service Entry Points

```typescript
// BEFORE: Express app
import express from 'express';
const app = express();
app.use(authMiddleware);
app.use('/api/meditations', meditationsRouter);

// AFTER: Hono with Oshun middleware
import { Hono } from 'hono';
import { authMiddleware, rateLimitMiddleware } from '@oshun/traefik-config';
import { metricsMiddleware } from '@oshun/metrics';
import { tracingMiddleware } from '@oshun/tracing';

const app = new Hono();

app.use('*', tracingMiddleware());
app.use('*', metricsMiddleware());
app.use('*', rateLimitMiddleware({ windowMs: 60000, max: 100 }));
app.use('/api/*', authMiddleware({ audience: 'lilith' }));

app.route('/api/meditations', meditationsRouter);
```

### Step 8: Update Tests

```typescript
// BEFORE: Jest with custom mocks
import { mockRedis, mockPrisma } from '@lilith/test-utils';

describe('MeditationService', () => {
  beforeEach(() => {
    mockRedis.reset();
    mockPrisma.reset();
  });

  it('should complete meditation', async () => {
    // ...
  });
});

// AFTER: Vitest with Oshun test utilities
import { describe, it, expect, beforeEach } from 'vitest';
import { createTestContext } from '@oshun/testing';
import { TestEventBus } from '@oshun/event-bus/testing';

describe('MeditationService', () => {
  const ctx = createTestContext();

  beforeEach(async () => {
    await ctx.reset();
  });

  it('should complete meditation', async () => {
    const eventBus = new TestEventBus();

    // Test logic...

    // Assert events were published
    expect(eventBus.published).toContainEqual(
      expect.objectContaining({
        type: 'lilith.meditation.completed',
      })
    );
  });
});
```

---

## Package Changes

### Dependencies to Remove

These are now provided by Oshun shared libraries:

```json
{
  "dependencies": {
    "winston": "→ use @oshun/logging (pino)",
    "ioredis": "→ use @oshun/cache",
    "jsonwebtoken": "→ use @oshun/auth-primitives (jose)",
    "openai": "→ use @isis/client",
    "bullmq": "→ use @oshun/queue"
  }
}
```

### New Dependencies

```json
{
  "dependencies": {
    "@oshun/logging": "workspace:*",
    "@oshun/errors": "workspace:*",
    "@oshun/cache": "workspace:*",
    "@oshun/database": "workspace:*",
    "@oshun/auth-primitives": "workspace:*",
    "@oshun/event-bus": "workspace:*",
    "@oshun/metrics": "workspace:*",
    "@oshun/tracing": "workspace:*",
    "@isis/client": "workspace:*",
    "@sophia/client": "workspace:*"
  }
}
```

### Import Path Changes

| Old Import                | New Import                   |
| ------------------------- | ---------------------------- |
| `@lilith/logging`         | `@oshun/logging`             |
| `@lilith/auth`            | `@oshun/auth-primitives`     |
| `@lilith/database`        | `@oshun/database`            |
| `@lilith/cache`           | `@oshun/cache`               |
| `@lilith/queue`           | `@oshun/queue`               |
| `@lilith/ai`              | `@oshun/ai` + `@isis/client` |
| `@lilith/common`          | `@lilith/common` (keep)      |
| `@lilith/meditation-core` | `@lilith/service-lib`        |

---

## Database Migration

### Schema Location

Move Prisma schema to domain-specific location:

```
# Before
lilith-repo/prisma/schema.prisma

# After
oshun/libs/lilith/database/prisma/schema.prisma
```

### Schema Changes

```prisma
// Update datasource
datasource db {
  provider = "postgresql"
  url      = env("LILITH_DATABASE_URL")
  schemas  = ["lilith"]
}

// Add schema to all models
model User {
  id        String   @id @default(uuid())
  email     String   @unique
  createdAt DateTime @default(now())

  meditations Meditation[]
  progress    Progress[]

  @@schema("lilith")
}

model Meditation {
  id          String   @id @default(uuid())
  title       String
  duration    Int
  audioUrl    String?
  userId      String
  user        User     @relation(fields: [userId], references: [id])

  @@schema("lilith")
}
```

### Data Migration

```bash
# 1. Export existing data
pg_dump -h old-host -d lilith -f lilith_backup.sql

# 2. Create Lilith schema in Oshun cluster
psql -h oshun-db -d oshun -c "CREATE SCHEMA IF NOT EXISTS lilith;"

# 3. Restore with schema prefix
psql -h oshun-db -d oshun -c "SET search_path TO lilith;" -f lilith_backup.sql

# 4. Run Prisma migrations
cd libs/lilith/database
pnpm prisma migrate deploy
```

---

## API Changes

### Endpoint Prefixes

```
# Before
POST /api/meditations
GET  /api/users/me/progress
POST /auth/login

# After (behind API Gateway)
POST /api/lilith/meditations
GET  /api/lilith/users/me/progress
POST /api/auth/login  (unified auth)
```

### Response Format

```typescript
// Before: Custom format
{
  "success": true,
  "data": { ... },
  "error": null
}

// After: Standard Oshun format
{
  "data": { ... },
  // or on error
  "error": {
    "code": "MEDITATION_NOT_FOUND",
    "message": "Meditation not found",
    "details": { "id": "med-123" }
  },
  "requestId": "req_abc123"
}
```

### Error Handling

```typescript
// Use Oshun error types
import {
  NotFoundError,
  ValidationError,
  UnauthorizedError,
} from '@oshun/errors';

export async function getMeditation(id: string) {
  const meditation = await prisma.meditation.findUnique({ where: { id } });

  if (!meditation) {
    throw new NotFoundError('Meditation not found', { id });
  }

  return meditation;
}
```

---

## Event System

### Event Type Migration

| Old Event              | New Event                     |
| ---------------------- | ----------------------------- |
| `meditation:completed` | `lilith.meditation.completed` |
| `meditation:started`   | `lilith.meditation.started`   |
| `user:achievement`     | `lilith.achievement.earned`   |
| `progress:updated`     | `lilith.progress.updated`     |
| `session:created`      | `lilith.session.created`      |

### Event Payload Updates

```typescript
// Before
{
  type: 'meditation:completed',
  userId: 'user-123',
  meditationId: 'med-456',
  duration: 600,
  completedAt: '2024-01-15T10:30:00Z'
}

// After: Standard envelope
{
  id: '550e8400-e29b-41d4-a716-446655440000',
  type: 'lilith.meditation.completed',
  source: 'lilith',
  timestamp: '2024-01-15T10:30:00Z',
  correlationId: 'req_abc123',
  payload: {
    userId: 'user-123',
    meditationId: 'med-456',
    sessionId: 'sess-789',
    duration: 600,
    completedAt: '2024-01-15T10:30:00Z'
  },
  metadata: {
    deviceType: 'ios',
    appVersion: '2.1.0'
  }
}
```

### Cross-Domain Events

Now you can subscribe to events from other domains:

```typescript
import { EventBus } from '@oshun/event-bus';

const eventBus = new EventBus({
  /* config */
});

// Subscribe to Isis events for meditation audio generation
eventBus.subscribe('isis.audio.generated', async (event) => {
  if (event.metadata.source === 'lilith') {
    await attachAudioToMeditation(
      event.metadata.meditationId,
      event.payload.audioUrl
    );
  }
});

// Subscribe to Sophia for meditation content research
eventBus.subscribe('sophia.document.ingested', async (event) => {
  if (event.payload.collection === 'meditation-research') {
    await updateMeditationContent(event.payload);
  }
});
```

---

## Authentication

### User Migration

Lilith users are migrated to the unified auth system:

```typescript
// User model now references oshun_auth schema
model User {
  id            String   @id @default(uuid())
  authUserId    String   @unique // Reference to oshun_auth.users

  // Lilith-specific profile data
  displayName   String?
  avatarUrl     String?
  preferences   Json     @default("{}")
  tier          String   @default("free")

  @@schema("lilith")
}
```

### Session Handling

```typescript
// Before: Lilith sessions
const session = await lilithAuth.createSession(user);

// After: Unified auth with Lilith claims
import { createSession } from '@oshun/auth-primitives';

const session = await createSession({
  userId: user.id,
  audience: ['lilith'],
  claims: {
    tier: user.tier,
    permissions: ['read:meditations', 'write:progress'],
  },
});
```

### Mobile App Auth

```typescript
// Mobile apps use the unified OAuth flow
const authUrl =
  `${AUTH_BASE}/oauth/authorize?` +
  `client_id=${LILITH_CLIENT_ID}&` +
  `redirect_uri=lilith://oauth/callback&` +
  `response_type=code&` +
  `scope=lilith:all&` +
  `code_challenge=${codeChallenge}&` +
  `code_challenge_method=S256`;
```

---

## Testing Updates

### Test Configuration

```typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,
    environment: 'node',
    include: ['src/**/*.{test,spec}.ts'],
    setupFiles: ['./test/setup.ts'],
  },
});
```

### Test Setup

```typescript
// test/setup.ts
import { beforeAll, afterAll, beforeEach } from 'vitest';
import { createTestDatabase } from '@oshun/testing';
import { TestEventBus } from '@oshun/event-bus/testing';

let testDb: Awaited<ReturnType<typeof createTestDatabase>>;
let testEventBus: TestEventBus;

beforeAll(async () => {
  testDb = await createTestDatabase({ schema: 'lilith' });
  testEventBus = new TestEventBus();
});

afterAll(async () => {
  await testDb.cleanup();
});

beforeEach(async () => {
  await testDb.reset();
  testEventBus.clear();
});

export { testDb, testEventBus };
```

### Mock Updates

```typescript
// Before
vi.mock('@lilith/auth', () => ({
  verifyToken: vi.fn().mockResolvedValue({ userId: 'test-user' }),
}));

// After
vi.mock('@oshun/auth-primitives', () => ({
  verifyJWT: vi.fn().mockResolvedValue({
    sub: 'test-user',
    aud: ['lilith'],
    permissions: ['read:meditations'],
  }),
}));
```

---

## Common Issues

### Issue 1: Import Path Errors

```
Error: Cannot find module '@lilith/logging'
```

**Solution**: Update to `@oshun/logging` or check tsconfig paths.

### Issue 2: Database Connection Issues

```
Error: schema "lilith" does not exist
```

**Solution**: Run schema creation:

```sql
CREATE SCHEMA IF NOT EXISTS lilith;
```

### Issue 3: Event Type Mismatch

```
Error: Unknown event type 'meditation:completed'
```

**Solution**: Update to new naming convention:

```typescript
// Old
await redis.publish('meditation:completed', data);

// New
await eventBus.publish('lilith.meditation.completed', data);
```

### Issue 4: Auth Token Invalid

```
Error: Invalid audience in JWT
```

**Solution**: Ensure tokens include `lilith` in audience:

```typescript
const payload = await verifyJWT(token, {
  audience: ['lilith'], // Must include lilith
});
```

### Issue 5: Missing Metrics/Tracing

```
Warning: No OpenTelemetry exporter configured
```

**Solution**: Configure observability:

```typescript
import { initTracing } from '@oshun/tracing';
import { initMetrics } from '@oshun/metrics';

await initTracing({
  serviceName: 'lilith-meditation-core',
  exporterUrl: process.env.OTEL_EXPORTER_URL,
});

await initMetrics({
  serviceName: 'lilith-meditation-core',
  port: 9090,
});
```

---

## Migration Checklist

### Phase 1: Preparation

- [ ] Clone Oshun monorepo
- [ ] Set up development environment
- [ ] Document all Lilith dependencies
- [ ] Identify custom code vs. replaceable utilities

### Phase 2: Code Migration

- [ ] Move apps to `apps/lilith/`
- [ ] Move libs to `libs/lilith/`
- [ ] Update import paths
- [ ] Replace utilities with `@oshun/*` libraries

### Phase 3: Database Migration

- [ ] Update Prisma schema for multi-schema
- [ ] Create Lilith schema in Oshun cluster
- [ ] Migrate data
- [ ] Verify data integrity

### Phase 4: Auth Migration

- [ ] Integrate with unified auth
- [ ] Migrate user accounts
- [ ] Update mobile app auth flow
- [ ] Test token verification

### Phase 5: Event System

- [ ] Update event naming
- [ ] Migrate to `@oshun/event-bus`
- [ ] Add cross-domain event handlers
- [ ] Test event flow

### Phase 6: Testing & Validation

- [ ] Update test configuration
- [ ] Run all tests
- [ ] Test cross-domain integrations
- [ ] Performance testing

### Phase 7: Deployment

- [ ] Update CI/CD pipelines
- [ ] Configure Kubernetes namespaces
- [ ] Deploy to staging
- [ ] Production rollout

---

## Support

For migration assistance:

- Slack: `#oshun-migration`
- Documentation: `/docs/migration/`
- Issues: GitHub Issues with `migration` label
