# Home sections (أقسام الصفحة الرئيسية) — mobile app contract

Staff manage the homepage's product sections on Admin → Products → Sections
(`App\Services\CustomHomeSections`): each section has a name, a type, products, an order, can be
hidden or deleted, and has a "View all" page. Today's Deal, Trending, Best Selling and New Products
are such sections too (since 2026-10-25 / 26). Since 2026-10-29 every section has a background
colour (section 3), and staff also make **strips**: sections of categories, stores or brands they
pick and order (section 3a). The Featured categories, Sellers and Brands strips became such
sections, so nothing is built in any more.

The website shows them in the order staff chose. The app should do the same. **New endpoints, new
app versions only**: older app versions never call them and keep working (section 5).

Base: `/api/v2`, usual headers (`System-Key`, `App-Language`). No sign-in needed. Answers are the
same for every user of a language and cached on the server (`api_cache:products`); a change by staff
shows on the next call.

## 1. `GET home-sections`

```json
{
  "data": [
    {
      "id": 15,
      "title": "صفقة اليوم",
      "title_ar": "صفقة اليوم",
      "title_en": "Today's Deal",
      "type": "manual",
      "products": [ { "id": 1988, "slug": "...", "name": "...", "main_price": "1,170 ل.س", "...": "..." } ],
      "links": { "all": "https://kapitano.shop/api/v2/home-sections/15/products" }
    }
  ],
  "layout": ["featured_categories", "custom_16", "custom_15", "strip_42", "custom_18", "best_sellers", "brands", "custom_19"],
  "strips": [ { "key": "featured_categories", "id": 93, "type": "categories", "title": "الفئات المميزة", "items": [ { "id": 144, "name": "...", "...": "..." } ], "links": { "all": "https://kapitano.shop/api/v2/categories", "web": "https://kapitano.shop/categories" } } ],
  "backgrounds": { "featured_categories": { "color": "#f8f9fa", "title_color": "#1b1b28" }, "custom_16": { "color": "#10164c", "title_color": "#ffffff" }, "...": "..." },
  "success": true,
  "status": 200
}
```

- `data`: the **shown** sections, in order. Hidden or deleted sections, and sections with no product
  a customer can see, are left out. `data: []` → show none.
- `title`: the name in the request's `App-Language` (the other language when staff left it empty);
  `title_ar` / `title_en` either may be `""`.
- `type`: `manual` (products staff pick), `best_selling`, `newest`, `category` (with its
  sub-categories), `brand`, `on_sale` (a discount running now), `flash_deal` (the one offers
  section, التصافي, 2026-11-05: see section 2a). For information only: the products are already
  chosen and ordered.
- `products`: the usual product card (`ProductMiniCollection`, as `products/todays-deal` and
  `products/search`), in order, cut to the number staff chose (1–50). Physical products only.
- `links.all`: the section's "View all" list (section 2); `links.web`: the same page on the website (`/section/<slug>`), to share.
- `id` is stable for the life of a section (a widget key).
- `data` holds **product sections only**, as it always did. Strips are in `strips` (section 3a).

## 2. `GET home-sections/{id}/products?page=N` — "View all"

Every product of the section, in its order, **20 a page**, shaped like `products/featured`
(`data` + `links` + `meta`: `current_page`, `last_page`, `per_page`, `total`). Follow `links.next`.
A hidden or deleted section, or a strip, answers **404** (`success: false`).

`{id}` may also be the section's **address** (`slug`, the end of `kapitano.shop/section/<slug>`): `home-sections/trending/products` answers the same as `home-sections/16/products`. That is what the deep link `kapitano://section/<slug>` uses (`docs/api/deep-links/README.md`). The answer also carries `section`: `{ "id": 16, "slug": "trending", "title": "تريندات", "title_ar": "تريندات", "title_en": "Trending" }`, for the screen's title (added 2026-10-30).

## 2a. The offers section (`type: flash_deal`, 2026-11-05)

Flash deals became **one** home section. Each of its products has its own discount, start and end; the
section lists only the products whose offer runs now, and it is placed by `layout` like any section
(key `custom_<id>`). Each product card of it (in `home-sections` and in `home-sections/{id}/products`)
carries two **added** keys:

```json
{ "id": 120, "...": "...", "offer_starts_at": 1762300800, "offer_ends_at": 1762387200 }
```

Unix seconds. Draw a countdown to `offer_ends_at` on the card; when it reaches 0, drop the card (the
next call no longer lists it). The price fields are already the offer price. Other sections never
carry these keys. Its "View all" page on the website is `/section/flash-sale` (`links.web`).
The website draws it with the usual card plus, under the price, the saving in pounds, "only N left" at
a real stock of 5 or fewer and a ring countdown, and a timer to the nearest end beside the title: the
look, in Arabic, is in `docs/api/offers-section-app-handoff.md` section 4.

Old app versions keep calling the flash deal endpoints, which now answer from this section in their
old shape: `flash-deals` and `flash-deals/info/{slug}` give **one** deal (`id` = the section id,
`slug`, `title`, `date` = the latest `offer_ends_at` of the running offers, `banner` = the
placeholder, its first 6 products) or `data: []` when nothing runs; `flash-deal-products/{slug}` its
products (with the two keys above); `flash-deals-banners` `data: []`. New versions should draw the
section from `home-sections` and stop calling them.

