React Clean Architecture
Prescriptive architecture for React Web applications with TypeScript and Vite.
Stack: React 19 - TypeScript - Vite - Zustand (client state) - React Query (server state) - React Router
Patterns: Ports/Adapters - Use Cases - Result Pattern - ViewModel - Atomic Design
Core Principle
Core depends on NOTHING. UI and Infrastructure can import from Core, never the other way around.
UI ──────────────┐
├──▶ Core (entities, use cases, ports)
Infrastructure ──┘
Project Structure
src/
├── ui/ # Global components and hooks
│ ├── components/ # Atomic Design
│ │ ├── atoms/ # e.g., Button, Text, Icon
│ │ ├── molecules/ # e.g., InputField, Card
│ │ ├── organisms/ # e.g., Header, Form
│ │ └── templates/ # e.g., PageLayout
│ ├── hooks/ # Global hooks (useToggle, useDebounce)
│ └── theme/ # CSS variables, Tailwind config
│
├── modules/
│ ├── [bounded-context]/ # e.g., authentication, labs, licenses
│ │ ├── core/ # Pure domain (no external dependencies)
│ │ │ ├── entities/ # Business types/interfaces
│ │ │ ├── ports/ # Interfaces (contracts)
│ │ │ └── usecases/ # Business logic
│ │ ├── infrastructure/ # Port implementations
│ │ │ └── adapters/
│ │ └── ui/ # React-specific for this context
│ │ ├── components/
│ │ ├── pages/
│ │ ├── hooks/
│ │ ├── stores/ # Zustand stores
│ │ └── viewModels/ # UI orchestration
│ ├── shared/ # Shared code between bounded contexts
│ └── app/ # Application configuration
│ ├── dependencies/
│ ├── react/
│ ├── router/
│ └── main.tsx
│
├── types/ # General types (ISO8601, Result)
└── utils/ # Utility functions
File Naming Conventions
| Type | Extension | Example |
|---|---|---|
| Entity | .entity.ts |
User.entity.ts |
| Port | .port.ts |
AuthRepository.port.ts |
| Use Case | .usecase.ts |
Login.usecase.ts |
| Adapter | .adapter.ts |
AuthApi.adapter.ts |
| ViewModel | .viewModel.tsx |
useLogin.viewModel.tsx |
| Store | .store.ts |
auth.store.ts |
| Model (API response) | .model.ts |
LoginResponse.model.ts |
| Query hook | .query.ts |
useUser.query.ts |
| Mutation hook | .mutation.ts |
useCreateUser.mutation.ts |
React components: PascalCase.tsx (e.g., LoginPage.tsx, AuthenticationCard.tsx)
Layer Rules
Core (/modules/[context]/core/)
Core is pure and unaware of the outside world.
Allowed:
- Defines entities (types/interfaces)
- Defines ports (dependency interfaces)
- Contains use cases (business logic)
- Uses Result pattern for errors
- Can import from: types/, utils/, other files in the same core
Forbidden:
- NEVER import from infrastructure/
- NEVER import from ui/
- NEVER depend on React
- NEVER call APIs directly
Infrastructure (/modules/[context]/infrastructure/)
Implements ports defined in Core.
Allowed:
- Adapters implement ports
- Handles API calls, storage, external services
- Transforms external data to Core entities
- Returns Result<T, E>
- Can import from: core/ (ports, entities)
Forbidden:
- NEVER contains business logic (just transformation/mapping)
- NEVER import from ui/
UI (/modules/[context]/ui/)
Everything React-specific for the bounded context.
Allowed:
- Pages, components, hooks specific to the context
- ViewModels orchestrate: use cases and stores
- Zustand stores for client state
- Can import from: core/ (entities, use cases, ports)
- Can call an adapter directly for simple CRUD (via React Query)
Forbidden:
- NEVER business logic in components
- NEVER business logic in viewModels (delegate to use cases)
When to use a Use Case vs direct Adapter?
| Situation | Approach |
|---|---|
| Simple fetch, basic CRUD | Direct adapter + React Query |
| Business logic, validation, orchestration | Use Case |
Key Patterns
- Result Pattern: Explicit success/error handling without exceptions. See references/result-pattern.md
- React Query: Server state management with query keys factory, hooks, and cache invalidation. See references/react-query-patterns.md
- Dependency Injection: React Context-based DI with environment-specific implementations. See references/dependency-injection.md
Workflows
Creating a New Feature
Follow the 9-step process: Entities → Port → Use Case → Adapter → Register dependency → Query Keys → Mutation Hook → ViewModel → Page.
Full walkthrough with code examples: references/feature-workflow.md
Refactoring Existing Code
Identify violations (business logic in components, direct API calls, inline types, hardcoded dependencies) and extract to the proper layer.
Process and examples: references/refactoring-guide.md
Code Review
See references/code-review-checklist.md for the complete checklist.
References
- references/result-pattern.md — Result type, use case usage, viewModel usage
- references/react-query-patterns.md — Query keys, hooks, mutations, conventions
- references/dependency-injection.md — DI structure, providers, environment config
- references/feature-workflow.md — Full 9-step feature creation walkthrough
- references/refactoring-guide.md — Violation identification, before/after examples
- references/file-templates.md — Complete templates for each file type
- references/code-review-checklist.md — Code review checklist