Metadata-Version: 2.5
Name: makea-cli
Version: 0.2.1
Summary: Makea admin CLI (browser login + Makea admin HTTP API)
Requires-Python: >=3.10
Requires-Dist: click<9,>=8.1
Requires-Dist: httpx>=0.27
Requires-Dist: platformdirs>=4.2
Requires-Dist: rich>=13.7
Requires-Dist: typer<0.25,>=0.12
Description-Content-Type: text/markdown

# makea-cli

给 **Makea** 同事（admin）、品牌（designer）和工厂（supplier）用的命令行工具，也是 Beeboo agent 的动作面：连的是线上正式环境，**装好就能用，不用配环境变量、不用改配置文件**。

第一次用时在浏览器里登录一次公司账号，之后在本机保存登录状态，即可查询用户、供应商等（具体能执行哪些命令取决于你的账号权限）。

---

## 怎么用（三步）

1. **安装**（本机需要已安装 [Python 3.10 或以上](https://www.python.org/downloads/)）
  - **从本仓库安装（开发 / 内网 clone）：** 在 `makea-cli/` 目录执行  
   `python3 -m pip install -e .`  
   若提示找不到 `python3`，可改用 `python`。
  - **不经过 GitHub：** 把本包的 **Python** 发行版发布到公司私有 PyPI / Artifact Registry 等，同事执行  
  `python3 -m pip install makea-cli`（或 `pipx install makea-cli`）即可；无需 clone 仓库。
  - **可选 — 用 npm 只占一个全局命令名：** 仓库里 `npm/makea-cli/` 是一个 **薄封装**，`npm install -g` 后会把 `makea-cli` 指到 `python3 -m makea_cli`；**仍需**在同一台机器上先用 `pip` 装好同名 Python 包（npm 不会替你安装 Python 依赖）。适合已经用 npm 管理全局工具的团队。
2. **登录（只需做一次，或过期后再做）**
  ```bash
   makea-cli auth
  ```
   会自动打开浏览器，按公司流程登录即可。完成后可以关掉浏览器标签页。
3. **执行功能**（示例）
  ```bash
   makea-cli admin list user
   makea-cli admin list supplier
   makea-cli admin list product-order
   makea-cli admin list sampling-order --product <product_reference_id>
   makea-cli admin list production-order --product <product_reference_id>
  ```
   **从「产品订单」JSON 下载附件：** `admin list product-order` 返回的每条 `result` 里已有 `user_id` 和 `available_documents`（含 `document_id`、`admin_user_id` 等），一般 **不必再调单独的 document metadata API**。可直接：
   若只有 `product_reference_id`，可用（建议加上设计师 `user_id` 避免扫全库）：
   更多子命令与参数：

退出登录（清除本机保存的令牌）：

```bash
makea-cli auth --logout
```

---

## 登录信息保存在哪

保存在本机当前用户下的应用数据目录里（例如 macOS 常见为 `~/Library/Application Support/makea-cli/`，Linux 常见为 `~/.config/makea-cli/`），文件名类似 `credentials.json`。一般不用手动打开。

---

## 给技术同事：可选环境变量

日常同事 **不需要** 看本节。只有要连 **非线上** 或 **自建环境** 时，才用环境变量覆盖内置地址（默认值在 `makea_cli/config.py` 里）：


| 变量                        | 说明                                             |
| ------------------------- | ---------------------------------------------- |
| `MAKEA_API_BASE_URL`      | API 根地址（无末尾 `/`）                               |
| `MAKEA_COGNITO_DOMAIN`    | Cognito Hosted UI 的**主机名**（不要写 `https://`）     |
| `MAKEA_COGNITO_CLIENT_ID` | Cognito 应用客户端 ID                               |
| `MAKEA_REDIRECT_URI`      | OAuth 回调地址，默认 `http://127.0.0.1:8250/callback` |


---

## 命令一览（0.2 语法）

`makea-cli <persona> <verb> <noun> [参数] [--flags]`。persona 说明谁在操作（`admin` / `designer` / `supplier`，后端按你的 token 校验；CLI 在发请求前也先比对本机登录的用户类型，不匹配 exit 3）；verb 说明读还是写：`list` `get` `search` `download` 是读，`create` `update` `delete` `submit` `upload` `send` `set` `generate` `backfill` 是写。

每条命令都有的开关：`--describe` 打印它的机器可读定义（flags、副作用、审批档位）；`--json` 强制纯 JSON（stdout 不是终端时默认就是）。读命令还有 `--fields a,b,c` 只保留这些字段；`list` 命令还有 `--limit N`（后端自己分页的就透传，不分页的在本地截断并在结果里写明 `truncated` / `returned` / `omitted`）；写命令还有 `--dry-run`（打印将要发出的请求，不发）和 `--idempotency-key <k>`。`makea-cli --describe --json` 打印全量 manifest。

exit code：`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不匹配 · `4` 后端拒绝（4xx，错误 JSON 在 stderr）· `5` 没跑完（5xx / 网络 / 超时）——读命令直接重试即可；**写命令可能已经生效了，重试前先读一遍状态**。

0.1 的平铺命令名（`list-users`、`submit-supplier-quote` …）仍可用，作为隐藏的过渡别名转发到新命令并在 stderr 打一行提示；**下一个 minor 版本删除**。完整的改名对照表在 [CHANGELOG.md](CHANGELOG.md)。

### `admin`

| 命令 | 读/写 | 后端 | 说明 | 旧名 |
|---|---|---|---|---|
| `makea-cli admin backfill supplier-id` | write（never） | `POST /admin/supplier/backfill_supplier_id_with_quote_requests` | Migrate supplier_id from a wrong UUID to the Cognito user sub (user_id): profile + Cognito supplierReferenceId, optio… | `backfill-supplier-id` |
| `makea-cli admin create library-element` | write（auto） | `POST /admin/designer/{user_id}/library_components` | save a reusable component under a designer. Provide --section and --values (see admin get library-schema). | `library-create` |
| `makea-cli admin create quote-request` | write（ask） | `POST /admin/supplier/create_quote_request` | create/send a quote request to a supplier for a product (admin). | `create-quote-request` |
| `makea-cli admin create supplier` | write（ask） | `POST /admin/supplier/add_supplier` | create supplier from JSON file (admin). Run `makea-cli get-supplier-profile-schema` FIRST to get the field taxonomy (… | `add-supplier` |
| `makea-cli admin create user` | write（never） | `POST /admin/users/create` | register a user and confirm the Cognito account in one step (no verification email). Allowed --user-type values: "Fas… | `create-user` |
| `makea-cli admin delete library-element` | write（never） | `DELETE /admin/designer/{user_id}/library_components/{component_id}` | remove a component from the designer's org library. | `library-delete` |
| `makea-cli admin download document` | read | `GET /admin/document/download` | save a document file (document id + designer user_id). | `download-document` |
| `makea-cli admin download product-document` | read | `GET /admin/document/download` | Resolve product via admin list product-order payload, then GET /admin/document/download. | `download-product-document` |
| `makea-cli admin generate pricing-groups` | write（ask） | `POST /admin/production_orders/{id}/details/update` | Lay a production order's variants into pricing groups along one axis (--by style \| colour \| variant \| all) with th… | `production-groups-generate` |
| `makea-cli admin get active-users` | read | `posthog` | Distinct active users per day over the last N days (DAU series). | `analytics-active-users` |
| `makea-cli admin get analytics-query` | read | `posthog` | Run an arbitrary HogQL query (escape hatch). Example: analytics-query "SELECT count() FROM events" | `analytics-query` |
| `makea-cli admin get currency-conversion` | read | `currency-api` | avoids repeated lookups. | `convert-currency` |
| `makea-cli admin get feature-usage` | read | `posthog` | How many distinct users used a feature recently, plus event volume. Matches $pageview path and feature_time_spent eve… | `analytics-feature-usage` |
| `makea-cli admin get library-schema` | read | `GET /admin/library_components/schema` | the tech-pack library taxonomy: sections and their library-role field keys (run this before create/update). | `library-schema` |
| `makea-cli admin get production-pricing` | read | `GET /admin/production_orders/{id}/details` | show a production order's price tiers, MOQ, sizes/colours, pricing groups and cart coverage. | `production-pricing-show` |
| `makea-cli admin get quote-request` | read | `GET /admin/quote_requests/{quote_request_id}` | one quote request in full. | — |
| `makea-cli admin get revenue-metrics` | read | `GET /admin/business-metrics/cumulative-payment-and-platform-revenue` | platform-wide payment received and platform revenue (service fee + transaction fee) bucketed over a date range. | `get-cumulative-payment-and-platform-revenue` |
| `makea-cli admin get supplier-profile-schema` | read | `GET /admin/supplier/profile/schema` | supplier profile v2 schema (section/field taxonomy: sections, fields, options, required rules). | `get-supplier-profile-schema` |
| `makea-cli admin get tech-spec-extraction` | read | `GET /admin/products/{id}/extract-tech-specifications` | AI-generate specs (not saved). | `extract-ai-tech-spec` |
| `makea-cli admin get top-clicks` | read | `posthog` | which buttons/elements get clicked most. | `analytics-top-clicks` |
| `makea-cli admin get top-features` | read | `posthog` | a quick map of which features get used most. | `analytics-top-features` |
| `makea-cli admin list library-element` | read | `GET /admin/designer/{user_id}/library_components` | list a designer's tech-pack library (org-fanned). Optional --section scopes to one type. | `library-list` |
| `makea-cli admin list misc-payment` | read | `GET /admin/products/{id}/misc-payments` | misc payments for one product (admin). | `list-misc-payments-by-product` |
| `makea-cli admin list product-order` | read | `GET /admin/designer/get_all_product_orders` | designer product (SKU) list. For 大货 use admin list production-order or admin list production-order --product. | `list-product-orders` |
| `makea-cli admin list production-order` | read | `GET /admin/production_orders?type=PRODUCTION` | 大货 (production) orders only. For restock use admin list restock-order; for shipping use admin list shipping-order. | `list-all-production-orders` |
| `makea-cli admin list quote-request` | read | `GET /admin/quote_requests` | quote requests, optionally for one product (--product) or one supplier (--supplier, GET /admin/quote_requests/supplie… | — |
| `makea-cli admin list restock-order` | read | `GET /admin/production_orders?type=RESTOCK` | restock orders only. Restock shares the production_orders table; this filters to type=RESTOCK. | `list-all-restock-orders` |
| `makea-cli admin list sampling-order` | read | `GET /admin/sampling_orders/get_all` | paginated list of all sampling orders (admin). | `list-all-sampling-orders` |
| `makea-cli admin list shipping-order` | read | `GET /admin/shipping_orders` | paginated list of all shipping orders (admin). | `list-all-shipping-orders` |
| `makea-cli admin list supplier` | read | `GET /admin/supplier/get_all_suppliers` | list all suppliers (admin). | `list-suppliers` |
| `makea-cli admin list supplier-link` | read | `GET /admin/product/linked_suppliers/by_supplier/{supplier_id}` | direct backend query. | `get-supplier-links-by-supplier-id` |
| `makea-cli admin list user` | read | `GET /admin/users` | list registered users (admin, optional pagination). | `list-users` |
| `makea-cli admin send email` | write（ask） | `POST /admin/email/send` | queue an HTML email (To required, Cc optional). From must be @makea.co; HTML from --html-file or stdin ('-'). Require… | `send-email` |
| `makea-cli admin set pricing-groups` | write（ask） | `POST /admin/production_orders/{id}/details/update` | Set a production order's pricing groups from a JSON file, copy them from the order's quote, or clear them (--clear) t… | `production-groups-set` |
| `makea-cli admin set production-tiers` | write（ask） | `POST /admin/production_orders/{id}/details/update` | Set the order-wide price tiers / MOQ / incoterm / currency on a production order (the schedule used when it has no pr… | `production-tiers-set` |
| `makea-cli admin set production-variants` | write（ask） | `POST /admin/production_orders/{id}/details/update` | Set a production order's available sizes and colours (the grid the buyer's cart and every pricing group's cart keys a… | `production-variants-set` |
| `makea-cli admin submit quote` | write（ask） | `POST /admin/quote_requests/{quote_request_id}/submit_quote` | admin submits a new quote (link) to a quote request. Pricing groups cannot be sent here (the submit endpoint ignores … | `submit-supplier-quote` |
| `makea-cli admin update library-element` | write（auto） | `PATCH /admin/designer/{user_id}/library_components/{component_id}` | update a component's name and/or values (empty value clears a field). | `library-update` |
| `makea-cli admin update quote` | write（ask） | `POST /admin/product/edit_supplier_link_override_info` | admin updates an existing quote (supplier link) in place. Only the options you pass are sent, and the backend leaves … | `update-supplier-quote` |
| `makea-cli admin update quote-request` | write（ask） | `PATCH /admin/quote_requests/{quote_request_id}/update` | set a quote request's stage, status and/or due date. Only what you pass is changed. This is the door that unblocks a … | `update-quote-request` |
| `makea-cli admin update supplier` | write（ask） | `PUT /admin/supplier/update_supplier` | update an existing supplier from a JSON file (admin). Run `makea-cli get-supplier-profile-schema` FIRST to get the fi… | `update-supplier` |
| `makea-cli admin update tech-spec` | write（ask） | `POST /admin/products/{id}/technical-specifications` | persist specs from a JSON file. | `save-product-tech-spec` |
| `makea-cli admin update user` | write（ask） | `PUT /admin/user-profiles/{user_id}/update` | admin updates DynamoDB user profile fields and/or Cognito custom:userType. Allowed --user-type values: "Fashion brand… | `update-user-profile` |
| `makea-cli admin upload financial-document` | write（auto） | `POST /admin/products/{product_id}/financial_documents` | upload one or more files to AWS S3 and return financial document metadata. | `upload-financial-documents` |
| `makea-cli admin upload link-document` | write（auto） | `POST /admin/upload_link_document` | upload a file to AWS S3 and return document domain metadata for reuse as input in other commands. | `upload-link-document` |
| `makea-cli admin upload product-document` | write（auto） | `POST /admin/designer/upload_document` | upload a file to AWS S3 under a product and return document domain metadata for reuse by other commands. | `upload-product-document` |
| `makea-cli admin upload production-order-document` | write（auto） | `POST /admin/production_orders/{production_order_id}/documents` | upload a file to AWS S3 for a production order and return document domain metadata. | `upload-production-order-document` |
| `makea-cli admin upload production-progress-document` | write（auto） | `POST /admin/production_orders/{production_order_id}/progress/{progress_id}/upload` | upload a file to AWS S3 for production progress and return document metadata. | `upload-production-progress-document` |
| `makea-cli admin upload sampling-order-document` | write（auto） | `POST /admin/sampling_orders/{sampling_order_id}/documents` | upload a file to AWS S3 for a sampling order and return document domain metadata. | `upload-sampling-order-document` |
| `makea-cli admin upload supplier-document` | write（auto） | `POST /admin/supplier/upload_document` | upload a supplier document to AWS S3 and return document domain metadata for reuse by other commands. | `upload-supplier-document` |

### `designer`

| 命令 | 读/写 | 后端 | 说明 | 旧名 |
|---|---|---|---|---|
| `makea-cli designer create collection` | write（auto） | `POST /designer/collections/create` | create or update a designer collection. | `designer-create-collection` |
| `makea-cli designer create note` | write（ask） | `POST /designer/products/{product_id}/notes` | post a message into a product's conversation. | — |
| `makea-cli designer create product` | write（ask） | `POST /designer/product/create_or_update_product` | payload must match manufacture/specifications (all frontend fields; categories/subcategories + collection_id in --hel… | `designer-upsert-product` |
| `makea-cli designer create rfq` | write（ask） | `POST /designer/product/send_rfq` | ask the chosen suppliers to quote on a product. --supplier repeats; --makea-sourcing also asks Makea to source. | — |
| `makea-cli designer create sampling-order` | write（ask） | `POST /designer/sampling_orders` | order samples. --file is the full order payload (product_order_id, items, fees …); run --dry-run first and read the b… | — |
| `makea-cli designer download document` | read | `GET /designer/document/download` | save bytes for user_id + document_id (designer-authenticated; same query contract as admin document download). | `designer-download-document` |
| `makea-cli designer get collection` | read | `GET /designer/collections/{collection_id}/overview` | one collection with its products, orders and lifecycle in a single read. | — |
| `makea-cli designer get lifecycle` | read | `GET /designer/product_orders/{product_order_id}/lifecycle` | which stage this product is in. | — |
| `makea-cli designer get product` | read | `GET /designer/get_product` | one product: status, documents, prices, links. | — |
| `makea-cli designer get quote-advice` | read | `GET /designer/product/quote_advice` | which quote to award and why, from cache. Reading never spends a model call; the web app is what asks for a fresh one. | — |
| `makea-cli designer get tech-pack` | read | `GET /designer/products/{product_id}/technical-specifications` | the product's tech pack. | — |
| `makea-cli designer get tech-pack-history` | read | `GET /designer/products/{product_id}/specification-change-history` | who changed which spec field, when, and from what. | — |
| `makea-cli designer list action` | read | `GET /designer/actions` | the pending actions on you, optionally for one product. An action is closed by the fact it asks for, not by acknowled… | — |
| `makea-cli designer list channel` | read | `GET /designer/products/{product_id}/channels` | the product's conversation channels. | — |
| `makea-cli designer list collection` | read | `GET /designer/collections` | the brand's collections. | — |
| `makea-cli designer list library-element` | read | `GET /designer/library_components` | the brand's own shelf (fabrics, trims, colours, artwork); --section narrows to one kind. | — |
| `makea-cli designer list payment` | read | `GET /designer/payments` | your charges and whether they are paid. | — |
| `makea-cli designer list product` | read | `GET /designer/get_all_products` | every product you can see (your own and your team's). | — |
| `makea-cli designer list production-order` | read | `GET /designer/production_orders` | your 大货 orders; --product narrows to one product (GET /designer/product_orders/{id}/production_orders). | — |
| `makea-cli designer list sampling-order` | read | `GET /designer/sampling_orders/user` | your sampling orders; --product narrows to one product (GET /designer/product_orders/{id}/sampling_orders). | — |
| `makea-cli designer list shipping-order` | read | `GET /designer/shipping_orders` | your shipments. | — |
| `makea-cli designer list supplier-link` | read | `GET /designer/product/linked_suppliers` | the suppliers linked to one product, with their quotes. | — |
| `makea-cli designer list task` | read | `GET /designer/tasks` | what the platform is waiting on you for. | — |
| `makea-cli designer search note` | read | `GET /designer/products/{product_id}/channel_search` | full-text search across a product's conversation; --channel narrows to one channel key. | — |
| `makea-cli designer set product-collection` | write（auto） | `POST /designer/products/{id}/link-to-collection` | assign product to a collection. | `designer-link-product-to-collection` |
| `makea-cli designer update action` | write（auto） | `POST /designer/actions/{action_id}/{acknowledge\|snooze\|dismiss}` | respond to one of the pending actions from `designer list action`. An action is closed by the fact it asks for, not b… | — |
| `makea-cli designer update note` | write（ask） | `POST /designer/products/{product_id}/notes/{note_id}/{accept\|reject}` | decide on a task the assistant proposed on a product. | — |
| `makea-cli designer update product` | write（auto） | `POST /designer/product/update_basic_info` | patch fields on a product. --cover-image / --back-image take a document id and are what the assistant's set_product_i… | — |
| `makea-cli designer update proposal` | write（ask） | `POST /designer/beeboo_proposals/approve` | apply one spec change the assistant proposed. This edits the pack, so read the proposal first. | — |
| `makea-cli designer update suggested-action` | write（ask） | `POST /designer/channels/{channel_id}/suggested_actions/bulk_accept` | accept several of a channel's suggested actions in one write. --action takes note_id:action_id and repeats. | — |
| `makea-cli designer update task` | write（auto） | `POST /designer/tasks/{complete\|dismiss}` | close one of the tasks from `designer list task`. Complete means you did it; dismiss means it does not apply. | — |
| `makea-cli designer upload document` | write（auto） | `POST /designer/document/upload` | upload a file for the current designer token; optional product_id (omit to start a new draft id server-side). | `designer-upload-document` |

### `supplier`

| 命令 | 读/写 | 后端 | 说明 | 旧名 |
|---|---|---|---|---|
| `makea-cli supplier create note` | write（ask） | `POST /supplier/products/{id}/channels/{key}/notes` | post a message into a product channel you are part of. | — |
| `makea-cli supplier download document` | read | `GET /supplier/document/download` | save a document you are allowed to read. | — |
| `makea-cli supplier get pack` | read | `GET /supplier/quote_requests/{id}/technical-specifications` | the tech pack for an RFQ, as the factory is allowed to see it. | — |
| `makea-cli supplier get pack-changes` | read | `GET /supplier/products/{product_id}/specification-change-history` | what changed in the pack since you quoted, field by field. | — |
| `makea-cli supplier get profile` | read | `GET /supplier/profile` | your own supplier profile. | — |
| `makea-cli supplier get rfq` | read | `GET /supplier/quote_requests` | one RFQ in full. | — |
| `makea-cli supplier list action` | read | `GET /supplier/actions` | what the platform is waiting on you for (pending actions). | — |
| `makea-cli supplier list channel` | read | `GET /supplier/products/{product_id}/channels` | the channels you are part of on a product. | — |
| `makea-cli supplier list note` | read | `GET /supplier/products/{product_id}/channels/{channel_key}/notes` | the conversation in one channel. | — |
| `makea-cli supplier list production-order` | read | `GET /supplier/production_orders` | your production orders, optionally for one RFQ. | — |
| `makea-cli supplier list quote-edit-request` | read | `GET /supplier/quote_requests/{quote_request_id}/quote_edit_requests` | changes the brand has asked you to make to a quote you already sent. | — |
| `makea-cli supplier list rfq` | read | `GET /supplier/quote_requests` | the RFQs (quote requests) sent to you. | — |
| `makea-cli supplier list task` | read | `GET /supplier/tasks` | your onboarding and per-order to-dos. | — |
| `makea-cli supplier submit quote` | write（ask） | `POST /supplier/quote_requests/{id}/submit_quote` | submit your quote for an RFQ. --file is the supplier link payload as JSON (same shape the web form posts); run with -… | — |
| `makea-cli supplier update action` | write（auto） | `POST /supplier/actions/{action_id}/{acknowledge\|snooze}` | respond to a pending action. Acknowledging says you have seen it; the action still closes on the fact it asks for. | — |
| `makea-cli supplier update quote` | write（ask） | `POST /supplier/quote_requests/{quote_request_id}/links/{link_id}/edit` | revise a quote you already sent. --file is the same payload shape as submit; --dry-run first. | — |
| `makea-cli supplier update rfq` | write（ask） | `POST /supplier/quote_requests/{quote_request_id}/{status\|archive\|accept_terms}` | answer an RFQ. --status accepts or declines the invitation; --archive takes it off your board; --accept-terms accepts… | — |
| `makea-cli supplier update task` | write（auto） | `POST /supplier/tasks/{complete\|dismiss}` | close one of the tasks from `supplier list task`. | — |

其它：`makea-cli auth [--logout]` 登录/登出；`makea-cli version` 版本号。

---

## 大货定价（price tier / 颜色尺码 / pricing group）

一张 production order 的价格由三部分组成：

1. `available_sizes` / `available_colors` — 买家购物车的网格。cart key 是 `"{尺码},{颜色}"`，颜色段有 hex 就用 `hex_code`，没有才退回 `color_name`。所以颜色尽量都给 hex。
2. `production_price_tiers` + `moq` — 整单一套阶梯价。**只在这张单没有 pricing group 时生效**。
3. `pricing_groups` — 若干个各自计价的 cart key 分组。分组回答"谁共用一套价目表"，`tier_basis` / `moq_basis` 回答"按什么量去查这套表"（VARIANT 每个 cart key 各算各的，GROUP 按组内合计，ORDER 按全单合计）。

MOQ 的几种配法就是这两个旋钮的组合：

| 想要的效果 | 命令 |
|---|---|
| 每个 style 自己的阶梯价 + 自己的 MOQ | `--by style --moq-basis group` |
| 每个颜色一个 MOQ，跨所有 style 累计 | `--by colour --moq-basis group` |
| 每个颜色 × 尺码单独计价 | `--by variant --moq-basis group` |
| 全单一套价，MOQ 看全单总量 | `--by all --moq-basis order` |

阶梯写法：`--tier 100-199:7.50 --tier 200-499:7.40 --tier 500+:7.20`。结尾的 `+`（或只写下限）表示不封顶，存成 `max_qty=0`；后端从低到高选，最后一个够 `min_qty` 的档位胜出。

单组覆盖：`--tier-for 'S=100-199:22.45'`、`--moq-for 'S=100'`，等号左边可以写组名、尺码、颜色名或 hex。

例（参考 Lacati 毯子那张报价的形态：三个尺寸各一套价，MOQ 100/组）：

```bash
makea-cli admin set production-variants <po_id> --sizes S,M,L --customized-color
makea-cli admin generate pricing-groups <po_id> --by style \
  --tier-for 'S=100-199:7.50'  --tier-for 'S=300+:7.20' \
  --tier-for 'M=100-199:22.45' --tier-for 'M=300+:21.85' \
  --tier-for 'L=100-199:33.05' --tier-for 'L=300+:32.25' \
  --moq 100 --moq-basis group --tier-basis VARIANT --dry-run
```

几条要记住的：

- 写命令都先打印 plan 再问一次；`--dry-run` 只看不发，`--yes` 跳过确认。默认打的是**生产环境**。
- 购物车里有、却没被任何组认领的 cart key，付款时会整单失败（不是按 0 计价）。plan 和保存结果都会把这些 key 列出来。
- 重跑 `admin generate pricing-groups` 会保留同名/同变体旧组的 `group_id` 和这次没指定的字段，所以"只改 MOQ"是安全的。
- 已经付过款的单，改这里不会动已经收的钱（发票读冻结值），只影响之后的扣款。

---

## Claude / Cursor skills（可选）

仓库内 `.claude/skills/` 下放有面向 agent 的操作说明，例如：

- `supplier-user-id-migration` — 供应商 ID 与 Cognito sub 对齐、与 `admin backfill supplier-id` 配套

