--- description: All phone-number data must use the PhoneNumber value object; extend the VO instead of adding alternate helpers alwaysApply: true --- # Phone Number Value Object ## Mandatory ALL phone-number data in the domain and application layers MUST use `PhoneNumber` from `src/common/value-objects/phone-number/`. - Construct only via `PhoneNumber.create(raw)` - Compare with `equals()`, serialize with `value` / `toString()` / `toJSON()` - Persist and transmit the canonical E.164 from `phone.value` (or `toString()` / `toJSON()`) ## Forbidden Do NOT: - Store or pass phone numbers as plain `string` / `number` in domain models, services, or repositories (beyond the DTO/HTTP or DB string boundary) - Add phone validators, parsers, formatters, regex helpers, pipes, or decorators that bypass the VO - Create new files or functions for phone-number validation or normalization - Use `libphonenumber-js` (or similar) outside the PhoneNumber VO ```typescript // BAD function normalizePhone(raw: string): string { /* ... */ } user.phone = '+6281234567890' // GOOD const phone = PhoneNumber.create(dto.phone) user.phone = phone // PhoneNumber type in domain await repo.save({ phoneNumber: phone.value }) // E.164 string only at persistence edge ``` ## When the VO is not enough If a requirement cannot be met with the current VO (e.g. national formats, default region, formatting for display): 1. **Update** `src/common/value-objects/phone-number/` (implementation + colocated tests) 2. Do **not** invent a parallel phone helper, type, or module ## Boundaries - HTTP DTOs may accept `string`; map to `PhoneNumber.create()` at the service boundary - Database columns may store E.164 `text`/`varchar`; map to/from `PhoneNumber` in the repository - `InvalidPhoneNumberError` is the only phone validation error; do not echo raw input in messages