The same rules, checked twice.
Build the fields on the page as part of the design. Every rule you set is evaluated in the browser while somebody types, and again on the server when it arrives — against one shared specification.

One specification, three implementations, one answer.
The browser, the editor and the server are held to the same fixture file, so a field cannot pass in one place and fail in another. Every case in it names a bug that shipped once.
Mark a field required, give it a regular expression, or attach rules like a minimum. An unparseable pattern fails open rather than rejecting everybody.
Uploads are accepted, stored against the submission, and pruned on a schedule so an inbox does not become a disk problem.
A hidden honeypot catches the simple bots. Cloudflare Turnstile handles the rest, on the endpoints whose visitors can render it. Neither asks a person to identify a bus.
Submissions are always stored. Email on top of that is a switch, and the visitor gets either your message or a redirect of your choosing.
Enquiries, bookings and orders in one list.
Three modules, three kinds of record, one place to read them — merged per site, newest first, filtered and searchable, each row still linked to the thing it came from.
A form that works without a framework.
A published page runs a small script, not a front-end framework. The form element emits a real submit button and the runtime posts it — which is what makes it work with the page cached and the framework absent.

Put a form on a page and send yourself a test.
It takes about five minutes, and it is the fastest way to see the whole chain work.