# Architektur-Überblick

Diese Übersicht beschreibt die Architektur von D-DOK. Code-Stand: Version **0.0.8** (Branch `master`). Quelle: [git.agrarforschung.at/ddok/ddok](https://git.agrarforschung.at/ddok/ddok).

### Architektur-Diagramm

```mermaid
flowchart LR
  subgraph Client["Browser-Client"]
    NG["Angular 21 SPA<br></br>(client/)"]
    PDFX["PDF-Volltext-Extraktion<br></br>im Browser (pdfparse)"]
    NG --- PDFX
  end

  subgraph Server["D-DOK Server (Node.js 22)"]
    API["Express 5 + Awilix (DI)<br></br>TypeScript, server/"]
  end

  subgraph SQL["MySQL: eine gemeinsame Datenbank (D-DOK + D-ESS)"]
    MY[("ddok_*-Tabellen<br></br>Projekte, Publikationen<br></br>Volltext-Index (FULLTEXT)")]
    DESSDB[("D-ESS tbl_*-Tabellen<br></br>Kostenträger, Benutzer:innen")]
  end

  MO[("MongoDB 7.0, GridFS<br></br>PDF-Dateien (Bucket je Projekt)")]

  subgraph Auth["Authentifizierung"]
    AD["Active Directory (LDAPS)"]
    KC["Keycloak OIDC<br></br>sso.agrarforschung.at"]
  end

  subgraph Web["Öffentliche BAB-Website (optionaler Publish)"]
    WEBMY[("MySQL WEB_DATABASE")]
    WEBMO[("MongoDB WEB_MONGO")]
    SITE["Public-Frontend"]
  end

  NG -- "HTTPS / REST" --> API
  PDFX -- "pdfText im Upload" --> API
  API -- "Metadaten + Volltext" --> MY
  API -- "Lookup (gleiche Verbindung)" --> DESSDB
  API -- "PDF-Blob" --> MO
  API -. OIDC .-> KC
  API -. LDAPS .-> AD
  API -- Publish --> WEBMY
  API -- Publish --> WEBMO
  WEBMY --> SITE
  WEBMO --> SITE

```

### Komponenten im Überblick

<table id="bkmrk-komponentestackquell" style="border-collapse:collapse;width:100%;"><thead><tr style="background:#f0f0f0;"><th>Komponente</th><th>Stack</th><th>Quelle</th></tr></thead><tbody><tr><td>Frontend (SPA)</td><td>Angular 21 · Angular Material · Wijmo (@mescius) · Quill (ngx-quill). Upgrade auf Angular 21 in 0.0.8 (zuvor Angular 20).</td><td>`client/`</td></tr><tr><td>Backend-API</td><td>Node.js 22 · Express 5 · **Awilix** / awilix-express (Dependency Injection) · TypeScript · TypeORM</td><td>`server/`</td></tr><tr><td>PDF-Volltext-Extraktion</td><td>Läuft **im Browser** (Bibliothek `pdfparse`, Git-Submodul `modules/pdfparse`); der extrahierte Text wird beim Upload an den Server mitgesendet – kein serverseitiger Parser-Worker.</td><td>`client/` (file-upload), `modules/pdfparse/`</td></tr><tr><td>Relationale DB</td><td>MySQL (Port 3306) · `ddok_*`-Tabellen: Projekte, Publikationen, Stammdaten + **Volltext-Index (MySQL-FULLTEXT auf `file_text`)** · TypeORM mit `synchronize:true`</td><td>Gemeinsame MySQL-DB mit D-ESS</td></tr><tr><td>Dokumenten-DB</td><td>MongoDB 7.0 (Port 27017) · PDF-Dateien als **GridFS**, ein Bucket pro Projekt (`PROJECT_<id>`). Kein Volltext-Index – der liegt in MySQL.</td><td>Lokale MongoDB</td></tr><tr><td>D-ESS-Anbindung</td><td>Lese-Zugriff auf die D-ESS-Tabellen (`tbl_*`) über **dieselbe MySQL-Verbindung**: Kostenträger/KS/KT + Benutzer:innen-/Berechtigungsdaten</td><td>`DESS_LINK_ENABLED` (Default `true`)</td></tr><tr><td>Authentifizierung</td><td>Lokal · Active Directory (LDAPS, `passport-ldapauth`) · Keycloak OIDC (`openid-client`, Realm `ddok` auf sso.agrarforschung.at)</td><td>`AD_ENABLED` / `OIDC_ENABLED` in `server/config/config.js`</td></tr><tr><td>Website-Publish (optional)</td><td>Manueller Publish-Vorgang: ausgewählte Projekte/Publikationen samt Dateien werden in separate Website-Datenbanken kopiert (eigener Publish-Worker)</td><td>`WEB_DATABASE_*` + `WEB_MONGO_DATABASE_*`</td></tr></tbody></table>

### Deployment

D-DOK läuft in Produktion **nicht als Container**. Das im Repository vorhandene `Dockerfile` ist ausschließlich eine reproduzierbare **Build-Umgebung** für die CI – die Laufzeit ist ein klassischer **Plesk-/Passenger-Node.js-Prozess**.

<table id="bkmrk-aspektdetails-laufze" style="border-collapse:collapse;width:100%;"><thead><tr style="background:#f0f0f0;"><th>Aspekt</th><th>Details</th></tr></thead><tbody><tr><td>Laufzeit-Host</td><td>Plesk-Server mit Phusion Passenger (LXC-Container). Geteilt mit D-ESS, Datenpool und Adressdatenbank (Co-Tenancy). Node 22 via `nodenv`.</td></tr><tr><td>App-Pfade</td><td>Live: `/var/www/vhosts/agrarforschung.at/ddok.agrarforschung.at`  
Staging: `/var/www/vhosts/agrarforschung.at/staging-ddok.agrarforschung.at`</td></tr><tr><td>SSO</td><td>Keycloak-Realm `ddok` auf `sso.agrarforschung.at`</td></tr></tbody></table>

#### Build – `npm run build`

Führt drei Workspace-Builds nacheinander aus (`package.json`):

- `build:pdfparse` – baut das PDF-Volltext-Modul (`modules/pdfparse/`).
- `build:client` – Angular-Produktions-Build (`client/`).
- `build:server` – bündelt den TypeScript-Server via **esbuild** (`node esbuild.mjs`) und erzeugt das Laufzeit-Lockfile (`npm --prefix ./dist install --package-lock-only`).

Resultat ist der Ordner `dist/` – das eigentliche Deployment-Artefakt.

#### Rolle des `Dockerfile`

Multi-Stage-Build: Die *builder*-Stage führt `npm ci` + `npm run build` aus und erzeugt `dist/`; die finale Stage übernimmt nur `dist/`, exponiert Port 3000 und definiert `CMD ["npm","run","start"]`. In der CI wird dieses Image jedoch **nicht als Runtime ausgerollt**, sondern dient als hermetische Build-Box: Nach dem Build wird ein Wegwerf-Container erzeugt und dessen `/usr/src/app` (= `dist/`) per `docker cp` als CI-Artefakt herauskopiert.

#### CI/CD – `.gitlab-ci.yml`

Drei Stages, ausschließlich auf Branch `master`:

1. **build** – Docker-Image bauen (Docker-in-Docker, BuildKit-Registry-Cache), nach **Harbor** pushen und `dist/` als Artefakt extrahieren.
2. **deploy:staging** (automatisch) – bestehendes Verzeichnis nach `backup/` sichern (außer `backup`/`log`/`config`/`config.js`), `dist/*` per `scp` auf den Staging-Host kopieren, `.npmrc` schreiben, `npm ci` (nodenv Node 22), `touch tmp/restart.txt` → Passenger-Reload.
3. **deploy:live** (manueller Trigger) – identischer Ablauf auf den Live-Host.

Das Deployment ist somit ein **scp-basiertes Datei-Rollout des `dist/`-Ordners** mit anschließendem Passenger-Restart – kein `docker run` und kein Image-Pull auf dem Zielhost.

### Datenflüsse

1. **Projekt-/Publikationsanlage:** Benutzer:innen erstellen Projekte und Publikationen im Angular-Frontend; die Metadaten werden über die Express-API in MySQL persistiert.
2. **PDF-Upload:** Der Browser extrahiert beim Hochladen den PDF-Volltext (Bibliothek `pdfparse`). Die Datei wird als GridFS-Blob in MongoDB abgelegt, der extrahierte Text in der MySQL-Spalte `file_text` (FULLTEXT-indiziert für die Suche).
3. **D-ESS-Lookup:** Kostenstellen, Kostenträger und Benutzer:innen-Stammdaten werden zur Laufzeit aus den D-ESS-Tabellen (`tbl_*`) in **derselben** MySQL-Datenbank gelesen (`DESS_LINK_ENABLED`).
4. **Website-Publish (optional):** Über einen manuellen Publish-Vorgang werden freigegebene Projekte/Publikationen samt Dateien in die separaten Website-Datenbanken (`WEB_*`) kopiert und auf der öffentlichen BAB-Website angezeigt.

---

*Letzte Aktualisierung: 2026-06-10 · Pflege: Roland Neissl · Quelle: [git.agrarforschung.at/ddok/ddok](https://git.agrarforschung.at/ddok/ddok)*