# Brief for the app AI — "China Shop Products: Sales Performance" screen

> Paste this whole file to the AI that builds the mobile app, together with `APP_API.md`
> (full API reference), the server **Base URL** and the **API key**.

## Goal

Build a screen that shows, for one China supplier shop, **every product with a clear verdict on
whether it sells well or not**, and why. The backend already does all the analysis; the app only
renders it. Do **not** recompute scores on the client.

## Data source

```
GET {BASE_URL}/api/app/china/shops/{shopId}?key={API_KEY}&sort=score
```

Optional query params:

| Param | Values | Use |
|---|---|---|
| `sort` | `code` (default) · `score` · `sold` · `remaining` · `name` | Sort chips at the top |
| `rating` | comma list of `excellent,good,average,weak,dead,new` | Rating filter chips |
| `filter` | `all` · `in_stock` · `out_of_stock` · `buyed` · `not_buyed` | Stock / China-order filter |

Response shape (abridged — see `APP_API.md` §8 for every field):

```json
{
  "data": {
    "shop":    { "id", "name", "code", "shop_number", "wechat", "note" },
    "summary": {
      "products", "remaining_qty", "remaining_cartons", "stock_value",
      "sold_qty", "sold_revenue", "sold_profit", "purchased_qty",
      "good_sellers", "good_sellers_pct", "avg_score",
      "ratings":         { "excellent", "good", "average", "weak", "dead", "new" },
      "recommendations": { "restock", "keep", "watch", "reduce", "clear", "wait" }
    },
    "products": [
      {
        "id", "name", "code", "brand",
        "images":   { "thumb", "medium", "image" },
        "prices":   { "p_price", "s_price", "w_price", "p_price_pcs", "s_price_pcs" },
        "stock":    { "qty", "pak_qty", "cartons", "low_stock", "stock_value" },
        "sales":    { "sold_qty", "sell_count", "revenue", "profit", "first_sold_at", "last_sold_at", "sold_cartons" },
        "rmb_price": 17.5, "cbm": 0.08,
        "purchases":{ "count", "total_qty", "first_at", "last_at",
                      "last": { "date", "qty", "cartons", "rmb_price", "cbm", "total_cbm", "rmb_cbm_source",
                                "p_price", "supplier", "note", "container": { "name", "code", "usd", "date_down" } } },
        "china":    { "buy", "buyed", "note" },
        "analysis": {
          "score": 87,
          "rating": "excellent",            "rating_ku": "زۆر باش",
          "color": "#16a34a",
          "is_good_seller": true,
          "recommendation": "restock",      "recommendation_ku": "پێویستە بکڕدرێتەوە",
          "trend": "up",
          "metrics": { "sold_qty", "remaining_qty", "sell_through_pct", "months_available",
                       "active_months", "consistency_pct", "avg_monthly_qty",
                       "qty_last_30", "qty_last_90", "qty_prev_90", "qty_last_180", "qty_last_365",
                       "unique_customers", "repeat_customers", "bills",
                       "restocks", "first_purchase_at", "last_purchase_at",
                       "first_sold_at", "last_sold_at", "months_since_last_sale",
                       "stock_cover_months" },
          "reasons": [ { "code": "repeated_restock", "text": "6 جار کڕاوەتەوە — خواستی بەردەوامی هەیە", "positive": true } ]
        }
      }
    ]
  },
  "meta": { "filter", "rating", "sort", "total" }
}
```

## What the verdict means (so the UI copy is right)

* `analysis.is_good_seller` — the **yes/no answer**. `true` = sells well.
* `analysis.rating` — 6 levels. Use `rating_ku` for the label and `color` for the badge:

  | rating | rating_ku | color | meaning |
  |---|---|---|---|
  | `excellent` | زۆر باش | `#16a34a` | sells very well, consistently, to many customers |
  | `good` | باش | `#65a30d` | sells well |
  | `average` | مامناوەند | `#ca8a04` | moves, but irregular or slow |
  | `weak` | لاواز | `#ea580c` | poor movement |
  | `dead` | زۆر لاواز | `#dc2626` | never / almost never sold |
  | `new` | نوێ | `#2563eb` | available < 2 months — too early to judge |

