Skip to content

Commit ab2e28e

Browse files
kenglxnCopilot
andcommitted
feat(dokument): erstatt dokgen med in-process templating og Gotenberg
Rendrer Handlebars-maler til HTML i backend og konverterer til PDF/A-2b via ny ekspertbistand-gotenberg NAIS-app (Gotenberg/Chromium), som erstatning for det avviklede ekspertbistand-dokgen. - DokumentRenderer, HandlebarsConfig (escaping + strict mode), TemplateRepository og GotenbergClient i dokument-pakken - DokumentService med uendrede metodesignaturer - Maler konvertert til ren HTML (tilskuddsbrev, soknad, arenaNotat) - Enhets- og integrasjonstester (veraPDF PDF/A-2b, PDFBox tekst) - Infra: Dockerfile, nais dev/prod, workflows, docker-compose, dependabot og outbound-regler - Gotenberg på host-port 3003 lokalt og i CI §8 (sletting av dokgen) tas i egen PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b012e6c commit ab2e28e

72 files changed

Lines changed: 3196 additions & 418 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/dependabot.yml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: docker
4+
directory: /gotenberg
5+
schedule:
6+
interval: weekly

‎.github/workflows/cicd-backend.yaml‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ jobs:
2929
--health-retries 5
3030
ports:
3131
- 5532:5432
32+
gotenberg:
33+
image: gotenberg/gotenberg:8.37.0
34+
env:
35+
CHROMIUM_DISABLE_JAVASCRIPT: "true"
36+
CHROMIUM_ALLOW_LIST: "^file:///tmp/.*"
37+
API_DISABLE_DOWNLOAD_FROM: "true"
38+
WEBHOOK_DISABLE: "true"
39+
LIBREOFFICE_DISABLE_ROUTES: "true"
40+
CHROMIUM_MAX_CONCURRENCY: "2"
41+
options: >-
42+
--health-cmd "curl -fsS http://localhost:3000/health || exit 1"
43+
--health-interval 10s
44+
--health-timeout 5s
45+
--health-retries 10
46+
ports:
47+
- 3003:3000
3248
steps:
3349
- uses: actions/checkout@v4
3450

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: CICD Gotenberg
2+
on:
3+
push:
4+
paths:
5+
- gotenberg/**
6+
- nais/dev-gcp-gotenberg.yaml
7+
- nais/prod-gcp-gotenberg.yaml
8+
workflow_dispatch:
9+
schedule:
10+
- cron: '0 6 * * 1' # bygg nytt image hver mandag morgen
11+
12+
jobs:
13+
compile-test-and-build:
14+
name: Compile, build and deploy image
15+
runs-on: ubuntu-latest
16+
permissions:
17+
contents: read
18+
id-token: write
19+
outputs:
20+
image: ${{ steps.docker-build-push.outputs.image }}
21+
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v5
25+
with:
26+
fetch-depth: 0
27+
28+
- uses: nais/docker-build-push@v0
29+
id: docker-build-push
30+
with:
31+
team: fager
32+
image_suffix: gotenberg
33+
tag: ${{ github.sha }}
34+
dockerfile: gotenberg/Dockerfile
35+
docker_context: gotenberg
36+
salsa: false
37+
38+
deploy-dev:
39+
if: github.ref == 'refs/heads/main'
40+
needs: [ compile-test-and-build ]
41+
runs-on: ubuntu-latest
42+
permissions:
43+
id-token: write
44+
steps:
45+
- uses: actions/checkout@v5
46+
- name: Deploy dev-gcp
47+
uses: nais/deploy/actions/deploy@v2
48+
env:
49+
VAR: image=${{ needs.compile-test-and-build.outputs.image }}
50+
RESOURCE: nais/dev-gcp-gotenberg.yaml
51+
CLUSTER: dev-gcp
52+
53+
deploy-prod:
54+
if: github.ref == 'refs/heads/main'
55+
needs: [ compile-test-and-build ]
56+
runs-on: ubuntu-latest
57+
permissions:
58+
id-token: write
59+
steps:
60+
- uses: actions/checkout@v5
61+
- name: Deploy prod-gcp
62+
uses: nais/deploy/actions/deploy@v2
63+
env:
64+
VAR: image=${{ needs.compile-test-and-build.outputs.image }}
65+
RESOURCE: nais/prod-gcp-gotenberg.yaml
66+
CLUSTER: prod-gcp
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Manuell deploy dev gotenberg
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
compile-and-build:
8+
name: Build gotenberg image
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
id-token: write
13+
outputs:
14+
image: ${{ steps.docker-build-push.outputs.image }}
15+
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v5
19+
20+
- name: Build and push image
21+
id: docker-build-push
22+
uses: nais/docker-build-push@v0
23+
with:
24+
team: fager
25+
image_suffix: gotenberg
26+
tag: ${{ github.sha }}
27+
dockerfile: gotenberg/Dockerfile
28+
docker_context: gotenberg
29+
salsa: false
30+
31+
deploy-to-dev-gcp:
32+
name: Deploy to dev-gcp
33+
runs-on: ubuntu-latest
34+
permissions:
35+
contents: read
36+
id-token: write
37+
needs: compile-and-build
38+
39+
steps:
40+
- name: Checkout
41+
uses: actions/checkout@v5
42+
43+
- name: Login to NAIS (sets registry and OIDC)
44+
uses: nais/login@v0
45+
with:
46+
team: fager
47+
48+
- name: Deploy dev-gcp
49+
uses: nais/deploy/actions/deploy@v2
50+
env:
51+
VAR: image=${{ needs.compile-and-build.outputs.image }}
52+
RESOURCE: nais/dev-gcp-gotenberg.yaml
53+
CLUSTER: dev-gcp

‎backend/README.md‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,34 @@ Backend applikasjonen består av et rest endepunkt, en database for lagring av s
1111
Løsningen er utviklet i kotlin med ktor og bruker postgresql for datalagring. Forretningslogikk er frakoblet fra rest endepunktet via en Event sourcing arkitektur, hvor rest endepunktet kun er ansvarlig for å motta og validere søknader, og deretter trigge hendelser som håndteres av separate event handlers som inneholder all forretningslogikk.
1212
se [egen README.md](src/main/kotlin/no/nav/ekspertbistand/event/README.md) for mer informasjon om denne arkitekturen.
1313

14+
## Dokumentgenerering (PDF)
15+
16+
Søknads-PDF, tilskuddsbrev og arena-notat rendres fra Handlebars-maler til HTML og konverteres til PDF/A-2b av `ekspertbistand-gotenberg` (Gotenberg/Chromium). `DokumentService` er domeneadapteren, `DokumentRenderer` er den domeneuavhengige templating-kjernen, og `GotenbergClient` gjør HTML → PDF.
17+
18+
- Maler og regler for dem: [`dokumentmaler/templates/README.md`](src/main/resources/dokumentmaler/templates/README.md).
19+
- Templating-kjernen: [`dokument/pdf/README.md`](src/main/kotlin/no/nav/ekspertbistand/dokument/pdf/README.md).
20+
21+
### Lokal kjøring og tester
22+
23+
Start Postgres og Gotenberg før `mvn verify`, på samme måte som Postgres-testene:
24+
25+
```bash
26+
docker compose -f backend/docker-compose.yml up -d
27+
mvn -f backend/pom.xml verify
28+
```
29+
30+
Testene når Gotenberg på `http://localhost:3003`. I CI kjører Gotenberg som service-container i `cicd-backend.yaml`. Testcontainers brukes ikke.
31+
32+
### Visuell sammenligning
33+
34+
`no.nav.ekspertbistand.executables.RenderDokumentmaler` rendrer alle `testdata/*.json` via lokal Gotenberg til `backend/target/dokumentmaler-preview/gotenberg/`. Legg dagens dokgen-PDF-er (fra lokal dokgen på port 9000) i `backend/target/dokumentmaler-preview/dokgen/` ved siden av, så kan de sammenlignes manuelt.
35+
36+
```bash
37+
docker compose -f backend/docker-compose.yml up -d gotenberg
38+
mvn -f backend/pom.xml -q exec:java -Dexec.mainClass=no.nav.ekspertbistand.executables.RenderDokumentmalerKt -Dexec.classpathScope=test
39+
```
40+
41+
1442

1543
## Ny løsning for Ekspertbistand
1644

‎backend/docker-compose.yml‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,15 @@ services:
1616
- "9000:8080"
1717
environment:
1818
SPRING_PROFILES_ACTIVE: dev
19+
20+
gotenberg:
21+
image: gotenberg/gotenberg:8.37.0
22+
ports:
23+
- "3003:3000"
24+
environment: # samme verdier som i nais (§4.2)
25+
CHROMIUM_DISABLE_JAVASCRIPT: "true"
26+
CHROMIUM_ALLOW_LIST: "^file:///tmp/.*"
27+
API_DISABLE_DOWNLOAD_FROM: "true"
28+
WEBHOOK_DISABLE: "true"
29+
LIBREOFFICE_DISABLE_ROUTES: "true"
30+
CHROMIUM_MAX_CONCURRENCY: "2"

‎backend/pom.xml‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,13 @@
248248
<version>${graphql-kotlin.version}</version>
249249
</dependency>
250250

251+
<!-- Dokumentgenerering: Handlebars-templating i backend, HTML -> PDF/A i Gotenberg. -->
252+
<dependency>
253+
<groupId>com.github.jknack</groupId>
254+
<artifactId>handlebars</artifactId>
255+
<version>4.4.0</version>
256+
</dependency>
257+
251258
<dependency>
252259
<groupId>io.ktor</groupId>
253260
<artifactId>ktor-server-test-host-jvm</artifactId>
@@ -284,6 +291,27 @@
284291
<version>1.5.3</version>
285292
<scope>test</scope>
286293
</dependency>
294+
<!-- HTML-validering av rendret mal-output (DokumentmalTest). -->
295+
<dependency>
296+
<groupId>org.jsoup</groupId>
297+
<artifactId>jsoup</artifactId>
298+
<version>1.21.2</version>
299+
<scope>test</scope>
300+
</dependency>
301+
<!-- PDF/A-2b-validering av Gotenberg-output (integrasjonstest). -->
302+
<dependency>
303+
<groupId>org.verapdf</groupId>
304+
<artifactId>validation-model</artifactId>
305+
<version>1.28.1</version>
306+
<scope>test</scope>
307+
</dependency>
308+
<!-- Tekstuttrekk fra generert PDF (integrasjonstest). -->
309+
<dependency>
310+
<groupId>org.apache.pdfbox</groupId>
311+
<artifactId>pdfbox</artifactId>
312+
<version>3.0.5</version>
313+
<scope>test</scope>
314+
</dependency>
287315
</dependencies>
288316
<build>
289317
<finalName>app</finalName>

‎backend/src/main/kotlin/no/nav/ekspertbistand/Application.kt‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ import no.nav.ekspertbistand.arena.startKafkaConsumers
3333
import no.nav.ekspertbistand.clamav.ClamAvClient
3434
import no.nav.ekspertbistand.dokarkiv.DokArkivClient
3535
import no.nav.ekspertbistand.dokarkiv.FagsakIdService
36-
import no.nav.ekspertbistand.dokgen.DokgenClient
36+
import no.nav.ekspertbistand.dokument.DokumentService
37+
import no.nav.ekspertbistand.dokument.gotenberg.GotenbergClient
38+
import no.nav.ekspertbistand.dokument.pdf.PdfKonverterer
3739
import no.nav.ekspertbistand.entraproxy.EntraProxyClient
3840
import no.nav.ekspertbistand.ereg.EregClient
3941
import no.nav.ekspertbistand.ereg.EregService
@@ -86,7 +88,8 @@ fun main() {
8688

8789
provide(AltinnTilgangerClient::class)
8890
provide(ClamAvClient::class)
89-
provide(DokgenClient::class)
91+
provide<PdfKonverterer>(GotenbergClient::class)
92+
provide<DokumentService> { DokumentService(resolve()) }
9093
provide(DokArkivClient::class)
9194
provide(EregClient::class)
9295
provide(EregService::class)

0 commit comments

Comments
 (0)