-
Notifications
You must be signed in to change notification settings - Fork 3
chore: docs #386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
chore: docs #386
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
5812166
#219: created the root documentation file
petermasking 4e35db8
#219: fixed typos
petermasking 323c272
#219: added assets docs
petermasking d96e8f0
#219: moved the tack stack below the architecture
petermasking cc233f0
#219: first draft of the Web UI docs
petermasking b563c7b
#219: empty design system message
petermasking 9dec346
#219: introduced the johnDoe object
petermasking cd468dd
#219: some web ui improvements
petermasking e9b8978
#219: first draft of the domain docs
petermasking be78015
Merge branch 'main' into 219-set-up-docs
petermasking 790afda
Merge branch 'main' into 219-set-up-docs
petermasking 720a48a
Merge branch 'main' into 219-set-up-docs
petermasking 9664606
#219: updated readme
petermasking 2ed43a9
#219: updated the webui readme
petermasking 070bf2b
#219: updated the domain readme
petermasking b872be3
#219: added integrations readme
petermasking 8ef1e45
#219: added authentication integration docs
petermasking 60da063
#219: added database integration docs
petermasking ec4ebff
#219: added event store integration docs
petermasking a55f7db
#219: added file store integration docs
petermasking f7024a7
#219: added HTTP integration docs
petermasking c3d9df8
#219: added logging integration docs
petermasking 03fecf0
#219: added notification integration docs
petermasking 43f198d
#219: added validation integration docs
petermasking 039bee7
#219: added runtime integration docs
petermasking 30c2cc7
#219: added additional info to integrations
petermasking 44d7f39
#219: final touches
petermasking 10f945b
#219: processed feedback
petermasking File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
|
||
# Comify docs | ||
|
||
Hi, welcome to the Comify documentation. 👋 | ||
|
||
Here you'll find all the technical details on how we are building the application. We'll start with the fundamentals below. From there you can zoom in at any part for the details. | ||
|
||
## Architecture | ||
|
||
At the heart of any application lies architecture. To explain ours, we found inspiration from the [C4 model](https://c4model.com/) and added our own sauce. | ||
|
||
### Context | ||
|
||
Comify runs as a stand-alone application and hasn't many external dependencies (yet?). The most important one is the `Creator` that represents the end-user. Without it, the application doesn't have any value. Secondly we're outsourcing the identity and access management (IAM) to save on development that doesn't add business value. | ||
|
||
<img width="1102" alt="Application context" src="./assets/images/architecture/context.png"> | ||
|
||
**Note:** We use OpenID Connect for the IAM integration. | ||
|
||
### Shadows | ||
|
||
The application has two shadows. Each shadow contains content related to the application. | ||
|
||
<img width="1102" alt="Application shadows" src="./assets/images/architecture/shadows.png"> | ||
|
||
If you're reading this, then you've already found the docs. This is the darkest shadow, because it's the furthest away from the code. The tests are more code related, and can be found in the `test` folder in the project root. The application itself is placed in the `src` folder also in the project root. | ||
|
||
The structure of the shadows mimic the application structure to make navigating them easy. This structure is explained in the containers section below. | ||
|
||
### Containers | ||
|
||
The application is divided into multiple parts, called containers. We have these four. | ||
|
||
<img width="1102" alt="Application containers" src="./assets/images/architecture/containers.png"> | ||
|
||
Let's look at their usages and responsibilities. | ||
|
||
* [**Web UI**](./webui/) - Contains the web based interface for user interaction (SPA). | ||
* [**Assets**](./assets/) - Contains shared things like images, downloads, etc... | ||
* [**Domain**](./domain/) - Contains business related components like business logic, data entities, etc.. | ||
* [**Integrations**](./integrations/) - Contains implementations for IAM, database, etc.. | ||
|
||
Each part has its own folder in the application (and its shadows). For more detailed information you can click on their names. | ||
|
||
## Technology stack | ||
|
||
The project is 100% [TypeScript](https://www.typescriptlang.org/) based. | ||
|
||
**Runtime requirements** | ||
|
||
* [Node.js](https://nodejs.org/) as runtime (version 20+). | ||
* [Docker](https://www.docker.com/) for additional services. | ||
|
||
**Main dependencies** | ||
|
||
* [Jitar](http://jitar.dev) for E2E communication and scaling concerns. | ||
* [React](https://react.dev) for the frontend. | ||
|
||
All backend components are written in pure TypeScript without a framework. | ||
|
||
**Additional services** | ||
|
||
* [MongoDB](https://www.mongodb.com/) as database. | ||
* [MinIO](https://min.io/) as file store (images). | ||
* [Keycloak](https://www.keycloak.org/) as identity and access manager. | ||
|
||
## Configuration | ||
|
||
The application has several configuration options. You can find them here. | ||
|
||
### Environment | ||
|
||
For both the application and Docker services we've set up environment variables that can be managed from a single configuration file. An example of this file is located in the root of the project with the name `example.env`. | ||
|
||
**Note:** The project uses the `development.env` file for development. | ||
|
||
### Segments | ||
|
||
The domain container can be split into multiple segments for scalability reasons like deployment, load balancing and fail over. This is a feature provided by Jitar, more information on this can be found in the [documentation](https://docs.jitar.dev/deploy/segmentation.html). The configuration files can be found in the `segments` folder in the project root. | ||
|
||
We use a backend for frontend (BFF) segmentation strategy. The `bff.json` file exposes all functions that can be remotely accessed by the frontend. The other segment files are used to demonstrate two deployment strategies: | ||
|
||
1. vertical slicing (`notification.json`) | ||
1. horizontal slicing (`reads.json` and `writes.json`) | ||
|
||
Based on this segmentation model, the application can run in a monolithic and microservice fashion. | ||
|
||
### Resources | ||
|
||
The application uses resources like a database, file store, event broker, etc. that need to be defined in Jitar for sharing them across segments that are running on the same node. More information on this can be found in the [documentation](https://docs.jitar.dev/deploy/resources.html). The configuration files can be found in the `resources` folder in the project root. | ||
|
||
### Services | ||
|
||
Jitar provides [multiple services](https://docs.jitar.dev/fundamentals/runtime-services.html) to deploy applications with different strategies. Currently, we have a configurations for running the application as a monolith and as microservices. The configuration files can de found in the `services` folder in the project root. | ||
|
||
The `standalone.json` configuration file configures the monolithic deployment. All other files configure the microservice setup. | ||
|
||
## Getting started | ||
|
||
Before you start, make sure you meet all the runtime requirements. Follow these instructions next. | ||
|
||
1. Run `npm install` from a terminal to install the dependencies. | ||
1. Copy the `example.env` file to a `development.env` file. | ||
1. Run `npm run build` to build the application. | ||
1. Run `npm run standalone` to run Jitar at port 3000. | ||
|
||
To start the application you need to open a new terminal and run `npm run dev`. Now a [Vite](https://vitest.dev/) dev server is running on port 5173. You can then navigate to <http://localhost:5173> to open the application. | ||
|
||
To stop the application you can press CONTROL+C in both terminals. | ||
|
||
### Build & run | ||
|
||
To build and run the application you can keep using the `npm run build` and `npm run standalone` commands. For convenience both commands are combined in the following command: `npm run rebuild`. | ||
|
||
### Test & lint | ||
|
||
To run the tests you can use the `npm run test` command. You can also run the linter with the `npm run lint` command. For convenience the **build**, **test** and **lint** commands are combined in the following command: `npm run review`. | ||
|
||
### Run without Vite | ||
|
||
If you want to run the application without a Vite dev server, you can change the port number in the `AUTHENTICATION_CLIENT_URI` environment variable to `3000`. After that you can start the application again as standalone and navigate to <http://localhost:3000> to open the application. | ||
|
||
### Run as microservices | ||
|
||
For running the application as microservices, you need to start some additional helper services: | ||
|
||
* Proxy - central access point for the web browser. | ||
* Repository - provider for static assets. | ||
* Gateway - locator and load balancer for all procedures. | ||
|
||
After that, the segment services can be started. You can follow these instructions: | ||
|
||
1. Start the proxy by running `npm run proxy`. | ||
1. Start the repository by running `npm run repository`. | ||
1. Start the gateway by running `npm run gateway`. | ||
1. Start the BFF service by running `npm run bff`. | ||
1. Start the Notification service by running `npm run notification`. | ||
1. Start the Reads service by running `npm run reads`. | ||
1. Start the Writes service by running `npm run writes`. | ||
|
||
You can then navigate to <http://localhost:3000> to open the application via the proxy service. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
|
||
# Assets | Comify docs | ||
|
||
The assets container contains all kind of non-code related things that can be use by the [Web UI](../webui/) and / or the [Domain](../domain/) containers. Currently it only holds the application icon, but sooner or later it will be accompanied by other files like the *privacy statement* and the *terms of use* documents. | ||
|
||
This shadow container serves the same goal. It contains all the images used for the documentation. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
|
||
# Domain | Comify docs | ||
|
||
The domain contains the implementation of all business related components. It leverages a procedural approach using [Jitar](https://jitar.dev). | ||
|
||
## Module structure | ||
|
||
We're using a feature-oriented approach. Our root module structure looks like this. | ||
|
||
<img width="1102" alt="Web UI module structure" src="../assets/images/domain/modules.png"> | ||
|
||
Basically, it boils down to a root module per domain concept. Each module contains its features. | ||
|
||
A module is implemented as a folder containing an index file that exposes its essentials for consumers. | ||
|
||
## Features | ||
|
||
A feature is a sub-module containing all components required for its implementation. Features vary in size, ranging from small (single components) to large (multiple components), depending on the requirements. | ||
|
||
Every feature exposes its main function as the default export through the index file. Additionally, its types, errors, etc., can be exposed if their consumers require them. | ||
|
||
We aim to keep features as autonomous as possible by encapsulating their internal components. If another feature requires the same component (such as retrieving data by ID), we tend to make a copy on the first occurrence and move the component to its own feature upon multiple occurrences. This decision heavily depends on the complexity of the component. | ||
|
||
## Components | ||
|
||
Components can have different types depending on their responsibilities. Currently, we distinct the following types: | ||
|
||
* **Process** - a series of steps, where each step is a separate component. | ||
* **Task** - handles calculations, data manipulations, etc. | ||
* **Persistence** - responsible for querying, inserting, and updating the database. | ||
* **Aggregation** - gathers all related data. | ||
* **Validation** - ensures incoming data meets the required criteria. | ||
* **Event** - handles publications and subscriptions. | ||
|
||
Each component is implemented in its own file and exported as the default. | ||
|
||
A feature typically contains a combination of these component types. Process components that perform multiple database writes follow the [SAGA pattern](https://microservices.io/patterns/data/saga.html) as described in the [Jitar documentation](https://docs.jitar.dev/develop/data-consistency.html). | ||
|
||
## Data | ||
|
||
Data is defined per domain concept. We distinguish between two types: | ||
|
||
* **Persistent** - data stored in the database. | ||
* **Aggregated** - a data view containing all referenced data. | ||
|
||
Both types are defined as TypeScript types with read-only fields to ensure immutability. | ||
|
||
Persistent data is defined in the `types.ts` file in the root of the domain concept folder, as it is used by multiple features. Aggregated data is defined in the `types.ts` file of the aggregation feature, as it is more specific. | ||
|
||
Persistent data is read and written by persistence components using the database integration. | ||
|
||
## Events | ||
|
||
We use a publish/subscribe model for side effects such as updating counters, creating notifications, etc. | ||
|
||
Features that trigger side effects contain both a **publish** and **subscribe** component. Both components use the event broker integration to manage events. | ||
|
||
The publish component is used as the last step in the process. The subscribe component is exported in the feature's index file for use by other features. | ||
|
||
Features leverage a **subscriptions** component that imports and uses the subscribe components of other features. The subscriptions component is also exported in the feature's index file. | ||
|
||
## Definitions | ||
|
||
Every module (domain, concept, and feature) can have two types of definitions: | ||
|
||
* **Types** - TypeScript types such as data and event definitions, defined in the `types.ts` file. | ||
* **Definitions** - constants such as enums, validation schemas, record types, etc., defined in the `definitions.ts` file. | ||
|
||
The location of a definition depends on its scope of use. For example, the base data model is located in the domain root module, a record type is defined per domain concept, and a validation schema is defined per validation feature. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
|
||
# Authentication | Comify docs | ||
|
||
The authentication integration provides a universal interaction layer with an actual identity provider solution. | ||
|
||
This integration is based on the following authentication flow: | ||
|
||
1. Browser redirects to the IDP login page. | ||
2. User authenticate at the IDP. | ||
3. IDP provides identity information to this integration. | ||
4. This integration starts a session based on the provided identity. | ||
5. Sessions can be refreshed via this integration. | ||
6. Until the user logs out via this integration. | ||
|
||
## Implementations | ||
|
||
Currently, there is only one implementation: | ||
|
||
* **OpenID** - persistent document storage (used in production). | ||
|
||
## Configuration | ||
|
||
The used implementation needs to be configured in the `.env` file, together with the client URL. | ||
|
||
```env | ||
AUTHENTICATION_IMPLEMENTATION="openid" | ||
AUTHENTICATION_CLIENT_URI="http://localhost:5173/identify" | ||
``` | ||
|
||
In case of OpenID, additional configuration is required. | ||
|
||
```env | ||
OPENID_ISSUER="http://localhost:8080/realms/comify" | ||
OPENID_CLIENT_ID="openid" | ||
OPENID_CLIENT_SECRET="" | ||
OPENID_REDIRECT_URI="http://localhost:3000/rpc/domain/authentication/login" | ||
OPENID_ALLOW_INSECURE_REQUESTS=true | ||
``` | ||
|
||
## How to use | ||
|
||
An instance of the configured identity provider implementation can be imported for performing authentication operations. | ||
|
||
```ts | ||
import identityProvider from '^/integrations/authentication'; | ||
|
||
// Perform operations with the identityProvider instance | ||
``` | ||
|
||
### Operations | ||
|
||
```ts | ||
import identityProvider, { Session } from '^/integrations/authentication'; | ||
|
||
// Open connection | ||
await identityProvider.connect(); | ||
|
||
// Close connection | ||
await identityProvider.disconnect(); | ||
|
||
// Request the URL of the login page | ||
const loginUrl: string = await identityProvider.getLoginUrl(); | ||
|
||
// Handle a login and get a session | ||
// Throws LoginFailed if not successful | ||
const firstSession: Session = await identityProvider.login(providedIdentity); | ||
|
||
// Refresh a session | ||
// Throws LoginFailed if not successful | ||
const secondSession: Session = await identityProvider.refresh(firstSession); | ||
|
||
// Logout | ||
await identityProvider.logout(secondSession); | ||
``` | ||
|
||
### Session structure | ||
|
||
The session has the following structure. | ||
|
||
```ts | ||
type Session = { | ||
key?: string; | ||
requester?: unknown; | ||
identity: Identity; | ||
accessToken: Token; | ||
refreshToken: Token; | ||
expires: Date; | ||
}; | ||
``` | ||
|
||
Every session has a unique key that will be provided to external clients. This key is a unrelated hash value that contains no session information. It's ony used for referencing and storage. | ||
|
||
The requester represents the actual logged in user retrieved from the identity information (email), and can be stored in the session for quick reference. The full Identity structure looks like this. | ||
|
||
```ts | ||
type Identity = { | ||
name: string; | ||
nickname: string | undefined; | ||
picture: string | undefined; | ||
email: string; | ||
email_verified: boolean; | ||
}; | ||
``` | ||
|
||
The access and refresh tokens can be of any type, but is always represented as string. This depends on the configured implementation. In most cases this will be a JWT. | ||
|
||
```ts | ||
type Token = string; | ||
``` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.