Skip to content

Commit 804f98e

Browse files
committed
Update backend README
1 parent f8527e6 commit 804f98e

1 file changed

Lines changed: 31 additions & 220 deletions

File tree

backend/README.md

Lines changed: 31 additions & 220 deletions
Original file line numberDiff line numberDiff line change
@@ -1,253 +1,64 @@
11
# Flotilla backend
22

3-
The backend of flotilla is created using ASP.NET.
4-
Useful documentation of concepts and features in the .NET frameworks can be found
5-
[here](https://docs.microsoft.com/en-us/dotnet/fundamentals/).
6-
7-
- [Flotilla backend](#flotilla-backend)
8-
- [Setup](#setup)
9-
- [Automatic environment setup](#automatic-environment-setup)
10-
- [Manual environment setup](#manual-environment-setup)
11-
- [Run](#run)
12-
- [Run in Docker](#run-in-docker)
13-
- [Test](#test)
14-
- [Components](#components)
15-
- [MQTT Client](#mqtt-client)
16-
- [Configuration](#configuration)
17-
- [Database model and EF Core](#database-model-and-ef-core)
18-
- [Installing EF Core](#installing-ef-core)
19-
- [Adding a new migration](#adding-a-new-migration)
20-
- [Notes](#notes)
21-
- [Applying the migrations to the dev database](#applying-the-migrations-to-the-dev-database)
22-
- [Applying migrations to staging and production databases](#applying-migrations-to-staging-and-production-databases)
23-
- [Formatting](#formatting)
24-
- [CSharpier](#csharpier)
25-
- [Monitoring](#monitoring)
26-
- [Authorization](#authorization)
27-
28-
## Setup
29-
30-
To set up the backend on **Windows/Mac**, install Visual Studio and include the "ASP.NET and web development" workload during install.
31-
If you already have Visual Studio installed, you can open the "Visual Studio Installer" and modify your install to add the workload.
32-
33-
To set up the backend on **Linux**, install .NET for Linux
34-
[here](https://docs.microsoft.com/en-us/dotnet/core/install/linux).
35-
You need to also install the dev certificate for local .NET development on Linux.
36-
Follow
37-
[this guide](https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-7.0&tabs=visual-studio%2Clinux-ubuntu#trust-https-certificate-on-linux),
38-
for each of the browser(s) you wish to trust it in.
39-
**NB:** You probably need to run the commands with `sudo` prefixed to have permission to change them.
40-
41-
For the configuration to be able to read secrets from the keyvault, you will need to have the client secret stored locally in your secret manager.
42-
43-
For the MQTT client to function, the application expects a config variable in the MQTT section called `Password`, containing the password for the MQTT broker.
44-
This must either be stored in a connected keyvault as "Mqtt--Password" or in the ASP.NET secret manager
45-
as described in the [configuration section](#Configuration).
46-
47-
### Automatic environment setup
48-
49-
See [Flotilla readme](../README.md#automatic-environment-setup)
50-
51-
### Manual environment setup
52-
53-
Add the client secret as described in the [Configuration Section](#Configuration).
54-
55-
## Run
56-
57-
To build and run the app, run the following command in the backend folder:
3+
The backend of Flotilla is an ASP.NET application. See the [.NET documentation](https://docs.microsoft.com/en-us/dotnet/fundamentals/) for framework concepts.
584

59-
```
60-
dotnet run --project api
61-
```
62-
63-
To change the ports of the application and various other launch settings (such as the Environment), this can be modified in
64-
[launchSettings.json](api/Properties/launchSettings.json).
65-
Read more about the `launchSettings.json` file
66-
[here](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-6.0&preserve-view=true&viewFallbackFrom=aspnetcore-2.2#lsj)
67-
68-
### Run in Docker
69-
70-
For the backend to work when dockerized, you need to have the client secret exposed as
71-
an environment variable named `AZURE_CLIENT_SECRET`.
72-
Note that if possible to run locally without exposing this secret locally, that is preferred.
73-
To do this, to store it in an `.env` file in the root of the flotilla repository.
74-
See [Using the “--env-file” option](https://docs.docker.com/compose/environment-variables/#using-the---env-file--option) for more information.
75-
76-
To run the backend in docker, run the following command in the root folder of flotilla:
77-
78-
```
79-
docker compose up --build backend
80-
```
81-
82-
### Run locally with SARA
83-
84-
To be able to run Flotilla and SARA locally to get analysis results into the Flotilla frontend the `.env` file needs to be populated with:
85-
86-
```
87-
SARA__BaseUrl=http://localhost:8100
88-
SARA__Scopes__0=...
89-
```
5+
For general setup (environment, Docker, database connection), see the [root README](../README.md).
906

91-
## Test
7+
## Common commands
928

93-
To unit test the backend, run the following command in the backend folder:
9+
Common commands are defined in the [Makefile](./Makefile):
9410

95-
```
96-
dotnet test
97-
```
98-
99-
## Components
100-
101-
### MQTT Client
102-
103-
The MQTT client is implemented in [MqttService.cs](api/MQTT/MqttService.cs)
104-
and runs as an ASP.NET
105-
[BackgroundService](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-6.0&tabs=visual-studio#backgroundservice-base-class).
106-
Each MQTT message has its own class representation, and is linked to its respective topic pattern in [MqttTopics.cs](api/MQTT/MqttTopics.cs).
107-
To match incoming topic messages against the topic patterns we use helper functions to convert from the
108-
[MQTT wildcards](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901242)
109-
to regEx wildcards for the dictionary lookup.
110-
111-
Each topic then has its respective [event](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/events/)
112-
which is triggered whenever a new message arrives in that topic.
113-
The list of topics being subscribed to is defined as an array in
114-
[appsettings.Development.json](api/appsettings.Development.json).
115-
116-
An example of the subscriber pattern for an MQTT event is implemented in
117-
[MqttEventHandler.cs](api/EventHandlers/MqttEventHandler.cs).
118-
119-
## Configuration
120-
121-
The project has two [appsettings](https://docs.microsoft.com/en-us/iis-administration/configuration/appsettings.json)
122-
files.
123-
The base `appsettings.json` file is for common variables across all environments, while the
124-
`appsettings.Development.json` file is for variables specific to the Dev environments, such as the client IDs for the
125-
various app registrations used in development.
126-
127-
The configuration will also read from a configured Azure keyvault, which can then be accessed the same way as any other config variables.
128-
For this to work you will need to have the client secret stored locally in the secret manager as described below.
129-
The client secret (and MQTT password if not connected to keyvault) should be in the following format:
130-
131-
```
132-
"AzureAd": {
133-
"ClientSecret": "SECRET"
134-
},
135-
"Mqtt": {
136-
"Password": "PASSWORD"
137-
}
11+
```bash
12+
make run # dotnet run --project api
13+
make build # dotnet build api
14+
make test # dotnet test
15+
make format # dotnet csharpier format .
16+
make migration name=AddSomething # create a new EF Core migration
13817
```
13918

140-
Any local secrets used for configuration should be added in the
141-
[ASP.NET Secret Manager](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0&tabs=linux#secret-manager).
19+
## Database migrations (EF Core)
14220

143-
## Database model and EF Core
21+
The database model lives in [`api/Database/Models`](./api/Database/Models) and we use [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) as an O/RM. When changing the model, add a [migration](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/).
14422

145-
Our database model is defined in the folder
146-
[`/backend/api/Database/Models`](/backend/api/Database/Models) and we use
147-
[Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) as an
148-
object-relational mapper (O/RM). When making changes to the model, we also need
149-
to create a new
150-
[migration](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/)
151-
and apply it to our databases.
152-
153-
### Installing EF Core
23+
Install the EF Core CLI once:
15424

15525
```bash
15626
dotnet tool install --global dotnet-ef
15727
```
15828

159-
### Adding a new migration
160-
161-
**NB: Make sure you have fetched the newest code from main and that no one else
162-
is making migrations at the same time as you!**
163-
164-
1. Set the environment variable `ASPNETCORE_ENVIRONMENT` to `Development`:
165-
166-
```bash
167-
export ASPNETCORE_ENVIRONMENT=Development
168-
```
169-
170-
2. Run the following command from `/backend/api`:
171-
```bash
172-
dotnet ef migrations add AddTableNamePropertyName
173-
```
174-
`add` will make changes to existing files and add 2 new files in
175-
`backend/api/Migrations`, which all need to be checked in to git.
176-
177-
### Notes
178-
179-
- The `your-migration-name-here` is basically a database commit message.
180-
- `Database__ConnectionString` will be fetched from the keyvault when running the `add` command.
181-
- `add` will _not_ update or alter the connected database in any way, but will add a
182-
description of the changes that will be applied later.
183-
- If you for some reason are unhappy with your migration, you can delete it with:
184-
```bash
185-
dotnet ef migrations remove
186-
```
187-
Once removed you can make new changes to the model
188-
and then create a new migration with `add`.
189-
190-
### Applying the migrations to the dev database
191-
192-
Updates to the database structure (applying migrations) are done in GitHub Actions.
193-
194-
When a pull request contains changes in the `backend/api/Migrations` folder,
195-
a workflow is triggered to notify that the pull request has database changes.
196-
197-
After the pull request is merged, apply the migrations to the Development database by
198-
manually running the
199-
["Run database migrations (Development)"](https://github.com/equinor/flotilla/actions/workflows/run_development_migrations.yml)
200-
workflow from the Actions tab.
201-
202-
### Applying migrations to staging and production databases
203-
204-
This is done automatically as part of the deployment workflows
205-
([deploy_to_staging](https://github.com/equinor/flotilla/blob/main/.github/workflows/deploy_to_staging.yml)
206-
and [promote_to_production](https://github.com/equinor/flotilla/blob/main/.github/workflows/promote_to_production.yml)).
29+
Create a new migration (make sure you have the latest `main` and that no one else is adding a migration at the same time):
20730

208-
## Database backup and cloning
209-
210-
You can use pg_dump to extract a PostgreSQL database into an SQL file and psql to import the data into the target database from that file. Have the server running on pgAdmin and then execute the following commands.
211-
212-
Extract the entire database:
213-
214-
```
215-
pg_dump -U Username -d postgres -h host_name_or_address -p port -f output_file_name.sql
31+
```bash
32+
make migration name=AddTableNamePropertyName
21633
```
21734

218-
Extract specific tables:
35+
This adds files under `backend/api/Migrations` that must be committed. `add` does not modify any database — it only describes the changes.
21936

220-
```
221-
pg_dump -U Username -d postgres -h host_name_or_address -p port -t '"table_name"' -t '"second_table_name"' -f input_file_name.sql
37+
To discard a migration you're not happy with:
38+
39+
```bash
40+
dotnet ef migrations remove
22241
```
22342

224-
Upload file information to new database:
43+
### Applying migrations
22544

226-
```
227-
psql -U Username -d postgres -h host_name_or_address -p port -f output_file_name.sql
228-
```
45+
- **Development**: after merging a PR that touches `backend/api/Migrations`, manually run the ["Run database migrations (Development)"](https://github.com/equinor/flotilla/actions/workflows/run_development_migrations.yml) workflow.
46+
- **Staging / Production**: applied automatically by the [deploy_to_staging](https://github.com/equinor/flotilla/blob/main/.github/workflows/deploy_to_staging.yml) and [promote_to_production](https://github.com/equinor/flotilla/blob/main/.github/workflows/promote_to_production.yml) workflows.
22947

23048
## Formatting
23149

232-
### CSharpier
50+
Formatting rules are defined in the [.editorconfig](../.editorconfig). We use [CSharpier](https://csharpier.com/) to auto-format on save (see [installation](https://csharpier.com/docs/About)). To check formatting locally:
23351

234-
The formatting of the backend is defined in the [.editorconfig file](../.editorconfig).
235-
236-
In everyday development we use [CSharpier](https://csharpier.com/) to auto-format code on save. Installation procedure is described [here](https://csharpier.com/docs/About). No configuration should be required. To run CSharpier locally, go to the backend folder and run:
237-
`csharpier check .`
52+
```bash
53+
make format
54+
```
23855

23956
## SignalR
24057

241-
We use SignalR to asynchronously send event updates to the frontend. Currently we only support sending
242-
events and not receiving them, and all transmissions are sent using the SignalRService class. When
243-
doing so it is important to make sure that the event name provided corresponds with the name expected
244-
in the frontend.
58+
We use SignalR to push event updates to the frontend via `SignalRService`. Event names must match what the frontend expects.
24559

246-
It is also crucial that we do not await sending SignalR messages in our code. Instead we ignore the
247-
await warning. In the current version of the SignalR library, sending a message in an
248-
asynchronous thread may cause the thread to silently exit without returning an exception, which is
249-
avoided by letting the SignalR code run asynchronously after the current thread has executed.
60+
Do **not** await SignalR sends — in the current library version, awaiting from an async thread can cause the thread to silently exit without an exception. Let SignalR run after the current thread completes and ignore the await warning.
25061

25162
## Monitoring
25263

253-
We use [OpenTelemetry](https://opentelemetry.io/) to monitor the backend of our application. Traces, metrics, and logs are exported via the OTLP exporter to a Grafana-compatible backend.
64+
The backend is instrumented with [OpenTelemetry](https://opentelemetry.io/). Traces, metrics, and logs are exported via OTLP to a Grafana-compatible backend. Locally, telemetry can be inspected in the Aspire dashboard (see the [root README](../README.md#using-the-aspire-dashboard)).

0 commit comments

Comments
 (0)