Back to Brain Lab Skill · System Architecture · system-architecture/
Skill Claude

System Architecture

system-architecture/

2 views 0 downloads

Pick the architecture pattern and the technology on purpose, before framework details: pattern trade-offs, design workflows and decision guides for databases, queues and APIs.

System Architecture: Brain Lab skill for Claude Code

Technology-agnostic system design, pick the pattern and the tech BEFORE touching framework mechanics.

Why use it

  • Jumping straight to schemas and modules bakes in an architecture nobody chose.
  • "Which database / queue / API style?" answered by habit rather than by the actual constraints.
  • Migrations and scale limits discovered after the build, not before it.

What it does

  • Architecture-pattern selection with trade-offs, monolith → modular monolith → microservices → event-driven → CQRS → event sourcing → hexagonal → clean → API gateway.
  • System-design workflows: capacity planning, API design, schema design, scalability assessment, migration planning.
  • Technology-decision frameworks: database, cache, message queue, auth, frontend, cloud, API style.
  • A lean map over three references, read the map, open the one that matches the question.

Benefits

  • Make the expensive call once. Pattern and tech chosen deliberately, and written down.
  • No accidental architecture. You stop inheriting a shape nobody picked.
  • Scale problems surface on paper, while they still cost nothing to fix.
  • Stack-agnostic. Pairs with whatever framework skill you already run.

Install

Download this skill and copy the system-architecture folder to .claude/skills/system-architecture/ in your project, or to ~/.claude/skills/system-architecture/ to use it in every project. Claude Code finds it on its own; you can also call it with /system-architecture.

Part of the Agent Engineering bundle. To get the whole set as a Claude Code plugin: /plugin marketplace add endorphin-ai/hasbrains-agent-kit, then /plugin install agent-engineering@hasbrains-agent-kit.

Source: endorphin-ai/hasbrains-agent-kit. License: MIT.

Files (8)

Files

architecture_patterns.md
# Architecture Patterns Reference

Detailed guide to software architecture patterns with trade-offs and implementation guidance.

## Patterns Index

