# Crafted SaaS - Crafted Web

🏆 **Niveau CRAFTED** - Software Craftsmanship, Web Only

## Configuration

- **Niveau**: Crafted (Software Craftsmanship)
- **Platform**: Web Only (Next.js)
- **Équipe**: 10-200+ développeurs
- **Durée**: 5-10+ ans (long-terme)
- **Users**: 10K-1M+ utilisateurs
- **Revenue**: $100K+ MRR

## Architecture

**Hexagonal Architecture** (Ports & Adapters) - Domain-Driven Design

```
apps/
└── web/                # Next.js 15 app

packages/
├── domain/             # ⭐ PURE BUSINESS LOGIC (ZERO deps)
│   ├── entities/       # Rich domain entities
│   ├── value-objects/  # Money, Email (immutable)
│   ├── use-cases/      # Application logic (< 10 lines)
│   └── repositories/   # Interfaces ONLY
│
├── api/                # Application layer (ultra-thin)
│   └── routers/        # tRPC routers (< 10 lines per procedure)
│
├── infrastructure/     # External implementations
│   ├── database/       # Prisma repositories
│   ├── payments/       # Stripe client
│   └── emails/         # Resend client
│
├── validators/         # Zod schemas (input validation)
├── database/           # Prisma schema + client
├── auth/               # Supabase Auth
└── ui/                 # shadcn/ui components
```

### Hexagonal Layers

```
┌─────────────────────────────────────────────┐
│         Application Layer (API)             │
│  • tRPC Routers (< 10 lines per procedure)  │
│  • Input validation (Zod)                   │
│  • Use case orchestration                   │
└─────────────────┬───────────────────────────┘
                  │
                  ↓
┌─────────────────────────────────────────────┐
│          Domain Layer (Core)                │
│  • Entities (User, Product)                 │
│  • Value Objects (Email, Money)             │
│  • Use Cases (CreateUser, CreateProduct)    │
│  • Repository Interfaces (ports)            │
│  • Result Pattern (no exceptions)           │
│  • ZERO external dependencies               │
└─────────────────┬───────────────────────────┘
                  │
                  ↓
┌─────────────────────────────────────────────┐
│       Infrastructure Layer (Adapters)       │
│  • PrismaUserRepository                     │
│  • PrismaProductRepository                  │
│  • StripeClient                             │
│  • ResendEmailService                       │
└─────────────────────────────────────────────┘
```

**Dependency Rule**: Dependencies point INWARD to domain, never outward.

## Règles de Code

| Aspect | Règle |
|--------|-------|
| **Max lignes/fonction** | 20 lignes |
| **Parameters** | Max 2 |
| **Duplication** | 0 duplication (❌ CI fail) |
| **Cyclomatic complexity** | < 5 |
| **SOLID** | Full + auditable |
| **Comments** | WHY + ADR reference |

## Testing

**Spec-First Testing** (Domain Layer) - 100% coverage enforced

### Domain Layer (Spec-First)
1. UNDERSTAND business rules first
2. Generate tests FIRST (they specify behavior)
3. Then generate implementation that satisfies tests

**Coverage Requirements**:
- ✅ Domain entities: 100% coverage
- ✅ Use-cases: 100% coverage
- ✅ Infrastructure: 80% coverage
- ✅ E2E complete test suite
- ✅ Architecture tests (dependency rules)

## Quick Start

```bash
# Install dependencies
pnpm install

# Setup environment
cp .env.example .env.local
# Edit .env.local with your keys

# Generate Prisma client
pnpm --filter @crafted/database db:generate

# Run domain tests (should pass 100%)
pnpm --filter @crafted/domain test

# Start dev server
pnpm --filter @crafted/web dev
```

## Domain Layer Examples

### Value Object (Email)
```typescript
// ZERO external dependencies
export class Email {
  private constructor(private value: string) {}

  static create(email: string): Result<Email, EmailInvalidError> {
    if (!this.isValid(email)) {
      return failure(new EmailInvalidError(email));
    }
    return success(new Email(email.toLowerCase().trim()));
  }

  private static isValid(email: string): boolean {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  }

  getValue(): string {
    return this.value;
  }
}
```

### Entity (User)
```typescript
export class User {
  private constructor(private props: UserProps) {}

  static create(props: UserProps): Result<User, UserInvalidError> {
    if (!props.name.trim()) {
      return failure(new UserInvalidError('Name cannot be empty'));
    }
    return success(new User(props));
  }

  suspend(): Result<User, UserInvalidError> {
    if (this.props.status === 'suspended') {
      return failure(new UserInvalidError('Already suspended'));
    }
    return success(new User({ ...this.props, status: 'suspended' }));
  }
}
```

### Use Case (CreateUser)
```typescript
export class CreateUser {
  constructor(private userRepository: IUserRepository) {}

  async execute(input: CreateUserInput): Promise<Result<User, Error>> {
    const emailResult = Email.create(input.email);
    if (emailResult.isFailure) return failure(emailResult.error);

    const userResult = User.create({ ...input, email: emailResult.value });
    if (userResult.isFailure) return failure(userResult.error);

    return this.userRepository.save(userResult.value);
  }
}
```

