Декомпозиция POS Phase 1 — Tables Canvas + order_type

Источник

План desktop-pos: «Точка управления заведением» — Phase 1 (см. план в ~/.claude/plans/jolly-crunching-lighthouse.md). Превращает desktop-pos из чистой кассы в HoReCa-точку управления.

Цель

Кассир выбирает тип заказа (takeaway / dine_in / delivery); для dine_in — открывает план зала с расположенными столами и привязывает заказ к столу. Менеджер может перемещать столы и редактировать вместимость/номер/подпись.

Затронутые сервисы / репозитории

СлойРепоЗадачи
desktop-poserp-pos-desktopDesktop POS
POS BFFerp-pos (bff/)POS BFF
Store Serviceerp-store-serviceStore Service

Backend готов на 95% до Phase 1

ZalTable entity, StoreService с CRUD/reserve/release/assignWaiter, public API под requireEdit, internal endpoints для list/get/lifecycle — всё уже было в составе ранее закрытых задач (пра-родитель — BR 2.5 dine-in flow + BR 3.2 waiter assignment). Phase 1 добавляет только internal CRUD + waiter (для POS BFF) и полностью новый фронт.

Последовательность выполнения

  1. Store Service — расширить InternalZalTableController (POST/PATCH/DELETE/PATCH waiter). Сервисный слой уже умеет всё. Деплой первым.
  2. POS BFF — новые routes (CRUD + waiter), новый middleware requireManager (требует pos.settings.edit). Деплой после Store Service.
  3. desktop-pos — domain types, api-client endpoints, ui-components (OrderTypeSwitcher, TableTile), TablesScreen с canvas+drag-edit, мock endpoints, расширение cartStore + MainScreen.

Decision points

  • Plan layout: canvas + drag-and-drop сразу, не grid (по запросу пользователя).
  • Halls/zones: отказ — плоский namespace столов на ТТ.
  • Manager permission: используем существующий pos.settings.edit (был в списке для cashier-stub), не вводим новый. Если в будущем понадобится точечный — заведём pos.tables.manage.
  • Mock: 6 seed-столов разных статусов для проверки UI без backend (free / occupied / reserved / VIP).
  • Coordinate system: position_x/y — пиксели от верхнего левого угла канваса (ограничено canvas.width - TILE_SIZE). Не нормализуем в 0–1000 — Tauri окно фиксированного размера, проще хранить пиксели.
  • Auto-release: уже работает через Kafka order.status.changed consumer (BR 2.5) — Phase 1 ничего не делает.

Acceptance criteria (PASS)

  1. ✅ Кассир открывает /tables, видит план: столы расположены по position_x/y, цвет зависит от статуса (free=зелёный, occupied=красный, reserved=жёлтый).
  2. ✅ Tap по свободному столу → action sheet → «Открыть заказ» → MainScreen с предзаполненным order_type=dine_in и tableId.
  3. ✅ Auto-release при закрытии заказа (Kafka consumer уже работает).
  4. ✅ Manager входит в режим «Редактировать план» → drag стола → PATCH сохраняет → перезагрузка показывает новую позицию.
  5. ✅ Бронь со временем — reserved_until сохраняется, статус reserved на UI.
  6. ✅ Tap на занятый стол → action sheet → «Открыть заказ» (deep-link на /orders/:id).
  7. ✅ Manager edit-mode: создание / редактирование / удаление столов через TableEditModal.

Прогресс

  • Store ServiceInternalZalTableController extended: POST /by-store/{storeId} (create), PATCH /{id} (update position/capacity/number/label), DELETE /{id} (soft delete), PATCH /{id}/waiter (BR 3.2 assign/unassign waiter)
  • POS BFFroutes/tables.ts extended (5 новых endpoints), middleware/auth.ts requireManager (требует pos.settings.edit поверх requireCashier)
  • desktop-pos:
    • domain types ZalTable, TableStatus, Create/Update/Reserve/AssignWaiterRequest
    • api-client createTablesEndpoints (9 методов)
    • UI: OrderTypeSwitcher (segmented), TableTile (canvas-positioned)
    • tablesStore (load/CRUD/lifecycle, auto-reload 30 сек)
    • TablesScreen (canvas с drag-edit manager-only)
    • Components: ReservationModal, TableActionSheet, TableEditModal
    • cartStore extended: orderType, tableId, tableNumber, setOrderType, setTable
    • MainScreen — OrderTypeSwitcher в чеке + индикатор стола + dine_in блокирует checkout без tableId
    • Mock endpoints + 6 seed-столов (для VITE_USE_MOCK_BFF=true)
    • App.tsx /tables route + AppShell.tsx nav-item «Столы»

Verification

  • TypeScript desktop-pos: zero errors (pnpm typecheck)
  • Vite build: passing
  • POS BFF tsc: новые правки без ошибок (pre-existing ошибка в catalog.ts не связана)
  • Store Service: maven build в Docker (Java 21) — passing на VPS
  • VPS deploy: store-service + pos-bff healthy после docker compose up -d --force-recreate

Out of scope (отложено в следующие фазы)

  • Phase 2: dine-in append-items («Добавить позиции» в существующий заказ), WaiterPickerModal, TableOrderScreen (детали активного заказа стола)
  • Phase 3: Customer attach по телефону, Manager-PIN approval, ручная скидка
  • Phase 4: Aggregator inbox в POS, авто-снятие истёкших броней (cron в Java)
  • Phase 5: Tips Нетмонет, KDS by stations
  • Phase 6: Reports в POS, Printer config, hotkeys, kiosk mode

Ссылки