1. [Monolithic Architecture](#1-monolithic-architecture)
2. [Modular Monolith](#2-modular-monolith)
3. [Microservices Architecture](#3-microservices-architecture)
4. [Event-Driven Architecture](#4-event-driven-architecture)
5. [CQRS (Command Query Responsibility Segregation)](#5-cqrs)
6. [Event Sourcing](#6-event-sourcing)
7. [Hexagonal Architecture (Ports & Adapters)](#7-hexagonal-architecture)
8. [Clean Architecture](#8-clean-architecture)
9. [API Gateway Pattern](#9-api-gateway-pattern)

---

## 1. Monolithic Architecture

**Problem it solves:** Need to build and deploy a complete application as a single unit with minimal operational complexity.

**When to use:**

- Small team (1-5 developers)
- MVP or early-stage product
- Simple domain with clear boundaries
- Deployment simplicity is priority

**When NOT to use:**

- Multiple teams need independent deployment
- Parts of system have vastly different scaling needs
- Technology diversity is required

**Trade-offs:**
| Pros | Cons |
|------|------|
| Simple deployment | Scaling is all-or-nothing |
| Easy debugging | Large codebase becomes unwieldy |
| No network latency between components | Single point of failure |
| Simple testing | Technology lock-in |

**Structure example:**

```
monolith/
├── src/
│   ├── controllers/    # HTTP handlers
│   ├── services/       # Business logic
│   ├── repositories/   # Data access
│   ├── models/         # Domain entities
│   └── utils/          # Shared utilities
├── tests/
└── package.json
```

---

## 2. Modular Monolith

**Problem it solves:** Need monolith simplicity but with clear boundaries that enable future extraction to services.

**When to use:**

- Medium team (5-15 developers)
- Domain boundaries are becoming clearer
- Want option to extract services later
- Need better code organization than traditional monolith

**When NOT to use:**

- Already need independent deployment
- Teams can't coordinate releases

**Trade-offs:**
| Pros | Cons |
|------|------|
| Clear module boundaries | Still single deployment |
| Easier to extract services later | Requires discipline to maintain boundaries |
| Single database simplifies transactions | Can drift back to coupled monolith |
| Team ownership of modules | |

**Structure example:**

```
modular-monolith/
├── modules/
│   ├── users/
│   │   ├── api/           # Public interface
│   │   ├── internal/      # Implementation
│   │   └── index.ts       # Module exports
│   ├── orders/
│   │   ├── api/
│   │   ├── internal/
│   │   └── index.ts
│   └── payments/
├── shared/                # Cross-cutting concerns
└── main.ts
```

**Key rule:** Modules communicate only through their public API, never by importing internal files.

---

## 3. Microservices Architecture

**Problem it solves:** Need independent deployment, scaling, and technology choices for different parts of the system.

**When to use:**

- Large team (15+ developers) organized around business capabilities
- Different parts need different scaling
- Independent deployment is critical
- Technology diversity is beneficial

**When NOT to use:**

- Small team that can't handle operational complexity
- Domain boundaries are unclear
- Distributed transactions are common requirement
- Network latency is unacceptable

**Trade-offs:**
| Pros | Cons |
|------|------|
| Independent deployment | Network complexity |
| Independent scaling | Distributed system challenges |
| Technology flexibility | Operational overhead |
| Team autonomy | Data consistency challenges |
| Fault isolation | Testing complexity |

**Structure example:**

```
microservices/
├── services/
│   ├── user-service/
│   │   ├── src/
│   │   ├── Dockerfile
│   │   └── package.json
│   ├── order-service/
│   └── payment-service/
├── api-gateway/
├── infrastructure/
│   ├── kubernetes/
│   └── terraform/
└── docker-compose.yml
```

**Communication patterns:**

- Synchronous: REST, gRPC
- Asynchronous: Message queues (RabbitMQ, Kafka)

---

## 4. Event-Driven Architecture

**Problem it solves:** Need loose coupling between components that react to business events asynchronously.

**When to use:**

- Components need loose coupling
- Audit trail of all changes is valuable
- Real-time reactions to events
- Multiple consumers for same events

**When NOT to use:**

- Simple CRUD operations
- Synchronous responses required
- Team unfamiliar with async patterns
- Debugging simplicity is priority

**Trade-offs:**
| Pros | Cons |
|------|------|
| Loose coupling | Eventual consistency |
| Scalability | Debugging complexity |
| Audit trail built-in | Message ordering challenges |
| Easy to add new consumers | Infrastructure complexity |

**Event structure example:**

```typescript
interface DomainEvent {
  eventId: string;
  eventType: string;
  aggregateId: string;
  timestamp: Date;
  payload: Record<string, unknown>;
  metadata: {
    correlationId: string;
    causationId: string;
  };
}

// Example event
const orderCreated: DomainEvent = {
  eventId: "evt-123",
  eventType: "OrderCreated",
  aggregateId: "order-456",
  timestamp: new Date(),
  payload: {
    customerId: "cust-789",
    items: [...],
    total: 99.99
  },
  metadata: {
    correlationId: "req-001",
    causationId: "cmd-create-order"
  }
};
```

---

## 5. CQRS

**Problem it solves:** Read and write workloads have different requirements and need to be optimized separately.

**When to use:**

- Read/write ratio is heavily skewed (10:1 or more)
- Read and write models differ significantly
- Complex queries that don't map to write model
- Different scaling needs for reads vs writes

**When NOT to use:**

- Simple CRUD with balanced reads/writes
- Read and write models are nearly identical
- Team unfamiliar with pattern
- Added complexity isn't justified

**Trade-offs:**
| Pros | Cons |
|------|------|
| Optimized read models | Eventual consistency between models |
| Independent scaling | Complexity |
| Simplified queries | Synchronization logic |
| Better performance | More code to maintain |

**Structure example:**

```typescript
// Write side (Commands)
interface CreateOrderCommand {
	customerId: string;
	items: OrderItem[];
}

class OrderCommandHandler {
	async handle(cmd: CreateOrderCommand): Promise<void> {
		const order = Order.create(cmd);
		await this.repository.save(order);
		await this.eventBus.publish(order.events);
	}
}

// Read side (Queries)
interface OrderSummaryQuery {
	customerId: string;
	dateRange: DateRange;
}

class OrderQueryHandler {
	async handle(query: OrderSummaryQuery): Promise<OrderSummary[]> {
		// Query optimized read model (denormalized)
		return this.readDb.query(
			`
      SELECT * FROM order_summaries
      WHERE customer_id = ? AND created_at BETWEEN ? AND ?
    `,
			[query.customerId, query.dateRange.start, query.dateRange.end],
		);
	}
}
```

---

## 6. Event Sourcing

**Problem it solves:** Need complete audit trail and ability to reconstruct state at any point in time.

**When to use:**

- Audit trail is regulatory requirement
- Need to answer "how did we get here?"
- Complex domain with undo/redo requirements
- Debugging production issues requires history

**When NOT to use:**

- Simple CRUD applications
- No audit requirements
- Team unfamiliar with pattern
- Reporting on current state is primary need

**Trade-offs:**
| Pros | Cons |
|------|------|
| Complete audit trail | Storage grows indefinitely |
| Time-travel debugging | Query complexity |
| Natural fit for event-driven | Learning curve |
| Enables CQRS | Eventual consistency |

**Implementation example:**

```typescript
// Events
type OrderEvent =
	| { type: 'OrderCreated'; customerId: string; items: Item[] }
	| { type: 'ItemAdded'; itemId: string; quantity: number }
	| { type: 'OrderShipped'; trackingNumber: string };

// Aggregate rebuilt from events
class Order {
	private state: OrderState;

	static fromEvents(events: OrderEvent[]): Order {
		const order = new Order();
		events.forEach((event) => order.apply(event));
		return order;
	}

	private apply(event: OrderEvent): void {
		switch (event.type) {
			case 'OrderCreated':
				this.state = { status: 'created', items: event.items };
				break;
			case 'ItemAdded':
				this.state.items.push({ id: event.itemId, qty: event.quantity });
				break;
			case 'OrderShipped':
				this.state.status = 'shipped';
				this.state.trackingNumber = event.trackingNumber;
				break;
		}
	}
}
```

---

## 7. Hexagonal Architecture

**Problem it solves:** Need to isolate business logic from external concerns (databases, APIs, UI) for testability and flexibility.

**When to use:**

- Business logic is complex and valuable
- Multiple interfaces to same domain (API, CLI, events)
- Testability is priority
- External systems may change

**When NOT to use:**

- Simple CRUD with no business logic
- Single interface to domain
- Overhead isn't justified

**Trade-offs:**
| Pros | Cons |
|------|------|
| Business logic isolation | More abstractions |
| Highly testable | Initial setup overhead |
| External systems are swappable | Can be over-engineered |
| Clear boundaries | Learning curve |

**Structure example:**

```
hexagonal/
├── domain/              # Business logic (no external deps)
│   ├── entities/
│   ├── services/
│   └── ports/           # Interfaces (what domain needs)
│       ├── OrderRepository.ts
│       └── PaymentGateway.ts
├── adapters/            # Implementations
│   ├── persistence/     # Database adapters
│   │   └── PostgresOrderRepository.ts
│   ├── payment/         # External service adapters
│   │   └── StripePaymentGateway.ts
│   └── api/             # HTTP adapters
│       └── OrderController.ts
└── config/              # Wiring it all together
```

---

## 8. Clean Architecture

**Problem it solves:** Need clear dependency rules where business logic doesn't depend on frameworks or external systems.

**When to use:**

- Long-lived applications that will outlive frameworks
- Business logic is the core value
- Team discipline to maintain boundaries
- Multiple delivery mechanisms (web, mobile, CLI)

**When NOT to use:**

- Short-lived projects
- Framework-centric applications
- Simple CRUD operations

**Trade-offs:**
| Pros | Cons |
|------|------|
| Framework independence | More code |
| Testable business logic | Can feel over-engineered |
| Clear dependency direction | Learning curve |
| Flexible delivery mechanisms | Initial setup cost |

**Dependency rule:** Dependencies point inward. Inner circles know nothing about outer circles.

```
┌─────────────────────────────────────────┐
│           Frameworks & Drivers          │
│  ┌─────────────────────────────────┐    │
│  │     Interface Adapters          │    │
│  │  ┌─────────────────────────┐    │    │
│  │  │    Application Layer    │    │    │
│  │  │  ┌─────────────────┐    │    │    │
│  │  │  │    Entities     │    │    │    │
│  │  │  │ (Domain Logic)  │    │    │    │
│  │  │  └─────────────────┘    │    │    │
│  │  └─────────────────────────┘    │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘
```

---

## 9. API Gateway Pattern

**Problem it solves:** Need single entry point for clients that routes to multiple backend services.

**When to use:**

- Multiple backend services
- Cross-cutting concerns (auth, rate limiting, logging)
- Different clients need different APIs
- Service aggregation needed

**When NOT to use:**

- Single backend service
- Simplicity is priority
- Team can't maintain gateway

**Trade-offs:**
| Pros | Cons |
|------|------|
| Single entry point | Single point of failure |
| Cross-cutting concerns centralized | Additional latency |
| Backend service abstraction | Complexity |
| Client-specific APIs | Can become bottleneck |

**Responsibilities:**

```
┌─────────────────────────────────────┐
│            API Gateway              │
├─────────────────────────────────────┤
│ • Authentication/Authorization      │
│ • Rate limiting                     │
│ • Request/Response transformation   │
│ • Load balancing                    │
│ • Circuit breaking                  │
│ • Caching                          │
│ • Logging/Monitoring               │
└─────────────────────────────────────┘
         │         │         │
         ▼         ▼         ▼
    ┌─────┐   ┌─────┐   ┌─────┐
    │Svc A│   │Svc B│   │Svc C│
    └─────┘   └─────┘   └─────┘
```

---

## Pattern Selection Quick Reference

| If you need...                        | Consider...        |
| ------------------------------------- | ------------------ |
| Simplicity, small team                | Monolith           |
| Clear boundaries, future flexibility  | Modular Monolith   |
| Independent deployment/scaling        | Microservices      |
| Loose coupling, async processing      | Event-Driven       |
| Separate read/write optimization      | CQRS               |
| Complete audit trail                  | Event Sourcing     |
| Testable, swappable externals         | Hexagonal          |
| Framework independence                | Clean Architecture |
| Single entry point, multiple services | API Gateway        |