Skip to content

Feature/ab#2225 public holiday import#334

Draft
witchpou wants to merge 92 commits into
it-at-m:sprintfrom
starwit:feature/ab#2225-public-holiday-import
Draft

Feature/ab#2225 public holiday import#334
witchpou wants to merge 92 commits into
it-at-m:sprintfrom
starwit:feature/ab#2225-public-holiday-import

Conversation

@witchpou

@witchpou witchpou commented Jul 6, 2026

Copy link
Copy Markdown

Description

see starwit#12

Issue References

Feature ab#2225: added public holidays from configurable API. In Default, https://openholidaysapi.org is used, but can be configured in database table configuration or Admin Portal -> Anwenderkonfiguration.

Definition of Done

  • Acceptance criteria are met
  • Testing is done (unit-tests, DEV-environment)
  • Build/Test workflow has successfully finished
  • Release notes are complemented
  • Documentation is complemented (operator manual, system specification, etc.)

Summary by CodeRabbit

  • New Features

    • Added configuration management in the app, including a new settings tab and save/import actions.
    • Added image upload and preview support for counting locations.
    • Added broader map mode options and a new “Dauerzählung” toggle.
    • Added local development and project documentation, plus updated licensing and project information.
  • Bug Fixes

    • Improved loading of city district data and related form selections.
    • Updated map display behavior and request handling for more reliable viewing.

Starwit and others added 26 commits February 26, 2026 14:20
…ounting-spot

feature/ab#2201 add image upload dialog, show image in counting spot overview
switch license to AGPLv3, refactor docs
@witchpou
witchpou marked this pull request as draft July 6, 2026 20:28
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR overhauls CI/CD workflows (build, PR checks, release with Docker/Helm publishing), replaces the license with AGPLv3, rewrites README/docs, restructures apigateway packaging (frontend static assets, Helm templates, logging), adds a Helm chart, and adds frontend features: configuration management UI, city information store, image upload/preview for Zählstellen, map base-layer switching, and a Dauerzählung field.

Changes

CI/CD, License and Documentation

Layer / File(s) Summary
Workflow rewrite
.github/workflows/build.yaml, .github/workflows/build_push.yaml, .github/workflows/build_push_latest.yaml, .github/workflows/pr_build.yaml, .github/workflows/release.yaml
Removes legacy build/build_push workflows; adds build_push_latest (build, Docker publish, Helm publish), pr_build (compliance, build-maven, check_helm), and rewrites release.yaml into a build → publish_docker → publish_helm pipeline.
License and docs rewrite
LICENSE, README.md, docs/Readme.md
Replaces MIT license with AGPLv3, rewrites README with English overview/component table/contributing/license/contact sections, and adds a new developer setup doc.

Apigateway build, resources, logging, and Helm chart

