Files
carmanagement/input-validation-plan.md
T
root 057d41e1c2
Build & Push / Pipeline Tests (push) Failing after 1m5s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Failing after 52s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Carplace Unit Tests (push) Has been skipped
Test / Admin Unit Tests (push) Has been skipped
Test / Dashboard Unit Tests (push) Has been skipped
Test / API Integration Tests (push) Has been skipped
add text input validation
2026-08-31 22:51:44 -04:00

9.6 KiB
Raw Blame History

Task: Add Input Validation for User Data Form

Objective

Add length/format/range validation for the fields listed below, enforced at three layers: frontend (UX), backend (source of truth), and database (last line of defense). Do not change unrelated form behavior, styling, or fields not listed here.

Scope

Only touch the files responsible for these fields: the form component(s), the API endpoint(s) that receive this data, the validation schema/middleware, and the DB migration/schema for these columns. If a field doesn't exist yet in the DB/API, flag it and ask before creating new schema — don't assume the shape.


Field Rules

Field Type Rule
firstName string required, trim, 150 chars, Unicode letters/spaces/hyphens/apostrophes allowed
lastName string required, trim, 150 chars, same charset as firstName
email string required, trim, max 254 chars, valid email format (use an existing validation library, don't hand-roll regex)
nationality enum required, must be a valid ISO 3166-1 country code (dropdown-backed, not free text)
phoneNumber string required, normalize to E.164 on save (use existing phone validation lib if the project has one; otherwise ask before adding a dependency), max 20 raw input chars
driverLicense string optional unless told otherwise, trim, 530 chars, alphanumeric only
date (generic) date must be a valid ISO 8601 date (YYYY-MM-DD); reject free text
address string required, trim, 1255 chars
idPassport string required, trim, 530 chars, alphanumeric
country enum required, valid ISO 3166-1 country code (dropdown-backed)
issuedDate date required, ISO 8601, must be ≤ today
expirationDate date required, ISO 8601, must be ≥ issuedDate
dateTime datetime required, store as ISO 8601 with UTC offset — do not store naive local time
vinNumber string required, exactly 17 chars, alphanumeric excluding I/O/Q, uppercase
city string required, trim, 185 chars
amount number required, numeric, > 0, max 2 decimal places, reasonable upper bound (ask what "reasonable" means for this use case if not obvious from context — don't guess a business rule)

Cross-field rules

  • expirationDate must be after issuedDate.
  • issuedDate must not be in the future.
  • Do not implement any cross-field rule not listed here without asking first.

Implementation steps

  1. Locate existing validation approach. Check if the project already uses a validation library (Zod, Yup, Joi, class-validator, pydantic, etc.) or a pattern for form validation. Use whatever already exists — do not introduce a new validation library if one is already in use.
  2. Frontend: add maxlength/type-appropriate input constraints and inline error messages matching the rules above. Reuse existing form error-display patterns in the codebase.
  3. Backend: add/extend the validation schema or middleware for the relevant endpoint(s) to enforce the same rules server-side. This is the authoritative check — assume the frontend check can be bypassed.
  4. Database: only if column definitions currently allow unbounded/incorrect lengths, add matching length constraints via migration. Do not touch unrelated columns or tables.
  5. Normalize country/nationality to ISO codes, phone to E.164, and dates to ISO 8601 at the point of validation/save — not scattered across multiple layers.

Explicitly out of scope (ask before doing any of this)

  • Adding a new third-party validation/phone/country-list library if one doesn't already exist in the project.
  • Changing the DB schema shape (splitting address into multiple columns, etc.) — flag it as a suggestion instead.
  • Any field not in the list above.
  • Deep format validation for driverLicense/idPassport beyond length + charset (these vary too much by issuing country to hardcode safely) — ask if stricter per-country validation is actually wanted.

Validation before reporting done

  • Confirm each rule above has a corresponding check in frontend AND backend (list them field by field in your report).
  • Confirm existing tests still pass; add new tests only for the fields touched here.
  • Report any field where the existing DB column type/length conflicts with the rule above, rather than silently changing it.

Task: Add Language-Aware Input Handling (EN / FR / AR)

Objective

Each record has ONE selected language (EN, FR, or AR). Free-text fields are typed and stored in that language's script. Add a language field to the record, validate free-text fields against the script rules for the selected language, and handle RTL display for Arabic. This extends input-validation-plan.md — do not redo work already covered there; only add what's described here.

Scope

Touch only: the form component(s) already handling these fields, the language selector (add one if it doesn't exist), the validation schema from the previous task, the API endpoint(s), and the DB column for storing the selected language. Do not touch fields/logic unrelated to language handling.


1. Data model change

  • Add a language column/field to the record: enum, one of en, fr, ar. Required, no default — must be explicitly selected (unless the project already has a default locale convention; ask if unsure).
  • This is a single value per record, not per field. All free-text fields in that record are assumed to be in this language/script.

2. Which fields are affected

Only free-text, human-language fields are language/script-dependent:

  • firstName, lastName, address, city

These are not language-dependent — keep exactly as specified in input-validation-plan.md, do not add script validation to them:

  • email, phoneNumber, driverLicense, idPassport, vinNumber, amount, all dates, nationality, country

nationality and country stay as ISO codes regardless of selected language — only their displayed label is translated (a UI/i18n concern, not a data validation concern). Do not store translated country names as the value.

3. Script validation per language

Update the charset rule for firstName, lastName, address, city based on the record's language value:

Language Allowed script Notes
en Latin (a-z, A-Z), spaces, hyphens, apostrophes Same as current rule in input-validation-plan.md
fr Latin + French diacritics (à, â, ç, é, è, ê, ë, î, ï, ô, œ, ù, û, ü, ÿ, etc.), spaces, hyphens, apostrophes Do not reject accented characters
ar Arabic script (Unicode range \u0600-\u06FF and \u0750-\u077F for extended Arabic), spaces, standard Arabic punctuation Do not force Latin transliteration

Implement this as a per-language regex/charset map, not a single hardcoded regex — so a future 4th language is a config addition, not a rewrite. Length limits (50 for names, 255 for address, 85 for city) stay the same as input-validation-plan.md regardless of language — do not add or remove digits from those limits.

Do not attempt to auto-detect the language from the text itself — the language field is user-selected and is the source of truth for which validation rule applies.

4. Frontend

  • Add a language selector if one doesn't already exist (dropdown or toggle: EN / FR / عربي).
  • When ar is selected, apply dir="rtl" to the affected text inputs (firstName, lastName, address, city) and their containing form section. Do not flip the entire page layout unless explicitly asked — scope this to the form only.
  • Switch the input validation pattern (pattern attribute / live validation) to match the table above based on the current language selection.
  • If the project already has an i18n/translation library in use (e.g. i18next, react-intl), use it for labels and error messages. Do not introduce a new i18n library if one already exists.

5. Backend

  • Validate language is one of en/fr/ar.
  • Apply the matching charset rule from the table above to firstName, lastName, address, city based on the submitted language value — reject if the text doesn't match the selected language's script (don't silently strip characters).
  • Store the text as submitted (UTF-8), no transliteration or normalization beyond standard Unicode NFC normalization (consistent with the rest of the validation plan).

6. Database

  • Ensure the column encoding/collation supports UTF-8 fully (utf8mb4 if MySQL; Postgres is UTF-8 by default) — Arabic and accented French characters will break under older utf8/latin1 collations. Only change this if it's actually currently a problem; check first, don't assume.
  • Add the language column via migration if it doesn't exist. Do not alter unrelated columns in the same migration.

Explicitly out of scope (ask before doing)

  • Translating the actual stored data between languages (e.g. auto-translating an English name to Arabic) — this task is about validating/storing what the user typed, not translation.
  • Full-page RTL layout changes beyond the form fields listed.
  • Adding a new i18n library if the project doesn't already have one — flag and ask which one to use.
  • Any language beyond en/fr/ar.
  • Changing how nationality/country are stored (they remain ISO codes).

Validation before reporting done

  • Confirm each of firstName/lastName/address/city is validated against the correct script for the selected language value, in both frontend and backend.
  • Confirm language is required and validated as an enum.
  • Confirm DB encoding supports Arabic/French characters (test by saving a record with Arabic text and reading it back unchanged).
  • Confirm unrelated fields (email, phone, VIN, dates, amount, nationality, country) are untouched by this change.