hexagonal-typescript-advanced

Advanced Hexagonal Architecture anti-patterns for TypeScript — domain importing framework dependencies, use cases depending on concrete adapters, HTTP handlers bypassing use cases, Zod validation inside the domain model. Each anti-pattern includes wrong/correct comparison with explanation.

8 stars

Best use case

hexagonal-typescript-advanced is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Advanced Hexagonal Architecture anti-patterns for TypeScript — domain importing framework dependencies, use cases depending on concrete adapters, HTTP handlers bypassing use cases, Zod validation inside the domain model. Each anti-pattern includes wrong/correct comparison with explanation.

Teams using hexagonal-typescript-advanced should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/hexagonal-typescript-advanced/SKILL.md --create-dirs "https://raw.githubusercontent.com/marvinrichter/clarc/main/skills/hexagonal-typescript-advanced/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/hexagonal-typescript-advanced/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How hexagonal-typescript-advanced Compares

Feature / Agenthexagonal-typescript-advancedStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Advanced Hexagonal Architecture anti-patterns for TypeScript — domain importing framework dependencies, use cases depending on concrete adapters, HTTP handlers bypassing use cases, Zod validation inside the domain model. Each anti-pattern includes wrong/correct comparison with explanation.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Hexagonal TypeScript — Anti-Patterns

This skill extends `hexagonal-typescript` with common violations and how to fix them. Load `hexagonal-typescript` first.

## When to Activate

- Reviewing code where domain classes import `typeorm`, `@nestjs/common`, or other framework packages
- Use case constructors receive concrete adapter classes instead of port interfaces
- HTTP handlers call repositories directly, skipping the use case layer
- Domain models contain Zod schemas or other validation library dependencies
- Auditing a codebase for dependency direction violations

---

## Anti-Patterns

### Domain Model Importing Framework Dependencies

**Wrong:**

```typescript
// domain/model/market.ts
import { Entity, Column } from 'typeorm'  // ORM leaks into domain
import { Injectable } from '@nestjs/common'

@Entity()
@Injectable()
export class Market {
  @Column() name: string
}
```

**Correct:**

```typescript
// domain/model/market.ts
// No framework imports — pure TypeScript only
export interface Market {
  readonly id: MarketId | null
  readonly name: string
  readonly status: MarketStatus
}
```

**Why:** Framework annotations in the domain couple your business logic to infrastructure, making it impossible to test without starting the full framework.

---

### Use Case Depending on the Concrete Adapter

**Wrong:**

```typescript
// application/usecase/CreateMarketService.ts
import { PrismaMarketRepository } from '../../adapter/out/persistence/PrismaMarketRepository'

export class CreateMarketService {
  constructor(private readonly repo: PrismaMarketRepository) {}  // concrete class
}
```

**Correct:**

```typescript
// application/usecase/CreateMarketService.ts
import type { MarketRepository } from '../../domain/port/out/MarketRepository'

export class CreateMarketService {
  constructor(private readonly repo: MarketRepository) {}  // port interface
}
```

**Why:** Depending on the concrete adapter prevents swapping implementations and forces integration tests even for pure business logic.

---

### HTTP Handler Calling the Repository Directly

**Wrong:**

```typescript
// adapter/in/http/createMarketHandler.ts
import { PrismaMarketRepository } from '../../out/persistence/PrismaMarketRepository'

export function createMarketHandler(repo: PrismaMarketRepository) {
  return async (req, res) => {
    const market = await repo.save({ name: req.body.name })  // skips use case
    res.status(201).json(market)
  }
}
```

**Correct:**

```typescript
// adapter/in/http/createMarketHandler.ts
import type { CreateMarketUseCase } from '../../../domain/port/in/CreateMarketUseCase'

export function createMarketHandler(createMarket: CreateMarketUseCase) {
  return async (req, res, next) => {
    const market = await createMarket.execute(req.body)
    res.status(201).json(market)
  }
}
```

**Why:** Bypassing the use case skips business rule enforcement and breaks the inward dependency rule — adapters may only call ports, never each other.

---

### Zod Validation Inside the Domain Model

