Guidelines Software Architecture - global-121/121-platform GitHub Wiki
This page contains the guidelines we have for backend development.The intended audience is anyone who wants to develop for the 121-platform. The current code base does not follow all these guidelines, but the intent is that any new code or refactoring follows these guidelines.
Guidelines Software Architecture
Encapsulation guidelines
- We keep datamodel loosely coupled (3e normalform)
- We don't want to move to microservices for now
- Each entity can only be created/updated/deleted within 1 module
- Reading entities from other modules is allowed
- But keep this limited with clear reasoning per entity (evaluate current list of imported entities)
- Put static function that are used in multiple places in the code in separate 'utils' module:
- When to import services from other modules:
- Because that other service modifies entities of that module (like transaction service being imported in payment service for storing transactions)
- Because the other service make external api calls
- Because the other service is static utils service
- Because the other service implements a complex read query to avoid code duplication / this could later be changed to repository inheritance
- authentication
- When to import entities from other modules:
- do not import entities from another module if you are gonna use it to create/update/delete the entity
- no general guidelines, but should be used sparsely. check case-by-case if it's really needed
API-design guidelines:
- Organize API around entities and not use cases
- Apply proper HTTP methods:
- GET/POST/DELETE/PUT/PATCH
- Don't use POST for GET to be able to pass payload/body
- Apply proper status codes in response:
- Document all specifically relevant status codes per endpoint
- Naming:
- Don't use verbs, only nouns; there can be exceptions, for example for tasks that go beyond simple manipulation of a resource, like retrying or approving a payment. In that case use /retry or /approve at the end.
- Use plural/singular per best practice
- Use IDs in names as per this table
- Limit to 2 levels in naming ("/noun/id/noun/id") > figure out how this works in practice
- Limit response to 2 levels deep (so relation of a relation is still OK)
- Use same endpoint with query-parameter for response format options (e.g. export vs json for PA-table)
- Improve documentation in separate PBI: #18132
Naming guidelines
- Name things with their full name, do not use abbreviations. Let your IDE auto-complete names, so no RSI because of long names.
- Class names are plural for Modules, Controllers and Services. For example: ProgramsModule, ProgramsService, ProgramsController. Reflected in the file names as well. For example: programs.module.ts, programs.service.ts, programs.controller.ts.
- Class names are singular for Entities. For example: ProgramEntity. With file name: program.entity.ts.
- Base folder names of a Module are plural. For example: src/programs/
121 Service Guidelines
-
Every NestJS Module has a single and clearly defined responsibility.
-
Every Service has a single and clearly defined responsibility.
-
All database interactions are in Repositories.
-
A NestJS Module only uses Repositories that belong to their own and Modules lower in the NestJS Module Hierarchy.
-
Functions only accept and return DTOs and not Entities.
121 Portal Guidelines
File / Folder structure
This is our desired file & folder structure:
app
├── components
│ └── component-name
│ ├── component-name.component.html
│ ├── component-name.component.scss
│ ├── component-name.component.spec.ts
│ └── component-name.component.ts
├── directives
│ ├── directive-name.directive.spec.ts
│ └── directive-name.directive.ts
├── enums
│ └── enum-name.enum.ts
├── mocks
│ ├── mock-name.mock.ts
│ └── helpers.ts
├── models
│ ├── model-name.api.model.ts
│ └── model-name.model.ts
├── pages/
│ └── page-name/
│ ├── components/
| | └── page-specific-component/
| | ├── ...
│ ├── page-name.module.ts
│ ├── page-name.page.html
│ ├── page-name.page.scss
│ └── page-name.page.ts
└── services
├── service-name.service.spec.ts
└── service-name.service.ts
- No new top-level (ie. direct descendants of
app
) folders should be added. - Domain-specific folders should be inside
app/pages
- The
models
folder should only contain the representation of entities that come from the backend - A domain-specific folder (such as
app/pages/payment
) or a top-level component folder (such asapp/components/data-table
) can replicate app's top-level folder structure. For example, we could have acomponents
anddirectives
folder withinapp/pages/payments
or anenum
folder/file withinapp/components/data-table
.
When creating a new component/enum/directive, where do I put it?
By default, create it close to where it would be used. (ie. create a component that is specific to payments
within the payments
domain).
Only move it to the equivalent top-level folder when
- It will inevitably be used by more than one domain (eg. a design atom like
Button
) - It becomes used by more than one domain