## 1. Shared escaping helper

- [x] 1.1 In `app/Models/Field.php`, add a static helper that returns the HTML-safe rendered value for a field: `e()` applied to the result of `transformValueByKey($code, $value)` (null/empty → `''`). Keep `transformValueByKey()` itself unchanged (design D1, D2, D4)
- [x] 1.2 In `Field::templateReplace()`, escape the payslip item name passed as `item_name` for `salary_information` with `e()`; leave `item_value_code` (the `${code}` placeholder) as is (design D5)

## 2. Use the helper in both render paths

- [x] 2.1 In `Contract::getPreviewByTemplate()` (`app/Models/Contract.php`), replace the "Transform value" loop with the helper so every value (default, custom, overriding) is escaped before `str_replace`
- [x] 2.2 In `ContractType::getPreviewByTemplate()` (`app/Models/ContractType.php`), do the same
- [x] 2.3 Confirm no other place substitutes field values into a template (`grep -rn "str_replace(\$keys" app/`, `grep -rn "transformValueByKey" app/`)

## 3. Tests

- [x] 3.1 Add a unit/feature test for the helper: `<b>` → `&lt;b&gt;`; `R&D "A"` → `R&amp;D &quot;A&quot;`; literal `&amp;` → `&amp;amp;`; `null` → `''`; Vietnamese text unchanged; date and salary formatting unchanged
- [x] 3.2 Add a test that `Contract::getPreviewByTemplate('<p><strong>${employee_position}</strong> tail</p>', collect(), true)` for an employee with `contract_position = 'Trưởng nhóm R&D / Kỹ thuật (Cấp 2) – "A" <b>'` returns `<p><strong>Trưởng nhóm R&amp;D / Kỹ thuật (Cấp 2) – &quot;A&quot; &lt;b&gt;</strong> tail</p>`
- [x] 3.3 Add a test that an `overriding_fields` value `<i>x</i>` is rendered as `&lt;i&gt;x&lt;/i&gt;`
- [x] 3.4 Run the related test suite and fix regressions (Unit 4/4 OK; Feature: escape + contract position tests OK against local MySQL; only the pre-existing `ExampleTest` fails with 302. Fixed 3.2 test to persist `contract_position`, since `getPreviewByTemplate()` reloads the employee relation)

## 4. Manual verification

- [x] 4.1 Lint the changed PHP files (`php -l`)
- [x] 4.2 On local, set an employee's `contract_position` to `Trưởng nhóm R&D / Kỹ thuật (Cấp 2) – "A" <b>`, call `previewByAccount` with a template containing `${employee_position}` followed by more text, and confirm the PDF shows `<b>` literally and the following text is not bold
- [x] 4.3 Preview a contract type template containing `${salary_information}` and confirm the list still renders as a bulleted list
