01Local media mirror
Every image, font and video was still being fetched from the old WordPress host, so the day that host went dark the new site would be broken images in the wrong typeface. I wrote a codemod to repoint them at a local mirror rather than a find-and-replace: about a fifth of the references are assembled from one- and two-letter prefix constants whose meaning changes from file to file, so it resolves constants per file and checks each target exists before writing the edit. A page still returns 200 when an image inside it 404s, so verification became fetching every asset on all 114 routes in all four locales.
02Reading WooCommerce
The live site runs HPOS, so orders sit in wp_wc_orders and wp_wc_orders_meta rather than wp_posts, and the booking plugin's camper and parent fields are stored under short meta keys I had to find by inspecting the database instead of assuming from convention. I was matching five Korea orders to a camp by name, which held until a second Korea camp was created and the first one was renamed. I moved matching to the product id on the line item: a name is a label that gets rewritten, and the id is what WooCommerce charged against.
03Bytes over headers
My document importer trusted Content-Type, and the old host served every .docx and .heic out of its uploads folder as text/plain, so it was throwing valid files away. It now reads magic numbers, which a misconfigured web server cannot get wrong, while still catching the case the header check existed for: a WordPress 404 answers 200 with HTML, and filing that as somebody's document is worse than not having it.
04Private documents
I serve customer documents through a route that resolves both authentication systems in play, Clerk and Auth.js, and proves ownership against the caller's own bookings rather than treating a valid session as sufficient. Marking the files private in Payload was the easy half. The route also falls back to local disk when object storage is not configured, instead of answering 503.
05Four locales
English, Arabic, Russian and Simplified Chinese share one routing and message setup, with per-locale type treatment: I set Arabic larger with its own display face, suppressed italics in Chinese, and gave Russian an explicit expansion budget on display headings. I store article bodies as a single HTML block rather than pretend Elementor markup converts losslessly into a typed block set, and the phase notes say so plainly. The Payload seed is additive and does not touch the render path, so I can make the switch from committed content to CMS content later, verify it, and revert it if it is wrong.