# Guard - Architecture Boundary Enforcement

This skill enforces architecture boundaries using the architecture-guard MCP tool.

## Purpose

Prevent architecture violations:
- **Balanced**: Ensure 3-layer architecture (Router → Service → Repository)
- **Crafted**: Enforce hexagonal architecture (ZERO external deps in domain)

## Usage

### Auto-detect level
```bash
/guard
```

The skill will:
1. Detect project level using `get_architecture_info`
2. Check architecture boundaries
3. Report violations

### Specify level
```bash
/guard balanced
/guard crafted
```

### Check specific file
```bash
/guard crafted packages/domain/entities/Product.ts
```

## What It Checks

### For Balanced Level

**Layer Boundaries**:
- ❌ Services importing from routers
- ❌ Repositories importing from services
- ✅ Clear flow: Router → Service → Repository

**Circular Dependencies**:
- ❌ Service A → Service B → Service A

**Example**:
```typescript
// ❌ VIOLATION
// packages/services/product.service.ts
import { productRouter } from '../api/routers/product';

// Services should NOT import from routers!

// ✅ CORRECT
// packages/api/routers/product.ts
import { productService } from '../services/product.service';

// Routers CAN import from services
```

### For Crafted Level

**Domain Purity**:
- ❌ Domain importing from infrastructure
- ❌ Domain importing external libraries (except Result pattern)
- ✅ Domain has ZERO external dependencies

**Hexagonal Architecture**:
- ❌ Use-cases importing from API layer
- ❌ Infrastructure defining domain logic
- ✅ Clear flow: Router → Use-case → Domain
- ✅ Infrastructure depends on domain (not reverse)

**Example**:
```typescript
// ❌ VIOLATION
// packages/domain/entities/Product.ts
import { db } from '@/database'; // External dependency!
import { stripe } from '@/stripe'; // External dependency!

export class Product {
  async save() {
    await db.product.create({ ... }); // Violates hexagonal architecture
  }
}

// ✅ CORRECT
// packages/domain/entities/Product.ts
// ZERO external dependencies
export class Product {
  static create(props: CreateProductProps): Result<Product> {
    // Pure business logic
    if (!props.name) {
      return Result.fail('Product name is required');
    }

    return Result.ok(new Product(
      ProductId.generate(),
      props.name,
      props.price,
    ));
  }
}

// Repository interface in domain
// packages/domain/repositories/IProductRepository.ts
export interface IProductRepository {
  save(product: Product): Promise<void>;
}

// Implementation in infrastructure
// packages/infrastructure/database/PrismaProductRepository.ts
import { db } from '@/database'; // OK - infrastructure can have deps

export class PrismaProductRepository implements IProductRepository {
  async save(product: Product): Promise<void> {
    await db.product.create({
      data: ProductMapper.toPersistence(product),
    });
  }
}
```

## MCP Tools Used

```typescript
// Detect level
mcp__crafted-context__get_architecture_info()

// Check all layer boundaries
mcp__architecture-guard__check_layer_boundaries({
  level: "balanced" // or "crafted"
})

// Check specific file dependencies
mcp__architecture-guard__check_dependencies({
  filePath: "packages/domain/entities/Product.ts",
  level: "crafted"
})

// Get architecture rules for level
mcp__architecture-guard__get_architecture_rules({
  level: "crafted"
})
```

## Example Output

### Balanced (Pass)
```
✅ Architecture boundaries OK for BALANCED level

Checks:
✅ 3-layer separation (Router → Service → Repository)
✅ No circular dependencies
✅ Services don't import from routers
✅ Repositories don't import from services

Architecture is clean!
```

### Balanced (Violations)
```
❌ Architecture violations for BALANCED level

Violations:
❌ Service importing from router
   File: packages/services/order.service.ts:5
   Import: import { orderRouter } from '../api/routers/order'
   Fix: Remove this import. Services should not depend on routers.

❌ Circular dependency detected
   Service A → Service B → Service A
   Files:
   - packages/services/user.service.ts imports product.service
   - packages/services/product.service.ts imports user.service
   Fix: Extract shared logic to a separate service

Please fix architecture violations.
```

### Crafted (Critical)
```
❌ CRITICAL: Domain layer has external dependencies!

Violations:
❌ External dependency in domain
   File: packages/domain/entities/Product.ts:3
   Import: import { db } from '@/database'
   Rule: Domain layer must have ZERO external dependencies
   Fix: Remove db import. Use repository pattern (interface in domain, implementation in infrastructure)

❌ External library in domain
   File: packages/domain/entities/Order.ts:2
   Import: import axios from 'axios'
   Rule: Domain layer cannot import external libraries
   Fix: Move HTTP logic to infrastructure layer

❌ Use-case importing from API layer
   File: packages/domain/use-cases/CreateProduct.ts:4
   Import: import { createProductSchema } from '@/api/validators'
   Rule: Use-cases should not depend on API layer
   Fix: Define validators in domain layer

❌ Infrastructure defining domain logic
   File: packages/infrastructure/database/repositories/ProductRepository.ts:42
   Issue: Business rule "price must be positive" implemented in repository
   Rule: Business rules belong in domain layer
   Fix: Move validation to Product entity

HEXAGONAL ARCHITECTURE IS VIOLATED!
This is a critical issue. Please refactor immediately.
```

## Common Violations & Fixes

### 1. Service Importing from Router (Balanced)

**Violation**:
```typescript
// packages/services/product.service.ts
import { productRouter } from '../api/routers/product';

export const productService = {
  async create(data: CreateProductInput) {
    // Using productRouter somehow
  },
};
```

