docs: add docs/features scaffold for feature documentation

Introduce docs/features/ with an index (conventions + feature registry),
a per-feature template, and a filled cart example. Reference the structure
from the root CLAUDE.md so context can be restored per feature on demand.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 13:33:37 +03:00
parent ed9d2c1b1f
commit d621baae45
4 changed files with 151 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
# Cart — корзина
## Назначение
Корзина покупателя в SPA (Telegram Mini App): отдаёт текущее содержимое корзины с
посчитанными ценами/итогами, принимает набор позиций из SPA и наполняет ими корзину
OpenCart перед оформлением заказа. Создание самого заказа — за пределами фичи (см.
[order](../order/CLAUDE.md), если описан).
## Точки входа
| action | Метод | Где объявлен |
|------------|-------------------------|------------------|
| `getCart` | `CartHandler::index` | `src/routes.php` |
| `checkout` | `CartHandler::checkout` | `src/routes.php` |
> `storeOrder` (`OrderHandler::store`) относится к оформлению заказа, не к корзине.
## Ключевые файлы по слоям
- **Handler:** `module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CartHandler.php`
`index()` возвращает содержимое корзины, `checkout()` принимает позиции из SPA
(`productId`, `quantity`, `options`) и кладёт их в корзину через `Cart\Cart::add()`.
- **Service:** `module/oc_telegram_shop/upload/oc_telegram_shop/src/Services/CartService.php`
`getCart()` собирает данные через OpenCart-реестр (`OcRegistryDecorator`): язык
`checkout/cart`, проверки стока, веса, цен, форматирование через `Cart\Currency`.
- **OpenCart-зависимости:** `Cart\Cart`, `Cart\Currency` — нативные классы OpenCart,
внедряются через DI.
- **Фронтенд (SPA):**
- `frontend/spa/src/stores/CartStore.js` — Pinia-стор корзины.
- `frontend/spa/src/ShoppingCart.js` — клиентская логика корзины.
- `frontend/spa/src/views/Cart.vue` — экран корзины.
- `frontend/spa/src/components/CartButton.vue` — кнопка/индикатор.
## Поток данных
**Просмотр:** SPA → `action=getCart``CartHandler::index``CartService::getCart()`
читает корзину из OpenCart-реестра → ответ оборачивается `Utf8Cleaner::clean()`
`JsonResponse { data }`.
**Передача в оформление:** SPA отправляет массив позиций → `action=checkout`
`CartHandler::checkout` маппит `options` (берёт `product_option_value_id`) и для каждой
позиции вызывает `$cart->add(productId, quantity, options)` → возвращает очищенные позиции.
## Связанные фичи
- Оформление заказа (`OrderHandler::store` / `OrderCreateService`).
- Настройки (`SettingsService`) влияют на отображение цен/стока в `getCart`.
## Нюансы и подводные камни
- **PHP 7.4.** Без синтаксиса 8.0+ (см. корневой `CLAUDE.md`).
- **Весь вывод чистится `App\Support\Utf8Cleaner::clean()`** перед отдачей — невалидный
UTF-8 из товаров OpenCart ломает `json_encode`.
- **`getCart` зависит от состояния OpenCart-сессии и реестра** (сток, валюта, логин
покупателя, язык `checkout/cart`) — это не чистая функция, результат меняется от конфига
магазина (`config_stock_checkout`, `config_customer_price`, `config_cart_weight` и т.д.).
- **`checkout` мутирует корзину OpenCart** (`Cart\Cart::add`), а не локальное состояние —
он переносит выбор из SPA в нативную корзину OpenCart.