## 3. `layout` — where each section goes

`layout` is the homepage order, top to bottom:

| key | section in the app |
|---|---|
| `custom_<id>` | the item of `data` with that `id` (every product section, Today's Deal, Trending, Best Selling and New Products included) |
| `best_sellers` | the shops strip (`shops`) |
| `brands` | the brands strip (`brands`) |
| `featured_categories` | the featured categories strip (`categories/featured`), since 2026-10-29. Staff move it, and may delete it like the other strips |
| `strip_<id>` | a strip staff made (since 2026-10-29): the item of `strips` with that `key` (section 3a) |

The three old strip keys stay as they were for old app versions. New versions should draw
`featured_categories`, `best_sellers` and `brands` from `strips` too: their item there has the same
`key`, and its contents are what staff arranged, which `shops` and `brands` do not follow.

Skip a key the app does not know or show; keep every other home element (sliders, banners) where
it is today. Flash deals are a section of the layout since 2026-11-05 (section 2a). A strip staff deleted is left out. Draw a section like
Trending: the title, a "View all" button, then a horizontal product carousel.

**Featured categories and the banners under them** (2026-10-29). Draw the featured categories
strip at the `featured_categories` key. The banners the app shows under the featured categories
today **stay at that place on the page; they do not move with the strip**. Draw them under the
**first key of `layout`**, whatever it is. If `featured_categories` is first, which is today's order,
nothing moves. If staff move it down, the banners stay under the section that is now first. The
website does the same. An app version that does not know the key skips it and keeps the
categories and banners where they are today, so nothing breaks. When staff delete the strip, the
key is missing from `layout`: hide the featured categories, and keep the banners under the first key.

**Background of each section: `backgrounds`** (2026-10-29). Staff choose each section's background
colour freely, the strips included. `backgrounds` has one entry per key of `layout`:

```json
"backgrounds": {
  "featured_categories": { "color": "#f8f9fa", "title_color": "#1b1b28" },
  "custom_16": { "color": "#10164c", "title_color": "#ffffff" },
  "custom_15": { "color": null, "title_color": "#1b1b28" },
  "brands": { "color": "#ffc519", "title_color": "#1b1b28" }
}
```

- `color`: the section's background as `#rrggbb`; `null` = white.
- `title_color`: the colour that reads on it, for the title, the "View all" button and the arrows.
  It is white on a dark colour and dark otherwise.
- Product cards, shop tiles and brand tiles stay white on any background.
- Until staff save a first colour, the first product section is `#10164c` and the others are white,
  which is the look the website always had.

App versions that do not read `backgrounds` keep painting the first product section navy (the old
rule: the first key that is not `featured_categories` / `best_sellers` / `brands`). New versions
should use `backgrounds` and drop that rule.

## 3a. `strips` — sections of categories, stores or brands (2026-10-29)

Staff create sections that show **categories, stores or brands** they pick, in their order (types
`categories`, `shops`, `brands`). A new one starts with what customers see today in that order;
after that it shows exactly what staff arranged, and nothing is added by itself. The old Featured
categories, Sellers and Brands strips are such sections now. A deleted section is gone for good:
there is no "bring back" any more.

Each item of `strips`:

- `key`: where it goes in `layout`. It is `featured_categories`, `best_sellers` or `brands` for the
  three that were built in, and `strip_<id>` for the others.
- `id`, `title`, `title_ar`, `title_en`: as in `data`.
- `type`: `categories`, `shops` or `brands`.
- `items`: in order, cut to the number staff chose (1–100). The shape is the one the app already
  draws:
  - `categories` items are shaped like `categories/featured`;
  - `shops` items like `shops`;
  - `brands` items like `brands`.
  Hidden categories, unverified stores and brands awaiting approval are never sent.
- `links.all`: the app's full list (`categories`, `shops` or `brands`); `links.web`: the same list on
  the website.

Draw a `categories` strip like the featured categories: its `title` and a "View all" on top, then
round images and names, as on the website (every categories strip, decided 2026-10-30). Draw a `shops` or `brands` strip like the Sellers / Brands strips (title, "View all",
logos). `categories/featured` now answers the converted Featured categories section's
categories, so old app versions follow staff's changes there too. It answers an empty list once
that section is hidden or deleted.

## 4. Bundled call (`app/data`)

The group **`custom_home_sections`** answers exactly `GET home-sections` (see
`docs/api/app-data-sync.md`). New app versions need no `todays_deal_products` /
`featured_products` / `best_selling_products` groups any more.

## 5. Old endpoints (old app versions)

`products/todays-deal`, `products/featured`, `products/best-seller` and the new arrivals list
(`products/search?sort_key=new_arrival` with no filter) still answer exactly as before (checked body
for body, `ApiHotPathsRuntimeTest`): they read the section that took their place. Once staff hide or
delete that section, the endpoint answers an empty list (the new arrivals list then is plain newest
first). The `todays_deal` / `featured` fields of the product resources still answer 0/1.

The Flutter handoff (Arabic): `docs/api/home-sections-app-handoff.md`; for the offers section: `docs/api/offers-section-app-handoff.md`.