**Wrong:**

```typescript
// domain/model/market.ts
import { z } from 'zod'  // framework dependency inside domain

export const marketSchema = z.object({ name: z.string().min(1) })
export type Market = z.infer<typeof marketSchema>
```

**Correct:**

```typescript
// adapter/in/http/marketSchemas.ts  ← validation belongs in the inbound adapter
import { z } from 'zod'
export const createMarketSchema = z.object({ name: z.string().min(1).max(200) })

// domain/model/market.ts  ← domain enforces invariants through pure logic
export function createMarket(name: string): Market {
  if (!name || name.trim() === '') throw new InvalidMarketError('name is required')
  return { id: null, name: name.trim(), status: 'DRAFT' }
}
```

**Why:** Schema validation libraries belong in the inbound adapter layer; the domain owns business invariants through pure guard clauses, not library-specific schemas.

---

## Reference

- `hexagonal-typescript` — package structure, port definitions, use cases, adapter patterns, DI wiring, testing strategy
- `ddd-typescript` — Value Objects, Entities, Aggregates, Domain Events
- `typescript-patterns` — TypeScript idioms and advanced type patterns

Related Skills

typescript-testing

8
from marvinrichter/clarc

TypeScript testing patterns: Vitest for unit/integration, Playwright for E2E, MSW for API mocking, Testing Library for React components. Core TDD methodology for TypeScript/JavaScript projects.

typescript-patterns

8
from marvinrichter/clarc

TypeScript patterns — type system best practices, strict mode, utility types, generics, discriminated unions, error handling with Result types, and module organization. Core patterns for production TypeScript.

typescript-patterns-advanced

8
from marvinrichter/clarc

Advanced TypeScript — mapped types, template literal types, conditional types, infer, type guards, decorators, async patterns, testing with Vitest/Jest, and performance. Extends typescript-patterns.

typescript-monorepo-patterns

8
from marvinrichter/clarc

TypeScript monorepo patterns with Turborepo + pnpm workspaces. Covers package structure, shared configs, task pipeline caching, build orchestration, and publishing strategy.

tdd-workflow-advanced

8
from marvinrichter/clarc

TDD anti-patterns — writing code before tests, testing implementation details instead of behavior, using waitForTimeout as a sync strategy, chaining tests that share state, mocking the system under test instead of its dependencies.

swift-patterns-advanced

8
from marvinrichter/clarc

Advanced Swift patterns — property wrappers, result builders, Combine basics, opaque & existential types, macro system, advanced generics, and performance optimization. Extends swift-patterns.

serverless-patterns-advanced

8
from marvinrichter/clarc

Advanced Serverless patterns — Lambda idempotency (Lambda Powertools + DynamoDB persistence layer), Lambda cost model (pricing formula, break-even vs containers), and CloudWatch Insights observability queries for cold starts, duration, and errors.

security-review-advanced

8
from marvinrichter/clarc

Security anti-patterns — localStorage token storage (XSS risk), trusting client-side authorization checks, reflecting full error details to clients, blacklist vs whitelist input validation, using npm install instead of npm ci in CI pipelines.

rust-testing-advanced

8
from marvinrichter/clarc

Advanced Rust testing anti-patterns and corrections — cfg(test) placement, expect() over unwrap(), mockall expectation ordering, executor mixing (#[tokio::test] vs block_on), PgPool isolation with

rust-patterns-advanced

8
from marvinrichter/clarc

Advanced Rust patterns — zero-cost abstractions, proc macros, unsafe FFI, WASM, Axum web architecture, trait objects vs generics, and performance profiling.

python-testing-advanced

8
from marvinrichter/clarc

Advanced Python testing — async testing with pytest-asyncio, exception/side-effect testing, test organization, common patterns (API, database, class methods), pytest configuration, and CLI reference. Extends python-testing.

python-patterns-advanced

8
from marvinrichter/clarc

Advanced Python patterns — concurrency (threading, multiprocessing, async/await), hexagonal architecture with FastAPI, RFC 7807 error handling, memory optimization, pyproject.toml tooling, and anti-patterns. Extends python-patterns.