Back to insights
Insight

Architecting a Flexible Administration Panel

An adaptable React administration-panel structure built with Domain-Driven Design, CQRS, TypeScript, and React Query.

An exploded architectural system plan with nested boundaries and a persimmon organizing connector

Picking the stack was the easy part. The harder problem was structuring the project so it stayed easy to work in as it grew. Here is the structure I used, built around Domain-Driven Design and CQRS, with React Query, TypeScript, Axios, and React Router doing the supporting work.

- src/
  - features/
    - Auth/
    - Common/
    - Feature1/
      - apis/
        - queries/
        - mutations/
      - components/
      - screens/
      - types/
    - Feature2/
      - apis/
      - components/
      - screens/
      - types/
  - layouts/
  - routes/
    - protected.ts
    - public.ts

Domain-Driven Design

The project is organized around Domain-Driven Design. The features folder is the cornerstone: each feature of the application gets its own space, which keeps related code together and responsibilities clearly separated.

One folder per feature

Each feature's sub-folder holds its own screens, components, types, and APIs. Adding, changing, or removing a feature stays contained instead of rippling into the rest of the app.

CQRS for the API layer

Inside each feature's apis folder, queries and mutations are kept apart, following Command Query Responsibility Segregation. Reads and writes rarely change for the same reasons, so separating them made both easier to maintain.

React Query for data

Every action gets its own custom hook built on React Query. Its caching and synchronization handle most of the coordination between client and server that I would otherwise have had to write by hand.

TypeScript and Axios

TypeScript covers the whole project, catching a category of runtime error before it ships. For API calls, Axios is the client. It is well-tested and does not need much configuration to behave predictably.

Routing

React Router handles navigation. The routes folder at the project root separates protected routes from public ones, each with its own layout, so access rules stay visible rather than scattered through the app.

What this structure buys

The result is a codebase that stays readable as it grows. Adding a feature does not require understanding the whole application first, and that has made collaboration considerably easier. Later articles will go into forms, lists, and detail pages, and the tooling that keeps them consistent.