### Ultra-Thin Router (< 10 lines)
```typescript
export const userRouter = router({
  create: publicProcedure
    .input(z.object({ id: z.string(), email: z.string(), name: z.string() }))
    .mutation(async ({ input }) => {
      const useCase = new CreateUser(userRepository);
      return useCase.execute(input);
    }),
});
```

## Result Pattern

We use the **Result pattern** instead of exceptions in the domain layer:

```typescript
type Result<T, E> = Success<T> | Failure<E>

// Usage
const result = Email.create('test@example.com');
if (result.isSuccess) {
  console.log(result.value.getValue()); // 'test@example.com'
} else {
  console.error(result.error.message);
}
```

**Why?**
- Explicit error handling (no forgotten try-catch)
- Type-safe (errors in type signature)
- Pure (no side effects)
- Composable

See [ADR 002](./docs/adr/002-result-pattern-over-exceptions.md) for full rationale.

## Features Included

- ✅ Authentication (Supabase)
- ✅ Payments (Stripe)
- ✅ Emails (Resend)
- ✅ Database (Prisma + PostgreSQL)
- ✅ UI Components (shadcn/ui)
- ✅ Type-safe API (tRPC)
- ✅ Domain Layer (pure business logic)
- ✅ Hexagonal Architecture
- ✅ Result Pattern (no exceptions in domain)

## Stack

- **Frontend**: Next.js 15 (App Router), React 19, TypeScript, Tailwind
- **Backend**: tRPC 11, Zod validation
- **Database**: Prisma + PostgreSQL (Supabase)
- **Auth**: Supabase Auth
- **Payments**: Stripe
- **Emails**: Resend + React Email
- **Testing**: Vitest, React Testing Library, Playwright

## Philosophie

> "Build it right. Architecture-first, sustainable pour 10+ ans."

## Principes Craft Actifs (16/16 - TOUS)

### De Rapid (6/16)
- ✅ Type Safety (TypeScript strict + Zod)
- ✅ Linting (ESLint)
- ✅ Git Hooks (pre-commit)
- ✅ Error Handling
- ✅ Security (input validation + auth)
- ✅ Self-Documenting Code

### De Balanced (6/16)
- ✅ Architecture Layered
- ✅ Testing 70% coverage
- ✅ Code Review
- ✅ Documentation
- ✅ SOLID (tous principes)
- ✅ Performance

### Nouveaux en Crafted (4/16)
- ✅ **Hexagonal Architecture** (Ports & Adapters)
- ✅ **Domain-Driven Design** (DDD)
- ✅ **Spec-First Testing** (domain layer)
- ✅ **Architecture Decision Records** (ADR)

## Architecture Decision Records

Important architectural decisions are documented in `/docs/adr/`:

1. [Hexagonal Architecture](./docs/adr/001-hexagonal-architecture.md)
2. [Result Pattern Over Exceptions](./docs/adr/002-result-pattern-over-exceptions.md)
3. [Zero Dependencies in Domain Layer](./docs/adr/003-zero-dependencies-domain-layer.md)

## Testing Strategy

### Domain Layer (Spec-First)
```bash
# Run domain tests (100% coverage required)
pnpm --filter @crafted/domain test:coverage
```

Tests are written FIRST to specify behavior, then implementation satisfies tests.

### Infrastructure Layer
```bash
# Run infrastructure tests (80% coverage required)
pnpm --filter @crafted/infrastructure test:coverage
```

### E2E Tests
```bash
# Run end-to-end tests
pnpm test:e2e
```

## Quand utiliser Crafted ?

✅ **Utilisez Crafted si**:
- Équipe ≥ 10 développeurs
- Durée de vie attendue ≥ 5 ans
- Users ≥ 10K
- MRR ≥ $100K
- Systèmes critiques nécessitant fiabilité maximale
- Besoin de maintenabilité long-terme

❌ **N'utilisez PAS Crafted si**:
- Équipe < 10 développeurs → Utilisez **Balanced**
- MVP / Validation marché → Utilisez **Rapid**
- Budget serré / Deadline courte → Utilisez **Rapid** ou **Balanced**

## Documentation

- `CLAUDE.md` - Rules pour Claude Code
- `ARCHITECTURE.md` - Architecture détaillée
- `docs/adr/` - Architecture Decision Records
- `.cursorrules` - Rules pour Cursor
- `.clinerules` - Rules pour Cline
- `.windsurfrules` - Rules pour Windsurf

## Commandes Utiles

```bash
# Development
pnpm dev                          # Start all apps
pnpm dev --filter @crafted/web    # Start web only

# Testing
pnpm test                         # Run all tests
pnpm test:coverage                # Run with coverage
pnpm --filter @crafted/domain test  # Domain tests only

# Build
pnpm build                        # Build all
pnpm build --filter @crafted/web  # Build web only

# Database
pnpm --filter @crafted/database db:generate  # Generate Prisma client
pnpm --filter @crafted/database db:push      # Push schema changes
pnpm --filter @crafted/database db:migrate   # Run migrations

# Linting
pnpm lint                         # Lint all packages
pnpm format                       # Format with Prettier
```

## License

MIT
