Skip to content

Markets

One WooCommerce install per market (ADR-007), one frontend deployment for all of them. A market is selected by Host, never by locale or cookie. Shared code contains no country conditionals (invariant 4); everything market-specific is one of the three levels below.

Three levels

LevelWhereWhatA change is
1 · Valuesplugin/config/markets/{CODE}.php and frontend/markets/{code}.tscurrency, locale, COD limits, VAT rules, gateway list, carriers, phone prefixes, rounding step; UPN IBAN and receivera config PR, no logic review
2 · Behaviourone named strategy class in plugin/src/**/Service/Market/, selected by configthe rare case where a market needs a different algorithm, not a different number (cash rounding, customs)a code PR, one class, with tests. Chosen by configuration, never by if.
3 · RolloutNF_FF_* env + nf_commerce_flagsswitching a finished feature on for some stores before the resta Doppler change. A flag that is on for a year is a bug.

Test: if two markets would want a different value, level 1. Different code, level 2. Same for all and just unfinished, level 3.

What defines a market

PieceLives inHolds
plugin/config/markets/{CODE}.phpnf-commerceLevel-1 values WooCommerce needs at runtime.
frontend/markets/{code}.tsfrontendStatic display facts: public host, WP_HOME host, locale, currency formatting, legal entity. What the store can do right now is not here — it comes from GET /nf/v1/capabilities at request time, so a store on an older plugin version serves its market safely.
store-template .env per installDopplerWP_HOME, DB, X-NF-Key, Cloudflare zone token, PSP credentials.
DNSCloudflare zonePublic host → frontend cluster; wp.{market} host → WordPress host.
Cloudflare zone configinfra/cloudflare/ as codeCache Rules (key host+path+_rsc, bypass list), URL rule stripping marketing params, Access on /wp/wp-admin, WAF, Turnstile. Plan tier per zone is an owner decision.
proxy.tsfrontendResolves Host → market and sets Cache-Control.

Adding a market

bin/new-market.sh {CODE} scaffolds steps 1–3; the rest is a checklist until automated.

  1. plugin/config/markets/{CODE}.php — values, gateway list (from F1), carriers, UPN data if BACS.
  2. frontend/markets/{code}.ts — hosts, locale, currency formatting; next-intl catalog for the language if new.
  3. contracts/fixtures/nf/capabilities/{code}.json.
  4. Provision the install from store-template (wp nf provision once it exists) with the market’s .env from Doppler; composer.json is shared — a market never adds a plugin alone.
  5. DNS: public host → frontend; wp.{market} → WordPress host. Cloudflare zone from infra/cloudflare/ (cache rules, bypass rules, Access, WAF).
  6. PSP accounts and webhooks per gateway in the market’s list; return URLs point at wp.{market}.
  7. verify:* clean, Phase 0 curl -sI gates pass on the new host, then the phase-6 wave.

Open

IdQuestionOwnerStatus
M3Pilot market — the first store rebuilt and cut over. Names the gateway set, locales and e-mail templates for Phases 3–5; unplaces DNK quiz (C18) and answers-endpoint until named.businessopen (Phase −1 proposal)
F1Gateway × market matrix: Stripe, Mollie, BLIK, PayPal, Bankart, UPN, COD per market. Known only for SI (6 active gateways); needs the fleet.business + PHPopen (Phase 3 at the latest)
O1WordPress hosting for 28 stores.businessopen
Cloudflare plan tier per zone.businessopen