Skip to content

fix(api): require a usual place of residence for cases and contacts - #20

Open
lbrunofidelis wants to merge 3 commits into
devfrom
fix/#36-address-required-and-deletion-lock
Open

lbrunofidelis wants to merge 3 commits into
devfrom
fix/#36-address-required-and-deletion-lock

Conversation

@lbrunofidelis

Copy link
Copy Markdown
Collaborator

Problem

With the outbreak option "Permitir cadastro de casos e contatos sem Endereço Atual preenchido" disabled, a case, contact or contact of contact could still be saved with no address at all. Deleting the address block on the create screen was enough.

POST /api/outbreaks/{outbreakId}/cases   {"firstName":"x","addresses":[]}   -> 200
POST /api/outbreaks/{outbreakId}/cases   {"firstName":"x"}                  -> 200
PUT  /api/outbreaks/{outbreakId}/cases/{id}  {"addresses":[]}               -> 200

Root cause

validatePersonAddresses in server/models/person.js runs every check inside if (Array.isArray(addresses) && addresses.length). An empty or missing list produces no error, so ADDRESS_MUST_HAVE_USUAL_PLACE_OF_RESIDENCE is never raised and the outbreak option is never read. The guard is original Go.Data code from 2018 and was never touched here; the new outbreak option only made the gap visible, because disabling it now carries an explicit promise.

The same request with a single notification address returns 422, which shows the validation itself works and only skips empty lists.

Fix

A missing usual place of residence is now reported for empty and absent lists as well. The requirement applies to cases, contacts and contacts of contacts, is enforced on create and whenever a request changes addresses, and is still relaxed when the outbreak allows saving without an address. Deletions, system triggered updates and sync keep their existing short circuits, so records saved before this rule can still be edited and replicated.

Events are unaffected: they do not carry an addresses property.

A second commit adds the preventAddressDeletion outbreak option and its language tokens. The flag is read by the frontend to hide the address delete button; the api does not enforce it, since the address requirement is what actually protects the data. It defaults to false so existing outbreaks keep their current behaviour.

Verification

Against a local instance, outbreak with the option disabled:

Case Result
create case with "addresses": [] 422 ADDRESS_MUST_HAVE_USUAL_PLACE_OF_RESIDENCE
create case without the addresses key 422
create case with a notification address only 422
create case with a usual place of residence 200
update case with "addresses": [] 422
update case without touching addresses 200
create event without addresses 200
create contact with "addresses": [] 422
create contact of contact with "addresses": [] 422
record already saved without addresses, edited without touching them 200
record already saved without addresses, sent an empty list 422

Outbreak with the option enabled: creating a case with an empty list and with no addresses key both return 200, unchanged.

The new outbreak flag round trips through GET /api/outbreaks/{id}, and the language tokens are created by the migration in every language, translated in Portuguese.

npm run lint passes on the changed files.

An empty or missing address list skipped validation entirely, so cases,
contacts and contacts of contacts could be saved without any address even
when the outbreak did not allow it. The requirement is enforced on create
and whenever a request changes the addresses.
When enabled the address delete button is hidden for cases, contacts and
contacts of contacts. Defaults to disabled so existing outbreaks keep the
current behaviour.
@lbrunofidelis
lbrunofidelis force-pushed the fix/#36-address-required-and-deletion-lock branch from b220675 to 308acdd Compare October 18, 2026 19:58
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.

1 participant