Skip to content

Feature 13797 & 13810 Malaria and Dengue diseases#13877

Open
KarnaiahPesula wants to merge 11 commits intodevelopmentfrom
feature-13797-malaria-disease
Open

Feature 13797 & 13810 Malaria and Dengue diseases#13877
KarnaiahPesula wants to merge 11 commits intodevelopmentfrom
feature-13797-malaria-disease

Conversation

@KarnaiahPesula
Copy link
Contributor

@KarnaiahPesula KarnaiahPesula commented Mar 11, 2026

Fixes # 13796 & 13810
Summary:
Incorporated Malaria into SORMAS.
Updated the Dengue disease as per Lux requirements.
Changes:
Introduced the Incubation period per disease level.
Introduced the custom case classification.
Updated the Case, Person and Hospitalization forms to reflect Malaria and Dengue changes as per Lux specification
#13797
#13798
#13799
#13811
#13812
#13815
#13797

Summary by CodeRabbit

  • New Features

    • Incubation period controls (enable/min/max) and case definition text per disease
    • Expanded vaccine catalog and manufacturers with ATC/INN/UNII metadata
    • Large set of Malaria/Dengue symptoms, Clinical Manifestation type, and health-condition fields for mosquito‑borne exposure/vaccination
    • Complications side-panel in case symptoms view with interactive toggles
  • Improvements

    • Disease configuration UI refactored into accordion sections and grid columns for incubation
    • Vaccination form surfaces vaccine code details and localized captions
    • Backend and database extended to persist new disease and symptom data
  • Chores

    • Minor annotation/visibility updates to reduce UI clutter for specific diseases

# Conflicts:
#	sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java
Summary:
Incorporated Malaria and Dengue disease changes to SORMAS.
Changes:
Included Malaria and Dengue specific Case form changes.
Included Symptoms and Case person form changes.
# Conflicts:
#	sormas-backend/src/main/resources/sql/sormas_schema.sql
Summary:
Enhanced the symptom form for the different sections.
Changes:
Adjusted the symptoms based on their category.
@KarnaiahPesula KarnaiahPesula requested a review from raulbob March 11, 2026 14:28
@KarnaiahPesula KarnaiahPesula linked an issue Mar 11, 2026 that may be closed by this pull request
3 tasks
@KarnaiahPesula KarnaiahPesula changed the title Feature 13797 malaria disease Feature 13797 & 13810 Malaria and Dengue diseases Mar 11, 2026
@sormas-vitagroup
Copy link
Contributor

@coderabbitai
Copy link

coderabbitai bot commented Mar 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Malaria and Dengue support across API, backend, UI and DB: new symptoms and clinical manifestation enum, a @Complication annotation and helper, incubation-period configuration (DTO/entity/facade/EJB), vaccine metadata, a complications side-panel UI with integration, i18n/resource updates, extensive schema changes, and test adjustments.

Changes

