- C# 68.6%
- TypeScript 30%
- JavaScript 1.1%
- Shell 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .github | ||
| .vscode | ||
| charts | ||
| config | ||
| db | ||
| environments | ||
| src | ||
| tests | ||
| .dockerignore | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| BDMS.sln | ||
| BDMS.slnLaunch | ||
| CHANGELOG.md | ||
| ct.yaml | ||
| docker-compose.ci.yml | ||
| docker-compose.dcproj | ||
| docker-compose.yml | ||
| get-changelog.sh | ||
| launchSettings.json | ||
| LICENSE | ||
| publiccode.yml | ||
| README.md | ||
| VERSION | ||
boreholes.swissgeol.ch
Webapplikation zur einfachen strukturierten und harmonisierten Erfassung von geologischen Bohrdaten.
Einrichten der Entwicklungsumgebung
Folgende Komponenten müssen auf dem Entwicklungsrechner installiert sein:
✔️ Git
✔️ Docker
✔️ Visual Studio 2022
✔️ Node.js 22 LTS
✔️ Optional, um die Onlinehilfe zu erstellen: MkDocs
Entwicklung mit Visual Studio 2022
Es wird eine lokale Installation von Node.js benötigt. Diese kann mit Visual Studio 2022 oder mit nvm installiert werden, um mehrere Node Version zu verwalten. Anschliessend kann mit nvm use die im Projekt verwendete Node Version aktiviert werden.
Das Projekt kann mit dem Launch Profile Boreholes gestartet werden.
Entwicklung mit Docker
Mit docker-compose up kann eine funktionierende Infrastruktur hochgefahren werden. Sie unterstützt Hot-Reload und lädt den Code aus dem lokalen Verzeichnis. Unter Windows mit Docker-Desktop kann die Synchronisierung in den mounted volumes zu Performance-Problemen führen.
Folgende Dienste/Anwendungen sind anschliessend wie folgt verfügbar
| 🔖 Dienst/Anwendung | 🔗Adresse | 🧞Benutzername | 🔐Passwort |
|---|---|---|---|
| Boreholes of Switzerland | localhost:3000 | admin |
swissforages |
| pgAdmin | localhost:3001 | n/a | n/a |
.NET REST API (v2)1 |
localhost:5000 localhost:3000/api/v2 | n/a | n/a |
| OIDC Server | localhost:4011 | admin |
swissforages |
Vitest Unit Tests
Die client seitigen Unit Tests werden mit Vitest ausgeführt. Testdateien folgen dem Muster *.test.ts / *.test.tsx.
Die Tests können mit folgenden Befehlen ausgeführt werden:
| Befehl | Beschreibung |
|---|---|
npm run test:unit |
Einmaliger Testlauf aller Unit Tests |
npm run test:unit:watch |
Startet Vitest im Watch-Modus für die Entwicklung |
Um einen einzelnen Test auszuführen, kann npx vitest run <Pfad/zur/Testdatei> verwendet werden.
Cypress Tests
Die Cypress Tests können mit npm run cy oder npm run test gestartet werden. Sie werden zudem automatisch in der CI/CD Pipeline ausgeführt. Das Projekt ist mit Cypress Cloud konfiguriert, wodurch unter anderem die parallele Ausführung der End-to-End (E2E) Tests ermöglicht wird. Testergebnisse und Aufzeichnungen sind ebenfalls direkt in Cypress Cloud einsehbar, was die Identifikation und Behebung möglicher Fehler und Probleme erleichtert. Um die detaillierten Testergebnisse einzusehen und die E2E-Tests des Projekts zu debuggen, kann die Cypress Dashboard-Seite besucht werden.
Authentifizierung & Architektur
Die Applikation nutzt das OpenID Connect (OIDC) Protokoll für die Authentifizierung und Teile der Autorisierung. Die Authentifizierung erfolgt über den OIDC Server, welcher in der Entwicklungsumgebung durch soluto/oidc-server-mock auf Basis von IdentityServer4 simuliert wird. Die Applikation nutzt den Authorization Code Flow mit PKCE für die Authentifizierung. Für den Zugriff auf die API wird der identity_token verwendet, welcher die Benutzerinformationen enthält. Die Grundsätzliche Autorisierung erfolgt über die Gruppenzugehörigkeit des Benutzers, welche im identity_token enthalten ist. Die Autorisierung auf API-Ebene erfolgt über die in der Datenbank definierten Workgroups & Administratoren-Rechte.
OpenID Connect (OIDC) Konfiguration
Die Applikation benötigt für die Authentifizierung und Autorisierung eine gültige OIDC-Konfiguration. Diese Konfiguration wird ausschliesslich in BDMS.Api benötigt. Sie wird über /api/v2/settings dem Client zur Verfügung gestellt. Die Werte werden durch den OIDC Server vergeben. Die folgenden Konfigurationen müssen gesetzt werden:
| Parameter | Beschreibung |
|---|---|
| Auth:Authority | Die URL des OpenID Connect Servers. Es ist vorausgesetzt, dass der Server ein gültiges OpenID Connect Discovery Dokument zur Verfügung stellt. |
| Auth:Audience | Der Wert des aud Claims, welcher in den identity_token des OIDC Servers enthalten ist. Die Audience wird als client_id verwendet beim Authentifizieren auf dem OIDC Endpunkt. |
| Auth:Scopes | Die benötigten Scopes, welche beim Authentifizieren auf dem OIDC Endpunkt angefragt werden. Default: openid profile |
| Auth:GroupClaimType | Der Name des Claims, welcher die Gruppenzugehörigkeit des Benutzers enthält. Default: cognito:groups |
| Auth:AuthorizedGroupName | Der Name der Gruppe, welche autorisiert ist, um auf die API zuzugreifen. |
| Auth:AnonymousModeEnabled | Gibt an, ob die OIDC-Konfiguration ignoriert und die Authentifizierung abgestellt werden soll. Ist für den Betrieb im anonymen Modus (read-only) erforderlich. |
Anonymer Modus (read-only)
Die Applikation kann auch im anonymen Modus betrieben werden, um die Bohrdaten öffentlich zugänglich zu machen. In diesem Modus ist die Applikation nur im read-only Modus verfügbar. Die Konfiguration erfolgt über OIDC-Konfiguration (siehe oben). Die Applikation wird im anonymen Modus gestartet, wenn Auth:AnonymousModeEnabled auf true gesetzt ist.
Release-Prozess
Publish
Jede Änderung, die in den main-Branch gemerged wird, löst automatisch den
Publish-Workflow aus. Dieser vergibt eine neue Versionsnummer, baut die Docker-Images mit derselben Version, taggt sie zusätzlich mit :edge, erstellt ein neues GitHub-Release und deployt die Version auf DEV.
Das Release wird bewusst weder als Pre-release noch als Latest markiert. Diese beiden Promotions sind die Auslöser für die weiteren Umgebungen (siehe unten).
PROD-Release
Ein PROD-Release entsteht, indem ein beliebiges Release im GitHub Release-Bereich
als „Set as the latest release" markiert wird. Das entsprechende Docker-Image bekommt dabei zusätzlich den latest-Tag.
Release Candidate (RC)
Um eine bestimmte Version als Release Candidate zu kennzeichnen, kann der GitHub-Workflow Release Candidate manuell gestartet werden. Er ergänzt den Release Candidate Docker-Image-Tag für eine bestehende Version.
So geht's:
- Im GitHub Repository unter Actions den Workflow Release Candidate auswählen.
- Auf Run workflow klicken.
- Die Quellversion eingeben (z.B.
2.1.1427ohnev).
Der Workflow erstellt dann für alle Docker-Images (Client, API, etc.) einen neuen Tag (z.B. :v2.1.1427-rc).
Hotfix-Release erstellen
Ein Hotfix-Release wird erstellt, indem vom letzten Release-Git-Tag ein neuer Branch angelegt wird. Dort werden die nötigen Korrekturen gemacht und anschliessend manuell ein neues GitHub Release erstellt, das dann wiederum als „Set as the latest release" markiert werden kann.
Docker-Image-Tags
| Tag | Beschreibung |
|---|---|
:edge |
Neuester Stand aus main (letzter Publish-Lauf) |
:v<version> |
Bestimmte Version, z.B. :v2.1.1427 |
:v<version>-rc |
Release Candidate einer bestimmten Version, z.B. :v2.1.1427-rc |
:v<major> |
Stabile Major-Version, z.B. :v2 (wird beim PROD-Release aktualisiert) |
:latest |
Aktuelle produktive Version (PROD-Release) |
Helm Chart Versionen
app.version wird automatisch durch release.yml bei jedem GitHub Release aktualisiert.
dataextraction.version und ocr.version müssen manuell in charts/swissgeol-boreholes/values.yaml aktualisiert werden, wenn diese Sub-Projekte ein neues Release erhalten.
Developer best practices
UI/UX
- Das UI-Design ist in Figma definiert. Unter Pages/Screens sind die definitiven Designs zu finden.
- Standardmässig werden die Lucid Icons verwendet. Custom-Icons können aus Figma kopiert und als SVG eingebunden werden. Um die Icons farblich stylen zu können, müssen
fillundstrokewie folgt angepasst werdenfill="currentColor" stroke="currentColor". - Wo möglich sollten UI-Komponenten der swissgeol-ui-core und swissgeol-ui-core-react Libraries verwendet werden.
- Sind keine Komponenten in den Swissgeol UI Libraries vorhanden, muss geklärt werden, ob die Komponente in der Swissgeol UI Library ergänzt werden soll. Je nach Entscheid wird die neue Komponente entwickelt oder MUI als UI Library verwendet. Allgemeine Styles werden im AppTheme.ts definiert und diese Styles werden, wo immer möglich, verwendet. MUI Styled Components im gleichen File mit der Komponente definieren, sobald die Styles mehrfach gebraucht werden. Übergreifende Styled Components werden in styledComponents.ts definiert. Für Abstände (margins, paddings, gaps etc.) sollten möglichst MUI Spacings verwendet werden.
Typescript
- Neue Komponenten werden in Typescript geschrieben.
- Es werden bevorzugt Interfaces statt Types verwendet.
- API-Typen werden aus der OpenAPI-Spezifikation generiert (siehe Abschnitt OpenAPI Codegen unten). Das generierte File
types.gen.tsdarf nicht manuell bearbeitet werden. - Verbleibende hand-geschriebene Interfaces für API Calls werden in den entsprechenden domänenspezifischen Files (z.B.
stratigraphy.ts) definiert oder – für das Legacy API – in ReduxStateInterfaces.ts. - Existieren mehrere Interfaces für eine Komponente, werden sie in einem separaten File neben der Komponente abgelegt.
- Das Interface für die React props der Komponente kann im selben File mit der Komponente definiert werden.
Translation
- Texte werden mit dem
useTranslationhook vonreact-i18nextübersetzt. DaswithTranslation HOCwird nicht mehr verwendet. - Neue Übersetzungskeys alphabetisch sortiert und in CamelCase in den
common.jsonFiles unter public/locale erfassen.
API
- Neue Endpoints werden immer im .NET API erstellt. Das Python Legacy API wird nicht erweitert.
- Redux wird nicht mehr erweitert. Datenabfragen werden mit dem Javascript Fetch API (siehe fetchApiV2.ts) oder wo sinnvoll mit
useQueryvontanstack-querygemacht. - Wenn Abfragen aus dem Redux Store in neuen Komponenten gebraucht werden, sollten die React hooks
useSelectorunduseDispatchverwendet werden.
OpenAPI Codegen
Die TypeScript-Typen für das .NET REST API v2 werden automatisch aus der OpenAPI-Spezifikation generiert.
Workflow bei API-Änderungen:
- .NET API lokal starten (z.B. via
docker-compose upoder Visual Studio) - OpenAPI-Spec aktualisieren und Typen neu generieren:
cd src/client npm run openapi # holt swagger.json vom laufenden Server und generiert types.gen.ts # oder einzeln: npm run openapi:fetch # nur swagger.json aktualisieren npm run openapi:gen # nur Typen aus bestehendem swagger.json generieren - Generiertes File
src/client/src/api/generated/types.gen.tsvia Git committen.
Konfiguration: src/client/openapi-ts.config.ts
⚠️
types.gen.tswird durch das Tool überschrieben – nie manuell bearbeiten.
Error Handling
Erwartbare Fehler
Inkorrekte User-Inputs, Formvalidation etc. werden direkt in der Komponente abgefangen und dem User als Inline-Message oder Alert angezeigt.
Unerwartete Fehler
Server Error, Render-Fehler etc. werden durch Error Boundaries abgefangen. Sie dienen als Fallback und sollten im normalen Ablauf der Anwendung nicht sichtbar sein. Wichtig: Error Boundaries im korrekten Scope platzieren (z.B. global, Übersichtsseite, Detailseite, Settings), damit möglichst viel der Applikation weiter funktioniert, wenn ein Fehler auftritt. Bei Bedarf können zusätzliche feingranularere Error Boundaries ergänzt werden.
Error Handling in Fetch-Requests
Für neue Fetch-Requests sollte immer fetchApiV2WithApiError (bzw. uploadWithApiError) verwendet werden.
-
Fetch-Requests mit TanStack Query (siehe
queryClient-Konfiguration inApp.tsx).:- GET-Requests Keine Daten im Cache: Die nächste Error Boundary wird gerendert.
- GET-Requests Daten im Cache vorhanden: Es werden veraltete Daten angezeigt und der Nutzer erhält einen Hinweis (Alert), dass die Daten nicht aktuell sein könnten.
- ADD/UPDATE/DELETE-Requests: Die bisherigen Daten werden weiterhin angezeigt, Nutzer erhält einen Hinweis (Alert), dass die die Aktion nicht erfolgreich war.
- Individuelle Reaktion auf Fehler: Bei Fehlern vom Typ
ApiErrorwird kein Standardalert angezeigt (siehequeryClient-Konfiguration inApp.tsx). DerisError-State bzw. deronError-Handler der Query/Mutation kann verwendet werden, um je nach Bedarf eine Fallback-Komponente zu rendern oder einen Alert anzuzeigen.ApiErrorwerden entweder direkt clientseitig von der Fetch-Funktion geworfen (siehe Beispiele infile.ts) oder sie werden für Problem-Responses mittype:"userError"geworfen (siehehandleFetchErrorinfetchApiV2.tsundStratigraphyV2Controller.cs).
-
Fetch-Requests, die nicht von TanStack Query gemanagt werden (legacy):
- Wird
fetchApiV2WithApiErrorverwendet, muss der Fetch-Request in einemtry-catch-Block ausgeführt und Fehler explizit behandelt werden. - Wird
fetchApiV2Legacyverwendet, erscheint im Fehlerfall ein Standard-Browser-Alert.
- Wird
Helm Charts
Die Helm Charts für das Deployment der Applikation befinden sich im Ordner charts/. Weitere Informationen zur Installation und Konfiguration finden sich in den jeweiligen Chart READMEs:
-
Authentifizierung via
AuthorizationHeader mit Bearer-Token (identity_token) von OIDC Server. Login-Konfigurationen können in config/oidc-mock-users.json getätigt werden. ↩︎