Эпик 3 ревью: каталог через SDK Zeus + модерация FIFO + edit clear #4

Merged
ant merged 2 commits from chore/review-E3-vitrina-fixes into marketplace2 2026-05-20 16:59:40 +00:00
Owner

Ревью Эпика 3 «Витрина, публикация, модерация, каталог офферов».

CRITICAL: MarketplaceCatalog/api использовал raw GraphQL строки с sendPOST('/v1/graphql', ...) и shape API не совпадал с backend (offset/sort vs page/sortOrder, total vs totalCount). Теперь:

  • Новые SDK queries: Queries.Marketplace.ListCatalog, Queries.Marketplace.CategoryOfferCounts (sdk/src/queries/marketplace/).
  • desktop/.../MarketplaceCatalog/api/index.ts полностью переписан через @coopenomics/sdk Queries + client.Query.
  • types.ts: total→totalCount/totalPages/currentPage.
  • MarketplaceCatalogPage: pagination через page вместо offset, mapSort('created_at_desc'|'price_*') → {sortBy, sortOrder}.

CRITICAL: marketplaceListPendingOffers (модерация) дефолт sortOrder DESC → ASC (FIFO — первой берётся самая старая заявка, как требует AC Story 3.3).

HIGH: при edit ACTIVE-оффера статус сбрасывался в PENDING_MODERATION, но поля approved_by/approved_at/rejected_by/rejected_at/reject_reason оставались — UI показывал stale данные. Теперь явно обнуляются в normalizedPatch.

Открытые фоллоуапы (не в этом PR):

  1. CRITICAL: 10 категорий в AC Story 3.5 vs 9 продовольственных в коде (BASELINE_CATEGORY_IDS=[1..9], @Max(9) в DTO). Требует решения PRD/PM.
  2. CRITICAL: admin-UI для whitelist (3.1) и модерации (3.3) не реализован на desktop — все страницы Marketplace в роутере закомментированы.
  3. HIGH: AC Story 3.2 «edit REJECTED» противоречит requireOwnedEditable (403 на REJECTED). Решение: либо разрешить edit с clear reject_*, либо добавить marketplaceCloneOffer.
  4. HIGH: isOfferer-кеш per-process (60s) → multi-replica дрейф. Нужно вытащить в Redis или снизить TTL.
  5. HIGH: CatalogPage не показывает supplier_name, category_badge, cycle-формулировки, warranty_days.
  6. HIGH: barcode_strategy/pack_size не передаются из CreateOffer UI.
  7. MEDIUM: applyConsumeDelta без status=ACTIVE проверки (применимо к WITHDRAWN-офферам).
  8. MEDIUM: hasActiveOrders заглушка (всегда false), AC Story 3.2 «withdraw блокируется при незакрытых Order'ах» не выполнен.

