The structure is inspired in big parts by:
- How To Structure React Projects From Beginner To Advanced. See the "Advanced Folder Structure".
- Elegant Frontend Architecture.
- 🏁️ Primary goals of this structure
- 🗂️ Folder and file naming
- 💁 Outline folder structure
- ℹ️ In-depth explanation
-
We want a strong separation between the frontend app and the backend language. Having a
domain
directory on the top level enables us to do so. Nothing inside ofapp
should have any knowledge about anything related to the backend. Example: data model from incoming API data. -
We want a comprehensive approach, which enables us to move fast and the community to contribute. Choosing an approach based on documented, established pattern avoids re-inventing the wheel. It also enables us to provide a lot of background references for the community.
-
We want to avoid spending too much time on "Which file is where?" By having only a
services
directory and no additionallib
(orutils
), we reduce the brain load.
- folders are in
kebab-case
- TypeScript files are in
kebab-case
- React files are in
PascaleCases
- Test files are mirroring the code file:
ReactComponent.test.tsx
typescript-file.test.ts
- Services files are in
kebab-cases
and includeservice
in the file nameuseful-function.service.ts
.
└── src/
├── app/
│ ├── assets/
│ │ ├── scss/
│ │ └── images/
│ ├── components/
│ │ ├── Form.tsx
│ │ ├── Form.test.tsx
│ │ ├── Pagination.tsx
│ │ └── Pagination.test.tsx
│ ├── features/
│ │ ├── overarching-feature/
│ │ │ ├── feature-one/
│ │ │ │ ├── components/
│ │ │ │ ├── hooks/
│ │ │ │ └── FeatureOne.tsx
│ │ │ ├── feature-two/
│ │ │ │ ├── components/
│ │ │ │ ├── hooks/
│ │ │ │ ├── utils/
│ │ │ │ └── FeatureOne.tsx
│ │ └── topics/
│ │ ├── components/
│ │ │ ├── list
│ │ │ └── select-environment
│ │ ├── hooks/
│ │ │ ├── list/
│ │ │ ├── environment/
│ │ └── Topics.tsx
│ ├── layout/
│ │ ├── LayoutForOneThing.tsx
│ │ └── LayoutForOneThing.test.tsx
│ ├── pages/
│ │ ├── topics/
│ │ │ └── index.tsx
│ │ ├── users/
│ │ │ └── index.tsx
│ │ └── Login.tsx
│ └── router.tsx
├── domain/
│ ├── environment/
│ │ ├── environment-api.ts
│ │ ├── environment-types.ts
│ │ └── index.ts
│ ├── team/
│ │ ├── team-api.ts
│ │ ├── team-types.ts
│ │ └── index.ts
└── services/
├── feature-flags/
│ ├── utils.test.ts
│ └── utils.ts.ts
├── api.test.ts
└── api.ts
Contains everything related to the UI application. app
consumes information from domain
that we cater to the needs of the UI app.
Nothing in app
knows anything from the content of domain
other than the exported modules / interfaces in the index.ts
(public API).
Contains assets like scss and images.
Contains all UI elements in form of React components that we use in different places of the app. The components should be clean, and uncomplicated to reuse. They have to be agnostic from any business logic.
As long as we have single component files, they are all located at the root level. When as the number of components grows, we will think about a more detailed structure.
In this directory, we group similar code together based on one feature. The structure enables us to add or remove certain parts of the UI.
- We can separate features into over-arching topics (e.g. all features related to Cluster). This is something we will work out in more detail in the progress.
- We name the folders in
features
based on the feature. - Every feature folder includes one component on the top level to export. This file is named the same as the features directory. -❗This root component should be the only one used in imports outside of this feature.
Contains every page of the application. The structure in this folder should mirror the structure of routing. If there is a link to a "dashboard" page in the web app, there should be a dashboard/index.tsx
page inside pages
. The files don't need to have a Page
pre- or postfix since the directory already gives that information.
Contains different domains we need to describe the UI application. They are specific to it. They are the concepts you would elaborate on when describing the Klaw UI app.
domain
is where business logic lives and a layer between e.g. the data from the backend API and app
. domain
is
the only place that speaks with the backend and knows what data from the backend looks like.
- We name the folders in
domain
based on the model / concept they are implementing. - Each
domain
has a main file called{entity}-api.ts
which holds handler functions for API operations, which are used in theapp
folder - Every folder includes a
index.ts
file to export modules / interfaces and act as a public API.
POST
- Creating a request: request{entity}{action noun}
Only use request
as a verb when the API handlers creates a request entity which needs to be approved, with the structure request{entity}{action}
.
Example: requestTopicCreation
, requestConnectorDeletion
, requestTopicPromotion
POST
- Acting on a created request: {action verb}{entity}Request
Only use Request
as a noun when the API handlers fires an action against a created request entity, with the structure {action}{entity}Request
.
Example: deleteTopicRequest
, approveTopicRequest
POST
/ GET
- Immediate action: {action verb}{entity}{optional category}
Do not use request
for immediate actions (no request entity created), but the structure {action}{entity}{optional category}
.
Example: updateTopicDocumentation
, getConnectorOverview
Contains functionality we use in many areas to reduce coupling between different layers. services
include utility functions as well as facades around external libraries. As a rule of thumb: We should not use a third-part library that is not related to the core packages like react outside of services
. We implement them in a Facade Pattern.
- We name files based on their exported functionality, e.g.
api.ts
. - We create folders for the same responsibilities, e.g. for
test-utils/
.