diff --git a/README.md b/README.md index 13cd2de..6e3245c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,6 @@ npm run dev ## Что уже есть - OTP-вход по email через Supabase Auth. -- Служебный вход `roles@local` для демонстрации ролей менеджера, логиста и водителя. - Role-based dashboard для менеджера, логиста и водителя. - Карточка заказа с составом, комментариями и историей. - Публичная страница `/delivery/:token` для выбора даты, половины дня и просмотра состава заказа. @@ -28,7 +27,7 @@ npm run dev - `src/` — интерфейс и клиентская логика. - `supabase/schema.sql` — структура БД, роли, индексы, RLS, триггеры. - `supabase/functions/` — Edge Functions для приглашений, статусов и чат-коммуникаций. -- `supabase/seed/stage-1-demo.sql` — рабочий набор seed-данных для показа. +- `supabase/seed/stage-1-demo.sql` — набор seed-данных для показа заказчику. - `docs/architecture.md` — архитектура фронтенда и модулей. - `docs/product-overview.md` — общий обзор продукта, ролей и сценариев. - `docs/scenarios.md` — сценарии жизненного цикла заказа. diff --git a/docs/customer-demo-readiness-audit-plan.md b/docs/customer-demo-readiness-audit-plan.md new file mode 100644 index 0000000..4d6f883 --- /dev/null +++ b/docs/customer-demo-readiness-audit-plan.md @@ -0,0 +1,299 @@ +# План подготовки приложения к демонстрации заказчику + +Дата проверки: 2026-04-27 +Цель: привести приложение к виду полноценного рабочего продукта перед показом заказчику, без упоминаний тестового, демо, локального, боевого или служебного режима в пользовательском интерфейсе. + +## Краткий вывод + +Приложение частично соответствует последнему продуктовому заданию: есть OTP-вход, роль-ориентированный кабинет, публичная клиентская страница выбора доставки, модель delivery sets, Supabase schema и Edge Functions. Тесты проходят, production build собирается. + +Главная проблема перед показом: в UI и публичных метаданных остались служебные и демонстрационные следы. Также логистический кабинет сейчас не использует готовую доску `LogisticsReadinessBoard`, хотя она описана в ТЗ и уже реализована как отдельный компонент. Из-за этого сценарий логиста в приложении не совпадает с документированным demo/customer flow. + +## Что проверено + +- `docs/product-overview.md` +- `docs/scenarios.md` +- `docs/superpowers/specs/2026-04-13-1c-delivery-ui-design.md` +- `docs/superpowers/plans/2026-04-13-1c-delivery-frontend-supabase.md` +- `src/pages/LoginPage.jsx` +- `src/components/auth/OtpLoginForm.jsx` +- `src/context/AuthContext.jsx` +- `src/pages/DashboardPage.jsx` +- `src/hooks/useOrders.js` +- `src/components/dashboard/RoleWorkspacePanel.jsx` +- `src/components/logistics/LogisticsReadinessBoard.jsx` +- `src/components/logistics/DeliverySetDetailPanel.jsx` +- `src/pages/ClientDeliveryPage.jsx` +- `src/components/client/DeliveryChoiceFlow.jsx` +- `src/components/client/DeliverySlotsPicker.jsx` +- `src/components/driver/DriverDeliveryPlanner.jsx` +- `src/components/driver/DriverDeliveryDetail.jsx` +- `public/manifest.webmanifest` +- `README.md` + +## Проверка команд + +```bash +npm test +``` + +Результат: проходит, 71 test file, 305 tests. + +```bash +npm run build +``` + +Результат: проходит, Vite production build собран. + +```bash +npm run lint +``` + +Результат: падает. Основные проблемы: + +- `src/pages/DashboardPage.jsx`: `React.useMemo` вызывается после условного `return`, нарушение `react-hooks/rules-of-hooks`. +- `src/services/deliveryInvitationApi.js`: неиспользуемые переменные `error` в `catch`. +- `.worktrees/role-focus-dashboard-slice/...`: ESLint также проверяет рабочие worktree-копии и находит там ошибки. Нужно либо исключить `.worktrees` из lint, либо привести эти worktree в порядок/удалить их, если они не нужны. + +## Соответствие ТЗ + +| Блок | Ожидание по ТЗ | Текущее состояние | Статус | +| --- | --- | --- | --- | +| Вход оператора | Email + одноразовый код, без служебных подсказок | Есть OTP, но видны служебный/локальный вход, выбор роли, `roles@local`, `000000`, "Рабочий режим" | Не соответствует для показа | +| Роли | Менеджер, логист, водитель, админ в рабочем контуре | Роли есть, но сохраняются legacy-следы `production_lead` и производственный контур | Частично | +| Логист | `LogisticsReadinessBoard` с наборами доставки | Компонент есть, но `DashboardPage` показывает старые колонки "Сегодня/Завтра/Послезавтра" по отдельным заказам | Не соответствует | +| Delivery sets | Набор доставки как основная единица | Хелперы и компоненты есть, но основной логистический экран их не использует | Частично | +| Клиентская ссылка | `/delivery/:token`, выбор даты и половины дня | Реализовано, flow выглядит близко к ТЗ | В целом соответствует | +| Водитель | Назначенные доставки, адрес, состав, быстрые статусы | Реализовано | В целом соответствует | +| Supabase | Live data, invitations, slots, history | Схема и API есть, но UI показывает "Данные загружены из Supabase, живой контур активен" | Технически есть, copy требует полировки | +| Публичные тексты | Не должно быть "демо", "тест", "локальный", "боевой", "рабочий режим" | Такие тексты найдены в login UI, manifest, README/scenarios | Не соответствует | + +## Найденные замечания + +### P0. Убрать служебный вход и режимные надписи из экрана входа + +Файлы: + +- `src/components/auth/OtpLoginForm.jsx` +- `src/pages/LoginPage.jsx` +- `src/context/AuthContext.jsx` +- `src/components/auth/OtpLoginForm.test.jsx` +- `src/context/AuthContext.test.js` + +Что сейчас видно пользователю: + +- "Для быстрого доступа к рабочим кабинетам можно использовать служебный адрес и выбрать роль вручную." +- "Служебный вход" +- "Локальный вход" +- "Роль для быстрого входа" +- "Войти без кода" +- "Локальный вход использует единый адрес и код 000000." +- "Локальный режим позволяет открыть интерфейс..." +- "Рабочий режим: код отправляется на email..." + +Что нужно сделать: + +- Оставить только обычный сценарий: email -> отправка кода -> ввод кода -> вход. +- Убрать из UI выбор роли на входе. +- Убрать публичное поведение `roles@local`. +- Убрать публичный текст про `000000`. +- Сохранить локальный fallback только как dev-only механизм, если он ещё нужен разработке, но не показывать его в интерфейсе. +- Переписать intro copy: "Введите email, мы отправим одноразовый код для входа." +- После отправки кода оставить нейтральное сообщение: "Код отправлен на указанную почту. Проверьте входящие и папку Спам." +- Обновить тесты, чтобы они проверяли отсутствие служебного/локального/рабочего режима. + +Критерий готовности: + +- На `/login` нет слов: `служебный`, `локальный`, `рабочий режим`, `демо`, `test`, `roles@local`, `local@local`, `000000`, `без кода`. + +### P0. Подключить реальный логистический экран delivery sets + +Файлы: + +- `src/pages/DashboardPage.jsx` +- `src/hooks/useOrders.js` +- `src/components/dashboard/RoleWorkspacePanel.jsx` +- `src/components/logistics/LogisticsReadinessBoard.jsx` +- `src/components/logistics/DeliverySetDetailPanel.jsx` +- `src/pages/DashboardPage.test.jsx` + +Что сейчас не совпадает: + +- ТЗ и `docs/scenarios.md` обещают логисту `LogisticsReadinessBoard`. +- В `DashboardPage.jsx` компонент импортирован не используется. +- Логист видит старый экран с колонками "Сегодня", "Завтра", "Послезавтра" по отдельным заказам. + +Что нужно сделать: + +- Передать `deliverySetBuckets` из `useOrders()` в `RoleWorkspacePanel`. +- Заменить старый `renderLogisticsWorkspace` на `LogisticsReadinessBoard`. +- При клике по набору открывать `DeliverySetDetailPanel`. +- Сохранить понятную карточку заказа там, где она нужна менеджеру. +- Добавить/обновить тест на то, что логист видит "Наборы доставки", "На подходе", "Готово к запуску", "Ожидает клиента", "Нужна ручная работа", "Согласовано", "Завершено". + +Критерий готовности: + +- Логистический сценарий в приложении совпадает с `docs/scenarios.md`. +- Логист работает с наборами доставки, а не с отдельными заказами как главной единицей. + +### P1. Убрать технические баннеры Supabase/live contour из UI + +Файлы: + +- `src/pages/DashboardPage.jsx` +- `src/hooks/useOrders.js` + +Что сейчас видно: + +- "Загружаем данные из Supabase..." +- "Данные загружены из Supabase, живой контур активен." +- Ошибки могут показывать "Supabase" как техническую деталь. + +Что нужно сделать: + +- Заменить на пользовательские формулировки: + - "Загружаем данные..." + - Баннер успешной загрузки убрать полностью. + - Ошибки показывать как "Не удалось загрузить данные. Обратитесь к администратору." +- Технические детали Supabase оставлять только в логах. + +Критерий готовности: + +- В рабочем UI нет слова `Supabase`, кроме внутренних логов/документации для команды. + +### P1. Очистить публичные метаданные и demo wording + +Файлы: + +- `public/manifest.webmanifest` +- `README.md` +- `docs/scenarios.md` +- `docs/product-overview.md` + +Что сейчас найдено: + +- `public/manifest.webmanifest`: "PWA-демо панели заказов и доставки..." +- `README.md`: "Служебный вход `roles@local` для демонстрации ролей..." +- `docs/scenarios.md`: "Demo-скрипт для первого платного milestone" + +Что нужно сделать: + +- В manifest заменить описание на рабочее: "Панель управления доставкой заказов с доступом к кабинетам логиста, водителя и менеджера." +- В README убрать служебный вход из публичного списка "Что уже есть". +- В `docs/scenarios.md` переименовать demo-скрипт в "Сценарий показа заказчику". +- Убрать из пользовательской/презентационной документации `roles@local`, `demo`, `тестовый`, `локальный`, если это не инструкция строго для разработчика. + +Критерий готовности: + +- Поиск по публичным файлам не находит демонстрационные маркеры в пользовательском контексте. + +### P1. Привести lint в зелёное состояние + +Файлы: + +- `src/pages/DashboardPage.jsx` +- `src/services/deliveryInvitationApi.js` +- `eslint.config.js` или `.eslintignore`/аналогичная настройка +- `.worktrees/`, если они остаются в репозитории/рабочей папке + +Что нужно сделать: + +- Перенести `useMemo` в `DashboardPage.jsx` выше раннего `return`, чтобы hooks всегда вызывались в одном порядке. +- В `deliveryInvitationApi.js` заменить `catch (error)` на `catch` там, где переменная не используется. +- Исключить `.worktrees/**` из lint, если эти директории не являются частью основного приложения. +- Повторно запустить `npm run lint`. + +Критерий готовности: + +- `npm run lint` проходит без ошибок. + +### P2. Убрать устаревшие производственные экраны из маршрута показа + +Файлы: + +- `src/constants/roles.js` +- `src/constants/deliveryWorkflow.js` +- `src/components/dashboard/ProductionQueuePanel.jsx` +- `src/components/orders/OrderEditorPanel.jsx` +- `src/services/orderService.js` +- `src/data/mockAppData.js` + +Что сейчас может сбивать: + +- `production_lead`, "Начальник производства", "Очередь производства". +- `OrderEditorPanel` всё ещё выглядит как форма ручного создания/редактирования заказа. +- `createOrder` и уведомление "Новый заказ" остаются в hook, хотя ТЗ говорит, что заказы приходят из 1С. + +Что нужно сделать: + +- Проверить, доступны ли эти экраны из текущего UI. Если недоступны, оставить как legacy code с задачей на последующую чистку. +- Если доступны, убрать их из демонстрационного маршрута. +- Для менеджера оставить только просмотр реестра, поиск и карточку заказа. +- Не показывать создание заказа как пользовательскую возможность. + +Критерий готовности: + +- На показе нет сценария ручного создания заказа в web app. +- Заказ в интерфейсе воспринимается как импортированный из 1С. + +### P2. Финальная визуальная проверка всех ролей + +Файлы: + +- UI-компоненты по факту найденных визуальных замечаний. + +Что нужно сделать: + +- Открыть `/login`. +- Проверить вход оператора. +- Проверить кабинет менеджера. +- Проверить кабинет логиста. +- Проверить кабинет водителя. +- Проверить `/delivery/client-flow-1001`. +- Проверить мобильную ширину для `/login`, `/dashboard`, `/delivery/client-flow-1001`. + +Чеклист: + +- Нет служебных/локальных/demo/test/боевых/рабочих режимов. +- Нет технических баннеров про Supabase/live contour. +- Тексты звучат как рабочий продукт, а не как стенд. +- Логист видит delivery sets. +- Клиентская страница понятна без объяснений команды. +- Водительский экран показывает только назначенные доставки и действия маршрута. + +## Рекомендуемый порядок работ + +1. Исправить экран входа и auth-copy. +2. Подключить `LogisticsReadinessBoard` в `DashboardPage`. +3. Убрать технические баннеры и режимные тексты из dashboard. +4. Очистить manifest/README/scenarios от demo wording. +5. Починить lint. +6. Пройти ручной smoke test по ролям. +7. Подготовить короткий сценарий показа заказчику. + +## Команды финальной проверки + +```bash +npm test +npm run lint +npm run build +rg -n "(demo|демо|test|тест|боев|рабочий режим|локальный|служебный|roles@local|local@local|000000|без кода|живой контур|Supabase)" src public README.md docs/product-overview.md docs/scenarios.md -S +``` + +Ожидание: + +- `npm test` проходит. +- `npm run lint` проходит. +- `npm run build` проходит. +- `rg` не находит запрещённые слова в пользовательском UI и публичных материалах. Допустимы только внутренние тесты, dev-only комментарии и техническая документация, не используемая в демонстрации. + +## Definition of Done + +- Экран входа выглядит как production-ready вход по email-коду. +- Все режимные и служебные подсказки убраны из UI. +- Логистический кабинет работает по delivery sets. +- Клиентская ссылка работает и не содержит технических пояснений. +- Водительский кабинет показывает назначенные доставки и статусы маршрута. +- Публичные метаданные приложения не называют продукт демо. +- Тесты, lint и build зелёные. +- Есть отдельный сценарий показа заказчику без внутренних технических деталей. diff --git a/docs/scenarios.md b/docs/scenarios.md index b0e8b73..e6d5160 100644 --- a/docs/scenarios.md +++ b/docs/scenarios.md @@ -10,14 +10,14 @@ ## 2. Логист открывает рабочее пространство доставки 1. Логист видит **LogisticsReadinessBoard** — доску с наборами доставки, сгруппированными по статусам: - - **На подходе**: не все заказы набора приняты ОТК. + - **На подходе**: не все заказы набора прошли контроль качества. - **Готово к запуску**: все заказы приняты, можно запускать доставку. - **Ожидает клиента**: отправлено приглашение, ждём ответа. - **Нужна ручная работа**: передано логисту, платное хранение, проблема. - **Согласовано**: клиент подтвердил слот. - **Завершено**: все заказы доставлены. 2. Клик по набору открывает **DeliverySetDetailPanel** с: - - Перечнем заказов набора, их 1С-номерами и шагами производства (раскрой, склейка, криволинейные, приёмка ОТК, отгрузка). + - Перечнем заказов набора, их 1С-номерами и шагами производства (раскрой, склейка, криволинейные, контроль качества, отгрузка). - Телефоном и email клиента, городом, связанными счетами. - Текущим статусом слота. 3. Логист может запустить приглашение, назначить водителя или перейти к ручной обработке. @@ -55,16 +55,16 @@ 2. После закрытия всех заказов набора он переходит в «Завершено». 3. В истории появляется финальная запись, а чат закрывается для активных действий. -## Demo-скрипт для первого платного milestone +## Сценарий показа заказчику -1. Зайти под логистом (email: `mk7029953@yandex.ru`). -2. На дашборде увидеть LogisticsReadinessBoard с наборами: +1. Зайти под логистом. +2. На дашборде увидеть `LogisticsReadinessBoard` с наборами: - Волкова М.А. — «На подходе» (кухня готова, столешница ещё в производстве). - - Савин А.П. — «Готово к запуску» (все заказы приняты ОТК). + - Савин А.П. — «Готово к запуску» (все заказы прошли контроль качества). - Тарасова Е.И. — «Ожидает клиента» (приглашение отправлено). - Фролова И.Д. — «Нужна ручная работа» (платное хранение). - Орлова Н.С. — «Завершено». 3. Кликнуть по набору Савина — увидеть source-поля, production-шаги, готовность к запуску. -4. Перейти на публичную страницу приглашения — увидеть DeliverySlotsPicker с выбором даты и половины дня. +4. Перейти на публичную страницу приглашения — увидеть `DeliverySlotsPicker` с выбором даты и половины дня. 5. Зайти под водителем — увидеть назначенные доставки с адресами и быстрыми действиями. -6. Зайти под несуществующим email — увидеть «Email не найден в системе. Обратитесь к администратору.» \ No newline at end of file +6. Зайти под несуществующим email — увидеть «Email не найден в системе. Обратитесь к администратору.» diff --git a/eslint.config.js b/eslint.config.js index dd2f86d..054a7d9 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -5,7 +5,7 @@ import reactHooks from "eslint-plugin-react-hooks"; export default [ { - ignores: ["dist/**", "node_modules/**"], + ignores: ["dist/**", "node_modules/**", ".worktrees/**"], }, js.configs.recommended, { diff --git a/public/manifest.webmanifest b/public/manifest.webmanifest index b8b7166..107202f 100644 --- a/public/manifest.webmanifest +++ b/public/manifest.webmanifest @@ -1,7 +1,7 @@ { - "name": "Школьное питание Demo", + "name": "Школьное питание", "short_name": "Школьное питание", - "description": "PWA-демо панели заказов и доставки с офлайн-доступом после первого запуска.", + "description": "Панель управления доставкой заказов с доступом к кабинетам логиста, водителя и менеджера.", "start_url": "/dashboard", "scope": "/", "display": "standalone", diff --git a/src/components/admin/UserDirectoryPanel.jsx b/src/components/admin/UserDirectoryPanel.jsx index 0a3ee24..7661027 100644 --- a/src/components/admin/UserDirectoryPanel.jsx +++ b/src/components/admin/UserDirectoryPanel.jsx @@ -47,9 +47,8 @@ export const UserDirectoryPanel = ({ currentUser, users }) => {
- Практичный сценарий: сотрудник добавляется по электронной почте и телефону, получает роль, после - чего к нему привязываются идентификаторы каналов. Для ботов лучше иметь два варианта - привязки: по номеру телефона и по имени пользователя или идентификатору в конкретном - мессенджере. + Сотрудник добавляется по электронной почте и телефону, получает роль и может получать + рабочие уведомления выбранным способом.
- Введите email, и код придет на почту. Для быстрого доступа к рабочим кабинетам можно - использовать служебный адрес и выбрать роль вручную. -
+ {!isOtpSent ? ( ++ Введите email, и мы отправим одноразовый код для входа. +
+ ) : null}- {isServiceAccessMode ? "Служебный вход" : "Локальный вход"} -
-- {isServiceAccessMode - ? "Выберите кабинет и войдите сразу без подтверждения кода." - : "Локальный вход использует единый адрес и код 000000."} -
-{item.text}
+{text}
+{answer}
+- Интерфейс показывает только то, что нужно для повседневной работы в доставочном контуре. -
-Отправка уведомлений и фиксация ответов клиента в истории заказа.
@@ -36,10 +36,8 @@ export const BotControlPanel = ({- Редактирование импортированного из 1С заказа с полями клиента, канала связи и даты доставки. + Редактирование импортированного из 1С заказа с полями клиента, способом связи и датой доставки.