Chuyển tới nội dung chính

Internal Marketing

In one line: the promo banners on the client app's home screen, and how a tap on one gets the customer to the right store.

What problem this solves​

Marketing wants to put brands and offers in front of customers and send them straight to a place where they can order. A banner can send people to a web page, to one specific store, or — for a brand with many branches — to the closest branch that's taking orders right now (or simply the closest one, if none nearby is). This module is the three client-app endpoints that make that work. All three live in locate-order-v2-api's client API (order-v2-client).

Example: from banner to menu​

Ids and names below are illustrative.

  1. Sara opens the app. The app calls Banners and shows an "Order Burger Bros" banner (link_type = nearest_branch, nearest_branch_merchant_id = 42).
  2. The banner comes into view. The app calls Nearest store with brand 42 and Sara's location, and gets back store 1874 (the JBR branch, 1.2 km away).
  3. Sara taps. The app calls Merchant by id (really store detail, GET /stores/1874) and opens the Burger Bros JBR menu.

A banner pointing at a single store skips step 2. A banner pointing at a web page skips steps 2 and 3.

How the pieces fit together​

  1. The app calls Banners to render the home screen. Each banner carries a link_type that decides what tapping it does:

    link_typeWhat a tap does
    url (default)Open the banner's link field verbatim.
    storeOpen the store identified by the banner's merchant_id field — which, despite the name, is the banner's store_id (see the hazard on Merchant by id).
    nearest_branchCall Nearest store with the banner's nearest_branch_merchant_id and the user's coordinates, then open the store_id it returns (or do nothing if that's null).
  2. However the app arrives at a store id — straight from a store banner, or resolved through Nearest store — it fetches the destination with Merchant by id to render the screen.

A brand-level (nearest_branch) banner therefore never carries a deeplink itself: the app always does one extra round trip (Nearest store, then Merchant by id) to work out which physical branch to show. See Nearest store for why that's cheap enough not to cache.

Endpoints​

AreaMethod & pathOpenAPI operation (openapi/order-v2-client.json)
BannersGET /api/v2/client/bannersClientBannersController_getBannersList
Merchant by idGET /api/v2/client/stores/{id}ClientStoresController_getStoreDetail
Nearest storeGET /api/v2/client/banners/merchant/{merchantId}/nearest-storeClientNearestStoreController_getNearestStore

The two-layer convention — read this before writing the next module​

This module is the template. Copy its shape, not its words:

  • This page and its area pages are handwritten and cover only what doesn't go stale: what a feature is, who calls it, how endpoints relate, business rules, and gotchas. They are not regenerated and nobody wipes them on a rebuild.
  • Field names, request/response shapes, and status codes are never restated here. Their source of truth is the service's OpenAPI snapshot in openapi/*.json (refreshed by npm run openapi:fetch) and the code behind it; they drift the moment they're copied by hand. This site stopped rendering those snapshots as pages on 2026-10-01, so every area page names its endpoint and OpenAPI operation instead — see the table above, and the > **Endpoint:** callouts inside each area page. Examples may name a field or show an illustrative value in prose (nearest_branch_merchant_id = 42), but never paste a request or response body. (The User Migration module is the one deliberate exception: its services publish no OpenAPI, so it documents fields itself — see its overview.)
  • Every page is written for the web/mobile dev first, the backend dev second. The module index.md uses: In one line → ## What problem this solves → ## Example: … (the whole journey across endpoints) → ## How the pieces fit together → ## Endpoints → this convention section. Area pages use this order, and keep the part above the --- free of source paths, SQL, and internal column names:
    1. > **In one line:** — what it does, in plain words.
    2. ## When you'd use this — the problem, before any mechanics.
    3. ## Example: … — a short, concrete story of the feature in use, with ids labelled illustrative, including what happens when it goes the "other" way (nothing found, error).
    4. ## How to call it — the endpoint, the > **Endpoint:** callout, and 2–4 steps.
    5. ## Watch out — at most three one-line gotchas.
    6. --- then ## Details (for backend) — business rules, hazards, performance, testing, and sources, as ### subsections. Nothing is dropped; it just moves down.
  • A new module gets its own folder under docs/modules/<module-name>/, an index.md like this one, one page per area, and a _category_.json with a position. Positions order the modules inside Modules — lower comes first.
  • Before writing a rule down, find it in the code or an existing doc and cite it. If a rule can't be established that way, say so on the page in one line ("not documented yet") instead of guessing.