* `analysis.score` 0–100 — show as a small progress ring or bar next to the badge.
* `analysis.recommendation` — what to do; show `recommendation_ku` as an action chip:
  `restock` (buy again — highlight!), `keep`, `watch`, `reduce`, `clear` (sell off, don't reorder), `wait`.
* `analysis.trend` — `up` ↑ green, `down` ↓ red, `stable` →, `none` (no recent sales) hide.
* `analysis.reasons[]` — the explanation. Render each as a line with a ✅ (`positive: true`),
  ❌ (`positive: false`) or ℹ️ (`positive: null`) icon and the Kurdish `text`. Order is already
  meaningful; keep it.

The logic behind the verdict (already applied server-side): a product that was **bought once a long
time ago** and has sold little of it is weak (`single_purchase_slow`); a product that was
**restocked many times** and **sells in most months** to **many different customers** is good
(`repeated_restock`, `consistent_sales`, `many_customers`). Products with **no stock but recent
sales** get `restock`; products with **stock for more than a year** get `overstock`.

## UI spec

### Header
* Shop name, `code`, `shop_number`, WeChat (tap → copy).
* Summary cards: `products`, `remaining_qty` (+ `remaining_cartons`), `sold_qty`, `stock_value`,
  `good_sellers` / `products` with `good_sellers_pct`, `avg_score`.
* A **stacked bar or donut** of `summary.ratings` using the colors above. Tapping a segment applies
  that `rating` filter.
* A row of recommendation counters from `summary.recommendations` (e.g. "🔁 Restock 127").

### Filters / sorting row
* Sort chips: `score` (default on this screen), `sold`, `remaining`, `code`, `name`.
* Rating chips (multi-select) → `rating=` param.
* Stock filter: all / in stock / out of stock → `filter=` param.
* Reload from the API on every change (the endpoint is fast, ~1 s for 400 products). Cache the last
  response for 2–3 minutes.

### Product list (one card per product)
Left: `images.thumb` (fallback placeholder on error).
Center:
* `name` (bold) · `code` · `brand`
* Line 2: **فرۆشراو** `sales.sold_qty` · **ماوە** `stock.qty` (`stock.cartons` کارتۆن)
* Line 3: `unique_customers` کڕیار · `restocks` جار کڕاوە · last sale `last_sold_at` (relative, e.g. "٣ مانگ لەمەوبەر")
* Line 4 (کۆتا کڕین): `purchases.last.date` · ¥`purchases.last.rmb_price` · CBM `purchases.last.cbm`
  (show a small "≈" prefix when `rmb_cbm_source == "product"`, meaning current value, not historical)
Right:
* Rating badge (`rating_ku`, background `color`) + `score` ring
* Trend arrow
* Recommendation chip (highlight `restock` in a filled style)

Tap → product detail bottom sheet / page.

### Product detail (bottom sheet or page)
1. Header: image (`images.medium`), name, code, badge, score, recommendation chip.
2. **"بۆچی؟" (Why?)** — list of `reasons` with ✅ / ❌ / ℹ️ icons. This is the most important
   part: the owner must understand the verdict at a glance.
3. **Numbers grid** from `analysis.metrics`:
   * فرۆشراو / ماوە / کڕدراو (`sold_qty`, `remaining_qty`, `purchased_qty`)
   * ڕێژەی فرۆش `sell_through_pct` %
   * بەردەوامی `consistency_pct` % (`active_months` لە `months_available` مانگ)
   * تێکڕای مانگانە `avg_monthly_qty`
   * کڕیاری جیاواز `unique_customers` · دووبارە `repeat_customers` · پسوڵە `bills`
   * جار کڕاوە `restocks` · یەکەم کڕین `first_purchase_at` · دوا کڕین `last_purchase_at`
   * یەکەم فرۆش `first_sold_at` · دوا فرۆش `last_sold_at`
   * ستۆک بەسە بۆ `stock_cover_months` مانگ
   * **کۆتا کڕین** card from `purchases.last`: بەروار `date` · بڕ `qty` (`cartons` کارتۆن) · نرخ ¥`rmb_price` ·
     CBM `cbm` (کۆی `total_cbm` m³) · کۆنتەینەر `container.name` (`container.code`, دۆلار `container.usd`) ·
     سەپلایەر `supplier` · تێبینی `note`
4. **Mini bar chart** of recent velocity: `qty_last_30`, `qty_last_90`, `qty_prev_90`,
   `qty_last_180`, `qty_last_365`.
5. Button "زانیاری تەواو" → opens the full product page which uses
   `GET /api/app/products/{id}` (sales by month, purchases list, etc.) and
   `GET /api/app/products/{id}/prices` (price chart, similar products). Both are documented in
   `APP_API.md`.

### Empty / error states
* `401` → wrong key screen.
* `404` → "shop not found".
* `products` empty after filters → "هیچ کاڵایەک بەم فلتەرە نییە".

## Display rules
* All text is RTL (Kurdish Sorani). Numbers may stay Latin digits; use thousands separators.
* Prices are **per dozen**; show `s_price` as "نرخ/دەرزەن" and `s_price_pcs` as "نرخ/دانە".
* Dates are `YYYY-MM-DD HH:MM:SS` in Asia/Baghdad; show relative time in lists, full date in detail.
* Treat every numeric field as `double`; `null` is possible for `stock_cover_months`,
  `sell_through_pct`, `months_since_last_sale`, `cartons`, dates.
* Never recompute `score` / `rating` on the client — the server is the single source of truth, so
  the verdict is identical everywhere in the app.

## Minimal Dart model

```dart
class ProductAnalysis {
  final int score;
  final String rating, ratingKu, color, recommendation, recommendationKu, trend;
  final bool isGoodSeller;
  final Map<String, dynamic> metrics;
  final List<AnalysisReason> reasons;

  ProductAnalysis.fromJson(Map<String, dynamic> j)
      : score = (j['score'] as num).toInt(),
        rating = j['rating'],
        ratingKu = j['rating_ku'],
        color = j['color'],
        isGoodSeller = j['is_good_seller'] == true,
        recommendation = j['recommendation'],
        recommendationKu = j['recommendation_ku'],
        trend = j['trend'],
        metrics = Map<String, dynamic>.from(j['metrics']),
        reasons = (j['reasons'] as List).map((r) => AnalysisReason.fromJson(r)).toList();
}

class AnalysisReason {
  final String code, text;
  final bool? positive;
  AnalysisReason.fromJson(Map<String, dynamic> j)
      : code = j['code'], text = j['text'], positive = j['positive'] as bool?;
}
```
