Problem
Several destinations need extra buyer details that Shopify has no native field for, or only offers in early access. Support was writing to customers after purchase to get them. The client wanted its own app only, no outside services, and validation that does not depend on a checkout script that Shopify is retiring.
Solution
The app is five extensions and a shared library. A checkout block shows fields only for the destination country. A validation Function repeats the same checks on the server, including for express wallets. A payment rule hides wallets where they would skip the fields. A thank-you block gives instructions for one market. Per-country rules are one JSON setting that the merchant edits in an app page.
Key decisions
Chose server-side validation in a Function over a checkout intercept
Why The intercept API is being retired, and a Function also covers express wallets that bypass checkout UI extensions.
Chose country rules as one JSON setting edited in the app
Why Labels, required fields and error texts change without a deploy, and a new country on existing validators is only config.
Chose a hard size limit on the config
Why A Function silently ignores metafield values over its size limit, so the app refuses to save a larger config.
Chose Shopify's native fields first, with mine as a fallback
Why Where a native field exists, the buyer never types the same ID twice.