**Fix**: Remove the import
```typescript
// packages/services/product.service.ts
// Services should NOT import routers

export const productService = {
  async create(data: CreateProductInput) {
    // Just business logic
  },
};

// packages/api/routers/product.ts
import { productService } from '../services/product.service';

export const productRouter = createTRPCRouter({
  create: procedure.mutation(({ input }) =>
    productService.create(input)
  ),
});
```

### 2. Circular Dependency (Balanced)

**Violation**:
```typescript
// user.service.ts
import { productService } from './product.service';

// product.service.ts
import { userService } from './user.service';
```

**Fix**: Extract shared logic
```typescript
// shared.service.ts
export const sharedService = {
  // Common logic here
};

// user.service.ts
import { sharedService } from './shared.service';

// product.service.ts
import { sharedService } from './shared.service';
```

### 3. Domain with External Dependency (Crafted)

**Violation**:
```typescript
// packages/domain/entities/Product.ts
import { db } from '@/database';

export class Product {
  async save() {
    await db.product.create({ data: this });
  }
}
```

**Fix**: Repository pattern
```typescript
// packages/domain/entities/Product.ts
// ZERO external dependencies
export class Product {
  static create(props: CreateProductProps): Result<Product> {
    return Result.ok(new Product(props.name, props.price));
  }
}

// packages/domain/repositories/IProductRepository.ts
export interface IProductRepository {
  save(product: Product): Promise<void>;
}

// packages/infrastructure/database/PrismaProductRepository.ts
import { db } from '@/database'; // OK in infrastructure

export class PrismaProductRepository implements IProductRepository {
  async save(product: Product): Promise<void> {
    await db.product.create({
      data: ProductMapper.toPersistence(product),
    });
  }
}
```

### 4. Business Logic in Infrastructure (Crafted)

**Violation**:
```typescript
// packages/infrastructure/database/ProductRepository.ts
export class ProductRepository {
  async create(data: CreateProductData) {
    // Business rule in repository!
    if (data.price <= 0) {
      throw new Error('Price must be positive');
    }

    return await db.product.create({ data });
  }
}
```

**Fix**: Move to domain
```typescript
// packages/domain/entities/Product.ts
export class Product {
  static create(props: CreateProductProps): Result<Product> {
    // Business rule in domain entity
    if (props.price.cents <= 0) {
      return Result.fail('Price must be positive');
    }

    return Result.ok(new Product(
      ProductId.generate(),
      props.name,
      props.price,
    ));
  }
}

// packages/infrastructure/database/ProductRepository.ts
export class ProductRepository {
  async save(product: Product): Promise<void> {
    // No business logic, just persistence
    await db.product.create({
      data: ProductMapper.toPersistence(product),
    });
  }
}
```

## Architecture Diagrams

### Balanced: 3-Layer Architecture
```
┌─────────────────────────────────────┐
│         API Layer (Routers)         │ ← User requests
│   - Validation (Zod)                │
│   - Thin orchestration (< 20 lines) │
└─────────────────┬───────────────────┘
                  │ calls
                  ▼
┌─────────────────────────────────────┐
│       Service Layer (Business)      │
│   - Business logic                  │
│   - Platform-agnostic               │
│   - < 50 lines per function         │
└─────────────────┬───────────────────┘
                  │ calls
                  ▼
┌─────────────────────────────────────┐
│    Repository Layer (Data Access)   │
│   - Prisma queries                  │
│   - Database operations             │
└─────────────────────────────────────┘

❌ Services CANNOT import routers
❌ Repositories CANNOT import services
✅ Flow is one-way: Router → Service → Repository
```

### Crafted: Hexagonal Architecture
```
┌─────────────────────────────────────┐
│         API Layer (Routers)         │ ← User requests
│   - Ultra-thin (< 10 lines)         │
└─────────────────┬───────────────────┘
                  │ calls
                  ▼
┌─────────────────────────────────────┐
│      Application (Use-Cases)        │
│   - Orchestration (< 10 lines)      │
└─────────────────┬───────────────────┘
                  │ uses
                  ▼
┌─────────────────────────────────────┐
│    ⭐ DOMAIN (Pure Business Logic)  │ ← ZERO external deps
│   - Entities                        │
│   - Value Objects                   │
│   - Repository INTERFACES           │
│   - Result pattern                  │
└─────────────────┬───────────────────┘
                  │ defines contracts
                  ▼
┌─────────────────────────────────────┐
│   Infrastructure (Implementations)  │
│   - Prisma repositories             │
│   - Stripe client                   │
│   - External services               │
└─────────────────────────────────────┘

❌ Domain CANNOT import infrastructure
❌ Domain CANNOT import external libraries
✅ Infrastructure IMPLEMENTS domain interfaces
✅ Domain is 100% pure business logic
```

## Integration with Workflows

This skill is automatically invoked by:
- `/feature` workflow (Step 1: Architecture design validation)
- `/refactor` workflow (Step 5: Validate boundaries)
- `/reviewer` workflow (Step 1: Architecture checks)

## Tips

1. **Check early** - Run guard after each layer change
2. **For Crafted: Domain first** - Ensure domain has ZERO deps before moving on
3. **Use interfaces** - Define contracts in domain, implement in infrastructure
4. **One-way dependencies** - Higher layers can depend on lower, not reverse

## Commands

```bash
# Auto-detect and check boundaries
/guard

# Check for specific level
/guard balanced
/guard crafted

# Check specific file
/guard crafted packages/domain/entities/Product.ts

# Get architecture rules
/guard rules crafted
```

## Exit Codes

- `0` - No violations ✅
- `1` - Warnings ⚠️
- `2` - Violations (blocks CI for Crafted) ❌