Cohort / File(s) Summary
Disease enum & configuration
sormas-api/.../Disease.java, sormas-api/.../disease/DiseaseConfigurationDto.java, sormas-api/.../disease/DiseaseConfigurationFacade.java, sormas-backend/.../disease/DiseaseConfiguration.java, sormas-backend/.../disease/DiseaseConfigurationFacadeEjb.java, sormas-api/.../disease/DiseaseConfigurationIndexDto.java
Expanded Disease constructor to include incubation defaults; added incubation and case-definition fields across DTO/entity/index and facade/EJB; made DISEASE_LIST final.
Symptoms model & mappings
sormas-api/.../symptoms/SymptomsDto.java, sormas-api/.../symptoms/ClinicalManifestation.java, sormas-backend/.../symptoms/Symptoms.java, sormas-backend/.../symptoms/SymptomsFacadeEjb.java
Added many Malaria/Dengue symptom constants and fields (clinical manifestation, offset date, neurological/hematologic indicators), new ClinicalManifestation enum, DTO/entity getters/setters, and bidirectional mappings.
Complication annotation & helper
sormas-api/.../utils/Complication.java, sormas-api/.../utils/AnnotationFieldHelper.java
Introduced @Complication annotation and helper method to collect fields annotated with both @Diseases and @Complication.
Health conditions
sormas-api/.../clinicalcourse/HealthConditionsDto.java, sormas-backend/.../clinicalcourse/HealthConditions.java, sormas-backend/.../clinicalcourse/HealthConditionsMapper.java
Added immunodeficiency-other-than-HIV, exposed/vaccinated-against-mosquito-borne-viruses fields with DTO/entity mapping and accessors.
Vaccine & manufacturer metadata
sormas-api/.../caze/Vaccine.java, sormas-api/.../caze/VaccineManufacturer.java, sormas-api/src/main/resources/enum.properties
Reworked Vaccine to per-constant metadata getters (vaccineType/INN/ATC/UNII/manufacturer), added new vaccine constants and manufacturers; updated enum properties.
Case/Person/Sample annotations
sormas-api/.../caze/CaseDataDto.java, sormas-api/.../person/PersonDto.java, sormas-api/.../sample/SampleMaterial.java
Added @Diseases to hide malaria quarantine fields, expanded entryDate/livingStatus disease sets, and added MALARIA/DENGUE to many sample material annotations.
UI — symptoms, side panel & controllers
sormas-ui/.../symptoms/SymptomsForm.java, sormas-ui/.../caze/CaseSymptomSideViewComponent.java, sormas-ui/.../caze/CaseSymptomsView.java, sormas-ui/.../caze/CaseController.java, sormas-ui/.../caze/CaseDataForm.java
Added CaseSymptomSideViewComponent and wiring; SymptomsForm can notify side view of complication toggles; CaseController signature extended to accept side component; CaseSymptomsView integrates side panel.
UI — disease configuration & grid
sormas-ui/.../configuration/disease/DiseaseConfigurationEditForm.java, sormas-ui/.../configuration/disease/DiseaseConfigurationGrid.java
Refactored edit form into accordion sections; added incubation-period controls and case-definition rich text; added incubation columns to grid.
UI — health, vaccination, person, epi
sormas-ui/.../clinicalcourse/HealthConditionsForm.java, sormas-ui/.../vaccination/VaccinationEditForm.java, sormas-ui/.../person/PersonEditForm.java, sormas-ui/.../epidata/EpiDataForm.java, sormas-ui/.../contact/ContactDataForm.java
Extended health form with immunodeficiency/mosquito exposure and vaccination listener; added vaccine ATC/INN/UNII fields and wiring; adjusted person entry-date disease set and occupation filtering; added exposure period heading; removed unused luxMeasles field.
i18n & resources
sormas-api/.../i18n/Captions.java, sormas-api/.../i18n/Strings.java, sormas-api/src/main/resources/captions.properties, sormas-api/src/main/resources/strings.properties
Added many caption/string keys for new symptoms, incubation settings, health conditions, vaccine metadata, and UI headings; adjusted several existing labels.
Database schema
sormas-backend/src/main/resources/sql/sormas_schema.sql
Large schema additions/ALTERs supporting incubation fields, new symptom/health/vaccine columns, new tables (adverse events, environments, surveys, etc.), indexes, triggers and versioning for expanded features.
Tests & test utilities
sormas-backend/.../TestDataCreator.java, sormas-backend/.../disease/DiseaseConfigurationFacadeEjbTest.java, sormas-backend/.../outbreak/*, sormas-backend/.../externalmessage/*, sormas-backend/.../report/*
Extended TestDataCreator.updateDiseaseConfiguration to accept incubation params and updated many tests to pass new arguments; various test callsite updates and minor formatting changes.
UI utils & field helpers
sormas-ui/.../utils/FieldHelper.java
Added setClearEnabled(boolean, Field...) utility to enable and clear fields.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SymptomsForm as rgba(52,152,219,0.5)
    participant SideView as rgba(46,204,113,0.5)
    participant Helper as rgba(155,89,182,0.5)

    User->>SymptomsForm: open symptoms editor
    SymptomsForm->>SideView: setCaseSymptomSideViewComponent(component)
    User->>SymptomsForm: toggle onset/complication symptom
    SymptomsForm->>Helper: getComplicatedSymptomsWithDiseases(clazz, disease)
    Helper-->>SymptomsForm: list of complicated symptom names
    SymptomsForm->>SideView: toggleComplicationSymptom(symptomName, valid)
    SideView->>SideView: refreshLayout()
    SideView-->>User: display updated complications
Loading
sequenceDiagram
    participant UI as rgba(52,152,219,0.5)
    participant Facade as rgba(231,76,60,0.5)
    participant Cache as rgba(149,165,166,0.5)
    participant DB as rgba(46,204,113,0.5)

    UI->>Facade: request disease configuration
    Facade->>Cache: check incubation maps
    alt cache hit
      Cache-->>Facade: return cached values
    else
      Facade->>DB: load DiseaseConfiguration entities
      DB-->>Facade: return entities with incubation fields
      Facade->>Cache: populate incubation maps
    end
    Facade-->>UI: return DTO with incubation settings
    UI->>UI: render accordion with incubation controls
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • obinna-h-n
  • roldy

Poem

🐰 I hop through fields and strings anew,

I mark complications, one, two, and few;
A side view blooms to show each troubling sign,
Incubation knobs and captions now align;
Hooray — the rabbit cheers: features stitched and true!

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature-13797-malaria-disease

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 16

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

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

⚠️ Outside diff range comments (3)
sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java (1)

83-88: ⚠️ Potential issue | 🟠 Major

Duplicate field location for CASE_IMPORTED_STATUS in layout.

EpiDataDto.CASE_IMPORTED_STATUS appears twice in the HTML layout:

  • Line 83: fluidRowLocs(6,EpiDataDto.CASE_IMPORTED_STATUS,6,"")
  • Line 88: fluidRowLocs(6,EpiDataDto.CASE_IMPORTED_STATUS,6,"")

The field is only added once via addField(EpiDataDto.CASE_IMPORTED_STATUS) at line 171. Having the same field ID in two layout positions will cause rendering issues—the field can only appear in one location.

🐛 Proposed fix: Remove duplicate layout entry

If the intent is to place CASE_IMPORTED_STATUS before the exposure period heading (new position), remove the duplicate at line 88:

 			loc(LOC_EXPOSURE_INVESTIGATION_HEADING) +
 					fluidRowLocs(6,EpiDataDto.CASE_IMPORTED_STATUS,6,"") +
 			loc(LOC_EXP_PERIOD_HEADING) +
 			loc(EpiDataDto.EXPOSURE_DETAILS_KNOWN) +
 			loc(EpiDataDto.EXPOSURES) +
 			loc(LOC_CONCLUSION_HEADING) +
-			fluidRowLocs(6,EpiDataDto.CASE_IMPORTED_STATUS,6,"") +
 			fluidRowLocs(6, EpiDataDto.IMPORTED_CASE, 6, EpiDataDto.COUNTRY)+

Alternatively, if the field should remain in the conclusion section, remove line 83 instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java` around
lines 83 - 88, The layout contains a duplicate placement of
EpiDataDto.CASE_IMPORTED_STATUS via two calls to
fluidRowLocs(6,EpiDataDto.CASE_IMPORTED_STATUS,6,""); remove the redundant call
so the field only appears once in the layout (keep the intended position—either
before LOC_EXP_PERIOD_HEADING or in the conclusion section between
LOC_CONCLUSION_HEADING and surrounding entries); ensure
addField(EpiDataDto.CASE_IMPORTED_STATUS) remains unchanged and the remaining
fluidRowLocs call matches the desired visual order.
sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/disease/DiseaseConfigurationEditForm.java (1)

179-191: ⚠️ Potential issue | 🟡 Minor

Remove debug System.out.println statements.

Lines 180-181 contain debug print statements that should not be in production code. These leak implementation details to stdout and may impact performance.

🧹 Proposed fix
 	public void attach() {
 		super.attach();
 
 		cbCaseSurveillance.addValueChangeListener(e -> {
-			System.out.println("not enabled" + !cbFollowUpEnabled.isEnabled());
-			System.out.println("value" + cbFollowUpEnabled.getValue());
 			if (!cbFollowUpEnabled.isEnabled() && cbFollowUpEnabled.getValue()) {
 				tfFollowUpDuration.setEnabled(false);
 				tfCaseFollowUpDuration.setEnabled(false);
 				tfEventParticipantFollowUpDuration.setEnabled(false);
 			} else if (cbFollowUpEnabled.isEnabled() && cbFollowUpEnabled.getValue()) {
 				tfFollowUpDuration.setEnabled(true);
 				tfCaseFollowUpDuration.setEnabled(true);
 				tfEventParticipantFollowUpDuration.setEnabled(true);
 			}
 		});
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/disease/DiseaseConfigurationEditForm.java`
around lines 179 - 191, Remove the two debug System.out.println calls inside the
cbCaseSurveillance.addValueChangeListener block to avoid leaking debug output
and affecting production performance; locate the listener attached to
cbCaseSurveillance in DiseaseConfigurationEditForm and delete the
System.out.println("not enabled" + !cbFollowUpEnabled.isEnabled()) and
System.out.println("value" + cbFollowUpEnabled.getValue()) lines, keeping the
conditional enable/disable logic for tfFollowUpDuration, tfCaseFollowUpDuration,
and tfEventParticipantFollowUpDuration intact (or replace prints with proper
logging via the class logger if you need runtime diagnostics).
sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java (1)

385-408: ⚠️ Potential issue | 🟡 Minor

Duplicate disease entries in multiple @Diseases annotations.

The file contains 11 fields with duplicate disease values in their @Diseases annotations:

  • 9 fields have duplicate DENGUE entries: abdominalPain, fever, headache, jointPain, musclePain, nausea, rapidBreathing, redBloodVomit, vomiting
  • 2 fields have duplicate GUINEA_WORM entries: otherComplications, otherComplicationsText

While Java annotations with array values don't cause compilation errors with duplicates, this is a code smell that should be cleaned up. Remove all duplicate entries from these 11 fields.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java`
around lines 385 - 408, Several `@Diseases` annotations contain duplicate disease
entries; remove duplicate values so each disease appears only once in the array
for the affected fields. Edit the `@Diseases` arrays on the SymptomState fields
abdominalPain, fever, headache, jointPain, musclePain, nausea, rapidBreathing,
redBloodVomit, vomiting (remove the duplicate DENGUE) and on otherComplications
and otherComplicationsText (remove the duplicate GUINEA_WORM), leaving a single
instance of each disease in each annotation while preserving the intended set of
diseases for each field.
🟡 Minor comments (8)
sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java-134-134 (1)

134-134: ⚠️ Potential issue | 🟡 Minor

Remove orphaned field logic from layout removal.

DENGUE_FEVER_TYPE has been removed from the HTML layout (line 134), but the field instantiation (line 212) and visibility logic (line 500) remain. Since the field no longer has a layout slot, this code is dead and will never render.

Remove or comment out:

  • Line 212: addField(CaseDataDto.DENGUE_FEVER_TYPE, NullableOptionGroup.class);
  • Lines 499-500: FieldHelper.setVisibleWhen(getFieldGroup(), Arrays.asList(CaseDataDto.DENGUE_FEVER_TYPE), ...)

(Note: Other forms like CaseDataForm.java and BulkCaseDataForm.java still retain this field in their layouts.)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java` at line
134, Remove the orphaned DENGUE_FEVER_TYPE field and its visibility rule: delete
or comment out the addField call that instantiates CaseDataDto.DENGUE_FEVER_TYPE
with NullableOptionGroup (the addField(...) call) and remove or comment out the
FieldHelper.setVisibleWhen(...) invocation that references
CaseDataDto.DENGUE_FEVER_TYPE (the call that uses getFieldGroup()). This will
eliminate dead code for a field that no longer has a layout slot; leave other
forms (CaseDataForm, BulkCaseDataForm) unchanged.
sormas-backend/src/main/resources/sql/sormas_schema.sql-15284-15293 (1)

15284-15293: ⚠️ Potential issue | 🟡 Minor

INSERT statements lack idempotency protection.

These inserts could create duplicate entries if the migration is re-run or if the values already exist. Consider wrapping each insert with a check to prevent duplicates.

Based on learnings: "When adding unique constraints to existing tables in SORMAS-Project, ensure schema migration scripts verify there are no duplicate values in the target columns before applying the constraint."

🛡️ Proposed fix using WHERE NOT EXISTS
-INSERT INTO customizableenumvalue (id, uuid, changedate, creationdate, datatype, value, caption, diseases, defaultvalue, properties)
-VALUES (nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'OCCUPATION_TYPE', 'WORK_IN_AIRPORT', 'Work in an airport', 'DENGUE,MALARIA',true,jsonb_build_object('hasDetails', false));
+INSERT INTO customizableenumvalue (id, uuid, changedate, creationdate, datatype, value, caption, diseases, defaultvalue, properties)
+SELECT nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'OCCUPATION_TYPE', 'WORK_IN_AIRPORT', 'Work in an airport', 'DENGUE,MALARIA', true, jsonb_build_object('hasDetails', false)
+WHERE NOT EXISTS (SELECT 1 FROM customizableenumvalue WHERE datatype = 'OCCUPATION_TYPE' AND value = 'WORK_IN_AIRPORT');

--- Livestock farmer - applicable only for DENGUE
-INSERT INTO customizableenumvalue (id, uuid, changedate, creationdate, datatype, value, caption, diseases, defaultvalue,properties)
-VALUES (nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'OCCUPATION_TYPE', 'LIVESTOCK_FARMER', 'Livestock farmer', 'DENGUE',true,jsonb_build_object('hasDetails', false));
+-- Livestock farmer - applicable only for DENGUE
+INSERT INTO customizableenumvalue (id, uuid, changedate, creationdate, datatype, value, caption, diseases, defaultvalue, properties)
+SELECT nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'OCCUPATION_TYPE', 'LIVESTOCK_FARMER', 'Livestock farmer', 'DENGUE', true, jsonb_build_object('hasDetails', false)
+WHERE NOT EXISTS (SELECT 1 FROM customizableenumvalue WHERE datatype = 'OCCUPATION_TYPE' AND value = 'LIVESTOCK_FARMER');

--- Veterinarian - applicable only for DENGUE
-INSERT INTO customizableenumvalue (id, uuid, changedate, creationdate, datatype, value, caption, diseases, defaultvalue,properties)
-VALUES (nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'OCCUPATION_TYPE', 'VETERINARIAN', 'Veterinarian', 'DENGUE', true,jsonb_build_object('hasDetails', false));
+-- Veterinarian - applicable only for DENGUE
+INSERT INTO customizableenumvalue (id, uuid, changedate, creationdate, datatype, value, caption, diseases, defaultvalue, properties)
+SELECT nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'OCCUPATION_TYPE', 'VETERINARIAN', 'Veterinarian', 'DENGUE', true, jsonb_build_object('hasDetails', false)
+WHERE NOT EXISTS (SELECT 1 FROM customizableenumvalue WHERE datatype = 'OCCUPATION_TYPE' AND value = 'VETERINARIAN');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-backend/src/main/resources/sql/sormas_schema.sql` around lines 15284 -
15293, The INSERTs into table customizableenumvalue for datatype
'OCCUPATION_TYPE' (values WORK_IN_AIRPORT, LIVESTOCK_FARMER, VETERINARIAN) are
not idempotent; modify each statement to first check for existence and only
insert if missing (e.g., use an INSERT ... SELECT ... WHERE NOT EXISTS(...) or
an IF NOT EXISTS check) matching on the unique identifying keys you care about
(at minimum datatype and value, optionally caption/diseases) so rerunning the
migration will not create duplicates.
sormas-backend/src/test/java/de/symeda/sormas/backend/report/AggregateReportFacadeEjbTest.java-413-415 (1)

413-415: ⚠️ Potential issue | 🟡 Minor

Assert the new result set here.

Line 415 still checks similarAggregateReports3.size(), so this branch never verifies the size of similarAggregateReports4 returned after the configuration reset.

Suggested fix
-		assertEquals(8, similarAggregateReports3.size());
+		assertEquals(8, similarAggregateReports4.size());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-backend/src/test/java/de/symeda/sormas/backend/report/AggregateReportFacadeEjbTest.java`
around lines 413 - 415, Replace the incorrect assertion that still references
similarAggregateReports3 with an assertion that checks the result of the second
query: after calling creator.updateDiseaseConfiguration(...) and assigning
List<AggregateReportDto> similarAggregateReports4 =
getAggregateReportFacade().getSimilarAggregateReports(selectedAggregateReport),
assert the expected size against similarAggregateReports4.size() (e.g.
assertEquals(<expectedCount>, similarAggregateReports4.size())) so the branch
actually verifies the new result set from getSimilarAggregateReports.
sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java-619-623 (1)

619-623: ⚠️ Potential issue | 🟡 Minor

Compare SKIN_RASH against SymptomState.YES here.

SKIN_RASH is a symptom-state field, so this initial visibility check never matches YesNoUnknown.YES. Existing cases with skin rash already set to yes will load with the caption hidden until the field is changed.

Suggested fix
 		skinRashDateLabel.setVisible(
 			isConfiguredServer(CountryHelper.COUNTRY_CODE_LUXEMBOURG)
-				&& FieldHelper.getNullableSourceFieldValue(getField(SKIN_RASH)) == YesNoUnknown.YES
+				&& FieldHelper.getNullableSourceFieldValue(getField(SKIN_RASH)) == SymptomState.YES
 				&& isVisibleAllowed(SKIN_RASH_ONSET_DATE));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java`
around lines 619 - 623, The visibility check for skinRashDateLabel incorrectly
compares FieldHelper.getNullableSourceFieldValue(getField(SKIN_RASH)) to
YesNoUnknown.YES; change the comparison to SymptomState.YES (i.e. treat
SKIN_RASH as a SymptomState) so the condition becomes
isConfiguredServer(CountryHelper.COUNTRY_CODE_LUXEMBOURG) &&
FieldHelper.getNullableSourceFieldValue(getField(SKIN_RASH)) == SymptomState.YES
&& isVisibleAllowed(SKIN_RASH_ONSET_DATE), ensuring skinRashDateLabel is shown
when the symptom state is YES; keep the rest of the logic (isConfiguredServer,
isVisibleAllowed, SKIN_RASH_ONSET_DATE, skinRashDateLabel) untouched.
sormas-api/src/main/resources/captions.properties-3012-3012 (1)

3012-3012: ⚠️ Potential issue | 🟡 Minor

Fix the medical term spellings in these new symptom captions.

Both values are user-facing, and the current spellings look off: Guillain-barré should be Guillain-Barré, and intra-vascular should be intravascular.

✏️ Proposed fix
-Symptoms.guillainBarreSyndrome=Guillain-barré syndrome
+Symptoms.guillainBarreSyndrome=Guillain-Barré syndrome
-Symptoms.disseminatedIntraVascularCoagulation=Disseminated intra-vascular coagulation
+Symptoms.disseminatedIntraVascularCoagulation=Disseminated intravascular coagulation

Also applies to: 3033-3033

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/resources/captions.properties` at line 3012, The caption
keys contain incorrect user-facing spellings: update
Symptoms.guillainBarreSyndrome to use "Guillain-Barré syndrome" (capital B and
accented É) and replace any occurrences of "intra-vascular" with "intravascular"
(no hyphen) in the captions file (e.g., the entry for
Symptoms.guillainBarreSyndrome and the caption at the other noted location
around the 3033 entry); ensure the exact keys/names remain unchanged and only
the right‑hand side values are corrected.
sormas-api/src/main/resources/captions.properties-3667-3667 (1)

3667-3667: ⚠️ Potential issue | 🟡 Minor

Remove the trailing space from this label value.

Line 3667 ends with a space. In a .properties file that space is part of the value and can leak into rendered labels or exports.

✏️ Proposed fix
-DiseaseConfiguration.maxIncubationPeriod=Maximum incubation period 
+DiseaseConfiguration.maxIncubationPeriod=Maximum incubation period
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/resources/captions.properties` at line 3667, The property
value for the key DiseaseConfiguration.maxIncubationPeriod contains a trailing
space; open the captions.properties file, locate the
DiseaseConfiguration.maxIncubationPeriod entry and remove the trailing
whitespace so the value ends with "Maximum incubation period" (no extra space)
to prevent leaking spaces into rendered labels or exports.
sormas-api/src/main/resources/captions.properties-1662-1664 (1)

1662-1664: ⚠️ Potential issue | 🟡 Minor

Complete the truncated caption and remove the embedded value whitespace.

HealthConditions.exposedToMosquitoBorneVirusesText reads unfinished, and HealthConditions.immunodeficiencyOtherThanHivText currently includes trailing spaces that become part of the caption value.

✏️ Proposed fix
-HealthConditions.exposedToMosquitoBorneVirusesText=Specify exposure to mosquito-borne
+HealthConditions.exposedToMosquitoBorneVirusesText=Specify exposure to mosquito-borne viruses
-HealthConditions.immunodeficiencyOtherThanHivText=Specify immunodeficiency other than HIV       
+HealthConditions.immunodeficiencyOtherThanHivText=Specify immunodeficiency other than HIV
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/resources/captions.properties` around lines 1662 - 1664,
Update the two caption values: complete
HealthConditions.exposedToMosquitoBorneVirusesText so it reads "Specify exposure
to mosquito-borne viruses" (replacing the truncated "Specify exposure to
mosquito-borne") and remove the trailing whitespace from
HealthConditions.immunodeficiencyOtherThanHivText so its value has no embedded
or trailing spaces; leave HealthConditions.vaccinatedAgainstMosquitoBorneViruses
as-is.
sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java-3028-3057 (1)

3028-3057: ⚠️ Potential issue | 🟡 Minor

Missing @Size annotation on String fields.

The fields clinicalManifestationText (line 3033) and otherNeurolocalSymptomText (line 3057) are missing the @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) annotation that is consistently applied to similar text fields in this DTO (e.g., otherHemorrhagicSymptomsText, otherComplicationsText).

This could allow unbounded string inputs, potentially causing database truncation or errors.

🛡️ Proposed fix to add `@Size` annotations
 `@Diseases`({
 	DENGUE })
 `@Outbreaks`
 `@HideForCountriesExcept`(countries = {
 	CountryHelper.COUNTRY_CODE_LUXEMBOURG })
+@Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
 private String clinicalManifestationText;
 `@Diseases`({
 	DENGUE })
 `@Outbreaks`
 `@HideForCountriesExcept`(countries = {
 	COUNTRY_CODE_LUXEMBOURG })
 `@DependantOn`(OTHER_NEUROLOCAL_SYMPTOM)
 `@SymptomGrouping`(SymptomGroup.NERVOUS_SYSTEM)
+@Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
 private String otherNeurolocalSymptomText;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java`
around lines 3028 - 3057, Add the missing `@Size`(max =
FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
annotation to the String fields clinicalManifestationText and
otherNeurolocalSymptomText in SymptomsDto; place the annotation alongside the
existing annotations (e.g., `@Diseases`, `@Outbreaks`, `@HideForCountriesExcept`,
`@DependantOn`) so these fields follow the same length constraint pattern as other
text fields like otherHemorrhagicSymptomsText and otherComplicationsText.
🧹 Nitpick comments (9)
sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java (1)

124-134: Keep the entry-date disease set form-local.

This looks like PersonEditForm-specific UI policy. Making it public unnecessarily expands the class API and invites cross-class coupling to a Luxembourg-specific rule. Prefer private static final unless another class already needs this constant.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java`
around lines 124 - 134, ENTRY_DATE_DISEASE is a UI-policy constant that should
be scoped to PersonEditForm only; change its declaration from public static
final to private static final (keep it static final and unmodifiable) so it
remains class-local and prevents external coupling—update the declaration of
ENTRY_DATE_DISEASE in PersonEditForm accordingly and ensure any internal
references within PersonEditForm still compile.
sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java (2)

135-136: Misleading variable name vaccinationListener.

The boolean vaccinationListener is used to skip the initial value-change event during form binding, but its name suggests it's related to the listener itself rather than tracking initialization state. A clearer name like initialized or skipInitialEvent would better convey its purpose.

Suggested rename for clarity
-	private boolean vaccinationListener = false;
+	private boolean vaccinationFieldInitialized = false;

And correspondingly at lines 291-298:

-				if (vaccinationListener) {
+				if (vaccinationFieldInitialized) {
 					boolean isVaccinated =
 						YesNoUnknown.YES.equals(FieldHelper.getNullableSourceFieldValue(vaccinatedAgainstMosquitoBorneViruses));
 					if (isVaccinated) {
 						ControllerProvider.getImmunizationController().create(personReferenceDto, disease);
 					}
 				}
-				vaccinationListener = true;
+				vaccinationFieldInitialized = true;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java`
around lines 135 - 136, Rename the misleading boolean field vaccinationListener
in HealthConditionsForm to a clearer name like skipInitialEvent or initialized
and update all references (including where it is toggled/checked during form
binding and in the value-change handling logic) so the variable reflects that it
skips the initial value-change event; ensure the field declaration, any
reads/writes, and any comments are updated consistently, and run a compile to
fix any remaining references in methods handling vaccination value changes.

147-155: Redundant disease assignment.

Line 154 sets this.disease = disease, but this is already set by the delegated constructor at line 143. Remove the redundant assignment.

Remove redundant assignment
 	public HealthConditionsForm(
 		Disease disease,
 		FieldVisibilityCheckers fieldVisibilityCheckers,
 		UiFieldAccessCheckers fieldAccessCheckers,
 		PersonReferenceDto personReferenceDto) {
 		this(disease, fieldVisibilityCheckers, fieldAccessCheckers);
 		this.personReferenceDto = personReferenceDto;
-		this.disease = disease;
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java`
around lines 147 - 155, The constructor HealthConditionsForm(Disease disease,
FieldVisibilityCheckers fieldVisibilityCheckers, UiFieldAccessCheckers
fieldAccessCheckers, PersonReferenceDto personReferenceDto) redundantly assigns
this.disease = disease after delegating to the other constructor; remove the
redundant assignment and only set this.personReferenceDto = personReferenceDto
(the delegated constructor already initializes the disease field).
sormas-api/src/main/java/de/symeda/sormas/api/Disease.java (1)

227-227: Wrap DISEASE_LIST with Collections.unmodifiableList() to prevent external mutation.

Arrays.asList() returns a mutable list that supports set() and other modification operations despite the final reference. External callers can mutate this public API. Add import java.util.Collections; and wrap the list initialization:

Suggested change
+import java.util.Collections;
 ...
-	public static final List<Disease> DISEASE_LIST = Arrays.asList(Disease.values());
+	public static final List<Disease> DISEASE_LIST = Collections.unmodifiableList(Arrays.asList(Disease.values()));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/Disease.java` at line 227,
DISEASE_LIST is currently exposed as a mutable list via
Arrays.asList(Disease.values()), allowing external callers to modify it; change
the initialization of the public static final DISEASE_LIST to wrap the result
with Collections.unmodifiableList(Arrays.asList(Disease.values())) and add the
required import for java.util.Collections so callers cannot mutate the returned
list while preserving the same contents.
sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java (1)

228-228: Make the new disease-configuration arguments explicit.

The trailing false, 0, 0 represents incubationPeriodEnabled, minIncubationPeriod, and maxIncubationPeriod—three positional primitives that are easy to swap accidentally. Using named locals would improve maintainability, particularly since this pattern is repeated across multiple test call sites (lines 228, 290, 340).

♻️ Example cleanup
+		final boolean incubationPeriodEnabled = false;
+		final int minIncubationPeriod = 0;
+		final int maxIncubationPeriod = 0;
-		creator.updateDiseaseConfiguration(externalMessage.getDisease(), true, true, true, true, null, 10, false, 0, 0);
+		creator.updateDiseaseConfiguration(
+			externalMessage.getDisease(),
+			true,
+			true,
+			true,
+			true,
+			null,
+			10,
+			incubationPeriodEnabled,
+			minIncubationPeriod,
+			maxIncubationPeriod);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java`
at line 228, The call to creator.updateDiseaseConfiguration currently passes
positional primitives at the end (false, 0, 0) which are the
incubationPeriodEnabled, minIncubationPeriod, and maxIncubationPeriod and are
easy to mix up; replace those trailing literals with clearly named local
variables (e.g. boolean incubationPeriodEnabled = false; int minIncubationPeriod
= 0; int maxIncubationPeriod = 0;) and use those locals in the call to
creator.updateDiseaseConfiguration in AutomaticLabMessageProcessorTest (and
mirror the same change at the other test call sites where the same pattern is
used) so the intent and order are explicit.
sormas-api/src/main/java/de/symeda/sormas/api/clinicalcourse/HealthConditionsDto.java (1)

104-108: Consider adding validation and sensitivity annotations to text fields.

The new text fields immunodeficiencyOtherThanHivText and exposedToMosquitoBorneVirusesText are missing @Size validation and @SensitiveData annotations that other similar text fields in this class have (e.g., otherConditions on lines 134-136).

♻️ Proposed fix for immunodeficiencyOtherThanHivText
 	`@HideForCountriesExcept`(countries = {
 		CountryHelper.COUNTRY_CODE_LUXEMBOURG })
 	`@Diseases`(value = {
 		Disease.DENGUE })
+	`@SensitiveData`
+	`@Size`(max = FieldConstraints.CHARACTER_LIMIT_BIG, message = Validations.textTooLong)
 	private String immunodeficiencyOtherThanHivText;
♻️ Proposed fix for exposedToMosquitoBorneVirusesText
 	`@HideForCountriesExcept`(countries = {
 		CountryHelper.COUNTRY_CODE_LUXEMBOURG })
 	`@Diseases`(value = {
 		Disease.DENGUE })
+	`@SensitiveData`
+	`@Size`(max = FieldConstraints.CHARACTER_LIMIT_BIG, message = Validations.textTooLong)
 	private String exposedToMosquitoBorneVirusesText;

Also applies to: 162-166

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-api/src/main/java/de/symeda/sormas/api/clinicalcourse/HealthConditionsDto.java`
around lines 104 - 108, Add the same validation and sensitivity annotations used
on other free-text fields (e.g., otherConditions) to the new fields: annotate
immunodeficiencyOtherThanHivText and exposedToMosquitoBorneVirusesText with
`@Size`(max = ...) matching the class standard and add `@SensitiveData` to mark them
as sensitive; ensure the annotations are imported and placed above the field
declarations alongside the existing `@HideForCountriesExcept/`@Diseases
annotations so they follow the same pattern as other text fields in this DTO.
sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java (1)

436-448: Consider null safety for incubation period lookups.

getMaxIncubationPeriod and getMinIncubationPeriod return primitive int but the map lookup returns Integer. If a disease is not in the map, auto-unboxing will throw NPE. This follows existing patterns (e.g., getFollowUpDuration), but consider returning Integer or adding null checks for defensive coding.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java`
around lines 436 - 448, The current getMaxIncubationPeriod and
getMinIncubationPeriod unbox Integer from
maxIncubationPeriod/minIncubationPeriod maps and can NPE; update both methods to
return Integer (change signatures of getMaxIncubationPeriod and
getMinIncubationPeriod) and simply return maxIncubationPeriod.get(disease) and
minIncubationPeriod.get(disease) (matching the existing getFollowUpDuration
pattern), or alternatively add explicit null checks inside those methods and
return a safe default or throw a clear IllegalArgumentException—make sure to
update any callers if you change the return type.
sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java (2)

2908-2933: Missing @SymptomGrouping annotations on convulsions and restlessness fields.

Both convulsions (lines 2908-2912) and restlessness (lines 2929-2933) lack @SymptomGrouping annotations. The existing similar fields convulsion and agitation are grouped under SymptomGroup.NERVOUS_SYSTEM.

♻️ Proposed fix
 `@Diseases`({
 	DENGUE })
+@SymptomGrouping(SymptomGroup.NERVOUS_SYSTEM)
 `@Complication`({
 	DENGUE })
 private SymptomState convulsions;
 `@Diseases`({
 	DENGUE })
+@SymptomGrouping(SymptomGroup.NERVOUS_SYSTEM)
 `@Complication`({
 	DENGUE })
 private SymptomState restlessness;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java`
around lines 2908 - 2933, Add the missing `@SymptomGrouping` annotations to the
SymptomState fields convulsions and restlessness: update the field declarations
for convulsions and restlessness to include
`@SymptomGrouping`(SymptomGroup.NERVOUS_SYSTEM), mirroring the grouping used by
related fields convulsion and agitation; keep the existing `@Diseases` and
`@Complication` annotations unchanged so the final declarations include
`@Diseases`({DENGUE}), `@SymptomGrouping`(SymptomGroup.NERVOUS_SYSTEM) and
`@Complication`({DENGUE}).

2903-2906: Missing @SymptomGrouping annotation on confusion field.

The confusion field lacks a @SymptomGrouping annotation, while similar neurological symptoms like lethargy, encephalitis, and confusedDisoriented are annotated with @SymptomGrouping(SymptomGroup.NERVOUS_SYSTEM).

This inconsistency may affect how symptoms are grouped and displayed in the UI.

♻️ Proposed fix
 `@Diseases`({
 	DENGUE })
-
+@SymptomGrouping(SymptomGroup.NERVOUS_SYSTEM)
 private SymptomState confusion;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java`
around lines 2903 - 2906, Add the missing
`@SymptomGrouping`(SymptomGroup.NERVOUS_SYSTEM) annotation to the confusion field
in the SymptomsDto class so it matches other neurological symptoms (lethargy,
encephalitis, confusedDisoriented); leave the existing `@Diseases`({ DENGUE }) in
place and annotate the private SymptomState confusion field directly above it to
ensure proper grouping/display in the UI.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java`:
- Around line 497-499: The DTO hides only quarantine itself for malaria; add the
same annotation `@Diseases`(value = { Disease.MALARIA }, hide = true) to all
quarantine-related fields in CaseDataDto so they are consistently hidden at the
DTO level; locate the fields quarantineTypeDetails, quarantineFrom,
quarantineTo, quarantineHelpNeeded, quarantineExtended, quarantineReduced,
quarantineOrderedVerbally, quarantineOrderedOfficialDocument,
quarantineOrderedVerballyDate, quarantineOrderedOfficialDocumentDate,
quarantineHomePossible, quarantineHomePossibleComment,
quarantineHomeSupplyEnsured, quarantineHomeSupplyEnsuredComment,
quarantineOfficialOrderSent, quarantineOfficialOrderSentDate and
quarantineChangeComment in class CaseDataDto and place the annotation directly
above each field declaration.

In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java`:
- Around line 95-101: The Vaccine enum currently uses the literal "N/A (not yet
assigned)" for missing regulatory codes which causes StringUtils.isBlank(...) to
treat them as non-blank; update the enum entries (e.g., QDENGA, RTS_S_AS01,
R21_MATRIX_M) in class Vaccine so that any unavailable regulatory code arguments
(ATC/INN/UNII) are passed as null instead of the placeholder string; this will
restore correct blank/missing behavior in VaccinationEditForm and keep the
constructor/signature unchanged.

In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/VaccineManufacturer.java`:
- Around line 68-71: The enum VaccineManufacturer currently contains only OXFORD
with a comment "Oxford/Serum Institute" that creates ambiguity; replace that
comment by adding an explicit, unambiguous enum constant (e.g., SERUM_INSTITUTE
or OXFORD_SERUM_INSTITUTE) alongside OXFORD in the VaccineManufacturer enum so
each real manufacturer is represented; update any related `@Diseases` annotation
usage if needed to include the new constant name so persistence and filtering
use the distinct manufacturer values.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumFacadeEjb.java`:
- Around line 279-283: The validation in getEnumValue currently only checks the
disease-specific list and rejects values present in the disease-agnostic (null)
bucket; update the guard so when disease != null it verifies the value exists
either in enumValues.get(type).getOrDefault(disease, Collections.emptyList()) OR
in the shared null bucket enumValues.get(type).getOrDefault(null,
Collections.emptyList()) (i.e., mirror the fallback logic used by
getEnumValues/getEnumInfo) and only throw IllegalArgumentException if the value
is absent from both.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfiguration.java`:
- Around line 172-178: Add the same length constraint to the caseDefinitionText
mapping as used for ageGroups: update the getCaseDefinitionText accessor to
declare `@Column`(length = CHARACTER_LIMIT_TEXT) (using the existing
CHARACTER_LIMIT_TEXT constant) so the caseDefinitionText field (and its getter
setCaseDefinitionText) uses the same character limit to avoid truncation and
keep consistency with ageGroups.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java`:
- Around line 231-234: In DiseaseConfigurationFacadeEjb, the DTO's
caseDefinitionText is incorrectly set from itself; update the assignment so
dto.setCaseDefinitionText(...) reads from the entity (use
entity.getCaseDefinitionText()) instead of dto.getCaseDefinitionText() to
correctly copy the value when populating the DTO.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/Symptoms.java`:
- Around line 285-311: The new symptom fields (confusion, convulsions,
encephalitis, alteredLevelOfConsciousness) are declared but not exported and
duplicate existing fields (confusedDisoriented, convulsion, acuteEncephalitis,
alteredConsciousness); update SymptomsHelper.buildSymptomsHumanString() to
include the new fields (or their consolidated equivalents) so stored values
appear in exports/reports, and then reconcile the mappings in SymptomsFacadeEjb
(where both old and new fields are set) by either mapping source data to only
one canonical field or clearly documenting and mapping both distinct concepts
consistently across all consumers; specifically adjust the code paths that set
confusion/convulsions/encephalitis/alteredLevelOfConsciousness and the formatter
that generates human-readable symptom strings to reflect the chosen
consolidation/semantics.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/SymptomsFacadeEjb.java`:
- Around line 251-275: The SymptomsFacadeEjb mappings omit the
DISSEMINATED_INTRA_VASCULAR_COAGULATION field so values entered are lost; add
mapping calls to copy this property in both directions (source→target and
target→source) where other symptoms are handled — e.g., add
target.setDisseminatedIntraVascularCoagulation(source.getDisseminatedIntraVascularCoagulation())
in the block around setClammySkin/... and the reciprocal
target.setDisseminatedIntraVascularCoagulation(source.getDisseminatedIntraVascularCoagulation())
(or
source.setDisseminatedIntraVascularCoagulation(target.getDisseminatedIntraVascularCoagulation())
depending on the direction) in the corresponding block around lines ~507-531 so
the field is persisted and restored.

In `@sormas-backend/src/main/resources/sql/sormas_schema.sql`:
- Line 15316: Rename the newly added columns in the ALTER TABLE statements to
use the all-lowercase convention and match ORM expectations: change
plasmaLeakagesign to plasmaleakagesign, scantHemorrhage to scanthhemorrhage,
otherNeurolocalSymptom to otherneurolocalsymptom, and otherNeurolocalSymptomText
to otherneurolocalsymptomtext in both the symptoms and symptoms_history table
ALTERs; ensure these exact lowercase names are used wherever the columns are
added (refer to the ALTER TABLE symptoms and ALTER TABLE symptoms_history
statements and the column identifiers plasmaLeakagesign, scantHemorrhage,
otherNeurolocalSymptom, otherNeurolocalSymptomText) so the database column names
are consistent with the existing schema naming convention and will map properly
to the Java field plasmaLeakageSign (or add an explicit `@Column` if you prefer
mapping instead).

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseSymptomSideViewComponent.java`:
- Around line 90-97: In refreshLayout(), clear the container before re-adding
components to avoid "Component is already in the container" errors: call
layout.removeAllComponents() (or the appropriate Vaadin remove-all method) at
the start of the method, then apply styles to each Component from componentMap
and add them back (use the existing layout, componentMap, and comp references);
keep the existing margin/spacing settings (layout.setMargin(false);
layout.setSpacing(false);) after clearing.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java`:
- Around line 289-299: The listener registration on
getField(VACCINATED_AGAINST_MOSQUITO_BORNE_VIRUSES) and the call to
ControllerProvider.getImmunizationController().create(...) can NPE; first,
null-check the result of getField(VACCINATED_AGAINST_MOSQUITO_BORNE_VIRUSES)
(the vaccinatedAgainstMosquitoBorneViruses variable) before calling
addValueChangeListener, and inside the listener guard the create call by
verifying personReferenceDto is not null (and that vaccinationListener logic
remains intact) — if personReferenceDto is null, skip calling
ControllerProvider.getImmunizationController().create(personReferenceDto,
disease) to avoid passing a null DTO.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java`:
- Line 78: The LOC_EXP_PERIOD_HEADING constant is never added to the UI; inside
addHeadingsAndInfoTexts() add a component for LOC_EXP_PERIOD_HEADING before the
conclusion heading block: call getContent().addComponent(...) creating a
MultilineLabel whose text comes from
I18nProperties.getString(Strings.infoExposurePeriodHeading), use
divsCss(VSPACE_3, ...) and ContentMode.HTML so the heading renders like the
other heading constants (match the pattern used for
LOC_EXPOSURE_INVESTIGATION_HEADING and LOC_CONCLUSION_HEADING).

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/externalmessage/physiciansreport/PhysiciansReportCaseEditComponent.java`:
- Around line 180-182: The TabConfig entry in PhysiciansReportCaseEditComponent
passes null for the side-component when calling
ControllerProvider.getCaseController().getSymptomsEditComponent(caze.getUuid(),
viewMode, null), which can drop disease-specific symptom wiring; either confirm
PhysiciansReportCaseEditComponent is unused and remove it, or update the call to
provide the same side-component used elsewhere (or adjust the controller to
handle null by delegating to the normal symptoms side wiring). Locate the
TabConfig.of(...) call in PhysiciansReportCaseEditComponent and: 1) search for
usages of PhysiciansReportCaseEditComponent to prove it's dead code and delete
if unused, or 2) replace the null argument with the proper side-component
provider used by the regular case flow (or modify getSymptomsEditComponent to
accept null safely and attach the disease-specific side view) so symptom
handling remains identical to the main workflow.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java`:
- Around line 419-421: When updating occupationTypeField items, preserve any
currently bound value even if the disease-filtered set no longer contains it:
before calling FieldHelper.updateItems(occupationTypeField,
FacadeProvider.getCustomizableEnumFacade().getEnumValues(CustomizableEnumType.OCCUPATION_TYPE,
disease)), capture the current value from occupationTypeField.getValue(); after
update, if that captured value is non-null and not present in the new items, add
or re-select that value (so the combo keeps showing the persisted
OccupationType) similar to the pattern used in initializePresentConditionField.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java`:
- Around line 1364-1371: The code unconditionally clears OFFSET_DATE and resets
CLINICAL_MANIFESTATION whenever any symptom toggles; change it so toggling only
enables/disables offsetDate (offsetDate.setEnabled(onsetSymptom.isEnabled()))
but does not wipe user input. Remove offsetDate.clear() and avoid forcing
cmCb.clear()/cmCb.setValue(...); instead, if onsetSymptom.isEnabled() and
getField(CLINICAL_MANIFESTATION).getValue() == null then set a default
(ClinicalManifestation.SIGN_OF_SEVERITY) — otherwise preserve the existing
value; do not clear values when disabling.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java`:
- Around line 102-113: The value-change listener on vaccineName only handles the
non-null case, so when the selection is cleared you must explicitly clear and
reset the dependent fields: set vaccineManufacturer, vaccineType, atcCode, inn,
and uniiCode to empty/null and set
vaccineType.setEnabled(true)/atcCode.setEnabled(true)/inn.setEnabled(true)/uniiCode.setEnabled(true)
(or the appropriate enabled state) in the else/null branch of the listener;
update the listener around the Vaccine cast (the
vaccineName.addValueChangeListener lambda) to handle both vaccine != null and
vaccine == null paths so old values are not retained when VACCINE_NAME is
cleared.

---

Outside diff comments:
In `@sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java`:
- Around line 385-408: Several `@Diseases` annotations contain duplicate disease
entries; remove duplicate values so each disease appears only once in the array
for the affected fields. Edit the `@Diseases` arrays on the SymptomState fields
abdominalPain, fever, headache, jointPain, musclePain, nausea, rapidBreathing,
redBloodVomit, vomiting (remove the duplicate DENGUE) and on otherComplications
and otherComplicationsText (remove the duplicate GUINEA_WORM), leaving a single
instance of each disease in each annotation while preserving the intended set of
diseases for each field.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/disease/DiseaseConfigurationEditForm.java`:
- Around line 179-191: Remove the two debug System.out.println calls inside the
cbCaseSurveillance.addValueChangeListener block to avoid leaking debug output
and affecting production performance; locate the listener attached to
cbCaseSurveillance in DiseaseConfigurationEditForm and delete the
System.out.println("not enabled" + !cbFollowUpEnabled.isEnabled()) and
System.out.println("value" + cbFollowUpEnabled.getValue()) lines, keeping the
conditional enable/disable logic for tfFollowUpDuration, tfCaseFollowUpDuration,
and tfEventParticipantFollowUpDuration intact (or replace prints with proper
logging via the class logger if you need runtime diagnostics).

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java`:
- Around line 83-88: The layout contains a duplicate placement of
EpiDataDto.CASE_IMPORTED_STATUS via two calls to
fluidRowLocs(6,EpiDataDto.CASE_IMPORTED_STATUS,6,""); remove the redundant call
so the field only appears once in the layout (keep the intended position—either
before LOC_EXP_PERIOD_HEADING or in the conclusion section between
LOC_CONCLUSION_HEADING and surrounding entries); ensure
addField(EpiDataDto.CASE_IMPORTED_STATUS) remains unchanged and the remaining
fluidRowLocs call matches the desired visual order.

---

Minor comments:
In `@sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java`:
- Around line 3028-3057: Add the missing `@Size`(max =
FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
annotation to the String fields clinicalManifestationText and
otherNeurolocalSymptomText in SymptomsDto; place the annotation alongside the
existing annotations (e.g., `@Diseases`, `@Outbreaks`, `@HideForCountriesExcept`,
`@DependantOn`) so these fields follow the same length constraint pattern as other
text fields like otherHemorrhagicSymptomsText and otherComplicationsText.

In `@sormas-api/src/main/resources/captions.properties`:
- Line 3012: The caption keys contain incorrect user-facing spellings: update
Symptoms.guillainBarreSyndrome to use "Guillain-Barré syndrome" (capital B and
accented É) and replace any occurrences of "intra-vascular" with "intravascular"
(no hyphen) in the captions file (e.g., the entry for
Symptoms.guillainBarreSyndrome and the caption at the other noted location
around the 3033 entry); ensure the exact keys/names remain unchanged and only
the right‑hand side values are corrected.
- Line 3667: The property value for the key
DiseaseConfiguration.maxIncubationPeriod contains a trailing space; open the
captions.properties file, locate the DiseaseConfiguration.maxIncubationPeriod
entry and remove the trailing whitespace so the value ends with "Maximum
incubation period" (no extra space) to prevent leaking spaces into rendered
labels or exports.
- Around line 1662-1664: Update the two caption values: complete
HealthConditions.exposedToMosquitoBorneVirusesText so it reads "Specify exposure
to mosquito-borne viruses" (replacing the truncated "Specify exposure to
mosquito-borne") and remove the trailing whitespace from
HealthConditions.immunodeficiencyOtherThanHivText so its value has no embedded
or trailing spaces; leave HealthConditions.vaccinatedAgainstMosquitoBorneViruses
as-is.

In `@sormas-backend/src/main/resources/sql/sormas_schema.sql`:
- Around line 15284-15293: The INSERTs into table customizableenumvalue for
datatype 'OCCUPATION_TYPE' (values WORK_IN_AIRPORT, LIVESTOCK_FARMER,
VETERINARIAN) are not idempotent; modify each statement to first check for
existence and only insert if missing (e.g., use an INSERT ... SELECT ... WHERE
NOT EXISTS(...) or an IF NOT EXISTS check) matching on the unique identifying
keys you care about (at minimum datatype and value, optionally caption/diseases)
so rerunning the migration will not create duplicates.

In
`@sormas-backend/src/test/java/de/symeda/sormas/backend/report/AggregateReportFacadeEjbTest.java`:
- Around line 413-415: Replace the incorrect assertion that still references
similarAggregateReports3 with an assertion that checks the result of the second
query: after calling creator.updateDiseaseConfiguration(...) and assigning
List<AggregateReportDto> similarAggregateReports4 =
getAggregateReportFacade().getSimilarAggregateReports(selectedAggregateReport),
assert the expected size against similarAggregateReports4.size() (e.g.
assertEquals(<expectedCount>, similarAggregateReports4.size())) so the branch
actually verifies the new result set from getSimilarAggregateReports.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java`:
- Line 134: Remove the orphaned DENGUE_FEVER_TYPE field and its visibility rule:
delete or comment out the addField call that instantiates
CaseDataDto.DENGUE_FEVER_TYPE with NullableOptionGroup (the addField(...) call)
and remove or comment out the FieldHelper.setVisibleWhen(...) invocation that
references CaseDataDto.DENGUE_FEVER_TYPE (the call that uses getFieldGroup()).
This will eliminate dead code for a field that no longer has a layout slot;
leave other forms (CaseDataForm, BulkCaseDataForm) unchanged.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java`:
- Around line 619-623: The visibility check for skinRashDateLabel incorrectly
compares FieldHelper.getNullableSourceFieldValue(getField(SKIN_RASH)) to
YesNoUnknown.YES; change the comparison to SymptomState.YES (i.e. treat
SKIN_RASH as a SymptomState) so the condition becomes
isConfiguredServer(CountryHelper.COUNTRY_CODE_LUXEMBOURG) &&
FieldHelper.getNullableSourceFieldValue(getField(SKIN_RASH)) == SymptomState.YES
&& isVisibleAllowed(SKIN_RASH_ONSET_DATE), ensuring skinRashDateLabel is shown
when the symptom state is YES; keep the rest of the logic (isConfiguredServer,
isVisibleAllowed, SKIN_RASH_ONSET_DATE, skinRashDateLabel) untouched.

---

Nitpick comments:
In
`@sormas-api/src/main/java/de/symeda/sormas/api/clinicalcourse/HealthConditionsDto.java`:
- Around line 104-108: Add the same validation and sensitivity annotations used
on other free-text fields (e.g., otherConditions) to the new fields: annotate
immunodeficiencyOtherThanHivText and exposedToMosquitoBorneVirusesText with
`@Size`(max = ...) matching the class standard and add `@SensitiveData` to mark them
as sensitive; ensure the annotations are imported and placed above the field
declarations alongside the existing `@HideForCountriesExcept/`@Diseases
annotations so they follow the same pattern as other text fields in this DTO.

In `@sormas-api/src/main/java/de/symeda/sormas/api/Disease.java`:
- Line 227: DISEASE_LIST is currently exposed as a mutable list via
Arrays.asList(Disease.values()), allowing external callers to modify it; change
the initialization of the public static final DISEASE_LIST to wrap the result
with Collections.unmodifiableList(Arrays.asList(Disease.values())) and add the
required import for java.util.Collections so callers cannot mutate the returned
list while preserving the same contents.

In `@sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java`:
- Around line 2908-2933: Add the missing `@SymptomGrouping` annotations to the
SymptomState fields convulsions and restlessness: update the field declarations
for convulsions and restlessness to include
`@SymptomGrouping`(SymptomGroup.NERVOUS_SYSTEM), mirroring the grouping used by
related fields convulsion and agitation; keep the existing `@Diseases` and
`@Complication` annotations unchanged so the final declarations include
`@Diseases`({DENGUE}), `@SymptomGrouping`(SymptomGroup.NERVOUS_SYSTEM) and
`@Complication`({DENGUE}).
- Around line 2903-2906: Add the missing
`@SymptomGrouping`(SymptomGroup.NERVOUS_SYSTEM) annotation to the confusion field
in the SymptomsDto class so it matches other neurological symptoms (lethargy,
encephalitis, confusedDisoriented); leave the existing `@Diseases`({ DENGUE }) in
place and annotate the private SymptomState confusion field directly above it to
ensure proper grouping/display in the UI.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java`:
- Around line 436-448: The current getMaxIncubationPeriod and
getMinIncubationPeriod unbox Integer from
maxIncubationPeriod/minIncubationPeriod maps and can NPE; update both methods to
return Integer (change signatures of getMaxIncubationPeriod and
getMinIncubationPeriod) and simply return maxIncubationPeriod.get(disease) and
minIncubationPeriod.get(disease) (matching the existing getFollowUpDuration
pattern), or alternatively add explicit null checks inside those methods and
return a safe default or throw a clear IllegalArgumentException—make sure to
update any callers if you change the return type.

In
`@sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java`:
- Line 228: The call to creator.updateDiseaseConfiguration currently passes
positional primitives at the end (false, 0, 0) which are the
incubationPeriodEnabled, minIncubationPeriod, and maxIncubationPeriod and are
easy to mix up; replace those trailing literals with clearly named local
variables (e.g. boolean incubationPeriodEnabled = false; int minIncubationPeriod
= 0; int maxIncubationPeriod = 0;) and use those locals in the call to
creator.updateDiseaseConfiguration in AutomaticLabMessageProcessorTest (and
mirror the same change at the other test call sites where the same pattern is
used) so the intent and order are explicit.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java`:
- Around line 135-136: Rename the misleading boolean field vaccinationListener
in HealthConditionsForm to a clearer name like skipInitialEvent or initialized
and update all references (including where it is toggled/checked during form
binding and in the value-change handling logic) so the variable reflects that it
skips the initial value-change event; ensure the field declaration, any
reads/writes, and any comments are updated consistently, and run a compile to
fix any remaining references in methods handling vaccination value changes.
- Around line 147-155: The constructor HealthConditionsForm(Disease disease,
FieldVisibilityCheckers fieldVisibilityCheckers, UiFieldAccessCheckers
fieldAccessCheckers, PersonReferenceDto personReferenceDto) redundantly assigns
this.disease = disease after delegating to the other constructor; remove the
redundant assignment and only set this.personReferenceDto = personReferenceDto
(the delegated constructor already initializes the disease field).

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java`:
- Around line 124-134: ENTRY_DATE_DISEASE is a UI-policy constant that should be
scoped to PersonEditForm only; change its declaration from public static final
to private static final (keep it static final and unmodifiable) so it remains
class-local and prevents external coupling—update the declaration of
ENTRY_DATE_DISEASE in PersonEditForm accordingly and ensure any internal
references within PersonEditForm still compile.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8efb4d24-29c2-428e-b0b6-da740d8fd012

📥 Commits

Reviewing files that changed from the base of the PR and between 5a262f6 and 4271928.

📒 Files selected for processing (48)
  • sormas-api/src/main/java/de/symeda/sormas/api/Disease.java
  • sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java
  • sormas-api/src/main/java/de/symeda/sormas/api/caze/VaccineManufacturer.java
  • sormas-api/src/main/java/de/symeda/sormas/api/clinicalcourse/HealthConditionsDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/disease/DiseaseConfigurationDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/disease/DiseaseConfigurationFacade.java
  • sormas-api/src/main/java/de/symeda/sormas/api/disease/DiseaseConfigurationIndexDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java
  • sormas-api/src/main/java/de/symeda/sormas/api/person/PersonDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java
  • sormas-api/src/main/java/de/symeda/sormas/api/symptoms/ClinicalManifestation.java
  • sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/utils/AnnotationFieldHelper.java
  • sormas-api/src/main/java/de/symeda/sormas/api/utils/Complication.java
  • sormas-api/src/main/resources/captions.properties
  • sormas-api/src/main/resources/enum.properties
  • sormas-api/src/main/resources/strings.properties
  • sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/HealthConditions.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/HealthConditionsMapper.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumFacadeEjb.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfiguration.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/Symptoms.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/SymptomsFacadeEjb.java
  • sormas-backend/src/main/resources/sql/sormas_schema.sql
  • sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java
  • sormas-backend/src/test/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjbTest.java
  • sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorPersonContactTest.java
  • sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java
  • sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/TuberculosisAutomaticLabMessageProcessorTest.java
  • sormas-backend/src/test/java/de/symeda/sormas/backend/outbreak/OutbreakFacadeEjbTest.java
  • sormas-backend/src/test/java/de/symeda/sormas/backend/report/AggregateReportFacadeEjbTest.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseSymptomSideViewComponent.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseSymptomsView.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/disease/DiseaseConfigurationEditForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/disease/DiseaseConfigurationGrid.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/externalmessage/physiciansreport/PhysiciansReportCaseEditComponent.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java
💤 Files with no reviewable changes (1)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataForm.java

Comment on lines +95 to +101
QDENGA(VaccineManufacturer.TAKEDA, "Live attenuated", "Live attenuated tetravalent dengue vaccine", "J07BF07", "N/A (not yet assigned)"),
@Diseases(value = {
Disease.MALARIA })
RTS_S_AS01(VaccineManufacturer.GSK, "Subunit", "Mosquirix (recombinant protein)", "J07BX03", "7C2S4M6X1H"),
@Diseases(value = {
Disease.MALARIA })
R21_MATRIX_M(VaccineManufacturer.OXFORD, "Subunit", "Recombinant protein vaccine", "N/A (not yet assigned)", "N/A (not yet assigned)"),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Keep unavailable regulatory codes as null, not placeholder text.

VaccinationEditForm uses StringUtils.isBlank(...) to decide whether ATC/INN/UNII stays editable. Storing "N/A (not yet assigned)" here turns those fields into read-only synthetic data instead of “missing data”.

Suggested fix
-	QDENGA(VaccineManufacturer.TAKEDA, "Live attenuated", "Live attenuated tetravalent dengue vaccine", "J07BF07", "N/A (not yet assigned)"),
+	QDENGA(VaccineManufacturer.TAKEDA, "Live attenuated", "Live attenuated tetravalent dengue vaccine", "J07BF07", null),
 	`@Diseases`(value = {
 		Disease.MALARIA })
 	RTS_S_AS01(VaccineManufacturer.GSK, "Subunit", "Mosquirix (recombinant protein)", "J07BX03", "7C2S4M6X1H"),
 	`@Diseases`(value = {
 		Disease.MALARIA })
-	R21_MATRIX_M(VaccineManufacturer.OXFORD, "Subunit", "Recombinant protein vaccine", "N/A (not yet assigned)", "N/A (not yet assigned)"),
+	R21_MATRIX_M(VaccineManufacturer.OXFORD, "Subunit", "Recombinant protein vaccine", null, null),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java` around lines
95 - 101, The Vaccine enum currently uses the literal "N/A (not yet assigned)"
for missing regulatory codes which causes StringUtils.isBlank(...) to treat them
as non-blank; update the enum entries (e.g., QDENGA, RTS_S_AS01, R21_MATRIX_M)
in class Vaccine so that any unavailable regulatory code arguments
(ATC/INN/UNII) are passed as null instead of the placeholder string; this will
restore correct blank/missing behavior in VaccinationEditForm and keep the
constructor/signature unchanged.

Comment on lines +68 to +71
@Diseases(value = {
Disease.MALARIA })
// Oxford/Serum Institute
OXFORD,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Replace the comment with an unambiguous manufacturer value.

Line 70 already shows the data model gap: this enum stores only OXFORD, but the code is acknowledging a different manufacturer concept as well. Persisting that ambiguity in VaccineManufacturer will make downstream vaccination data and filters unreliable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/VaccineManufacturer.java`
around lines 68 - 71, The enum VaccineManufacturer currently contains only
OXFORD with a comment "Oxford/Serum Institute" that creates ambiguity; replace
that comment by adding an explicit, unambiguous enum constant (e.g.,
SERUM_INSTITUTE or OXFORD_SERUM_INSTITUTE) alongside OXFORD in the
VaccineManufacturer enum so each real manufacturer is represented; update any
related `@Diseases` annotation usage if needed to include the new constant name so
persistence and filtering use the distinct manufacturer values.

Comment on lines 279 to 283
public <T extends CustomizableEnum> T getEnumValue(CustomizableEnumType type, Disease disease, String value) {
//As of today diseases are not applicable for environment.
if (disease!=null && !enumValues.get(type).getOrDefault(disease, Collections.emptyList()).contains(value)) {
if (disease != null && !enumValues.get(type).getOrDefault(disease, Collections.emptyList()).contains(value)) {
throw new IllegalArgumentException(String.format("Invalid enum value %s for customizable enum type %s", value, type.toString()));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use the existing generic-disease fallback in this validation.

getEnumValues(...) and getEnumInfo(...) both accept values from the disease-agnostic (null) bucket, but this guard only checks the disease-specific list. A shared default value will therefore throw here whenever the caller passes a disease.

Suggested fix
-		if (disease != null && !enumValues.get(type).getOrDefault(disease, Collections.emptyList()).contains(value)) {
+		if (disease != null && getEnumInfo(type, disease, value) == null) {
 			throw new IllegalArgumentException(String.format("Invalid enum value %s for customizable enum type %s", value, type.toString()));
 		}
📝 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
public <T extends CustomizableEnum> T getEnumValue(CustomizableEnumType type, Disease disease, String value) {
//As of today diseases are not applicable for environment.
if (disease!=null && !enumValues.get(type).getOrDefault(disease, Collections.emptyList()).contains(value)) {
if (disease != null && !enumValues.get(type).getOrDefault(disease, Collections.emptyList()).contains(value)) {
throw new IllegalArgumentException(String.format("Invalid enum value %s for customizable enum type %s", value, type.toString()));
}
public <T extends CustomizableEnum> T getEnumValue(CustomizableEnumType type, Disease disease, String value) {
//As of today diseases are not applicable for environment.
if (disease != null && getEnumInfo(type, disease, value) == null) {
throw new IllegalArgumentException(String.format("Invalid enum value %s for customizable enum type %s", value, type.toString()));
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumFacadeEjb.java`
around lines 279 - 283, The validation in getEnumValue currently only checks the
disease-specific list and rejects values present in the disease-agnostic (null)
bucket; update the guard so when disease != null it verifies the value exists
either in enumValues.get(type).getOrDefault(disease, Collections.emptyList()) OR
in the shared null bucket enumValues.get(type).getOrDefault(null,
Collections.emptyList()) (i.e., mirror the fallback logic used by
getEnumValues/getEnumInfo) and only throw IllegalArgumentException if the value
is absent from both.

private static final String LOC_ACTIVITY_AS_CASE_INVESTIGATION_HEADING = "locActivityAsCaseInvestigationHeading";
private static final String LOC_SOURCE_CASE_CONTACTS_HEADING = "locSourceCaseContactsHeading";
private static final String LOC_EPI_DATA_FIELDS_HINT = "locEpiDataFieldsHint";
private static final String LOC_EXP_PERIOD_HEADING = "locExpPeriodHeading";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Find localization keys related to exposure period and verify implementation pattern

# Search for exposure period related strings in properties files
echo "=== Searching for exposure period localization keys ==="
rg -i "exposurePeriod" --type=properties

# Search for how other headings are added in this file
echo "=== Pattern: How other LOC_ constants are used ==="
rg -n "LOC_.*HEADING" sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java

# Search for any usage of LOC_EXP_PERIOD_HEADING
echo "=== Verifying LOC_EXP_PERIOD_HEADING usage ==="
rg "LOC_EXP_PERIOD_HEADING" --type=java

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 1725


🏁 Script executed:

# Get the addHeadingsAndInfoTexts method to see the pattern and confirm missing component
sed -n '232,270p' sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 1912


🏁 Script executed:

# Search all Java files for references to LOC_EXP_PERIOD_HEADING
rg "LOC_EXP_PERIOD_HEADING" -t=java -B 2 -A 2

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 1253


🏁 Script executed:

# Search for localization keys with "expPeriod" or "ExposurePeriod"
find . -name "*.properties" -type f -exec grep -l -i "expperiod\|exposureperiod" {} \;

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 126


🏁 Script executed:

# Look for how other heading implementations work - check around line 242
sed -n '235,250p' sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 946


🏁 Script executed:

grep -n "locExpPeriodHeading\|headingExposurePeriod\|infoExposurePeriod" sormas-api/src/main/resources/strings.properties

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 144


🏁 Script executed:

# Also check the Strings enum to see if these keys are defined
rg "headingExposurePeriod|infoExposurePeriod|locExpPeriodHeading" --type=java -t=java

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 463


🏁 Script executed:

grep -n "headingExposurePeriod" sormas-api/src/main/resources/strings.properties

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 58


🏁 Script executed:

# Check the Strings enum for all available heading/info keys
rg "String heading|String info" sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java | grep -i "exposure\|period" -i

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 775


Missing component implementation for LOC_EXP_PERIOD_HEADING.

This constant is declared at line 78 and referenced in the layout at line 84, but unlike other heading constants (LOC_EXPOSURE_INVESTIGATION_HEADING, LOC_CONCLUSION_HEADING, etc.), no component is ever added to the content for this location in addHeadingsAndInfoTexts(). The heading will not render in the UI.

The localization key infoExposurePeriodHeading exists and contains text to display, but the component needs to be added to the form. Add the following in the addHeadingsAndInfoTexts() method (before the conclusion heading block at line 253):

Proposed fix
getContent().addComponent(
    new MultilineLabel(
        divsCss(VSPACE_3, I18nProperties.getString(Strings.infoExposurePeriodHeading)),
        ContentMode.HTML),
    LOC_EXP_PERIOD_HEADING);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java` at line
78, The LOC_EXP_PERIOD_HEADING constant is never added to the UI; inside
addHeadingsAndInfoTexts() add a component for LOC_EXP_PERIOD_HEADING before the
conclusion heading block: call getContent().addComponent(...) creating a
MultilineLabel whose text comes from
I18nProperties.getString(Strings.infoExposurePeriodHeading), use
divsCss(VSPACE_3, ...) and ContentMode.HTML so the heading renders like the
other heading constants (match the pattern used for
LOC_EXPOSURE_INVESTIGATION_HEADING and LOC_CONCLUSION_HEADING).

Comment on lines +180 to +182
TabConfig.of(
Captions.CaseData_symptoms,
() -> ControllerProvider.getCaseController().getSymptomsEditComponent(caze.getUuid(), viewMode, null)));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t drop the new symptoms side wiring in the physician-report flow.

Passing null here means this entry point may miss the disease-specific symptoms side component that was added elsewhere in the PR. If PhysiciansReportCaseEditComponent is still reachable, Malaria/Dengue symptom handling can now diverge between the regular case workflow and physician-report editing.

Verify two things: 1) whether this component is still used, and 2) whether getSymptomsEditComponent(..., null) intentionally supports this flow without losing required UI behavior. Expected result: either this class is dead code, or the controller explicitly handles null and preserves the same symptom functionality.

#!/bin/bash
set -euo pipefail

echo "Inspecting getSymptomsEditComponent signatures and call sites"
rg -n -C4 'getSymptomsEditComponent\s*\(' sormas-ui/src/main/java

echo
echo "Inspecting side-component wiring for symptoms views/forms"
rg -n -C4 'CaseSymptomSideViewComponent|setCaseSymptomSideViewComponent|setSymptom.*Side|SymptomsView' sormas-ui/src/main/java

echo
echo "Inspecting whether PhysiciansReportCaseEditComponent is still referenced"
rg -n -C2 'PhysiciansReportCaseEditComponent' sormas-ui/src/main/java
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/externalmessage/physiciansreport/PhysiciansReportCaseEditComponent.java`
around lines 180 - 182, The TabConfig entry in PhysiciansReportCaseEditComponent
passes null for the side-component when calling
ControllerProvider.getCaseController().getSymptomsEditComponent(caze.getUuid(),
viewMode, null), which can drop disease-specific symptom wiring; either confirm
PhysiciansReportCaseEditComponent is unused and remove it, or update the call to
provide the same side-component used elsewhere (or adjust the controller to
handle null by delegating to the normal symptoms side wiring). Locate the
TabConfig.of(...) call in PhysiciansReportCaseEditComponent and: 1) search for
usages of PhysiciansReportCaseEditComponent to prove it's dead code and delete
if unused, or 2) replace the null argument with the proper side-component
provider used by the regular case flow (or modify getSymptomsEditComponent to
accept null safely and attach the disease-specific side view) so symptom
handling remains identical to the main workflow.

Comment on lines +419 to +421
FieldHelper.updateItems(
occupationTypeField,
FacadeProvider.getCustomizableEnumFacade().getEnumValues(CustomizableEnumType.OCCUPATION_TYPE, disease));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Preserve stored occupation values when disease filtering narrows the list.

This now limits occupationTypeField to disease-specific values, but unlike initializePresentConditionField there is no fallback for an already persisted OccupationType that is no longer returned by the current configuration. Older records can therefore end up with a bound value that the combo box can’t represent cleanly. Please preserve the current value after binding, even if it is outside the filtered set.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java`
around lines 419 - 421, When updating occupationTypeField items, preserve any
currently bound value even if the disease-filtered set no longer contains it:
before calling FieldHelper.updateItems(occupationTypeField,
FacadeProvider.getCustomizableEnumFacade().getEnumValues(CustomizableEnumType.OCCUPATION_TYPE,
disease)), capture the current value from occupationTypeField.getValue(); after
update, if that captured value is non-null and not present in the new items, add
or re-select that value (so the combo keeps showing the persisted
OccupationType) similar to the pattern used in initializePresentConditionField.

Comment on lines +1364 to +1371
ComboBox cmCb = getField(CLINICAL_MANIFESTATION);
DateField offsetDate = getField(OFFSET_DATE);
offsetDate.setEnabled(onsetSymptom.isEnabled());
offsetDate.clear();
if (onsetSymptom.isEnabled()) {
cmCb.clear();
cmCb.setValue(ClinicalManifestation.SIGN_OF_SEVERITY);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't wipe manifestation/offset data on every symptom toggle.

This listener clears OFFSET_DATE and forces CLINICAL_MANIFESTATION back to SIGN_OF_SEVERITY whenever any symptom changes. A user who enters an offset date or picks another manifestation will lose that input as soon as they edit another symptom.

Suggested fix
-				offsetDate.setEnabled(onsetSymptom.isEnabled());
-				offsetDate.clear();
-				if (onsetSymptom.isEnabled()) {
-					cmCb.clear();
-					cmCb.setValue(ClinicalManifestation.SIGN_OF_SEVERITY);
-				}
+				boolean hasOnsetSymptoms = onsetSymptom.isEnabled();
+				offsetDate.setEnabled(hasOnsetSymptoms);
+				if (!hasOnsetSymptoms) {
+					offsetDate.clear();
+				} else if (cmCb.getValue() == null) {
+					cmCb.setValue(ClinicalManifestation.SIGN_OF_SEVERITY);
+				}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java`
around lines 1364 - 1371, The code unconditionally clears OFFSET_DATE and resets
CLINICAL_MANIFESTATION whenever any symptom toggles; change it so toggling only
enables/disables offsetDate (offsetDate.setEnabled(onsetSymptom.isEnabled()))
but does not wipe user input. Remove offsetDate.clear() and avoid forcing
cmCb.clear()/cmCb.setValue(...); instead, if onsetSymptom.isEnabled() and
getField(CLINICAL_MANIFESTATION).getValue() == null then set a default
(ClinicalManifestation.SIGN_OF_SEVERITY) — otherwise preserve the existing
value; do not clear values when disabling.

@sormas-vitagroup
Copy link
Contributor

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java (1)

96-102: ⚠️ Potential issue | 🟠 Major

Use null for unavailable regulatory codes instead of placeholder text.

The placeholder "N/A (not yet assigned)" causes StringUtils.isBlank() to return false in VaccinationEditForm, making these fields read-only when they should remain editable for missing data.

🐛 Suggested fix
-	QDENGA(VaccineManufacturer.TAKEDA, "Live attenuated", "Live attenuated tetravalent dengue vaccine", "J07BF07", "N/A (not yet assigned)"),
+	QDENGA(VaccineManufacturer.TAKEDA, "Live attenuated", "Live attenuated tetravalent dengue vaccine", "J07BF07", null),
 	`@Diseases`(value = {
 		Disease.MALARIA })
 	RTS_S_AS01(VaccineManufacturer.GSK, "Subunit", "Mosquirix (recombinant protein)", "J07BX03", "7C2S4M6X1H"),
 	`@Diseases`(value = {
 		Disease.MALARIA })
-	R21_MATRIX_M(VaccineManufacturer.OXFORD, "Subunit", "Recombinant protein vaccine", "N/A (not yet assigned)", "N/A (not yet assigned)"),
+	R21_MATRIX_M(VaccineManufacturer.OXFORD, "Subunit", "Recombinant protein vaccine", null, null),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java` around lines
96 - 102, The enum entries QDENGA, RTS_S_AS01, and R21_MATRIX_M in Vaccine use
the literal "N/A (not yet assigned)" for regulatory code fields which prevents
StringUtils.isBlank() from treating them as missing; update those enum constants
in class Vaccine to use null for the unavailable code arguments (replace "N/A
(not yet assigned)" with null) so VaccinationEditForm will treat those fields as
empty/editable.
🧹 Nitpick comments (4)
sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java (1)

668-675: Simplify redundant visibility logic.

Lines 668-671 compute visibility with a complex condition, but lines 673-675 unconditionally override it to false for parasitic diseases and Luxembourg Dengue. This creates redundant logic where the initial computation is immediately overridden.

♻️ Suggested simplification
-		clinicalMeasurementsHeadingLabel.setVisible(
-			(Set.of(TEMPERATURE_SOURCE, BLOOD_PRESSURE_SYSTOLIC, BLOOD_PRESSURE_DIASTOLIC, HEART_RATE, RESPIRATORY_RATE, WEIGHT, GLASGOW_COMA_SCALE)
-				.stream()
-				.anyMatch(e -> getFieldGroup().getField(e).isVisible())) || !(isParasiticInfectiousDiseases || isLuxDengue));
-		// clinical Measurements HeadingLabel should be hidden for LUX Dengue and  Crypto & Giardiasis
-		if ((isParasiticInfectiousDiseases || isLuxDengue)) {
-			clinicalMeasurementsHeadingLabel.setVisible(false);
-		}
+		// Hide clinical measurements heading for LUX Dengue and Crypto/Giardiasis diseases
+		if (isParasiticInfectiousDiseases || isLuxDengue) {
+			clinicalMeasurementsHeadingLabel.setVisible(false);
+		} else {
+			clinicalMeasurementsHeadingLabel.setVisible(
+				Set.of(TEMPERATURE_SOURCE, BLOOD_PRESSURE_SYSTOLIC, BLOOD_PRESSURE_DIASTOLIC, HEART_RATE, RESPIRATORY_RATE, WEIGHT, GLASGOW_COMA_SCALE)
+					.stream()
+					.anyMatch(e -> getFieldGroup().getField(e).isVisible()));
+		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java`
around lines 668 - 675, The visibility logic for
clinicalMeasurementsHeadingLabel is redundant: compute the visibility once by
checking whether any of the measurement fields (TEMPERATURE_SOURCE,
BLOOD_PRESSURE_SYSTOLIC, BLOOD_PRESSURE_DIASTOLIC, HEART_RATE, RESPIRATORY_RATE,
WEIGHT, GLASGOW_COMA_SCALE) is visible via
getFieldGroup().getField(e).isVisible() AND ensure it is only shown when not
isParasiticInfectiousDiseases and not isLuxDengue; replace the two-step approach
with a single clinicalMeasurementsHeadingLabel.setVisible(...) that evaluates
anyMatch(...) && !(isParasiticInfectiousDiseases || isLuxDengue).
sormas-backend/src/main/resources/sql/sormas_schema.sql (2)

15296-15304: Same naming inconsistency in healthconditions columns.

These columns use camelCase while the symptoms columns added below use lowercase. Apply the same lowercase convention for consistency.

♻️ Suggested fix for consistency
-- healthcondition table
-ALTER TABLE healthconditions ADD COLUMN IF NOT EXISTS immunodeficiencyOtherThanHivText varchar(255);
-ALTER TABLE healthconditions ADD COLUMN IF NOT exists exposedToMosquitoBorneViruses varchar(255);
-ALTER TABLE healthconditions ADD COLUMN IF NOT exists exposedToMosquitoBorneVirusesText varchar(255);
-ALTER TABLE healthconditions ADD COLUMN IF NOT exists vaccinatedAgainstMosquitoBorneViruses varchar(255);
+ALTER TABLE healthconditions ADD COLUMN IF NOT EXISTS immunodeficiencyotherthanhivtext varchar(255);
+ALTER TABLE healthconditions ADD COLUMN IF NOT EXISTS exposedtomosquitoborneviruses varchar(255);
+ALTER TABLE healthconditions ADD COLUMN IF NOT EXISTS exposedtomosquitobornevirusestext varchar(255);
+ALTER TABLE healthconditions ADD COLUMN IF NOT EXISTS vaccinatedagainstmosquitoborneviruses varchar(255);

-ALTER TABLE healthconditions_history ADD COLUMN IF NOT EXISTS immunodeficiencyOtherThanHivText varchar(255);
-ALTER TABLE healthconditions_history ADD COLUMN IF NOT exists exposedToMosquitoBorneViruses varchar(255);
-ALTER TABLE healthconditions_history ADD COLUMN IF NOT exists exposedToMosquitoBorneVirusesText varchar(255);
-ALTER TABLE healthconditions_history ADD COLUMN IF NOT exists vaccinatedAgainstMosquitoBorneViruses varchar(255);
+ALTER TABLE healthconditions_history ADD COLUMN IF NOT EXISTS immunodeficiencyotherthanhivtext varchar(255);
+ALTER TABLE healthconditions_history ADD COLUMN IF NOT EXISTS exposedtomosquitoborneviruses varchar(255);
+ALTER TABLE healthconditions_history ADD COLUMN IF NOT EXISTS exposedtomosquitobornevirusestext varchar(255);
+ALTER TABLE healthconditions_history ADD COLUMN IF NOT EXISTS vaccinatedagainstmosquitoborneviruses varchar(255);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-backend/src/main/resources/sql/sormas_schema.sql` around lines 15296 -
15304, The new columns in tables healthconditions and healthconditions_history
use camelCase names (immunodeficiencyOtherThanHivText,
exposedToMosquitoBorneViruses, exposedToMosquitoBorneVirusesText,
vaccinatedAgainstMosquitoBorneViruses) which conflicts with the lowercase naming
convention used elsewhere; rename these column identifiers to lowercase with
underscores (e.g., immunodeficiency_other_than_hiv_text,
exposed_to_mosquito_borne_viruses, exposed_to_mosquito_borne_viruses_text,
vaccinated_against_mosquito_borne_viruses) in the ALTER TABLE statements for
both healthconditions and healthconditions_history so they follow the existing
lowercase convention and ensure any references in code/migrations are updated
accordingly.

15272-15280: Column naming inconsistency with schema conventions.

The disease configuration columns use camelCase (incubationPeriodEnabled, minIncubationPeriod, etc.) while the symptoms columns added in the same migration use the established all-lowercase convention (clammyskin, guillainbarresyndrome). Although PostgreSQL folds unquoted identifiers to lowercase, explicit lowercase naming improves consistency and readability.

♻️ Suggested fix for consistency
-- 2026-02-04 - Malaria and Dengue requirements `#13797`
-ALTER TABLE diseaseconfiguration ADD COLUMN IF NOT EXISTS incubationPeriodEnabled boolean default false;
-ALTER TABLE diseaseconfiguration ADD COLUMN IF NOT EXISTS minIncubationPeriod integer;
-ALTER TABLE diseaseconfiguration ADD COLUMN IF NOT EXISTS maxIncubationPeriod integer;
-ALTER TABLE diseaseconfiguration ADD COLUMN IF NOT EXISTS caseDefinitionText text;
+ALTER TABLE diseaseconfiguration ADD COLUMN IF NOT EXISTS incubationperiodenabled boolean default false;
+ALTER TABLE diseaseconfiguration ADD COLUMN IF NOT EXISTS minincubationperiod integer;
+ALTER TABLE diseaseconfiguration ADD COLUMN IF NOT EXISTS maxincubationperiod integer;
+ALTER TABLE diseaseconfiguration ADD COLUMN IF NOT EXISTS casedefinitiontext text;

-ALTER TABLE diseaseconfiguration_history ADD COLUMN IF NOT EXISTS incubationPeriodEnabled boolean default false;
-ALTER TABLE diseaseconfiguration_history ADD COLUMN IF NOT EXISTS minIncubationPeriod integer;
-ALTER TABLE diseaseconfiguration_history ADD COLUMN IF NOT EXISTS maxIncubationPeriod integer;
-ALTER TABLE diseaseconfiguration_history ADD COLUMN IF NOT EXISTS caseDefinitionText text;
+ALTER TABLE diseaseconfiguration_history ADD COLUMN IF NOT EXISTS incubationperiodenabled boolean default false;
+ALTER TABLE diseaseconfiguration_history ADD COLUMN IF NOT EXISTS minincubationperiod integer;
+ALTER TABLE diseaseconfiguration_history ADD COLUMN IF NOT EXISTS maxincubationperiod integer;
+ALTER TABLE diseaseconfiguration_history ADD COLUMN IF NOT EXISTS casedefinitiontext text;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-backend/src/main/resources/sql/sormas_schema.sql` around lines 15272 -
15280, The new columns on table diseaseconfiguration and
diseaseconfiguration_history use camelCase names (incubationPeriodEnabled,
minIncubationPeriod, maxIncubationPeriod, caseDefinitionText); change them to
the project's lowercase convention (e.g., incubationperiodenabled or better
incubation_period_enabled and similarly for min_incubation_period,
max_incubation_period, case_definition_text) by updating the ALTER TABLE
statements to create the lowercase column names and also update any code,
migrations, or references that expect the camelCase identifiers (look for usages
of incubationPeriodEnabled, minIncubationPeriod, maxIncubationPeriod,
caseDefinitionText) so everything remains consistent.
sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java (1)

432-448: Add missing @Override annotations.

isIncubationPeriodEnabled (line 432) and getCaseDefinitionText (line 446) implement interface methods from DiseaseConfigurationFacade but are missing @Override annotations, unlike getMaxIncubationPeriod and getMinIncubationPeriod which correctly have them.

♻️ Proposed fix
+	`@Override`
 	public boolean isIncubationPeriodEnabled(Disease disease) {
 		return incubationEnabledDiseases.contains(disease);
 	}

 	`@Override`
 	public int getMaxIncubationPeriod(Disease disease) {
 		return maxIncubationPeriod.get(disease);
 	}

 	`@Override`
 	public int getMinIncubationPeriod(Disease disease) {
 		return minIncubationPeriod.get(disease);
 	}

+	`@Override`
 	public String getCaseDefinitionText(Disease disease) {
 		return service.getDiseaseConfiguration(disease).getCaseDefinitionText();
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java`
around lines 432 - 448, Add the missing `@Override` annotations to the methods
that implement the DiseaseConfigurationFacade interface: put `@Override` above
isIncubationPeriodEnabled(Disease disease) and above
getCaseDefinitionText(Disease disease) in DiseaseConfigurationFacadeEjb so they
are consistent with getMaxIncubationPeriod and getMinIncubationPeriod; no other
logic changes are needed—just add the annotation lines immediately before those
method declarations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java`:
- Around line 87-93: Replace the locale-dependent I18nProperties.getString calls
in the Vaccine enum constant DENGVAXIA with hardcoded literal strings (for the
display name/label and the technical INN, ATC and UNII codes) so the enum
initialization is consistent with other constants (e.g., QDENGA, RTS_S_AS01,
R21_MATRIX_M) and so ATC/UNII remain stable across locales; locate the Vaccine
enum declaration and update the DENGVAXIA constructor arguments (currently using
I18nProperties.getString and Strings.* constants) to the appropriate hardcoded
values while keeping VaccineManufacturer.SANOFI_PASTEUR and the constructor
parameter order unchanged.

In `@sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java`:
- Line 213: Rename the misspelled constant dengvaxiaUniicCode to
dengvaxiaUniiCode in Strings.java and update all usages to the new identifier;
also update the corresponding key in strings.properties (change the
"dengvaxiaUniicCode" key to "dengvaxiaUniiCode") and fix references in
Vaccine.java (and any other callers, e.g., code that uses
VACCINE_UNII_CODE/getUniiCode) so they refer to dengvaxiaUniiCode; ensure
compilation by running a project-wide search/replace for the old name and update
any tests or resource lookups accordingly.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java`:
- Line 1354: In SymptomsForm (class SymptomsForm) there is a duplicated call to
onsetSymptom.setEnabled(!onsetSymptom.getItemIds().isEmpty()); remove the
redundant duplicate so the method is invoked only once (keep the first/earlier
call and delete the successive identical call), ensuring no change to argument
logic or surrounding state updates.

---

Duplicate comments:
In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java`:
- Around line 96-102: The enum entries QDENGA, RTS_S_AS01, and R21_MATRIX_M in
Vaccine use the literal "N/A (not yet assigned)" for regulatory code fields
which prevents StringUtils.isBlank() from treating them as missing; update those
enum constants in class Vaccine to use null for the unavailable code arguments
(replace "N/A (not yet assigned)" with null) so VaccinationEditForm will treat
those fields as empty/editable.

---

Nitpick comments:
In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java`:
- Around line 432-448: Add the missing `@Override` annotations to the methods that
implement the DiseaseConfigurationFacade interface: put `@Override` above
isIncubationPeriodEnabled(Disease disease) and above
getCaseDefinitionText(Disease disease) in DiseaseConfigurationFacadeEjb so they
are consistent with getMaxIncubationPeriod and getMinIncubationPeriod; no other
logic changes are needed—just add the annotation lines immediately before those
method declarations.

In `@sormas-backend/src/main/resources/sql/sormas_schema.sql`:
- Around line 15296-15304: The new columns in tables healthconditions and
healthconditions_history use camelCase names (immunodeficiencyOtherThanHivText,
exposedToMosquitoBorneViruses, exposedToMosquitoBorneVirusesText,
vaccinatedAgainstMosquitoBorneViruses) which conflicts with the lowercase naming
convention used elsewhere; rename these column identifiers to lowercase with
underscores (e.g., immunodeficiency_other_than_hiv_text,
exposed_to_mosquito_borne_viruses, exposed_to_mosquito_borne_viruses_text,
vaccinated_against_mosquito_borne_viruses) in the ALTER TABLE statements for
both healthconditions and healthconditions_history so they follow the existing
lowercase convention and ensure any references in code/migrations are updated
accordingly.
- Around line 15272-15280: The new columns on table diseaseconfiguration and
diseaseconfiguration_history use camelCase names (incubationPeriodEnabled,
minIncubationPeriod, maxIncubationPeriod, caseDefinitionText); change them to
the project's lowercase convention (e.g., incubationperiodenabled or better
incubation_period_enabled and similarly for min_incubation_period,
max_incubation_period, case_definition_text) by updating the ALTER TABLE
statements to create the lowercase column names and also update any code,
migrations, or references that expect the camelCase identifiers (look for usages
of incubationPeriodEnabled, minIncubationPeriod, maxIncubationPeriod,
caseDefinitionText) so everything remains consistent.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java`:
- Around line 668-675: The visibility logic for clinicalMeasurementsHeadingLabel
is redundant: compute the visibility once by checking whether any of the
measurement fields (TEMPERATURE_SOURCE, BLOOD_PRESSURE_SYSTOLIC,
BLOOD_PRESSURE_DIASTOLIC, HEART_RATE, RESPIRATORY_RATE, WEIGHT,
GLASGOW_COMA_SCALE) is visible via getFieldGroup().getField(e).isVisible() AND
ensure it is only shown when not isParasiticInfectiousDiseases and not
isLuxDengue; replace the two-step approach with a single
clinicalMeasurementsHeadingLabel.setVisible(...) that evaluates anyMatch(...) &&
!(isParasiticInfectiousDiseases || isLuxDengue).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 30b1ffb0-98e0-4531-b4d0-abb2135365d7

📥 Commits

Reviewing files that changed from the base of the PR and between 4271928 and 173e01d.

📒 Files selected for processing (12)
  • sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java
  • sormas-api/src/main/resources/strings.properties
  • sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfiguration.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/Symptoms.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/SymptomsFacadeEjb.java
  • sormas-backend/src/main/resources/sql/sormas_schema.sql
  • sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java

Comment on lines +87 to +93
@Diseases(value = {
Disease.DENGUE })
DENGVAXIA(VaccineManufacturer.SANOFI_PASTEUR,
I18nProperties.getString(Strings.dengvaxiaVaccineType),
I18nProperties.getString(Strings.dengvaxiaInn),
I18nProperties.getString(Strings.dengvaxiaAtcCode),
I18nProperties.getString(Strings.dengvaxiaUniicCode)),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Java enum I18nProperties getString static initialization locale issues

💡 Result:

In Java, an enum + getString() i18n pattern usually breaks for locale changes because you’re doing the lookup during static/enum initialization, i.e., once, using whatever the default locale was at that moment.

What’s going wrong

  1. Your bundle is bound to the locale used at initialization

    • ResourceBundle.getBundle(baseName) explicitly uses Locale.getDefault() at the time it’s called. If you call it in a static final field initializer, you “freeze” the bundle to that locale. Changing the default locale later won’t rebuild that already-stored bundle. [1]
  2. Enum constants are initialized before (most) static initialization you expect

    • Enum constants are constructed during class initialization, and there are special ordering rules; relying on static state during enum construction is a common trap. So if your enum constructor calls bundle.getString(key) (directly or indirectly), it happens during enum init, not “later when the app is ready.” [2]
  3. Caching is already handled (so “call getBundle every time” is usually fine)

    • ResourceBundle.getBundle() is cached by the JDK, so you typically don’t need your own global static bundle instance for performance. [3]

Robust fix pattern (recommended)

Store only the key in the enum; resolve the localized string at call time (with an explicit locale, or with a locale supplier):

public enum Msg {
  HELLO("hello"),
  BYE("bye");

  private final String key;
  Msg(String key) { this.key = key; }

  public String text(Locale locale) {
    return ResourceBundle.getBundle("messages", locale).getString(key);
  }

  public String text() { // uses current default locale *at call time*
    return ResourceBundle.getBundle("messages").getString(key);
  }
}

This avoids “wrong locale at startup” because you don’t translate during enum/static initialization; you translate when you actually need the message. [1]


🏁 Script executed:

# Find and examine the Vaccine.java file
fd -t f "Vaccine.java" sormas-api/src/main/java

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 139


🏁 Script executed:

# Check the context around the DENGVAXIA definition and the getter methods
rg -A 5 "DENGVAXIA\(" sormas-api/src/main/java/de/symeda/sormas/api/caze/

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 746


🏁 Script executed:

# Look for other enums using I18nProperties.getString() at initialization
rg "I18nProperties\.getString\(" sormas-api/src/main/java/de/symeda/sormas/api --type java | head -30

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 4372


🏁 Script executed:

# Read the Vaccine.java file to see the full implementation
cat -n sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 7052


🏁 Script executed:

# Check if dengvaxia properties are defined in translation/property files
rg "dengvaxia" sormas-api/src/main/resources --type properties

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 110


🏁 Script executed:

# Check what Strings constants are defined for dengvaxia
rg "dengvaxia" sormas-api/src/main/java/de/symeda/sormas/api/i18n --type java

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 523


🏁 Script executed:

# Check if dengvaxia properties are defined in translation/property files (without file type restriction)
rg "dengvaxia" sormas-api/src/main/resources

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 444


Use hardcoded strings for consistency with other vaccines.

DENGVAXIA uniquely calls I18nProperties.getString() during enum initialization (lines 89-93), while other vaccines (QDENGA, RTS_S_AS01, R21_MATRIX_M) use hardcoded strings. Additionally, calling getString() during static enum initialization freezes the values to whatever locale is active at class-load time, preventing runtime locale changes. The ATC code and UNII code are international standards that should not vary by locale.

For consistency and clarity, use hardcoded strings for these technical vaccine properties:

Suggested change
 	`@Diseases`(value = {
 		Disease.DENGUE })
-	DENGVAXIA(VaccineManufacturer.SANOFI_PASTEUR,
-		I18nProperties.getString(Strings.dengvaxiaVaccineType),
-		I18nProperties.getString(Strings.dengvaxiaInn),
-		I18nProperties.getString(Strings.dengvaxiaAtcCode),
-		I18nProperties.getString(Strings.dengvaxiaUniicCode)),
+	DENGVAXIA(VaccineManufacturer.SANOFI_PASTEUR, "Live attenuated", "Chimeric yellow fever dengue tetravalent vaccine (live, attenuated)", "J07BF06", "39V92P2S5S"),
📝 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
@Diseases(value = {
Disease.DENGUE })
DENGVAXIA(VaccineManufacturer.SANOFI_PASTEUR,
I18nProperties.getString(Strings.dengvaxiaVaccineType),
I18nProperties.getString(Strings.dengvaxiaInn),
I18nProperties.getString(Strings.dengvaxiaAtcCode),
I18nProperties.getString(Strings.dengvaxiaUniicCode)),
`@Diseases`(value = {
Disease.DENGUE })
DENGVAXIA(VaccineManufacturer.SANOFI_PASTEUR, "Live attenuated", "Chimeric yellow fever dengue tetravalent vaccine (live, attenuated)", "J07BF06", "39V92P2S5S"),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java` around lines
87 - 93, Replace the locale-dependent I18nProperties.getString calls in the
Vaccine enum constant DENGVAXIA with hardcoded literal strings (for the display
name/label and the technical INN, ATC and UNII codes) so the enum initialization
is consistent with other constants (e.g., QDENGA, RTS_S_AS01, R21_MATRIX_M) and
so ATC/UNII remain stable across locales; locate the Vaccine enum declaration
and update the DENGVAXIA constructor arguments (currently using
I18nProperties.getString and Strings.* constants) to the appropriate hardcoded
values while keeping VaccineManufacturer.SANOFI_PASTEUR and the constructor
parameter order unchanged.

String DefaultPassword_unchanged = "DefaultPassword.unchanged";
String dengvaxiaAtcCode = "dengvaxiaAtcCode";
String dengvaxiaInn = "dengvaxiaInn";
String dengvaxiaUniicCode = "dengvaxiaUniicCode";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if UNIIC or UNII is used elsewhere in the codebase
echo "Searching for UNIIC pattern:"
rg -i "uniic" --type java
echo ""
echo "Searching for UNII pattern:"
rg -i "unii" --type java | head -30

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 28374


🏁 Script executed:

rg "dengvaxiaUniicCode" --type java

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 390


Fix typo in constant name: dengvaxiaUniicCode should be dengvaxiaUniiCode.

The standard acronym is UNII (Unique Ingredient Identifier). This constant name has "Uniic" which should be "Unii" to match the consistent naming throughout the codebase (e.g., vaccineUniiCode, VACCINE_UNII_CODE, getUniiCode). Update required in:

  • Strings.java (line 213)
  • strings.properties
  • Vaccine.java reference
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java` at line 213,
Rename the misspelled constant dengvaxiaUniicCode to dengvaxiaUniiCode in
Strings.java and update all usages to the new identifier; also update the
corresponding key in strings.properties (change the "dengvaxiaUniicCode" key to
"dengvaxiaUniiCode") and fix references in Vaccine.java (and any other callers,
e.g., code that uses VACCINE_UNII_CODE/getUniiCode) so they refer to
dengvaxiaUniiCode; ensure compilation by running a project-wide search/replace
for the old name and update any tests or resource lookups accordingly.

}
}
onsetSymptom.setEnabled(!onsetSymptom.getItemIds().isEmpty());
onsetSymptom.setEnabled(!onsetSymptom.getItemIds().isEmpty());
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate line.

onsetSymptom.setEnabled(...) is called twice in succession with the same arguments. This appears to be a copy-paste error.

🧹 Suggested fix
 				onsetSymptom.setEnabled(!onsetSymptom.getItemIds().isEmpty());
-				onsetSymptom.setEnabled(!onsetSymptom.getItemIds().isEmpty());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java` at
line 1354, In SymptomsForm (class SymptomsForm) there is a duplicated call to
onsetSymptom.setEnabled(!onsetSymptom.getItemIds().isEmpty()); remove the
redundant duplicate so the method is invoked only once (keep the first/earlier
call and delete the successive identical call), ensuring no change to argument
logic or surrounding state updates.

@sormas-vitagroup
Copy link
Contributor

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java (2)

369-371: ⚠️ Potential issue | 🟠 Major

Don’t persist placeholder text as the ATC code.

Line 370 returns "N/A (not yet assigned)" as if it were a real ATC value. Downstream code uses blank/null semantics to decide whether the field is missing, so this placeholder will be treated as populated data instead of “not available”.

Suggested fix
 		`@Override`
 		public String getAtcCode() {
-			return "N/A (not yet assigned)";
+			return null;
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java` around lines
369 - 371, The getter Vaccine.getAtcCode currently returns the literal
placeholder "N/A (not yet assigned)" which will be treated as a populated value;
change it to return null (or the actual backing field if present) when no ATC is
assigned so downstream blank/null checks work correctly—update the getAtcCode
method in class Vaccine to return null instead of the placeholder (or return the
real atc field) and ensure any serialization/persistence expectations still
treat null as missing.

275-286: ⚠️ Potential issue | 🟠 Major

Restore DENGVAXIA’s fixed INN/ATC/UNII metadata.

These getters currently return blanks, so VaccinationEditForm treats DENGVAXIA’s regulatory fields as missing/editable even though this vaccine has defined values. That will save incomplete metadata for every DENGVAXIA selection.

Suggested fix
 		`@Override`
 		public String getInn() {
-			return "";
+			return "Chimeric yellow fever dengue tetravalent vaccine (live, attenuated)";
 		}
 
 		`@Override`
 		public String getAtcCode() {
-			return "";
+			return "J07BF06";
 		}
 
 		`@Override` public Optional<String> getUniiCode() {
-			return Optional.of("");
+			return Optional.of("39V92P2S5S");
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java` around lines
275 - 286, The getters getInn(), getAtcCode(), and getUniiCode() in class
Vaccine currently return empty values causing DENGVAXIA’s regulatory metadata to
be treated as missing; update these methods to return the fixed DENGVAXIA values
instead of blank strings/Optionals (e.g., return the known INN, ATC and
Optional.of(UNII) for the DENGVAXIA vaccine) and for other vaccines preserve
existing behavior (delegate to existing fields/logic). Locate and change the
implementations of getInn(), getAtcCode(), and getUniiCode() in Vaccine to check
for the DENGVAXIA identifier/constant and return the correct constants rather
than empty values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java`:
- Around line 110-139: In VaccinationEditForm fix three bugs: (1) change the
misplaced assignment so the ATC "not available" message is written to
atcCode.setValue(...) instead of inn.setValue(...); (2) when handling
vaccine.getUniiCode() unwrap the Optional and pass the String to
uniiCode.setValue(vaccine.getUniiCode().get()) (only after checking isPresent
and non-blank); (3) avoid retaining stale values by clearing fields (e.g.
setValue("") or appropriate empty string) when the source is null or blank
instead of writing localized "not available" placeholders; update the branches
around vaccine.getAtcCode(), vaccine.getInn(), and vaccine.getUniiCode() and
keep the existing enable/disable logic for vaccineType, atcCode, and inn.

---

Duplicate comments:
In `@sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java`:
- Around line 369-371: The getter Vaccine.getAtcCode currently returns the
literal placeholder "N/A (not yet assigned)" which will be treated as a
populated value; change it to return null (or the actual backing field if
present) when no ATC is assigned so downstream blank/null checks work
correctly—update the getAtcCode method in class Vaccine to return null instead
of the placeholder (or return the real atc field) and ensure any
serialization/persistence expectations still treat null as missing.
- Around line 275-286: The getters getInn(), getAtcCode(), and getUniiCode() in
class Vaccine currently return empty values causing DENGVAXIA’s regulatory
metadata to be treated as missing; update these methods to return the fixed
DENGVAXIA values instead of blank strings/Optionals (e.g., return the known INN,
ATC and Optional.of(UNII) for the DENGVAXIA vaccine) and for other vaccines
preserve existing behavior (delegate to existing fields/logic). Locate and
change the implementations of getInn(), getAtcCode(), and getUniiCode() in
Vaccine to check for the DENGVAXIA identifier/constant and return the correct
constants rather than empty values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ff8d4072-689d-4674-8728-9df495f72a1d

📥 Commits

Reviewing files that changed from the base of the PR and between 173e01d and 263a273.

📒 Files selected for processing (4)
  • sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java
  • sormas-api/src/main/resources/strings.properties
  • sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • sormas-api/src/main/resources/strings.properties
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java

@sormas-vitagroup
Copy link
Contributor

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java (2)

148-149: ⚠️ Potential issue | 🟠 Major

Clearing VACCINE_NAME still leaves the derived fields dirty.

Line 149 only toggles clearability. It does not null the current values or restore the enabled state, so removing the vaccine can leave the previous manufacturer/type/ATC/INN/UNII behind.

🧹 Proposed fix
 			} else {
-				FieldHelper.setClearEnabled(true, vaccineManufacturer, vaccineType, atcCode, inn, uniiCode);
+				vaccineManufacturer.setValue(null);
+				vaccineType.setValue(null);
+				atcCode.setValue(null);
+				inn.setValue(null);
+				uniiCode.setValue(null);
+				vaccineManufacturer.setEnabled(true);
+				vaccineType.setEnabled(true);
+				atcCode.setEnabled(true);
+				inn.setEnabled(true);
+				uniiCode.setEnabled(true);
+				FieldHelper.setClearEnabled(true, vaccineManufacturer, vaccineType, atcCode, inn, uniiCode);
 			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java`
around lines 148 - 149, When VACCINE_NAME is cleared the current
manufacturer/type/ATC/INN/UNII values remain and only their clearability is
toggled; update the VaccinationEditForm change-handler so that when VACCINE_NAME
becomes empty/null it not only calls FieldHelper.setClearEnabled(true,
vaccineManufacturer, vaccineType, atcCode, inn, uniiCode) but also clears those
components' values (e.g. setValue(null)/clear) and restores their enabled state
(e.g. setEnabled(true) or unset read-only) for vaccineManufacturer, vaccineType,
atcCode, inn, uniiCode so no stale data remains.

109-145: ⚠️ Potential issue | 🟠 Major

Keep “not available” text out of the bound metadata fields.

Lines 113, 122, 131, and 141 write localized placeholder text into fields that are bound back to VaccinationDto. That stores presentation strings instead of the actual vaccine metadata/null state.

🩹 Proposed fix
-					vaccineType
-						.setValue(StringUtils.isBlank(vacTypeVal) ? I18nProperties.getString(Strings.Vaccine_vaccineType_notAvailable) : vacTypeVal);
+					vaccineType.setValue(StringUtils.isBlank(vacTypeVal) ? null : vacTypeVal);
 					vaccineType.setEnabled(false);
@@
-					atcCode.setValue(StringUtils.isBlank(atcCodeVal) ? I18nProperties.getString(Strings.Vaccine_atcCode_notAvailable) : atcCodeVal);
+					atcCode.setValue(StringUtils.isBlank(atcCodeVal) ? null : atcCodeVal);
 					atcCode.setEnabled(false);
@@
-					inn.setValue(StringUtils.isBlank(innVal) ? I18nProperties.getString(Strings.Vaccine_inn_notAvailable) : innVal);
+					inn.setValue(StringUtils.isBlank(innVal) ? null : innVal);
 					inn.setEnabled(false);
@@
-					uniiCode
-						.setValue((StringUtils.isBlank(uniiCodeVal)) ? I18nProperties.getString(Strings.Vaccine_uniiCode_notAvailable) : uniiCodeVal);
+					uniiCode.setValue(StringUtils.isBlank(uniiCodeVal) ? null : uniiCodeVal);
 					uniiCode.setEnabled(false);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java`
around lines 109 - 145, The code in VaccinationEditForm is writing localized
"not available" strings into bound fields (vaccineType, atcCode, inn, uniiCode)
which will be persisted into VaccinationDto; instead, when the vaccine metadata
is absent or blank set the field value to null (so DTO stays null) and move the
localized "not available" text to the UI placeholder/empty caption. Update the
blocks that handle vaccine.getVaccineType(), getAtcCode(), getInn(),
getUniiCode() so that: if present and non-blank call setValue(vacTypeVal) /
setValue(atcCodeVal) etc. and setEnabled(false); if present but blank or not
present call setValue(null) and setEnabled(false) (or true for absent as
currently desired), and call setPlaceholder(I18nProperties.getString(...)) on
the component instead of setting the placeholder text into setValue; ensure you
reference the components vaccineType, atcCode, inn, uniiCode and the getters
vaccine.getVaccineType(), vaccine.getAtcCode(), vaccine.getInn(),
vaccine.getUniiCode() when making the changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sormas-api/src/main/resources/strings.properties`:
- Around line 2028-2043: Fix the placeholder strings for vaccine fields: correct
the spelling "Not avilable" to "Not available" for the keys
Vaccine.vaccineType.notAvailable, Vaccine.atcCode.notAvailable and
Vaccine.inn_notAvailable, and add a space after the slash for
Vaccine.uniiCode.notAvailable changing "N/A(Not yet assigned)" to "N/A (Not yet
assigned)" so the user-visible text is clean and consistent in the vaccination
form.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java`:
- Around line 104-107: In the vaccineName value-change listener, don't pass the
Optional<VaccineManufacturer> into the Vaadin field; instead unwrap it and set
the raw enum (or null) on vaccineManufacturer. Replace the direct call to
vaccine.getManufacturer() with logic that extracts the value (e.g.
vaccine.getManufacturer().orElse(null) or vaccine.getManufacturer().ifPresent(m
-> vaccineManufacturer.setValue(m))) so VaccinationDto.VACCINE_MANUFACTURER
receives the actual enum, not an Optional.

---

Duplicate comments:
In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java`:
- Around line 148-149: When VACCINE_NAME is cleared the current
manufacturer/type/ATC/INN/UNII values remain and only their clearability is
toggled; update the VaccinationEditForm change-handler so that when VACCINE_NAME
becomes empty/null it not only calls FieldHelper.setClearEnabled(true,
vaccineManufacturer, vaccineType, atcCode, inn, uniiCode) but also clears those
components' values (e.g. setValue(null)/clear) and restores their enabled state
(e.g. setEnabled(true) or unset read-only) for vaccineManufacturer, vaccineType,
atcCode, inn, uniiCode so no stale data remains.
- Around line 109-145: The code in VaccinationEditForm is writing localized "not
available" strings into bound fields (vaccineType, atcCode, inn, uniiCode) which
will be persisted into VaccinationDto; instead, when the vaccine metadata is
absent or blank set the field value to null (so DTO stays null) and move the
localized "not available" text to the UI placeholder/empty caption. Update the
blocks that handle vaccine.getVaccineType(), getAtcCode(), getInn(),
getUniiCode() so that: if present and non-blank call setValue(vacTypeVal) /
setValue(atcCodeVal) etc. and setEnabled(false); if present but blank or not
present call setValue(null) and setEnabled(false) (or true for absent as
currently desired), and call setPlaceholder(I18nProperties.getString(...)) on
the component instead of setting the placeholder text into setValue; ensure you
reference the components vaccineType, atcCode, inn, uniiCode and the getters
vaccine.getVaccineType(), vaccine.getAtcCode(), vaccine.getInn(),
vaccine.getUniiCode() when making the changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1e98eaaf-4811-48c3-88fc-7c49f8e46ebc

📥 Commits

Reviewing files that changed from the base of the PR and between 263a273 and 8e9722e.

📒 Files selected for processing (4)
  • sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java
  • sormas-api/src/main/resources/strings.properties
  • sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java

Comment on lines +2028 to +2043
Vaccine.vaccineType.notAvailable=Not avilable
Vaccine.qdenga.inn=Live attenuated tetravalent dengue vaccine
Vaccine.qdenga.atcCode=J07BF07

Vaccine.dengvaxia.inn=Chimeric yellow fever dengue tetravalent vaccine (live, attenuated)
Vaccine.dengvaxia.uniiCode=39V92P2S5S
Vaccine.dengvaxia.atcCode=J07BF06

Vaccine.r21_matrix_m.inn=Recombinant protein vaccine
Vaccine.rts_s_as01.uniiCode=7C2S4M6X1H
Vaccine.rts_s_as01.atcCode=J07BX03
Vaccine.rts_s_as01.inn=Mosquirix (recombinant protein)

Vaccine.atcCode.notAvailable=Not avilable
Vaccine.inn_notAvailable=Not avilable
Vaccine.uniiCode.notAvailable=N/A(Not yet assigned)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clean up the new placeholder copy.

Lines 2028, 2041, and 2042 say "Not avilable", and Line 2043 is missing a space after N/A. These strings are user-visible in the vaccination form.

✏️ Proposed fix
-Vaccine.vaccineType.notAvailable=Not avilable
+Vaccine.vaccineType.notAvailable=Not available
@@
-Vaccine.atcCode.notAvailable=Not avilable
-Vaccine.inn_notAvailable=Not avilable
-Vaccine.uniiCode.notAvailable=N/A(Not yet assigned)
+Vaccine.atcCode.notAvailable=Not available
+Vaccine.inn_notAvailable=Not available
+Vaccine.uniiCode.notAvailable=N/A (not yet assigned)
📝 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
Vaccine.vaccineType.notAvailable=Not avilable
Vaccine.qdenga.inn=Live attenuated tetravalent dengue vaccine
Vaccine.qdenga.atcCode=J07BF07
Vaccine.dengvaxia.inn=Chimeric yellow fever dengue tetravalent vaccine (live, attenuated)
Vaccine.dengvaxia.uniiCode=39V92P2S5S
Vaccine.dengvaxia.atcCode=J07BF06
Vaccine.r21_matrix_m.inn=Recombinant protein vaccine
Vaccine.rts_s_as01.uniiCode=7C2S4M6X1H
Vaccine.rts_s_as01.atcCode=J07BX03
Vaccine.rts_s_as01.inn=Mosquirix (recombinant protein)
Vaccine.atcCode.notAvailable=Not avilable
Vaccine.inn_notAvailable=Not avilable
Vaccine.uniiCode.notAvailable=N/A(Not yet assigned)
Vaccine.vaccineType.notAvailable=Not available
Vaccine.qdenga.inn=Live attenuated tetravalent dengue vaccine
Vaccine.qdenga.atcCode=J07BF07
Vaccine.dengvaxia.inn=Chimeric yellow fever dengue tetravalent vaccine (live, attenuated)
Vaccine.dengvaxia.uniiCode=39V92P2S5S
Vaccine.dengvaxia.atcCode=J07BF06
Vaccine.r21_matrix_m.inn=Recombinant protein vaccine
Vaccine.rts_s_as01.uniiCode=7C2S4M6X1H
Vaccine.rts_s_as01.atcCode=J07BX03
Vaccine.rts_s_as01.inn=Mosquirix (recombinant protein)
Vaccine.atcCode.notAvailable=Not available
Vaccine.inn_notAvailable=Not available
Vaccine.uniiCode.notAvailable=N/A (not yet assigned)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/resources/strings.properties` around lines 2028 - 2043,
Fix the placeholder strings for vaccine fields: correct the spelling "Not
avilable" to "Not available" for the keys Vaccine.vaccineType.notAvailable,
Vaccine.atcCode.notAvailable and Vaccine.inn_notAvailable, and add a space after
the slash for Vaccine.uniiCode.notAvailable changing "N/A(Not yet assigned)" to
"N/A (Not yet assigned)" so the user-visible text is clean and consistent in the
vaccination form.

@sormas-vitagroup
Copy link
Contributor

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java (2)

107-107: ⚠️ Potential issue | 🔴 Critical

Unwrap the Optional safely using orElse(null) instead of get().

The getManufacturer() method returns Optional<VaccineManufacturer>. Calling .get() directly without first checking isPresent() will throw NoSuchElementException if the Optional is empty (e.g., for vaccines that don't override the base method).

🐛 Proposed fix
-				vaccineManufacturer.setValue(vaccine.getManufacturer().get());
+				vaccineManufacturer.setValue(vaccine.getManufacturer().orElse(null));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java`
at line 107, In VaccinationEditForm, avoid calling Optional.get() directly on
vaccine.getManufacturer(); update the code that sets vaccineManufacturer (the UI
field bound in VaccinationEditForm) to unwrap the Optional safely by using
vaccine.getManufacturer().orElse(null) so you pass null when absent instead of
risking NoSuchElementException; locate the line with
vaccineManufacturer.setValue(...) and replace the .get() usage with
.orElse(null).

110-146: ⚠️ Potential issue | 🟠 Major

Placeholder strings may be persisted to the database.

When a vaccine's type/ATC/INN/UNII code is present but blank (per Vaccine.java contract: Optional.of("") for unavailable codes), the code sets localized "not available" strings (e.g., Strings.Vaccine_atcCode_notAvailable) into fields bound to VaccinationDto. If the form is saved, these placeholder strings will persist to the database rather than null.

Consider setting null instead of the placeholder string and using a different UI mechanism (e.g., field placeholder attribute or CSS styling) to display "not available" status without affecting the stored value.

🐛 Proposed fix for one field (apply similar pattern to others)
 				// AtcCode
 				if (vaccine.getAtcCode().isPresent()) {
 					String atcCodeVal = vaccine.getAtcCode().get();
-					atcCode.setValue(StringUtils.isBlank(atcCodeVal) ? I18nProperties.getString(Strings.Vaccine_atcCode_notAvailable) : atcCodeVal);
+					atcCode.setValue(StringUtils.isBlank(atcCodeVal) ? null : atcCodeVal);
 					atcCode.setEnabled(false);
 				} else {
 					atcCode.setEnabled(true);
 					atcCode.setValue(null);
 				}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java`
around lines 110 - 146, The form currently writes localized "not available"
placeholder strings into fields (vaccineType, atcCode, inn, uniiCode) when the
Vaccine Optional is present but blank, causing those placeholders to be
persisted; instead, when the Optional is present but its value is blank, set the
field value to null so the bound VaccinationDto stays null, and move the
localized "not available" text to the UI-only placeholder (e.g., use
setPlaceholder or equivalent) while keeping the field disabled; apply this
change in VaccinationEditForm where
vaccine.getVaccineType()/getAtcCode()/getInn()/getUniiCode() are handled so all
four fields use value=null + placeholder(localized string) when
present-but-blank and retain the existing enabled/disabled behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java`:
- Line 107: In VaccinationEditForm, avoid calling Optional.get() directly on
vaccine.getManufacturer(); update the code that sets vaccineManufacturer (the UI
field bound in VaccinationEditForm) to unwrap the Optional safely by using
vaccine.getManufacturer().orElse(null) so you pass null when absent instead of
risking NoSuchElementException; locate the line with
vaccineManufacturer.setValue(...) and replace the .get() usage with
.orElse(null).
- Around line 110-146: The form currently writes localized "not available"
placeholder strings into fields (vaccineType, atcCode, inn, uniiCode) when the
Vaccine Optional is present but blank, causing those placeholders to be
persisted; instead, when the Optional is present but its value is blank, set the
field value to null so the bound VaccinationDto stays null, and move the
localized "not available" text to the UI-only placeholder (e.g., use
setPlaceholder or equivalent) while keeping the field disabled; apply this
change in VaccinationEditForm where
vaccine.getVaccineType()/getAtcCode()/getInn()/getUniiCode() are handled so all
four fields use value=null + placeholder(localized string) when
present-but-blank and retain the existing enabled/disabled behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c7cd2d6b-4a41-45b4-a327-f98c29ba61c7

📥 Commits

Reviewing files that changed from the base of the PR and between 8e9722e and c67461c.

📒 Files selected for processing (1)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/VaccinationEditForm.java

@sormas-vitagroup
Copy link
Contributor

1 similar comment
@sormas-vitagroup
Copy link
Contributor

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.

Modify disease enum for Malaria

3 participants