Тесты: 168/169 marketplace зелёные (1 фейл geocoder-factory — Эпик 2, фикс в PR #2). Controller tsc чист.

Ревью Эпика 3 «Витрина, публикация, модерация, каталог офферов». CRITICAL: MarketplaceCatalog/api использовал raw GraphQL строки с sendPOST('/v1/graphql', ...) и shape API не совпадал с backend (offset/sort vs page/sortOrder, total vs totalCount). Теперь: - Новые SDK queries: Queries.Marketplace.ListCatalog, Queries.Marketplace.CategoryOfferCounts (sdk/src/queries/marketplace/). - desktop/.../MarketplaceCatalog/api/index.ts полностью переписан через @coopenomics/sdk Queries + client.Query. - types.ts: total→totalCount/totalPages/currentPage. - MarketplaceCatalogPage: pagination через page вместо offset, mapSort('created_at_desc'|'price_*') → {sortBy, sortOrder}. CRITICAL: marketplaceListPendingOffers (модерация) дефолт sortOrder DESC → ASC (FIFO — первой берётся самая старая заявка, как требует AC Story 3.3). HIGH: при edit ACTIVE-оффера статус сбрасывался в PENDING_MODERATION, но поля approved_by/approved_at/rejected_by/rejected_at/reject_reason оставались — UI показывал stale данные. Теперь явно обнуляются в normalizedPatch. Открытые фоллоуапы (не в этом PR): 1. CRITICAL: 10 категорий в AC Story 3.5 vs 9 продовольственных в коде (BASELINE_CATEGORY_IDS=[1..9], @Max(9) в DTO). Требует решения PRD/PM. 2. CRITICAL: admin-UI для whitelist (3.1) и модерации (3.3) не реализован на desktop — все страницы Marketplace в роутере закомментированы. 3. HIGH: AC Story 3.2 «edit REJECTED» противоречит requireOwnedEditable (403 на REJECTED). Решение: либо разрешить edit с clear reject_*, либо добавить marketplaceCloneOffer. 4. HIGH: isOfferer-кеш per-process (60s) → multi-replica дрейф. Нужно вытащить в Redis или снизить TTL. 5. HIGH: CatalogPage не показывает supplier_name, category_badge, cycle-формулировки, warranty_days. 6. HIGH: barcode_strategy/pack_size не передаются из CreateOffer UI. 7. MEDIUM: applyConsumeDelta без status=ACTIVE проверки (применимо к WITHDRAWN-офферам). 8. MEDIUM: hasActiveOrders заглушка (всегда false), AC Story 3.2 «withdraw блокируется при незакрытых Order'ах» не выполнен. Тесты: 168/169 marketplace зелёные (1 фейл geocoder-factory — Эпик 2, фикс в PR #2). Controller tsc чист.
ant added 1 commit 2026-05-20 14:07:42 +00:00
ant reviewed 2026-05-20 15:02:41 +00:00
@@ -31,8 +31,10 @@ export interface MarketplaceOfferView {
}
export interface MarketplaceOfferPage {
Author
Owner

А нельзя чтоль взять IOutput с запроса нормально также как я везде беру и использовать напрямую? Зачем здесь тип переопределять если можно этого не делать??

А нельзя чтоль взять IOutput с запроса нормально также как я везде беру и использовать напрямую? Зачем здесь тип переопределять если можно этого не делать??
@@ -0,0 +8,4 @@
{ input: $('input', 'MarketplaceListCatalogInput') },
{
items: marketplaceOfferSelector,
totalCount: true,
Author
Owner

У меня есть PaginatedSelector!! Через него делать надо! Если не подходит - значит ты нарушил канон и надо переделывать пагинацию! Должно подходить.

У меня есть PaginatedSelector!! Через него делать надо! Если не подходит - значит ты нарушил канон и надо переделывать пагинацию! Должно подходить.
ant added 1 commit 2026-05-20 16:08:10 +00:00
По ревью-комментариям к PR #4 (Эпик 3 vitrina):

1. categoryOfferCounts.ts query: было inline-объявление полей в
   `Selector('Query')(...)`. Создан селектор
   `marketplaceCategoryOfferCountSelector` с _validate-проверкой
   на `MakeAllFieldsRequired<ValueTypes['MarketplaceCategoryOfferCount']>`,
   query использует его.

2. listCatalog.ts query: было inline `{ items, totalCount, totalPages,
   currentPage }`. Создан селектор `marketplaceOfferPaginationSelector`
   (по канону `paginatedAgreementsSelector`, `paginatedMarketplace
   WriteoffProposalsSelector`) на тип `MarketplaceOfferPaginationResult`
   с _validate. Query берёт его целиком.

3. MarketplaceCatalog/types.ts: убраны ручные типы `MarketplaceOfferView`,
   `MarketplaceOfferPage`, `MarketplaceCategoryView`,
   `MarketplaceCategoryOfferCount` — теперь все четыре выведены из
   `Queries.Marketplace.{ListCatalog,ListCategories,CategoryOfferCounts}.
   IOutput`. Канон как в других страницах desktop'а.

4. api/index.ts: убраны `as MarketplaceOfferPage`/`as
   MarketplaceCategoryView[]`/`as MarketplaceCategoryOfferCount[]` cast'ы
   и `?? []` fallback'и — destructure от Queries даёт уже типизированный
   результат через IOutput.

5. selectors/marketplace/index.ts: добавлены оба новых selector файла.

SDK перебилжен (unbuild succeeded, 438 kB). controller/tsc + vue-tsc по
изменённым файлам без ошибок.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ant merged commit 333212593f into marketplace2 2026-05-20 16:59:40 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: C9S/mono#4