Layer / File(s) Summary
Maven parent/version updates
pom.xml, apigateway/pom.xml, frontend/pom.xml
Updates project version/SCM/release-plugin config and shifts apigateway/frontend to inherit from a shared parent POM, removing Hazelcast and frontend runtime dependencies.
Resource packaging and build plugins
apigateway/.gitignore, apigateway/pom.xml
Adjusts resource filtering for static assets and wires plugins to copy frontend dist and Helm templates into build output.
Logging and local gateway config
apigateway/src/main/resources/logback-spring.xml, apigateway/application-local.yml
Switches non-debug logging to plain-text STDOUT and adds new local gateway CORS/route/filter configuration.
Helm chart
stack/helm/dave-admin-portal/*
Adds a full Helm chart (Chart.yaml, helpers, ConfigMap, Deployment, Ingress, Service, values.yaml) for deploying the admin portal.

Frontend features

Layer / File(s) Summary
City information store and DTOs
frontend/src/types/configuration/CityDistrictDTO.ts, frontend/src/api/service/CityInformationService.ts, frontend/src/store/CityInformationStore.ts, frontend/src/App.vue
Adds city district DTO/service/store and wires district loading into app startup, removing prior Fachadmin gating.
Stadtbezirk/Stadtbezirksviertel usage in forms
frontend/src/components/zaehlstelle/CreateZaehlstelleForm.vue, .../UpdateZaehlstelleForm.vue, frontend/src/types/enum/Stadtbezirksviertel.ts
Sources district data from the store instead of enums and adds a Wolfsburg entry to the Stadtbezirksviertel mapping.
Application configuration management
frontend/src/types/configuration/ConfigurationItemDTO.ts, frontend/src/api/service/ConfigurationService.ts, .../PublicHolidaysService.ts, frontend/src/components/config/ConfigApplication.vue, frontend/src/views/ConfigView.vue
Adds configuration CRUD service methods, a public-holidays import service, and a new configuration UI tab/component.
Zählstelle image upload/preview
frontend/src/api/service/ZaehlstellenImageService.ts, frontend/src/api/service/FetchService.ts, frontend/src/api/util/FetchUtils.ts, .../UpdateZaehlstelleForm.vue, .../ZaehlstelleInfo.vue, frontend/src/views/ZaehlstelleView.vue
Adds blob-based fetch support and an image upload/preview service, wired into the update form and info display.
Map base layer and Dauerzählung field
frontend/src/components/map/*, frontend/src/components/zaehlung/*, frontend/src/types/zaehlung/ZaehlungDTO.ts
Switches default base map layer to OpenStreetMap, replaces showLuftbild with mapType prop, adds a dauerzaehlung boolean field/checkbox, and adjusts related form watchers.

Estimated code review effort: 4 (Complex) | ~75 minutes

Possibly related PRs

  • it-at-m/dave-admin-portal#283: Both PRs modify the zaehlart watcher logic in ZaehlungForm.vue, affecting category reset behavior on form changes.

Suggested reviewers: AnHo314

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the main change: adding public holiday import support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Tools execution failed with the following error:

Failed to run tools: 13 INTERNAL: Received RST_STREAM with code 2 (Internal server error)


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
frontend/src/components/map/MiniMap.vue (1)

100-138: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use L.tileLayer for the OpenStreetMap base layer

L.tileLayer.wms(...) is for WMS services and expects WMS-style parameters such as layers; this URL is a standard XYZ tile endpoint, so it should use L.tileLayer(...) instead. Because OpenStreetMaps is the default base layer here, this affects initial map load.

Suggested fix
-  const osm = L.tileLayer.wms(
+  const osm = L.tileLayer(
     "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
     {
       attribution: mapAttributionOpenStreetMap,
       referrerPolicy: "strict-origin-when-cross-origin"
     }
   );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/map/MiniMap.vue` around lines 100 - 138, The
OpenStreetMap base layer in createBaseLayers is being created with
L.tileLayer.wms, but that endpoint is an XYZ tile source, not a WMS service.
Update the OpenStreetMaps layer to use L.tileLayer instead, keeping the existing
attribution and referrerPolicy options, so createLayersAndAddToMap can add the
correct default base layer via baseLayers.OpenStreetMaps.
frontend/src/components/map/ZaehlstelleMap.vue (1)

345-385: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use L.tileLayer(...) for the OpenStreetMap base layer.

https://tile.openstreetmap.org/{z}/{x}/{y}.png is an XYZ tile endpoint, not WMS. L.tileLayer.wms(...) will send WMS GetMap requests to that URL, so the default base layer won't load correctly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/map/ZaehlstelleMap.vue` around lines 345 - 385, The
OpenStreetMap base layer in createBaseLayers is using the wrong Leaflet
constructor: switch the osm layer from L.tileLayer.wms to L.tileLayer because
the XYZ tile URL is not a WMS endpoint. Keep the rest of createBaseLayers and
createLayersAndAddToMap unchanged, and ensure the OpenStreetMap entry returned
from createBaseLayers is a normal tile layer so the default base layer loads
correctly.
frontend/src/components/map/ZaehlungCardMap.vue (1)

94-140: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use L.tileLayer(...) for the OSM base layer
L.tileLayer.wms(...) is for WMS endpoints; this URL should use L.tileLayer(...) instead. Keep referrerPolicy: "strict-origin-when-cross-origin" on the layer so OSM gets a Referer header.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/map/ZaehlungCardMap.vue` around lines 94 - 140, The
OSM base layer in createBaseLayers is using the wrong Leaflet factory: replace
the L.tileLayer.wms call for the openstreetmaps branch with L.tileLayer because
the URL is a standard tile endpoint, not a WMS service. Keep the existing
attribution and add referrerPolicy: "strict-origin-when-cross-origin" on that
L.tileLayer instance so the OpenStreetMap request includes the expected Referer
header.
frontend/src/components/zaehlstelle/UpdateZaehlstelleForm.vue (2)

202-214: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Image upload races independently of the save outcome.

ZaehlstellenImageService.uploadImage(...) fires concurrently with saveZaehlstelle(...) rather than after its success. "saved" is emitted as soon as the save resolves, regardless of the image upload's outcome, and there's no success feedback for the upload. Consider chaining the upload after a successful save and emitting once both complete.

♻️ Suggested fix
 function save(): void {
   ZaehlstellenService.saveZaehlstelle(zaehlstelle.value)
-    .then(() => {
-      emits("saved");
+    .then(() => {
+      if (selectedImage.value) {
+        return ZaehlstellenImageService.uploadImage(zaehlstelle.value.id, selectedImage.value)
+          .catch((error) => snackbarStore.showApiError(error));
+      }
     })
+    .then(() => emits("saved"))
     .catch((error) => snackbarStore.showApiError(error));
-
-  if (selectedImage.value) {
-    ZaehlstellenImageService.uploadImage(zaehlstelle.value.id, selectedImage.value)
-      .catch((error) => snackbarStore.showApiError(error));
-  }
-
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/zaehlstelle/UpdateZaehlstelleForm.vue` around lines
202 - 214, The save flow in save() is starting
ZaehlstellenImageService.uploadImage() independently of
ZaehlstellenService.saveZaehlstelle(), so the image upload can race the save and
emits("saved") fires before the upload finishes. Update save() in
UpdateZaehlstelleForm.vue to chain the upload after a successful save, using the
existing zaehlstelle value and selectedImage check, and only emit "saved" once
both operations complete successfully; keep error handling via
snackbarStore.showApiError for either step.

157-173: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Missing assignment breaks Stadtbezirksviertel lookup for all non-Wolfsburg districts.

In the else branch, StadtbezirksviertelToBeschreibung.get(zaehlstelle.value.stadtbezirkNummer) is evaluated but never assigned to stadtbezirksviertelMap. As a result, for every district number below 100 (i.e., all standard Munich districts), the map stays undefined and the computed always falls through to the "could not be determined" fallback text.

🐛 Proposed fix
 const getStadtbezirksviertel = computed(() => {
   let stadtbezirksviertelMap: Map<number, string> | undefined;
   if(zaehlstelle.value.stadtbezirkNummer >= 100) { // TODO for obvious reasons
     stadtbezirksviertelMap = StadtbezirksviertelToBeschreibung.get(100);
   } else {
-    StadtbezirksviertelToBeschreibung.get(zaehlstelle.value.stadtbezirkNummer);
+    stadtbezirksviertelMap = StadtbezirksviertelToBeschreibung.get(zaehlstelle.value.stadtbezirkNummer);
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/zaehlstelle/UpdateZaehlstelleForm.vue` around lines
157 - 173, The computed lookup in getStadtbezirksviertel is missing an
assignment in the else branch, so stadtbezirksviertelMap stays undefined for
normal district numbers. Update the else path to store the result of
StadtbezirksviertelToBeschreibung.get(zaehlstelle.value.stadtbezirkNummer) in
stadtbezirksviertelMap, keeping the rest of the fallback logic unchanged, so the
computed can resolve the correct Stadtbezirksviertel instead of always returning
the default message.
🧹 Nitpick comments (13)
stack/helm/dave-admin-portal/templates/ingress.yaml (1)

41-45: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Backend service name is hardcoded instead of using the fullname helper.

Other resources consistently use include "daveAdminPortal.fullname" for naming; hardcoding admin-portal here (and in service.yaml) breaks that convention and can collide across releases/namespaces.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@stack/helm/dave-admin-portal/templates/ingress.yaml` around lines 41 - 45,
The backend service name is hardcoded instead of following the chart naming
helper convention. Update the service references in ingress.yaml and the
matching Service definition in service.yaml to use include
"daveAdminPortal.fullname" so the admin-portal resource names stay
release-scoped and consistent with the rest of the chart.
stack/helm/dave-admin-portal/templates/deployment.yaml (1)

95-103: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

extraEnvVars is injected twice — once via env, once via envFrom (same ConfigMap).

configmap.yaml already renders .Values.extraEnvVars into ConfigMap data, and envFrom.configMapRef (Line 101-103) loads that same ConfigMap. Explicitly re-injecting the same values via env (Line 95-100) is redundant. It won't error since explicit env takes precedence over envFrom, but it's confusing/duplicated config that will drift.

♻️ Proposed fix — drop the explicit env block, rely on envFrom
-          {{- with .Values.extraEnvVars }}
-          {{- range $name, $value := . }}
-            - name: {{ $name }}
-              value: {{ $value | quote }}
-          {{- end }}
-          {{- end }}
           envFrom:
             - configMapRef:
                 name: {{ include "daveAdminPortal.fullname" . }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@stack/helm/dave-admin-portal/templates/deployment.yaml` around lines 95 -
103, The deployment template is duplicating `extraEnvVars` by rendering them
both in the explicit `env` block and again through `envFrom` from the same
ConfigMap. Remove the redundant `env` range under the `deployment.yaml` template
and keep the `envFrom.configMapRef` path as the single source of truth, using
the existing `extraEnvVars` and `envFrom` sections to locate the change.
.github/workflows/pr_build.yaml (1)

17-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inconsistent actions/checkout major version within the same workflow.

Line 18 uses actions/checkout@v4 while line 56 uses @v6 in the same file. Both are valid releases, but mixing majors without reason is confusing and makes it harder to reason about checkout behavior (v6 changed credential persistence) across jobs.

Also applies to: 55-58

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/pr_build.yaml around lines 17 - 18, The workflow is using
different major versions of actions/checkout in the same file, which should be
standardized for consistency. Update the checkout step in this job to match the
other checkout usage already present in the workflow, and keep both occurrences
aligned by referencing the shared actions/checkout invocation so behavior stays
consistent across jobs.
.github/workflows/release.yaml (1)

60-68: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Fragile changelog-change detection.

git status | grep "modified" parses human-readable porcelain output rather than a script-friendly format, so it's more likely to have false positives/negatives than git status --porcelain or git diff --quiet. Given this gates whether the changelog commit/push happens during a release, a stricter check would be safer.

🔧 Proposed fix
-          modifications=$(git status | grep "modified" || true)
-          if [ ! -z "$modifications" ]
+          if ! git diff --quiet -- CHANGELOG.md
           then
-            echo "modifications found: $modifications"
             git commit -m "modified changelog"
             git push
           fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yaml around lines 60 - 68, The changelog commit
gate is using fragile human-readable git output, so replace the `git status |
grep "modified"` check with a script-safe change detection method in the release
workflow step that runs after `git add .` and before `git commit`/`git push`.
Use a deterministic status check such as `git diff --quiet` or `git status
--porcelain` so the changelog update is only committed when tracked files
actually changed, and keep the existing `modifications`, `git commit -m
"modified changelog"`, and `git push` flow wired to that stricter condition.
apigateway/src/main/resources/logback-spring.xml (1)

58-66: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate appender definition across profiles.

This STDOUT appender (name, class, and pattern) is identical to the one already defined earlier in the file (lines 10-17). Consider extracting the shared appender definition (e.g., via a top-level <property>/<include> or a common pattern property) to avoid config drift between the debug and non-debug profiles.

♻️ Example: extract shared pattern into a property
+    <property name="COMMON_LOG_PATTERN" value="%date{yyyy.MM.dd HH:mm:ss.SSS} | ${springAppName} | TraceId: %X{traceId:-} | SpanId: %X{spanId:-}] | %level | [%thread] | %logger{0} | [%file : %line] - %msg%n"/>
     ...
     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
         <encoder>
-            <pattern>
-                %date{yyyy.MM.dd HH:mm:ss.SSS} | ${springAppName} | TraceId: %X{traceId:-} | SpanId: %X{spanId:-}] |
-                %level | [%thread] | %logger{0} | [%file : %line] - %msg%n
-            </pattern>
+            <pattern>${COMMON_LOG_PATTERN}</pattern>
         </encoder>
     </appender>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apigateway/src/main/resources/logback-spring.xml` around lines 58 - 66, The
STDOUT appender is duplicated across profiles with the same name, class, and
pattern, so update the logback-spring.xml configuration to share a single
definition or shared pattern property instead of repeating it. Refactor the
repeated STDOUT appender setup into a common top-level property or reusable
include, and make both profile sections reference that shared configuration to
keep the debug and non-debug setups aligned.
frontend/src/components/config/ConfigApplication.vue (1)

29-36: 📐 Maintainability & Code Quality | 🔵 Trivial

Hardcoded key name couples UI to backend config key.

item.keyname === 'publicHolidaysApiUrl' silently breaks the import button if the backend key ever changes/renames. Consider extracting this to a named constant near the top of the script for a single source of truth.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/config/ConfigApplication.vue` around lines 29 - 36,
The import button condition in ConfigApplication.vue is tightly coupled to the
backend key via item.keyname === 'publicHolidaysApiUrl'. Extract that key into a
named constant in the component script and use the constant in the template and
any related logic, so the ConfigApplication UI has a single source of truth and
is easier to update if the backend config key changes.
frontend/src/api/service/FetchService.ts (1)

64-117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

sendRequestForBlob duplicates sendRequest almost verbatim.

The entire error-handling chain (400/403/409/412/opaqueredirect/fallback) is copy-pasted from sendRequest (Lines 118-172), differing only in the success-path return (response.blob() vs response.json()). This is now duplicated a third time in a very similar form in sendRequestForPDF. Any future change to status-code handling (e.g., adding a new code) needs to be applied in multiple places, risking drift.

Consider extracting the shared non-OK handling into a single private helper that both methods call.

♻️ Proposed refactor
+  private static handleErrorResponse(
+    response: Response,
+    errorMessage: string
+  ): never {
+    if (response.status === 400) {
+      throw new ApiError(
+        Levels.ERROR,
+        errorMessage,
+        `Fehlerhafte Anfrage an das Backend geschickt, HTTP: 400.`
+      );
+    } else if (response.status === 403) {
+      throw new ApiError(
+        Levels.ERROR,
+        `Sie haben nicht die nötigen Rechte um diese Aktion durchzuführen.`
+      );
+    } else if (response.status === 409) {
+      throw new ApiError(
+        Levels.ERROR,
+        errorMessage,
+        `Eine Zählstelle mit der angegebenen Zählstellennummer und Zählart existiert bereits.`
+      );
+    } else if (response.status === 412) {
+      location.reload();
+      throw new ApiError(
+        Levels.ERROR,
+        `Die Daten wurden in der Zwischenzeit verändert. Die Seite wird neu geladen.`
+      );
+    } else if (response.type === FetchService.RESPONSE_TYPE_OPAQUE_REDIRECT) {
+      location.reload();
+    }
+    throw new ApiError(
+      Levels.ERROR,
+      errorMessage,
+      `Fehler: ${response.status} ${response.statusText}`
+    );
+  }
+
   private static sendRequestForBlob(
     url: string,
     request: RequestInit,
     errorMessage: string
   ): Promise<Blob> {
     return fetch(url, request)
       .catch((error) => {
         throw new ApiError(
           Levels.ERROR,
           `Die Verbindung zum Service konnte nicht aufgebaut werden.`,
           error
         );
       })
       .then((response) => {
         if (!response.ok) {
-          if (response.status === 400) {
-            ...
-          }
-          throw new ApiError(...);
+          return FetchService.handleErrorResponse(response, errorMessage);
         }
         return response.blob();
       });
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/api/service/FetchService.ts` around lines 64 - 117, Extract the
shared non-OK response handling from sendRequestForBlob and sendRequest into a
single private helper so the 400/403/409/412/opaqueredirect/fallback logic is
maintained in one place. Keep the success-path differences separate by having
sendRequest, sendRequestForBlob, and sendRequestForPDF reuse that helper before
returning response.json(), response.blob(), or the PDF-specific result. Use the
existing FetchService methods and ApiError handling as the main anchors when
refactoring.
frontend/src/api/service/ZaehlstellenImageService.ts (1)

25-75: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

uploadImage reimplements fetch error-handling instead of reusing FetchService.

This method manually duplicates the fetch/error-mapping logic already centralized in FetchService (network-error → ApiError, 400/403 mapping) but diverges from it: it omits the 409 and 412 (optimistic-lock) handling and the opaqueredirect/location.reload() behavior present in sendRequest/sendRequestForBlob. If the upload endpoint can ever return those statuses, this silently falls into the generic "else" branch instead of the specialized handling used everywhere else.

Consider adding a postFormData-style method to FetchService/FetchUtils (similar to how getBlobGETConfig was added for blob GETs) so multipart uploads share the same error-handling path as the rest of the app.

♻️ Suggested direction
// FetchUtils.ts
+  static getFormDataPOSTConfig(formData: FormData): RequestInit {
+    const headers = this.getHeaders();
+    headers.delete("Content-Type"); // let the browser set the multipart boundary
+    return {
+      method: "POST",
+      body: formData,
+      headers,
+      mode: "cors",
+      credentials: "same-origin",
+      redirect: "manual",
+    };
+  }
// FetchService.ts
+  static postFormData(
+    formData: FormData,
+    endpoint: string,
+    errorMessage: string
+  ): Promise<any> {
+    const url = `${this.BASE}/${endpoint}`;
+    const request = FetchUtils.getFormDataPOSTConfig(formData);
+    return FetchService.sendRequest(url, request, errorMessage);
+  }
// ZaehlstellenImageService.ts
   static uploadImage(id: string, file: File): Promise<any> {
-    const url = `${BaseUrlProvider.getBaseUrl()}/${this.ENDPOINT}/${id}`;
     const formData = new FormData();
-    formData.append('image', file);
-    ...
-    return fetch(url, request).catch(...).then(...);
+    formData.append("image", file);
+    return FetchService.postFormData(
+      formData,
+      `${this.ENDPOINT}/${id}`,
+      "Beim Hochladen des Bildes ist ein Fehler aufgetreten."
+    );
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/api/service/ZaehlstellenImageService.ts` around lines 25 - 75,
The uploadImage method is duplicating fetch error handling instead of using the
centralized FetchService flow, so it misses the shared 409/412 and
opaqueredirect handling. Move the multipart POST logic into a reusable
FetchService/FetchUtils helper (for example a postFormData-style method) and
have ZaehlstellenImageService.uploadImage call that helper, reusing the same
ApiError mapping and redirect/reload behavior as sendRequest and
sendRequestForBlob.
frontend/src/api/util/FetchUtils.ts (1)

17-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a doc comment for consistency.

Every other config builder in this file has a JSDoc-style comment (e.g. getGETConfig, getPOSTConfig); getBlobGETConfig is missing one.

✏️ Suggested addition
+  /**
+   * Liefert eine default GET-Config für fetch für Blob-Antworten (ohne Content-Type-Header)
+   */
   static getBlobGETConfig(): RequestInit {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/api/util/FetchUtils.ts` around lines 17 - 27, The
getBlobGETConfig method in FetchUtils is missing the same JSDoc-style
documentation used by the other config builders like getGETConfig and
getPOSTConfig. Add a matching doc comment directly above getBlobGETConfig, using
the existing comment style in this class, so the API utility methods stay
consistent and easy to scan.
pom.xml (1)

7-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

<name> looks copy-pasted from the frontend module.

This is the root aggregator POM (packaging=pom, scm points to dave-admin-portal), yet <name> was changed to dave_adminportal_frontend. Likely leftover from the frontend module's POM.

Suggested fix
-    <name>dave_adminportal_frontend</name>
+    <name>dave-admin-portal</name>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pom.xml` around lines 7 - 10, The root aggregator POM’s <name> value appears
to be copied from the frontend module and should be corrected to match the
parent project represented by this pom.xml. Update the <name> in the top-level
POM (the one with packaging=pom) to the appropriate root/aggregator project name
used by the rest of the repository, keeping it consistent with the SCM and
parent module identity.
apigateway/pom.xml (1)

267-352: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Remove the duplicate maven-resources-plugin block. Maven merges repeated plugin declarations, so this only adds noise; keep the resources-helm-deployment execution in a single declaration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apigateway/pom.xml` around lines 267 - 352, The pom currently declares
maven-resources-plugin twice, with the same resources-helm-deployment execution
duplicated. Remove the extra plugin block and keep a single
maven-resources-plugin declaration containing both the copy-resources and
resources-helm-deployment executions so Maven configuration stays clean and
unambiguous.
frontend/src/App.vue (1)

84-100: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inconsistent import path style for newly added imports.

Lines 84, 92, 99-100 use relative paths (./api/..., ./store/..., ./types/...) while sibling imports on lines 83, 85-91 use the @/ alias. Consider aligning with the alias convention used throughout the file.

♻️ Suggested fix
-import CityInformationService from "./api/service/CityInformationService";
+import CityInformationService from "`@/api/service/CityInformationService`";
 import SsoUserInfoService from "`@/api/service/SsoUserInfoService`";
...
-import { useCityInformationStore } from "./store/CityInformationStore";
+import { useCityInformationStore } from "`@/store/CityInformationStore`";
...
-import type CityDistrictDTO from "./types/configuration/CityDistrictDTO";
-import { BeschreibungToStadtbezirk, stadtbezirke, StadtbezirkToBeschreibung } from "./types/enum/Stadtbezirk";
+import type CityDistrictDTO from "`@/types/configuration/CityDistrictDTO`";
+import { BeschreibungToStadtbezirk, stadtbezirke, StadtbezirkToBeschreibung } from "`@/types/enum/Stadtbezirk`";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/App.vue` around lines 84 - 100, The newly added imports in
App.vue use a mix of relative paths and the existing `@/` alias convention, so
align them for consistency. Update the imports for CityInformationService,
useCityInformationStore, CityDistrictDTO, and Stadtbezirk to use the same alias
style as the other imports in this file, keeping the import section uniform and
easier to maintain.
frontend/src/api/service/CityInformationService.ts (1)

5-15: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Class name doesn't match file purpose.

The exported class is named ConfigurationService, identical to the unrelated ConfigurationService in @/api/service/ConfigurationService.ts. This looks like a copy/paste leftover and risks confusion or accidental import collisions.

♻️ Proposed rename
-export default class ConfigurationService {
+export default class CityInformationService {
   private static readonly ENDPOINT: string =
     "api/dave-backend-service/cityinformation";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/api/service/CityInformationService.ts` around lines 5 - 15, The
exported class name in this service does not match its purpose and duplicates
the unrelated ConfigurationService symbol, which can cause confusion and import
collisions. Rename the class in CityInformationService to a
city-information-specific name, and update the static getAllDistricts method
references if needed so the file’s exported symbol clearly reflects its endpoint
and avoids clashing with the existing ConfigurationService elsewhere.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build_push_latest.yaml:
- Around line 6-7: Grant the workflow explicit repository read access by adding
contents: read to the existing permissions block in the build_push_latest
workflow; the current permissions declaration only sets packages: read, which
implicitly removes checkout access. Update the permissions for the workflow so
actions/checkout@v4 can clone the repo while preserving packages access.
- Around line 70-87: Update the Docker workflow actions to the current majors by
bumping docker/login-action, docker/setup-buildx-action, and
docker/build-push-action from the older pinned versions to their latest majors.
Keep the existing Login to Docker Hub, Set up Docker Buildx, and Build and push
steps intact, but revise the action references so the workflow runs on the newer
Node 24-based releases.

In @.github/workflows/pr_build.yaml:
- Around line 20-29: The compliance step is currently neutered because the
Advance Security Policy as Code action is both set to continue-on-error and
invoked with flags that disable its checks, so it can never fail the build.
Update the pr_build workflow entry for advance-security/policy-as-code@v2.11.0
to remove the failure-ignoring behavior and stop disabling the relevant checks,
keeping the policy enforcement in the job so this step can actually block the PR
when compliance fails.
- Around line 66-81: The check_helm job is relying on files left behind by
build-maven instead of restoring its own inputs. Update the workflow steps in
check_helm to explicitly fetch the repository contents with actions/checkout and
restore the Helm chart artifacts with actions/download-artifact before running
helm dep update and helm template, so the job no longer depends on runner state.

In `@frontend/src/api/service/ConfigurationService.ts`:
- Around line 24-32: The return type of saveConfiguration is mismatched with its
input and likely copied from getConfiguration; update
ConfigurationService.saveConfiguration to return the correct DTO type for the
list payload it sends (ConfigurationItemDTO[]), and keep the
FetchService.postData call aligned with that signature so future callers see an
accurate promise type.

In `@frontend/src/components/config/ConfigApplication.vue`:
- Around line 21-28: The ConfigApplication.vue save flow does not enforce the
existing validateDatatype rules before persisting values. Wrap the editable
fields in a v-form with a ref in the ConfigApplication component, and update
saveConfigValues() to call form.value.validate() before saveConfiguration is
invoked; if validation fails, abort the save. Also ensure the Speichern button
is disabled or otherwise blocked when the form is invalid, using the same form
ref and validation state.

In `@frontend/src/components/zaehlstelle/ZaehlstelleInfo.vue`:
- Around line 78-104: In loadPreviewImage, add a stale-response guard so an
earlier getByZaehlstelleIdAsFile request cannot overwrite previewImageUrl after
props.zaehlstelleUuid has changed; compare the resolved imageId against the
current Zaehlstelle UUID before calling URL.createObjectURL and updating state.
Also remove the leftover console.log and console.error debug statements from
loadPreviewImage while keeping the existing revokePreviewUrl cleanup behavior.

In `@frontend/src/store/CityInformationStore.ts`:
- Around line 7-18: The store state in useCityInformationStore is not reactive
because cityDistricts is reassigned as a plain let, and stadtbezirke2 /
StadtbezirkToBeschreibung2 are also plain values. Convert these to reactive
state (for example refs/reactive) inside the store setup, and update
setCityDistricts to mutate the reactive containers instead of replacing local
variables so consumers see changes. Make sure any returned properties from
useCityInformationStore, including cityDistricts, stadtbezirke2, and
StadtbezirkToBeschreibung2, stay reactive for components like
UpdateZaehlstelleForm and CreateZaehlstelleForm.

In `@stack/helm/dave-admin-portal/templates/service.yaml`:
- Around line 9-20: The Service template has two spec-level ports sections in
the same resource, and the first block is stale dead code. Remove the initial
ports entry in service.yaml and keep only the ranged .Values.service.ports block
in the Service template so the rendered YAML has a single authoritative ports
list; use the Service spec and the existing .Values.service.ports loop to locate
the duplicate.

In `@stack/helm/dave-admin-portal/values.yaml`:
- Around line 123-125: The commented example for extraEnvVars uses
list-of-objects syntax, but the chart templates expect a flat map; update the
example in values.yaml to match the structure used by routes and hazelcast so
deployment.yaml’s range over .Values.extraEnvVars and configmap.yaml’s toYaml
under data render correctly. Keep the example as key/value entries rather than
name/value objects, and make sure the documented shape aligns with the symbols
extraEnvVars, deployment.yaml, and configmap.yaml.

---

Outside diff comments:
In `@frontend/src/components/map/MiniMap.vue`:
- Around line 100-138: The OpenStreetMap base layer in createBaseLayers is being
created with L.tileLayer.wms, but that endpoint is an XYZ tile source, not a WMS
service. Update the OpenStreetMaps layer to use L.tileLayer instead, keeping the
existing attribution and referrerPolicy options, so createLayersAndAddToMap can
add the correct default base layer via baseLayers.OpenStreetMaps.

In `@frontend/src/components/map/ZaehlstelleMap.vue`:
- Around line 345-385: The OpenStreetMap base layer in createBaseLayers is using
the wrong Leaflet constructor: switch the osm layer from L.tileLayer.wms to
L.tileLayer because the XYZ tile URL is not a WMS endpoint. Keep the rest of
createBaseLayers and createLayersAndAddToMap unchanged, and ensure the
OpenStreetMap entry returned from createBaseLayers is a normal tile layer so the
default base layer loads correctly.

In `@frontend/src/components/map/ZaehlungCardMap.vue`:
- Around line 94-140: The OSM base layer in createBaseLayers is using the wrong
Leaflet factory: replace the L.tileLayer.wms call for the openstreetmaps branch
with L.tileLayer because the URL is a standard tile endpoint, not a WMS service.
Keep the existing attribution and add referrerPolicy:
"strict-origin-when-cross-origin" on that L.tileLayer instance so the
OpenStreetMap request includes the expected Referer header.

In `@frontend/src/components/zaehlstelle/UpdateZaehlstelleForm.vue`:
- Around line 202-214: The save flow in save() is starting
ZaehlstellenImageService.uploadImage() independently of
ZaehlstellenService.saveZaehlstelle(), so the image upload can race the save and
emits("saved") fires before the upload finishes. Update save() in
UpdateZaehlstelleForm.vue to chain the upload after a successful save, using the
existing zaehlstelle value and selectedImage check, and only emit "saved" once
both operations complete successfully; keep error handling via
snackbarStore.showApiError for either step.
- Around line 157-173: The computed lookup in getStadtbezirksviertel is missing
an assignment in the else branch, so stadtbezirksviertelMap stays undefined for
normal district numbers. Update the else path to store the result of
StadtbezirksviertelToBeschreibung.get(zaehlstelle.value.stadtbezirkNummer) in
stadtbezirksviertelMap, keeping the rest of the fallback logic unchanged, so the
computed can resolve the correct Stadtbezirksviertel instead of always returning
the default message.

---

Nitpick comments:
In @.github/workflows/pr_build.yaml:
- Around line 17-18: The workflow is using different major versions of
actions/checkout in the same file, which should be standardized for consistency.
Update the checkout step in this job to match the other checkout usage already
present in the workflow, and keep both occurrences aligned by referencing the
shared actions/checkout invocation so behavior stays consistent across jobs.

In @.github/workflows/release.yaml:
- Around line 60-68: The changelog commit gate is using fragile human-readable
git output, so replace the `git status | grep "modified"` check with a
script-safe change detection method in the release workflow step that runs after
`git add .` and before `git commit`/`git push`. Use a deterministic status check
such as `git diff --quiet` or `git status --porcelain` so the changelog update
is only committed when tracked files actually changed, and keep the existing
`modifications`, `git commit -m "modified changelog"`, and `git push` flow wired
to that stricter condition.

In `@apigateway/pom.xml`:
- Around line 267-352: The pom currently declares maven-resources-plugin twice,
with the same resources-helm-deployment execution duplicated. Remove the extra
plugin block and keep a single maven-resources-plugin declaration containing
both the copy-resources and resources-helm-deployment executions so Maven
configuration stays clean and unambiguous.

In `@apigateway/src/main/resources/logback-spring.xml`:
- Around line 58-66: The STDOUT appender is duplicated across profiles with the
same name, class, and pattern, so update the logback-spring.xml configuration to
share a single definition or shared pattern property instead of repeating it.
Refactor the repeated STDOUT appender setup into a common top-level property or
reusable include, and make both profile sections reference that shared
configuration to keep the debug and non-debug setups aligned.

In `@frontend/src/api/service/CityInformationService.ts`:
- Around line 5-15: The exported class name in this service does not match its
purpose and duplicates the unrelated ConfigurationService symbol, which can
cause confusion and import collisions. Rename the class in
CityInformationService to a city-information-specific name, and update the
static getAllDistricts method references if needed so the file’s exported symbol
clearly reflects its endpoint and avoids clashing with the existing
ConfigurationService elsewhere.

In `@frontend/src/api/service/FetchService.ts`:
- Around line 64-117: Extract the shared non-OK response handling from
sendRequestForBlob and sendRequest into a single private helper so the
400/403/409/412/opaqueredirect/fallback logic is maintained in one place. Keep
the success-path differences separate by having sendRequest, sendRequestForBlob,
and sendRequestForPDF reuse that helper before returning response.json(),
response.blob(), or the PDF-specific result. Use the existing FetchService
methods and ApiError handling as the main anchors when refactoring.

In `@frontend/src/api/service/ZaehlstellenImageService.ts`:
- Around line 25-75: The uploadImage method is duplicating fetch error handling
instead of using the centralized FetchService flow, so it misses the shared
409/412 and opaqueredirect handling. Move the multipart POST logic into a
reusable FetchService/FetchUtils helper (for example a postFormData-style
method) and have ZaehlstellenImageService.uploadImage call that helper, reusing
the same ApiError mapping and redirect/reload behavior as sendRequest and
sendRequestForBlob.

In `@frontend/src/api/util/FetchUtils.ts`:
- Around line 17-27: The getBlobGETConfig method in FetchUtils is missing the
same JSDoc-style documentation used by the other config builders like
getGETConfig and getPOSTConfig. Add a matching doc comment directly above
getBlobGETConfig, using the existing comment style in this class, so the API
utility methods stay consistent and easy to scan.

In `@frontend/src/App.vue`:
- Around line 84-100: The newly added imports in App.vue use a mix of relative
paths and the existing `@/` alias convention, so align them for consistency.
Update the imports for CityInformationService, useCityInformationStore,
CityDistrictDTO, and Stadtbezirk to use the same alias style as the other
imports in this file, keeping the import section uniform and easier to maintain.

In `@frontend/src/components/config/ConfigApplication.vue`:
- Around line 29-36: The import button condition in ConfigApplication.vue is
tightly coupled to the backend key via item.keyname === 'publicHolidaysApiUrl'.
Extract that key into a named constant in the component script and use the
constant in the template and any related logic, so the ConfigApplication UI has
a single source of truth and is easier to update if the backend config key
changes.

In `@pom.xml`:
- Around line 7-10: The root aggregator POM’s <name> value appears to be copied
from the frontend module and should be corrected to match the parent project
represented by this pom.xml. Update the <name> in the top-level POM (the one
with packaging=pom) to the appropriate root/aggregator project name used by the
rest of the repository, keeping it consistent with the SCM and parent module
identity.

In `@stack/helm/dave-admin-portal/templates/deployment.yaml`:
- Around line 95-103: The deployment template is duplicating `extraEnvVars` by
rendering them both in the explicit `env` block and again through `envFrom` from
the same ConfigMap. Remove the redundant `env` range under the `deployment.yaml`
template and keep the `envFrom.configMapRef` path as the single source of truth,
using the existing `extraEnvVars` and `envFrom` sections to locate the change.

In `@stack/helm/dave-admin-portal/templates/ingress.yaml`:
- Around line 41-45: The backend service name is hardcoded instead of following
the chart naming helper convention. Update the service references in
ingress.yaml and the matching Service definition in service.yaml to use include
"daveAdminPortal.fullname" so the admin-portal resource names stay
release-scoped and consistent with the rest of the chart.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ad53459e-6891-4efd-bffe-a4f360f46d3a

📥 Commits

Reviewing files that changed from the base of the PR and between 792b047 and 3a19018.

⛔ Files ignored due to path filters (2)
  • docs/img/admin-portal.png is excluded by !**/*.png
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (50)
  • .github/workflows/build.yaml
  • .github/workflows/build_push.yaml
  • .github/workflows/build_push_latest.yaml
  • .github/workflows/pr_build.yaml
  • .github/workflows/release.yaml
  • CHANGELOG.md
  • LICENSE
  • README.md
  • apigateway/.gitignore
  • apigateway/application-local.yml
  • apigateway/pom.xml
  • apigateway/runLocal.sh
  • apigateway/runLocalNoSecurity.sh
  • apigateway/src/main/resources/logback-spring.xml
  • docs/Readme.md
  • frontend/pom.xml
  • frontend/src/App.vue
  • frontend/src/api/service/CityInformationService.ts
  • frontend/src/api/service/ConfigurationService.ts
  • frontend/src/api/service/FetchService.ts
  • frontend/src/api/service/PublicHolidaysService.ts
  • frontend/src/api/service/ZaehlstellenImageService.ts
  • frontend/src/api/util/FetchUtils.ts
  • frontend/src/components/config/ConfigApplication.vue
  • frontend/src/components/map/MiniMap.vue
  • frontend/src/components/map/ZaehlstelleMap.vue
  • frontend/src/components/map/ZaehlungCardMap.vue
  • frontend/src/components/zaehlstelle/CreateZaehlstelleForm.vue
  • frontend/src/components/zaehlstelle/UpdateZaehlstelleForm.vue
  • frontend/src/components/zaehlstelle/ZaehlstelleInfo.vue
  • frontend/src/components/zaehlung/ZaehlungCard.vue
  • frontend/src/components/zaehlung/form/AllgemeineInfoForm.vue
  • frontend/src/components/zaehlung/form/KnotenLageForm.vue
  • frontend/src/components/zaehlung/form/VerkehrsartForm.vue
  • frontend/src/components/zaehlung/form/ZaehlungForm.vue
  • frontend/src/store/CityInformationStore.ts
  • frontend/src/types/configuration/CityDistrictDTO.ts
  • frontend/src/types/configuration/ConfigurationItemDTO.ts
  • frontend/src/types/enum/Stadtbezirksviertel.ts
  • frontend/src/types/zaehlung/ZaehlungDTO.ts
  • frontend/src/views/ConfigView.vue
  • frontend/src/views/ZaehlstelleView.vue
  • pom.xml
  • stack/helm/dave-admin-portal/Chart.yaml
  • stack/helm/dave-admin-portal/templates/_helpers.tpl
  • stack/helm/dave-admin-portal/templates/configmap.yaml
  • stack/helm/dave-admin-portal/templates/deployment.yaml
  • stack/helm/dave-admin-portal/templates/ingress.yaml
  • stack/helm/dave-admin-portal/templates/service.yaml
  • stack/helm/dave-admin-portal/values.yaml
💤 Files with no reviewable changes (2)
  • .github/workflows/build.yaml
  • .github/workflows/build_push.yaml
📜 Review details
🔇 Additional comments (47)
stack/helm/dave-admin-portal/templates/configmap.yaml (1)

8-10: 🗄️ Data Integrity & Integration

ConfigMap data expects a map, but the documented extraEnvVars format is list-style.

See the related comment on values.yaml — if a user follows the documented example (- name: ... / value: ...), this renders an invalid list under data. Root cause and fix suggestion detailed there.

stack/helm/dave-admin-portal/Chart.yaml (1)

5-6: 🗄️ Data Integrity & Integration

Confirm Maven resource filtering covers this file.

version/appVersion rely on ${project.version} being substituted at build time. If the resource-filtering config in apigateway/pom.xml doesn't include stack/helm/**, the packaged chart will literally contain ${project.version}, which is invalid semver and will break helm package/helm install.

stack/helm/dave-admin-portal/templates/_helpers.tpl (1)

1-52: LGTM!

stack/helm/dave-admin-portal/templates/deployment.yaml (1)

32-32: 🩺 Stability & Availability

Verify Hazelcast references are still needed.

serviceAccountName: dave-hazelcast and the app.spring.hazelcast env vars (also mirrored in service.yaml's 5701 port and values.yaml) reference Hazelcast, but the AI summary indicates this PR removes Hazelcast runtime dependencies elsewhere. Confirm whether these Helm configs are stale leftovers that should be removed, or whether Hazelcast is still used at runtime.

Also applies to: 89-94

stack/helm/dave-admin-portal/values.yaml (1)

1-139: LGTM on the remainder of the defaults (image, ingress, autoscaling, resources sections).

LICENSE (1)

1-661: LGTM!

README.md (1)

1-46: LGTM!

docs/Readme.md (1)

1-23: LGTM!

.github/workflows/release.yaml (1)

94-150: 🩺 Stability & Availability

Add an explicit checkout or artifact handoff for these publish jobs. git describe and the Helm chart path shouldn’t depend on leftover workspace state from build; pass the tag as a job output and fetch the repo or generated artifacts here.

.github/workflows/build_push_latest.yaml (1)

59-116: 🩺 Stability & Availability

Add an explicit checkout or artifact handoff before these publish jobs. context: . and apigateway/target/helm/... assume the workspace and build outputs are still present on this self-hosted runner; if a different runner picks up the job, these steps will fail or publish stale content.

apigateway/src/main/resources/logback-spring.xml (1)

58-66: 🩺 Stability & Availability

Non-debug profile now emits plain-text logs instead of structured JSON.

The non-debug appender was switched from a LogstashEncoder-based JSON_STDOUT appender to a plain-text ConsoleAppender. If any downstream log pipeline (ELK/Loki/Splunk, etc.) parses this profile's stdout as JSON, this change will break ingestion/parsing for the default (non-debug) profile. Please confirm the log aggregation stack for this environment no longer requires structured JSON output.

Also applies to: 67-102

apigateway/application-local.yml (2)

1-3: 🎯 Functional Correctness | ⚡ Quick win

Ineffective spring.profile.active setting.

Two issues here:

  1. The key is spring.profile.active (singular) — Spring Boot's actual property is spring.profiles.active spring.profiles.active and spring.profiles.default can only be used in non-profile-specific documents.
  2. Even with the correct key name, per Spring Boot docs this property can only be used in non-profile-specific documents...they cannot be included in profile specific files or documents activated by spring.config.activate.on-profile — and this file (application-local.yml) is itself a profile-specific document for the "local" profile.

This block is effectively dead configuration and, as written with value prod, is also confusing inside a file meant for the local profile. Recommend removing it.

🐛 Suggested fix
 spring:
-  profile:
-    active: prod
   cloud:
     gateway:

4-42: LGTM!

frontend/src/components/map/ZaehlungCardMap.vue (1)

29-29: 🎯 Functional Correctness

Verify mapType is always passed and matches switch's lowercase literals.

mapType is required with no default, and the switch compares against lowercase strings ("luftbild", "stadtkarte", "openstreetmaps"). Confirm the caller (ZaehlungCard.vue) always supplies a value using this exact casing; otherwise it silently falls back to "stadtkarte" via the default case.

frontend/src/components/zaehlung/form/VerkehrsartForm.vue (1)

121-127: LGTM!

frontend/src/components/zaehlung/form/ZaehlungForm.vue (1)

134-139: LGTM!

frontend/src/components/zaehlung/ZaehlungCard.vue (2)

46-46: LGTM!

Also applies to: 331-334


6-10: 🎯 Functional Correctness

Verify mapType is a supported prop on ZaehlungCardMap.
If mapType is not declared there, mapType="openstreetmaps" will be treated as a plain attribute and won’t change the map layer.

frontend/src/components/zaehlung/form/KnotenLageForm.vue (1)

29-29: 🎯 Functional Correctness

Same mapType prop contract concern as ZaehlungCard.vue.

This mirrors the mapType="openstreetmaps" change flagged in ZaehlungCard.vue; the underlying map component's prop definition isn't in this review batch, so the same verification applies here too.

frontend/src/components/zaehlung/form/AllgemeineInfoForm.vue (1)

36-41: 🎯 Functional Correctness

Check that quaternary is defined in the Vuetify theme. Vuetify does not ship a default quaternary color, so this checkbox only renders as intended if the app registers that custom theme color.

frontend/src/types/zaehlung/ZaehlungDTO.ts (1)

21-21: 🎯 Functional Correctness

Ensure every ZaehlungDTO construction initializes dauerzaehlung.
Any object literal or cast that still omits the new required field will produce undefined at runtime.

frontend/src/types/configuration/ConfigurationItemDTO.ts (1)

1-10: LGTM!

frontend/src/api/service/ConfigurationService.ts (1)

17-22: LGTM!

frontend/src/api/service/PublicHolidaysService.ts (2)

10-11: 📐 Maintainability & Code Quality | ⚡ Quick win

Error message copied from configuration loading, not import.

The failure message says "aller Anwendungskonfigurationen" (loading all application configurations) instead of describing a public holidays import failure. This text may surface to the user via the error object in ConfigApplication.vue's catch handler.

✏️ Suggested fix
     return FetchService.getData(
       `${this.ENDPOINT}/import`,
-      "Beim Laden aller Anwendungskonfigurationen ist ein Fehler aufgetreten."
+      "Beim Importieren der Feiertage ist ein Fehler aufgetreten."
     );

8-13: 🎯 Functional Correctness

Check the return type and error message

BigInteger needs a declared ambient type here; otherwise this won’t compile. The error string also still refers to application configuration, which doesn’t match a public-holidays import.

frontend/src/components/config/ConfigApplication.vue (1)

107-113: LGTM!

frontend/src/views/ConfigView.vue (1)

41-44: LGTM!

Also applies to: 66-68, 77-77, 92-92

frontend/src/api/service/FetchService.ts (1)

18-23: LGTM!

frontend/src/api/service/ZaehlstellenImageService.ts (1)

11-23: LGTM!

frontend/src/components/zaehlstelle/ZaehlstelleInfo.vue (3)

10-39: LGTM!


115-149: LGTM!


45-61: 🎯 Functional Correctness

Guard zaehlstelleUuid before calling .trim() if it can ever be non-string.

frontend/src/views/ZaehlstelleView.vue (1)

19-19: LGTM!

pom.xml (1)

19-34: LGTM!

apigateway/pom.xml (3)

5-9: LGTM!


157-172: LGTM!


267-286: 🎯 Functional Correctness

Confirm frontend build order Copying ../frontend/dist in validate can race with the frontend module once the runtime dependency is removed. Ensure the root pom.xml still builds frontend before apigateway and that CI does not use parallel Maven reactor builds.

frontend/pom.xml (1)

6-13: LGTM!

apigateway/.gitignore (1)

34-36: LGTM!

frontend/src/types/configuration/CityDistrictDTO.ts (1)

1-7: LGTM!

frontend/src/store/CityInformationStore.ts (2)

26-36: LGTM!


20-24: 🎯 Functional Correctness

BeschreibungToStadtbezirk2 should build an inverted map

reverse() only reorders entries; it does not swap key/value pairs. If this is meant to map description → district number, return a real inverted Map<string, number> instead.

frontend/src/App.vue (2)

130-156: LGTM!


2-2: 🔒 Security & Privacy

Restore the Fachadmin gate or move it to a router/backend check

<v-app> now renders unconditionally and the no-rights overlay is gone. If this page is still intended to stay Fachadmin-only, the role check needs to live elsewhere; otherwise non-Fachadmin users can reach the admin UI.

frontend/src/components/zaehlstelle/CreateZaehlstelleForm.vue (1)

164-170: LGTM! Note: correctness here depends on the store reactivity fix flagged in CityInformationStore.ts.

Also applies to: 200-206

frontend/src/components/zaehlstelle/UpdateZaehlstelleForm.vue (1)

64-73: LGTM! (Line 148's getStadtbezirksnummer correctness depends on the store reactivity fix flagged in CityInformationStore.ts.)

Also applies to: 116-124, 139-156, 175-186

frontend/src/types/enum/Stadtbezirksviertel.ts (1)

560-565: LGTM!

Also applies to: 592-592, 678-680

Comment on lines +6 to +7
permissions:
packages: read

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Missing contents: read permission will likely break checkout.

Once a permissions: block is declared, GitHub sets all unlisted scopes to none (not their normal default). This block only grants packages: read, so contents is implicitly none. The actions/checkout@v4 step (line 44) needs at least contents: read to clone the repo — this will fail for anything other than a fully public/anonymous checkout.

🔧 Proposed fix
 permissions:
+  contents: read
   packages: read
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
permissions:
packages: read
permissions:
contents: read
packages: read
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build_push_latest.yaml around lines 6 - 7, Grant the
workflow explicit repository read access by adding contents: read to the
existing permissions block in the build_push_latest workflow; the current
permissions declaration only sets packages: read, which implicitly removes
checkout access. Update the permissions for the workflow so actions/checkout@v4
can clone the repo while preserving packages access.

Comment on lines +70 to +87
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ env.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
sbom: true
provenance: mode=max
tags: ${{ env.DOCKERHUB_ORG }}/${{ env.IMAGE_NAME }}:${{ env.VERSION_BUILD }}-${{ github.run_number }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What is the latest major version of docker/login-action, docker/setup-buildx-action, and docker/build-push-action, and do older majors still run on Node 20?

💡 Result:

As of July 6, 2026, the latest major versions for the specified Docker GitHub Actions are as follows: - docker/login-action: v4 [1][2] - docker/setup-buildx-action: v4 [3][4] - docker/build-push-action: v7 [5][6] Regarding Node.js compatibility: Older major versions of these actions generally run on Node 20, as they were updated to use it as their runtime [7][8]. However, these older versions may no longer function reliably or at all in GitHub Actions workflows. GitHub has deprecated Node.js 20 on its runners, and GitHub Actions environments are actively migrating to newer Node.js runtimes (such as Node 24) [9][10][11]. Actions that rely on deprecated Node.js versions are subject to failure as the underlying support is removed from runner images [12][9]. It is strongly recommended to update to the latest major versions of these actions to ensure compatibility with current GitHub Actions runners [9][10].

Citations:


🌐 Web query:

Check the release notes or repository docs for docker/login-action, docker/setup-buildx-action, and docker/build-push-action: which major versions are current, and which Node.js runtime do v3/v5 use?

💡 Result:

As of July 6, 2026, the current major versions and their associated Node.js runtimes for the specified GitHub Actions are as follows: docker/login-action Current Major Version: v4 [1] Node.js Runtime: v4 uses Node.js 24 as its default runtime [2]. Version 3 used Node.js 20 [3][4]. docker/setup-buildx-action Current Major Version: v4 [5] Node.js Runtime: v4 uses Node.js 24 as its default runtime [6][7]. Version 3 used Node.js 20 [7]. docker/build-push-action Current Major Version: v7 [8] Node.js Runtime: v7 uses Node.js 24 as its default runtime [9]. Version 6 used Node.js 20 [10][11]. Note: The shift to Node.js 24 was introduced in the major version releases (v4 for login-action and setup-buildx-action, and v7 for build-push-action) in early March 2026 and requires GitHub Actions Runner v2.327.1 or later [2][6][9].

Citations:


Bump the Docker action majors
docker/login-action@v3, docker/setup-buildx-action@v3, and docker/build-push-action@v5 are behind the current majors (v4, v4, and v7). The newer releases moved to Node 24, so keeping these pins leaves the workflow on the older Node 20 runtime.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build_push_latest.yaml around lines 70 - 87, Update the
Docker workflow actions to the current majors by bumping docker/login-action,
docker/setup-buildx-action, and docker/build-push-action from the older pinned
versions to their latest majors. Keep the existing Login to Docker Hub, Set up
Docker Buildx, and Build and push steps intact, but revise the action references
so the workflow runs on the newer Node 24-based releases.

Comment on lines +20 to +29
- name: Advance Security Policy as Code
uses: advanced-security/policy-as-code@v2.11.0
continue-on-error: true
with:
policy: GeekMasher/security-queries
policy-path: $GITHUB_WORKSPACE/policies/default.yml
token: ${{ secrets.GITHUB_TOKEN }}
argvs: '--disable-dependabot --disable-secret-scanning --disable-code-scanning'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Compliance check can't actually block anything.

continue-on-error: true combined with --disable-dependabot --disable-secret-scanning --disable-code-scanning means this step both disables most of its own checks and ignores any remaining failure. As configured, the "compliance" job is effectively a no-op that can never fail the PR build.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/pr_build.yaml around lines 20 - 29, The compliance step is
currently neutered because the Advance Security Policy as Code action is both
set to continue-on-error and invoked with flags that disable its checks, so it
can never fail the build. Update the pr_build workflow entry for
advance-security/policy-as-code@v2.11.0 to remove the failure-ignoring behavior
and stop disabling the relevant checks, keeping the policy enforcement in the
job so this step can actually block the PR when compliance fails.

Comment on lines +66 to +81
check_helm:
name: "Check if Helm chart is correct"
needs: build-maven
runs-on: [self-hosted, linux, X64]

steps:
- name: get helm
uses: azure/setup-helm@v4

- name: run helm dependency update
working-directory: apigateway/target/helm/dave-admin-portal
run: helm dep update

- name: run helm template
working-directory: apigateway/target/helm
run: helm template dave-admin-portal No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '1,220p' .github/workflows/pr_build.yaml

Repository: it-at-m/dave-admin-portal

Length of output: 1973


🌐 Web query:

site:github.com/it-at-m/dave-admin-portal .github/workflows/pr_build.yaml check_helm helm dependency update checkout artifact-download

💡 Result:

To successfully execute Helm commands like helm dependency update in a GitHub Actions workflow that relies on build artifacts, you must ensure the file system is properly prepared before running the Helm operations [1][2]. Because GitHub Actions jobs run on fresh, isolated virtual machines, they do not automatically share workspaces, meaning both the source code and the generated artifacts must be explicitly restored [1]. The standard pattern for a check_helm or similar job involves these steps in order: 1. Checkout the Repository: Use the actions/checkout@v4 action to ensure the project files are present in the runner's workspace [1][2]. 2. Restore Artifacts: Use the actions/download-artifact@v4 action to retrieve the specific Helm chart directory or packaged artifacts generated by a previous build job [1][2]. Ensure the artifact name matches exactly what was used in the upload step [1]. 3. Execute Helm Commands: With the directory structure restored (e.g., apigateway/target/helm), you can then successfully run commands like helm dependency update or helm template, specifying the appropriate working-directory [1][2]. If you omit the checkout or download-artifact steps, the Helm command will fail because it cannot find the Chart.yaml file or the expected directory structure [1]. Always ensure that the job requiring these files specifies the producer job using the needs keyword to guarantee the artifacts are available [1].

Citations:


🌐 Web query:

site:github.com/it-at-m/dave-admin-portal .github/workflows/pr_build.yaml build-maven upload-artifact checkout apigateway/target/helm

💡 Result:

The elements provided (.github/workflows/pr_build.yaml, build-maven, upload-artifact, checkout, apigateway/target/helm) relate to CI/CD pipeline issues in the GitHub repository it-at-m/dave-admin-portal [1][2][3]. In this project's workflow, separate GitHub Actions jobs (such as build-maven and check_helm) run on different runners, meaning they do not share a common workspace [1][2]. The error arises because the check_helm job attempts to access build artifacts located in apigateway/target/helm that were created during the build-maven job, but those files are not preserved or available to subsequent jobs [1][2]. To resolve this, the workflow needs the following adjustments [1][2]: 1. In the build-maven job: Add a step using actions/upload-artifact to save the output files located in apigateway/target/helm as an artifact [1][2]. 2. In the check_helm (or publish) job: - Add a step using actions/checkout to ensure the repository code is present on the runner [1][2]. - Add a step using actions/download-artifact to download the specific artifact created by the build-maven job, thereby restoring the apigateway/target/helm directory before running subsequent Helm commands like helm dep update or helm template [1][2]. This ensures that the Helm charts and metadata are reliably available across the pipeline stages [1].

Citations:


Restore the Helm inputs in check_helm. This job has no actions/checkout or actions/download-artifact, so it depends on build-maven leaving apigateway/target/helm behind on the same runner. Add explicit checkout/artifact restoration to make the job self-contained.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/pr_build.yaml around lines 66 - 81, The check_helm job is
relying on files left behind by build-maven instead of restoring its own inputs.
Update the workflow steps in check_helm to explicitly fetch the repository
contents with actions/checkout and restore the Helm chart artifacts with
actions/download-artifact before running helm dep update and helm template, so
the job no longer depends on runner state.

Comment on lines +24 to +32
static saveConfiguration(
configuration: ConfigurationItemDTO[]
): Promise<ConfigurationDTO[]> {
return FetchService.postData(
configuration,
`${this.ENDPOINT}/all`,
"Beim Speichern der Anwendungskonfiguration ist ein Fehler aufgetreten."
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

saveConfiguration return type looks mismatched.

Method takes ConfigurationItemDTO[] but returns Promise<ConfigurationDTO[]> — that's the singular-config DTO type used by getConfiguration(), not the list-item DTO. Looks like a copy/paste leftover. Current caller ignores the resolved value, but the type is misleading for future consumers.

💡 Suggested fix
   static saveConfiguration(
     configuration: ConfigurationItemDTO[]
-  ): Promise<ConfigurationDTO[]> {
+  ): Promise<ConfigurationItemDTO[]> {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static saveConfiguration(
configuration: ConfigurationItemDTO[]
): Promise<ConfigurationDTO[]> {
return FetchService.postData(
configuration,
`${this.ENDPOINT}/all`,
"Beim Speichern der Anwendungskonfiguration ist ein Fehler aufgetreten."
);
}
static saveConfiguration(
configuration: ConfigurationItemDTO[]
): Promise<ConfigurationItemDTO[]> {
return FetchService.postData(
configuration,
`${this.ENDPOINT}/all`,
"Beim Speichern der Anwendungskonfiguration ist ein Fehler aufgetreten."
);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/api/service/ConfigurationService.ts` around lines 24 - 32, The
return type of saveConfiguration is mismatched with its input and likely copied
from getConfiguration; update ConfigurationService.saveConfiguration to return
the correct DTO type for the list payload it sends (ConfigurationItemDTO[]), and
keep the FetchService.postData call aligned with that signature so future
callers see an accurate promise type.

Comment on lines +21 to +28
<v-text-field
:label="item.keyname"
v-model="item.valuefield"
variant="outlined"
density="compact"
class="flex-grow-1 pt-2"
:rules="[validateDatatype(item)]"
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validation rules aren't enforced before save.

validateDatatype only drives the v-text-field hint text; saveConfigValues() isn't gated by any form validity check, so invalid values (e.g., non-numeric input for a DOUBLE/INTEGER field) can still be persisted.

Wrap the fields in a v-form with a ref, and call form.value.validate() before invoking saveConfiguration, or disable the Speichern button while invalid.

Also applies to: 81-95, 115-121

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/config/ConfigApplication.vue` around lines 21 - 28,
The ConfigApplication.vue save flow does not enforce the existing
validateDatatype rules before persisting values. Wrap the editable fields in a
v-form with a ref in the ConfigApplication component, and update
saveConfigValues() to call form.value.validate() before saveConfiguration is
invoked; if validation fails, abort the save. Also ensure the Speichern button
is disabled or otherwise blocked when the form is invalid, using the same form
ref and validation state.

Comment on lines +78 to +104
const loadPreviewImage = (): void => {
const imageId = props.zaehlstelleUuid?.trim() ?? "";
if (!imageId) {
revokePreviewUrl();
return;
}

ZaehlstellenImageService.getByZaehlstelleIdAsFile(imageId)
.then((blob) => {
console.log("Blob received:", blob);
if (blob) {
revokePreviewUrl();
currentObjectUrl = URL.createObjectURL(blob);
previewImageUrl.value = currentObjectUrl;
} else {
revokePreviewUrl();
}
})
.catch(() => {
console.error("Error fetching image for Zaehlstelle with ID:", imageId);
revokePreviewUrl();
});
};

onMounted(loadPreviewImage);
watch(() => props.zaehlstelleUuid, loadPreviewImage);
onBeforeUnmount(revokePreviewUrl);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Missing stale-response guard in loadPreviewImage, plus leftover debug logging.

If zaehlstelleUuid changes again before a previous getByZaehlstelleIdAsFile call resolves (e.g., navigating between Zählstellen without unmounting this component), responses can resolve out of order. There's no check that the resolved blob still corresponds to the currently requested imageId, so an older/slower response can overwrite the preview with the wrong Zählstelle's image after the newer request already applied its result.

Also, console.log/console.error debug statements (Lines 87, 97) should be removed before shipping.

🔒 Proposed fix: guard against stale responses
 const loadPreviewImage = (): void => {
   const imageId = props.zaehlstelleUuid?.trim() ?? "";
   if (!imageId) {
     revokePreviewUrl();
     return;
   }

+  const requestId = imageId;
   ZaehlstellenImageService.getByZaehlstelleIdAsFile(imageId)
     .then((blob) => {
-      console.log("Blob received:", blob);
+      if (requestId !== (props.zaehlstelleUuid?.trim() ?? "")) {
+        return; // stale response, a newer request is already in flight/applied
+      }
       if (blob) {
         revokePreviewUrl();
         currentObjectUrl = URL.createObjectURL(blob);
         previewImageUrl.value = currentObjectUrl;
       } else {
         revokePreviewUrl();
       }
     })
     .catch(() => {
-      console.error("Error fetching image for Zaehlstelle with ID:", imageId);
-      revokePreviewUrl();
+      if (requestId === (props.zaehlstelleUuid?.trim() ?? "")) {
+        revokePreviewUrl();
+      }
     });
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const loadPreviewImage = (): void => {
const imageId = props.zaehlstelleUuid?.trim() ?? "";
if (!imageId) {
revokePreviewUrl();
return;
}
ZaehlstellenImageService.getByZaehlstelleIdAsFile(imageId)
.then((blob) => {
console.log("Blob received:", blob);
if (blob) {
revokePreviewUrl();
currentObjectUrl = URL.createObjectURL(blob);
previewImageUrl.value = currentObjectUrl;
} else {
revokePreviewUrl();
}
})
.catch(() => {
console.error("Error fetching image for Zaehlstelle with ID:", imageId);
revokePreviewUrl();
});
};
onMounted(loadPreviewImage);
watch(() => props.zaehlstelleUuid, loadPreviewImage);
onBeforeUnmount(revokePreviewUrl);
const loadPreviewImage = (): void => {
const imageId = props.zaehlstelleUuid?.trim() ?? "";
if (!imageId) {
revokePreviewUrl();
return;
}
const requestId = imageId;
ZaehlstellenImageService.getByZaehlstelleIdAsFile(imageId)
.then((blob) => {
if (requestId !== (props.zaehlstelleUuid?.trim() ?? "")) {
return; // stale response, a newer request is already in flight/applied
}
if (blob) {
revokePreviewUrl();
currentObjectUrl = URL.createObjectURL(blob);
previewImageUrl.value = currentObjectUrl;
} else {
revokePreviewUrl();
}
})
.catch(() => {
if (requestId === (props.zaehlstelleUuid?.trim() ?? "")) {
revokePreviewUrl();
}
});
};
onMounted(loadPreviewImage);
watch(() => props.zaehlstelleUuid, loadPreviewImage);
onBeforeUnmount(revokePreviewUrl);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/zaehlstelle/ZaehlstelleInfo.vue` around lines 78 -
104, In loadPreviewImage, add a stale-response guard so an earlier
getByZaehlstelleIdAsFile request cannot overwrite previewImageUrl after
props.zaehlstelleUuid has changed; compare the resolved imageId against the
current Zaehlstelle UUID before calling URL.createObjectURL and updating state.
Also remove the leftover console.log and console.error debug statements from
loadPreviewImage while keeping the existing revokePreviewUrl cleanup behavior.

Comment on lines +7 to +18
export const useCityInformationStore = defineStore("cityInformationStore", () => {
let cityDistricts = Array<CityDistrictDTO>();
const stadtbezirke2 = Array<KeyVal>();
const StadtbezirkToBeschreibung2 = new Map<number, string>();

function setCityDistricts(payload: Array<CityDistrictDTO>) {
cityDistricts = payload;
for(const district of cityDistricts) {
stadtbezirke2.push({value: district.number.toString(), title: district.number + " " + district.name})
StadtbezirkToBeschreibung2.set(district.number, district.number + " " + district.name)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Store state isn't reactive — cityDistricts never updates for consumers.

cityDistricts is a plain let reassigned inside setCityDistricts. Returning it from the setup function captures the array reference at store-creation time; reassigning the local variable afterward does not propagate to the object already handed to consumers, so cityInformationStore.cityDistricts will always read as the initial empty array. stadtbezirke2 and StadtbezirkToBeschreibung2 are mutated in place (so their references stay correct) but, being plain (non-ref/non-reactive) values, mutations won't reliably trigger re-renders in computed properties/templates that read them.

🐛 Proposed fix using ref/reactive
-import { defineStore } from "pinia";
+import { defineStore } from "pinia";
+import { ref } from "vue";

 import type CityDistrictDTO from "`@/types/configuration/CityDistrictDTO`";
 import type KeyVal from "`@/types/common/KeyVal`";
 import { stadtbezirksviertel } from "`@/types/enum/Stadtbezirksviertel`";

 export const useCityInformationStore = defineStore("cityInformationStore", () => {
-  let cityDistricts = Array<CityDistrictDTO>();
-  const stadtbezirke2 = Array<KeyVal>();
-  const StadtbezirkToBeschreibung2 = new Map<number, string>();
+  const cityDistricts = ref<Array<CityDistrictDTO>>([]);
+  const stadtbezirke2 = ref<Array<KeyVal>>([]);
+  const StadtbezirkToBeschreibung2 = ref(new Map<number, string>());

   function setCityDistricts(payload: Array<CityDistrictDTO>) {
-    cityDistricts = payload;
-    for(const district of cityDistricts) {
-      stadtbezirke2.push({value: district.number.toString(), title: district.number + " " + district.name})
-      StadtbezirkToBeschreibung2.set(district.number, district.number + " " + district.name)
+    cityDistricts.value = payload;
+    stadtbezirke2.value = [];
+    StadtbezirkToBeschreibung2.value = new Map();
+    for (const district of payload) {
+      stadtbezirke2.value.push({value: district.number.toString(), title: district.number + " " + district.name})
+      StadtbezirkToBeschreibung2.value.set(district.number, district.number + " " + district.name)
     }
   }

Note: consumers reading cityInformationStore.StadtbezirkToBeschreibung2 / stadtbezirke2 directly (e.g., UpdateZaehlstelleForm.vue, CreateZaehlstelleForm.vue) would need .value accordingly, or you can return refs and let Pinia's storeToRefs/auto-unwrap handle them.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const useCityInformationStore = defineStore("cityInformationStore", () => {
let cityDistricts = Array<CityDistrictDTO>();
const stadtbezirke2 = Array<KeyVal>();
const StadtbezirkToBeschreibung2 = new Map<number, string>();
function setCityDistricts(payload: Array<CityDistrictDTO>) {
cityDistricts = payload;
for(const district of cityDistricts) {
stadtbezirke2.push({value: district.number.toString(), title: district.number + " " + district.name})
StadtbezirkToBeschreibung2.set(district.number, district.number + " " + district.name)
}
}
import { defineStore } from "pinia";
import { ref } from "vue";
import type CityDistrictDTO from "`@/types/configuration/CityDistrictDTO`";
import type KeyVal from "`@/types/common/KeyVal`";
import { stadtbezirksviertel } from "`@/types/enum/Stadtbezirksviertel`";
export const useCityInformationStore = defineStore("cityInformationStore", () => {
const cityDistricts = ref<Array<CityDistrictDTO>>([]);
const stadtbezirke2 = ref<Array<KeyVal>>([]);
const StadtbezirkToBeschreibung2 = ref(new Map<number, string>());
function setCityDistricts(payload: Array<CityDistrictDTO>) {
cityDistricts.value = payload;
stadtbezirke2.value = [];
StadtbezirkToBeschreibung2.value = new Map();
for (const district of payload) {
stadtbezirke2.value.push({value: district.number.toString(), title: district.number + " " + district.name})
StadtbezirkToBeschreibung2.value.set(district.number, district.number + " " + district.name)
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/store/CityInformationStore.ts` around lines 7 - 18, The store
state in useCityInformationStore is not reactive because cityDistricts is
reassigned as a plain let, and stadtbezirke2 / StadtbezirkToBeschreibung2 are
also plain values. Convert these to reactive state (for example refs/reactive)
inside the store setup, and update setCityDistricts to mutate the reactive
containers instead of replacing local variables so consumers see changes. Make
sure any returned properties from useCityInformationStore, including
cityDistricts, stadtbezirke2, and StadtbezirkToBeschreibung2, stay reactive for
components like UpdateZaehlstelleForm and CreateZaehlstelleForm.

Comment on lines +9 to +20
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
ports:
{{- range .Values.service.ports }}
- port: {{ .port }}
targetPort: {{ .targetPort }}
protocol: {{ .protocol }}
name: {{ .name }}
{{- end }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Duplicate ports: key in Service spec.

Two ports: keys exist directly under spec: (Lines 9-13 and 14-20). This is invalid/ambiguous YAML — only one can survive rendering, making the first block (with targetPort: http, which doesn't correspond to any container port name) dead code.

🐛 Proposed fix — remove the stale first ports block
 spec:
   type: {{ .Values.service.type }}
   ports:
-    - port: {{ .Values.service.port }}
-      targetPort: http
-      protocol: TCP
-      name: http
-  ports:
     {{- range .Values.service.ports }}
     - port: {{ .port }}
       targetPort: {{ .targetPort }}
       protocol: {{ .protocol }}
       name: {{ .name }}
     {{- end }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
ports:
{{- range .Values.service.ports }}
- port: {{ .port }}
targetPort: {{ .targetPort }}
protocol: {{ .protocol }}
name: {{ .name }}
{{- end }}
ports:
{{- range .Values.service.ports }}
- port: {{ .port }}
targetPort: {{ .targetPort }}
protocol: {{ .protocol }}
name: {{ .name }}
{{- end }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@stack/helm/dave-admin-portal/templates/service.yaml` around lines 9 - 20, The
Service template has two spec-level ports sections in the same resource, and the
first block is stale dead code. Remove the initial ports entry in service.yaml
and keep only the ranged .Values.service.ports block in the Service template so
the rendered YAML has a single authoritative ports list; use the Service spec
and the existing .Values.service.ports loop to locate the duplicate.

Comment on lines +123 to +125
extraEnvVars:
# - name: "TZ"
# value: "Europe/Berlin"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Documented extraEnvVars example format doesn't match what the templates expect.

The commented example uses list-of-objects syntax, but deployment.yaml's range $name, $value := .Values.extraEnvVars and configmap.yaml's toYaml under data: both require extraEnvVars to be a flat map (like routes/hazelcast above). Following the documented example would render broken env entries and invalid ConfigMap data.

📝 Proposed fix — correct the example to map syntax
 extraEnvVars:
-#  - name: "TZ"
-#    value: "Europe/Berlin"
+#  TZ: "Europe/Berlin"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
extraEnvVars:
# - name: "TZ"
# value: "Europe/Berlin"
extraEnvVars:
# TZ: "Europe/Berlin"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@stack/helm/dave-admin-portal/values.yaml` around lines 123 - 125, The
commented example for extraEnvVars uses list-of-objects syntax, but the chart
templates expect a flat map; update the example in values.yaml to match the
structure used by routes and hazelcast so deployment.yaml’s range over
.Values.extraEnvVars and configmap.yaml’s toYaml under data render correctly.
Keep the example as key/value entries rather than name/value objects, and make
sure the documented shape aligns with the symbols extraEnvVars, deployment.yaml,
and configmap.yaml.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants