feat(contacts): validate phone/timezone/country/postal (fix contact phone 500) [PMS-325] #247

Merged
vas2000-work merged 1 commit from fix/PMS-325-contact-field-validation into main 2026-06-15 19:45:49 +02:00
Owner

What

Backend field validation for contacts, companies, and sites (PMS-325). Phone, time zone, country, and postal code were previously unvalidated, so bad input was either stored as-is or failed downstream and surfaced as an HTTP 500 (the reported "contact phone" failure). Each is now a clear, per-field 422 so the client can show the user exactly what to fix.

Changes (crate mokosh-types)

  • Phone / mobile / fax: a normalizing deserializer strips common formatting (spaces, dashes, parens, dots) so +1 (415) 555-1234 is stored as +14155551234, then a validator enforces E.164 (optional +, 2-15 digits, first 1-9). Non-numeric input (e.g. not-a-phone) is rejected rather than silently emptied.
  • Time zone: validated against the IANA tz database via chrono-tz. America/New York (space) is rejected; America/New_York is accepted.
  • Country: ISO 3166-1 alpha-2 (validated against the official set, case-insensitive). USA / United States are rejected.
  • Postal code: permissive, country-agnostic rule (2-12 chars: letters, digits, spaces, hyphens).
  • Wired to the request DTOs: Create/Update Contact, Create/Update Company, Create/Update Site, and the shared Address (now nest-validated on sites too).
  • Added chrono-tz to mokosh-types.

Tests

  • Unit tests for each validator (phone normalize + E.164, IANA tz, ISO country, postal).
  • Integration tests (tests/contacts.rs): invalid phone -> 422 (not 500), spaced time zone -> 422, non-ISO country -> 422, over-long postal -> 422, and a formatted phone round-tripping as normalized E.164. Existing contact/company/site tests updated for the new normalized phone form and ISO country.

Verification

  • cargo test -p mokosh-types and the full tests/contacts.rs suite (10/10) green against Postgres.
  • cargo clippy --all-targets -- -D warnings and cargo fmt --all --check clean.

Client-side inline mirror is MAPPS-177 (linked).

#PMS-325

## What Backend field validation for contacts, companies, and sites (PMS-325). Phone, time zone, country, and postal code were previously unvalidated, so bad input was either stored as-is or failed downstream and surfaced as an HTTP 500 (the reported "contact phone" failure). Each is now a clear, per-field 422 so the client can show the user exactly what to fix. ## Changes (crate `mokosh-types`) - **Phone / mobile / fax**: a normalizing deserializer strips common formatting (spaces, dashes, parens, dots) so `+1 (415) 555-1234` is stored as `+14155551234`, then a validator enforces E.164 (optional `+`, 2-15 digits, first 1-9). Non-numeric input (e.g. `not-a-phone`) is rejected rather than silently emptied. - **Time zone**: validated against the IANA tz database via `chrono-tz`. `America/New York` (space) is rejected; `America/New_York` is accepted. - **Country**: ISO 3166-1 alpha-2 (validated against the official set, case-insensitive). `USA` / `United States` are rejected. - **Postal code**: permissive, country-agnostic rule (2-12 chars: letters, digits, spaces, hyphens). - Wired to the request DTOs: Create/Update Contact, Create/Update Company, Create/Update Site, and the shared `Address` (now nest-validated on sites too). - Added `chrono-tz` to `mokosh-types`. ## Tests - Unit tests for each validator (phone normalize + E.164, IANA tz, ISO country, postal). - Integration tests (`tests/contacts.rs`): invalid phone -> 422 (not 500), spaced time zone -> 422, non-ISO country -> 422, over-long postal -> 422, and a formatted phone round-tripping as normalized E.164. Existing contact/company/site tests updated for the new normalized phone form and ISO country. ## Verification - `cargo test -p mokosh-types` and the full `tests/contacts.rs` suite (10/10) green against Postgres. - `cargo clippy --all-targets -- -D warnings` and `cargo fmt --all --check` clean. Client-side inline mirror is MAPPS-177 (linked). #PMS-325
feat(contacts): validate phone, timezone, country, and postal fields
All checks were successful
Create release / Create release from merged PR (pull_request) Has been skipped
E2E / Playwright against staging (pull_request) Successful in 41s
Check / fmt + clippy + compile + unit/doc tests (pull_request) Successful in 1m16s
Integration / integration tests (pull_request) Successful in 3m1s
90cefed8ae
Phone, time zone, country, and postal code on contacts, companies, and sites were unvalidated, so bad input was stored as-is or failed downstream and surfaced as an HTTP 500 (the reported contact-phone failure). Validate each at the request-model layer so invalid input returns a clear per-field 422 instead.

Phone/mobile/fax are normalized (formatting stripped: spaces, dashes, parens, dots) and checked against E.164; time zone is validated against the IANA database via chrono-tz (rejecting "America/New York"); country must be an ISO 3166-1 alpha-2 code; postal code uses a permissive 2-12 character rule. Wired to the Create/Update Contact, Company, and Site request DTOs and the shared Address (now nest-validated on sites). Adds unit tests per validator and integration tests asserting 422 (not 500) for each, plus a normalized-phone round-trip; existing contact/company/site tests updated for the normalized phone form and ISO country code.

#PMS-325

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-server!247
No description provided.