Platform
    • FSD Layers
    • Entity Structure
Projects
  • API Connections & Tools
  1. Documentation
  2. Documentation

Business Domain (Entities)

Entities are the core business units of the project. This section describes the unified structure of any entity based on strict architectural rules.

Entities Layer Structure

Each business entity inside src/entities/* must follow a strict directory structure for logic and UI isolation.

File Structure

Standard Entity Modules

A complete entity consists of these required modules:

01/api

Responsible exclusively for network interaction with the backend application within a single entity. It takes arguments for the request and returns raw DTOs, which must then be passed to converters.

Learn RTK Query architecture
api/[entity-name].api.ts
1import { mainApi } from "@/shared/api"; 2 3export const entityApi = mainApi.injectEndpoints({ 4 endpoints: (builder) => ({ 5 getEntities: builder.query<TResponse, TFilters>({ 6 query: (filters) => ({ url: "/entities" }), 7 providesTags: [ENUM_API_TAGS.ENTITIES] 8 }) 9 }) 10});

02/converters

Data mappers. They transform a raw server DTO into a convenient Domain Model. This isolates UI components from sudden changes in backend contracts.

Converters architecture
converters/[entity-name].converters.ts
1export const mapEntityToFrontend = (data: IEntityBackend): IEntity => ({ 2 id: data.id, 3 type: data.type as ENUM_ENTITY_TYPE, 4 dateCreated: formatDate(data.date_created), 5 client: data.client, 6 status: data.status as ENUM_ENTITY_STATUS 7}); 8 9export const mapEntityToBackend = (data: Partial<IEntityDetail>): 10 Partial<IEntityDetailBackend> => ({ 11 id: data.id, 12 type: data.type, 13 date_created: data.dateCreated, 14 client: data.client, 15 status: data.status 16}); 17

03/handlers

MSW (Mock Service Worker) handlers. Used to intercept network calls during development and in integration tests (Vitest / RTL).

How MSW works
handlers/[entity-name].handlers.ts
1import { HttpResponse, http } from "msw"; 2import { ENV } from "@/shared/config"; 3import { ENTITIES_MOCK } from "../mock"; 4 5export const entityHandlers = [ 6 http.get(`${ENV.VITE_API_URL}/entities`, ({ request }) => { 7 const url = new URL(request.url); 8 return HttpResponse.json({ 9 data: [...ENTITIES_MOCK], 10 total: ENTITIES_MOCK.length 11 }); 12 }), 13 http.get(`${ENV.VITE_API_URL}/entities/:id`, ({ params }) => { 14 const entity = ENTITIES_MOCK.find((e) => e.id === params.id); 15 if (!entity) return new HttpResponse(null, { status: 404 }); 16 return HttpResponse.json(entity); 17 }) 18];

04/mock

Static fixtures and fake data (mock data) used to emulate server responses in conjunction with MSW handlers or for Storybook.

MSW and mock data section
mock/[entity-name].mock.ts
1import type { IEntityDetail } from "../types"; 2 3export const ENTITIES_MOCK: IEntityDetail[] = [ 4 { 5 id: "ENT-001", 6 type: "individual", 7 dateCreated: "2024-03-15T12:00:00Z", 8 client: "John Doe", 9 pax: 2, 10 dates: { from: "2024-04-01", to: "2024-04-10" }, 11 status: "CONFIRMED", 12 // ... full fields 13 } 14];

05/schema

Single Source of Truth for entity data types. Contains Zod objects with built-in internationalization (i18n) of errors.

Using Zod
schema/[entity-name].schema.ts
1import { z } from "zod"; 2import { i18nKey } from "@/shared/config"; 3 4const msg = i18nKey<TEntityKeys>(); 5 6export const ENTITY_SCHEMA = z.object({ 7 client: z.string().min(1, { message: msg("errors.client.required") }), 8 status: z.enum(["PENDING", "CONFIRMED"]), 9 pax: z.number().min(1) 10}); 11 12export type TEntitySchema = z.infer<typeof ENTITY_SCHEMA>;

06/slice

Redux state of the entity (if it stores global data). Selectors and actions often reside here as well. Note: state should depend solely on the Domain Model, not on DTOs.

slice/[entity-name].slice.ts
1import { createSlice, PayloadAction } from "@reduxjs/toolkit"; 2 3interface IEntitySliceState { 4 selectedId: string | null; 5} 6 7const initialState: IEntitySliceState = { 8 selectedId: null 9}; 10 11export const entitySlice = createSlice({ 12 name: "entity", 13 initialState, 14 reducers: { 15 setSelectedEntity: (state, action: PayloadAction<string>) => { 16 state.selectedId = action.payload; 17 } 18 } 19});

07/ui

Dump or Smart components at the entity level. For example: UserCard, UserAvatar. Can be reused across different features and widgets.

ui/[entity-name]-card.tsx
1interface IEntityCardProps { 2 entity: IEntity; 3 onSelect: (id: string) => void; 4} 5 6export const EntityCard = ({ entity, onSelect }: IEntityCardProps) => ( 7 <Card onClick={() => onSelect(entity.id)}> 8 <CardHeader>{entity.client}</CardHeader> 9 <CardContent>Pax: {entity.pax}</CardContent> 10 </Card> 11);

08/types

Global TS interfaces and types for a specific entity (e.g., Domain Model interface if Zod doesn't cover all logic). Type inference from Zod schemas is recommended, but when not possible, types are defined here.

Type inference in Zod
types/[entity-name].types.ts
1export interface IEntityDates { 2 from: string; 3 to: string; 4} 5 6export interface IEntity { 7 id: string; 8 type: ENUM_ENTITY_TYPE; 9 dateCreated: string; 10 client: string; 11 pax: number; 12 dates: IEntityDates; 13 status: ENUM_ENTITY_STATUS; 14}