---
id: wiki-2026-0508-대규모-typescript-애플리케이션-아키텍처-설계
title: 대규모 TypeScript 애플리케이션 아키텍처 설계
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Large TS App Architecture, TS Monorepo Design, Enterprise TypeScript]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [typescript, architecture, monorepo, enterprise, modular]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
  language: TypeScript
  framework: TypeScript 5.7+/Nx/Turborepo
---

# 대규모 TypeScript 애플리케이션 아키텍처 설계

## 매 한 줄
> **"매 module boundary + project references + branded domain + monorepo tooling"**. 100k+ LOC TypeScript codebase 가 매 type safety 와 매 build performance 동시 유지하려면 매 4-layer (domain/application/infra/interface) + Nx/Turborepo + Project References + strict configuration 가 매 2026 년 default.

## 매 핵심

### 매 4-layer (Hexagonal-influenced)
- **Domain**: 매 entity, value object, domain event. 매 zero external dep.
- **Application**: 매 use case, port interface. 매 domain 만 import.
- **Infrastructure**: 매 adapter (DB, HTTP, queue). 매 port 구현.
- **Interface**: 매 controller, CLI, GraphQL resolver. 매 application 호출.

### 매 monorepo 구조
- **Apps**: 매 deployable unit (web, api, worker, mobile).
- **Libs**: 매 shared package (domain, ui, utils).
- **Tools**: 매 build/codegen/migration script.
- **Boundaries**: 매 ESLint rule + Nx tag 로 enforce.

### 매 응용
1. SaaS B2B platform (multi-tenant).
2. Fintech transaction system (audit + compliance).
3. Marketplace (catalog + checkout + fulfillment).
4. Internal developer platform.

## 💻 패턴

### Project references (TS 5.7+)
```jsonc
// tsconfig.base.json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "isolatedModules": true,
    "moduleResolution": "bundler",
    "composite": true,
    "incremental": true
  }
}

// apps/api/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "references": [
    { "path": "../../libs/domain" },
    { "path": "../../libs/application" },
    { "path": "../../libs/infrastructure" }
  ]
}
```

### Hexagonal layer (port + adapter)
```ts
// libs/domain/src/order/order.ts
import { Brand } from "effect";
type OrderId = string & Brand.Brand<"OrderId">;

export class Order {
  constructor(
    readonly id: OrderId,
    readonly items: ReadonlyArray<LineItem>,
    readonly status: OrderStatus,
  ) {}
  confirm(): Order { /* ... */ }
}

// libs/application/src/order/place-order.usecase.ts
import { OrderRepo } from "./ports/order-repo.port.js";
import { PaymentGateway } from "./ports/payment.port.js";

export class PlaceOrderUseCase {
  constructor(
    private readonly orders: OrderRepo,
    private readonly payments: PaymentGateway,
  ) {}
  async execute(input: PlaceOrderInput): Promise<OrderId> {
    const order = Order.fromInput(input);
    await this.payments.charge(order);
    await this.orders.save(order);
    return order.id;
  }
}

// libs/infrastructure/src/order/postgres-order-repo.ts
export class PostgresOrderRepo implements OrderRepo {
  async save(o: Order) { /* ... */ }
  async byId(id: OrderId) { /* ... */ }
}
```

### Boundary enforcement (Nx tags)
```jsonc
{
  "rules": {
    "@nx/enforce-module-boundaries": ["error", {
      "depConstraints": [
        { "sourceTag": "scope:domain",
          "onlyDependOnLibsWithTags": ["scope:domain"] },
        { "sourceTag": "scope:application",
          "onlyDependOnLibsWithTags": ["scope:domain", "scope:application"] },
        { "sourceTag": "scope:infrastructure",
          "onlyDependOnLibsWithTags": ["scope:domain", "scope:application", "scope:infrastructure"] },
        { "sourceTag": "scope:interface",
          "onlyDependOnLibsWithTags": ["*"] }
      ]
    }]
  }
}
```

### Branded domain types
```ts
import { Brand } from "effect";
export type UserId = string & Brand.Brand<"UserId">;
export type Email = string & Brand.Brand<"Email">;
export type Money = { readonly cents: number; readonly currency: "USD" | "EUR" }
                    & Brand.Brand<"Money">;

export const UserId = Brand.refined<UserId>(
  (s) => /^u_[0-9a-f]{16}$/.test(s),
  (s) => Brand.error(`invalid UserId: ${s}`),
);
```

### Effect-style use case (typed errors)
```ts
import { Effect, Context } from "effect";

class OrderRepo extends Context.Tag("OrderRepo")<
  OrderRepo,
  { save: (o: Order) => Effect.Effect<void, DbError> }
>() {}

class PaymentGateway extends Context.Tag("PaymentGateway")<
  PaymentGateway,
  { charge: (o: Order) => Effect.Effect<void, PaymentError> }
>() {}

const placeOrder = (input: PlaceOrderInput) => Effect.gen(function* () {
  const orders = yield* OrderRepo;
  const payments = yield* PaymentGateway;

  const order = Order.fromInput(input);
  yield* payments.charge(order);
  yield* orders.save(order);
  return order.id;
});
```

### Codegen for shared schema
```ts
import { generate } from "openapi-typescript";

await generate({
  input: "schemas/api.openapi.yaml",
  output: "libs/api-contracts/src/types.ts",
  exportType: true,
});
```

### Build cache (Turborepo)
```jsonc
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"],
      "cache": true
    },
    "test": { "dependsOn": ["build"], "cache": true },
    "lint": { "cache": true }
  }
}
```

## 매 결정 기준
| 규모 | 추천 |
|---|---|
| < 10k LOC, 1팀 | Single repo, 매 simple structure |
| 10-50k LOC, 2-5 팀 | Monorepo + Project references |
| 50k+ LOC, 5+ 팀 | Nx/Turborepo + 4-layer + branded |
| 강한 audit 요구 | Effect-TS typed errors |
| Public API 공개 | OpenAPI codegen + branded |

**기본값**: Nx + 4-layer hexagonal + Effect Brand + strict tsconfig + Turborepo cache.

## 🔗 Graph
- 부모: [[Software Architecture]] · [[TypeScript]]
- 변형: [[Cloud_Native|Modular Monolith]] · [[Hexagonal Architecture]] · [[Clean Architecture]]
- 응용: [[Turborepo]] · [[Effect-TS]]
- Adjacent: [[브랜디드 타입 (Branded Types)]] · [[Domain-Driven Design]] · [[Project References]]

## 🤖 LLM 활용
**언제**: 매 50k+ LOC, 매 multi-team, 매 long-lived product, 매 strong type discipline 요구.
**언제 X**: 매 prototype, 매 1-week MVP, 매 single-developer script.

## ❌ 안티패턴
- **Domain → infrastructure import**: 매 layer 역방향 — 매 hex 원칙 위반.
- **God lib**: 매 `libs/shared` 가 매 모든 것 — 매 boundary X.
- **Strict 매 disable**: 매 `any` cascade — 매 type 가치 0.
- **No project references**: 매 단일 거대 tsconfig — 매 build 매 분 단위.
- **Codegen 매 manual sync**: 매 frontend/backend type drift.

## 🧪 검증 / 중복
- Verified (Nx docs, Turborepo guides, Effect-TS docs, Vladimir Khorikov "DDD in TypeScript", Khalil Stemmler patterns).
- 신뢰도 A.

## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 4-layer + Nx + Effect 통합 patterns |
