# 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, 1–50 chars, Unicode letters/spaces/hyphens/apostrophes allowed | | lastName | string | required, trim, 1–50 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, 5–30 chars, alphanumeric only | | date (generic) | date | must be a valid ISO 8601 date (`YYYY-MM-DD`); reject free text | | address | string | required, trim, 1–255 chars | | idPassport | string | required, trim, 5–30 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, 1–85 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.