Skip to main content

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:
kds-frontend/
├── application/        # Use cases and contracts
├── bases/             # Base/primitive UI components
├── components/        # Feature components
├── contexts/          # React Context providers
├── domain/            # Business logic and rules
├── dtos/              # Data transfer objects
├── helpers/           # Utility functions
├── infraestructure/   # External integrations
├── layouts/           # Page layouts
├── orchestrators/     # Coordination layer
├── pages/             # Next.js pages
├── public/            # Static assets
├── services/          # Service instances
├── styles/            # Global styles and variables
├── biome.json         # Linting configuration
├── next.config.mjs    # Next.js configuration
├── package.json       # Dependencies
└── tsconfig.json      # TypeScript configuration

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.
export type OrderStatus =
  | "RECEIVED"
  | "CONFIRMED"
  | "PREPARING"
  | "READY"
  | "PICKED_UP"
  | "DELIVERED"
  | "CANCELLED";

export const ALL_ORDER_STATUSES: OrderStatus[] = [
  "RECEIVED",
  "CONFIRMED",
  "PREPARING",
  "READY",
  "PICKED_UP",
  "DELIVERED",
  "CANCELLED",
];
  • 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:
application/
├── hook/
│   └── use-order-detail.ts    # Hooks for data fetching
├── order/
│   ├── order-events.ts        # Event type definitions
│   ├── order-realtime.ts      # Real-time contract
│   └── order-repository.ts    # Repository interface
└── shared/
    └── realtime.ts            # Base real-time interface
export interface OrderRepository {
  getAll(): Promise<OrderListDto[]>;
  getById(id: string): Promise<OrderDetailDto>;
  updateStatus(id: string, status: OrderStatus): Promise<void>;
}
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:
infraestructure/
├── http/
│   ├── axios.instance.ts      # Configured Axios client
│   └── order.repository.ts    # HTTP implementation
└── socket/
    └── order.realtime.ts      # WebSocket implementation
  • 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:
components/
├── Column/
│   ├── Column.tsx
│   └── Column.module.scss
├── Kanban/
│   ├── Kanban.tsx
│   └── Kanban.module.scss
├── Riders/
│   ├── Riders.tsx
│   └── Riders.module.scss
├── card/
│   ├── OrderCard.tsx
│   └── OrderCard.module.scss
├── modal/
│   ├── OrderDetailsModal.tsx
│   └── OrderDetailsModal.module.scss
├── order/
│   └── OrderItems/
└── theme/
    └── ThemeToggle.tsx
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:
bases/
├── Logo/
├── Rider/
├── card/
│   └── Card.tsx           # Generic card component
└── modal/
    └── Modal.tsx          # Generic modal component
These are pure presentational components that can be reused across features.

Contexts Layer

Location: contexts/ Manages global application state using React Context.
// Global state for all orders
export function OrdersProvider({ children }) {
  const [orders, setOrders] = useState<Map<string, OrderListDto>>(new Map());
  // Derived state using useMemo
  const ordersByStatus = useMemo(() => groupByStatus(orders), [orders]);
  // ...
}
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
export class OrderOrchestrator {
  constructor(
    private repository: OrderRepository,
    private realtime: OrderRealtime
  ) {}

  async initialize() {
    // 1. Load initial data via HTTP
    const orders = await this.repository.getAll();
    // 2. Connect to WebSocket for updates
    this.realtime.connect();
    // 3. Set up event listeners
    this.setupListeners();
  }
}
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
export interface OrderListDto {
  id: string;
  displayNumber: string;
  status: OrderStatus;
  partnerName: string;
  partnerImage?: string;
  priority: "NORMAL" | "HIGH";
  activeTimer?: string;
}
  • 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.
pages/
├── _app.tsx          # App wrapper with providers
├── _document.tsx     # HTML document structure
└── index.tsx         # Home page (Kanban board)
export default function App({ Component, pageProps }: AppProps) {
  return (
    <ThemeProvider>
      <OrdersProvider>
        <Component {...pageProps} />
      </OrdersProvider>
    </ThemeProvider>
  );
}

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:
1

User action

User drags an order card to a new column
2

UI component

Kanban.tsx handles the drop event
3

Domain validation

Check if transition is valid using canTransition(from, to)
4

Orchestrator

Call orderOrchestrator.updateStatus(orderId, newStatus)
5

Repository

HTTP request sent via orderRepository.updateStatus()
6

Real-time update

WebSocket receives order.status.updated event
7

Context update

OrdersContext updates the global state
8

UI re-renders

All components subscribed to the order automatically update

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 enabled

Testability

Interfaces allow easy mocking and testing

Optimization Strategies

Orders are stored in a Map<string, OrderListDto> for O(1) lookup time instead of array iteration.
Grouping orders by status is computed once and memoized:
const ordersByStatus = useMemo(
  () => groupOrdersByStatus(orders),
  [orders]
);
Heavy components are wrapped with React.memo() to prevent unnecessary re-renders.
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

Build docs developers (and LLMs) love