# Form Patterns

- **Library**: React Hook Form + Zod + `@hookform/resolvers`
- **Feedback**: FieldError under controls; Sonner for server errors
- **Submit**: disable while `mutation.isPending`
- **Dirty**: rely on RHF `formState.isDirty` for future autosave
- **Server validation**: map `AccountingApiError.message` to toast (field mapping when backend returns field errors)

Voucher create uses `useFieldArray` with minimum two balanced lines (enforced by Zod + backend).
