Architecture Overview
KDS Frontend uses a layered architecture inspired by Clean Architecture and Domain-Driven Design principles. The codebase is organized to ensure clear separation of concerns, testability, and maintainability.The architecture enforces that UI components never directly access infrastructure. All communication flows through well-defined layers.
Directory Structure
Here’s the complete directory tree:Layer-by-Layer Breakdown
Domain Layer
Location:domain/
Contains pure business logic with no external dependencies. This layer defines the core rules and entities of the application.
Domain layer principles
Domain layer principles
- No framework dependencies
- Pure TypeScript/JavaScript
- Contains business invariants
- Defines valid state transitions
- Reusable across different UIs
Application Layer
Location:application/
Defines contracts and use cases. This layer acts as a bridge between the domain and infrastructure.
Structure:
The application layer defines what the app needs, not how it’s implemented. This enables easy testing with mocks.
Infrastructure Layer
Location:infraestructure/
Implements the contracts defined in the application layer using real external services.
Structure:
Why separate infrastructure?
Why separate infrastructure?
- Easy to swap implementations (e.g., REST → GraphQL)
- Testable with mocks
- Keeps external dependencies isolated
- Can run without a real backend in tests
Components Layer
Location:components/
Contains feature-specific React components. These are composed of base components and implement application features.
Structure:
Each component has its own SCSS module for scoped styling. See the Styling Guide for more details.
Bases Layer
Location:bases/
Contains primitive/reusable UI components with no business logic.
Structure:
Contexts Layer
Location:contexts/
Manages global application state using React Context.
Design decision: Derived state
Design decision: Derived state
Riders and grouped orders are derived from the main orders state using
useMemo, rather than stored separately. This prevents state duplication and synchronization issues.Orchestrators Layer
Location:orchestrators/
Coordinates between repository and real-time implementations. Acts as a facade for complex operations.
orchestrators/order/order.orchestrator.ts
Orchestrators simplify complex workflows by coordinating multiple services. The UI only needs to call the orchestrator.
DTOs (Data Transfer Objects)
Location:dtos/
Defines explicit contracts for data flowing between layers.
OrderList.dto.ts
Why use DTOs?
Why use DTOs?
- Clear API contracts
- Type safety across boundaries
- Decouples internal domain from external APIs
- Makes refactoring safer
Pages Layer
Location:pages/
Next.js file-based routing. Each file becomes a route.
Helpers and Services
Helpers (helpers/): Pure utility functions (e.g., date formatting, string manipulation)
Services (services/): Singleton instances of orchestrators and repositories
Data Flow
Here’s how data flows through the architecture:Key Design Principles
Separation of Concerns
Each layer has a single, well-defined responsibility
Dependency Inversion
High-level modules don’t depend on low-level implementation details
Type Safety
Strict TypeScript with
exactOptionalPropertyTypes enabledTestability
Interfaces allow easy mocking and testing
Optimization Strategies
Order lookup performance
Order lookup performance
Orders are stored in a
Map<string, OrderListDto> for O(1) lookup time instead of array iteration.Derived state with useMemo
Derived state with useMemo
Grouping orders by status is computed once and memoized:
Component memoization
Component memoization
Heavy components are wrapped with
React.memo() to prevent unnecessary re-renders.Lazy loading
Lazy loading
Images use
loading="lazy" attribute for performance.Next Steps
Setup Guide
Learn how to install and run the project
Styling Guide
Understand the SCSS modules and theming system