О проекте
Команда: any
Кейс HackAlem.ai: Торговля — Электрокомплект · ekt.kz
Стадия: Доведённый продукт
Задача кейса: AI-консультант по каталогу ekt.kz: товары, аналоги, цены, остатки, корзина
Суть
Встраиваемый чат-виджет консультанта ekt.kz на русском и казахском: поиск по артикулу, остатки, аналоги с объяснением совместимости, условия оплаты и доставки со ссылками на источники. Товар попадает в корзину только после отдельного подтверждения, есть разбор вложений PDF/DOCX/XLSX.
Как устроено
React-виджет работает в Shadow DOM и обращается к Fastify API. API ведёт синтетический или разрешённый live-каталог с индексом кандидатов и проверенные публичные условия покупки, локально разбирает документы и при разрешении подключает шлюз OpenAI для неоднозначных запросов и фото. Корзина меняется по цепочке «сессия → предложение → явное подтверждение»: сервер проверяет origin, CSRF, срок предложения и остаток, а ключ идемпотентности не даёт задублировать товар. Модель не пишет в корзину напрямую, для работы без ключа есть детерминированный fallback.
Ключевые решения
- индекс кандидатов каталога
- подтверждение корзины с CSRF и идемпотентностью
- локальный разбор PDF/DOCX/XLSX
- AI-роутинг с fallback
- ограничение вызовов модели
Особенности
Виджет встраивается одним JS-файлом (EktAssistant.mount), а неизвестные цены и сертификаты не дополняются догадками. Приёмка повторена из чистого клона: 96 backend-тестов, 10 браузерных с подставным API и 4 интеграционных с настоящим API.
Стек
TypeScript · React · Vite · Fastify · Node.js 22 · Playwright · Shadow DOM widget
Модели
OpenAI
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-0571bab2-any.
README
README.mdHackAlem AI — ИИ-помощник Электрокомплекта
Прототип консультанта для ekt.kz: поиск товара и характеристик, наличие, аналоги с объяснением, условия покупки и добавление в корзину только после отдельного подтверждения. Помощник работает поверх подготовленного мокапа сайта и собирается отдельно для встраивания.
По умолчанию используются синтетический каталог и собственная корзина прототипа. Ключи и доступ к ekt.kz для демонстрации не нужны. Это не подключение к реальной корзине ekt.kz.
Быстрый запуск из чистого клона
Нужны доступ к приватному репозиторию, Git, Node.js 22.12+ и npm. Команды ниже рассчитаны на macOS/Linux. Запускать npm ci из указанных каталогов.
git clone [email protected]:BAITC-Hacks/hack-0571bab2-any.git
cd hack-0571bab2-any
Терминал 1 — backend, из корня клона:
cd apps/api
npm ci
CATALOG_MODE=demo AI_PROVIDER=none EXTERNAL_AI_ALLOWED=false WEB_ORIGIN=http://localhost:5173 npm run dev
Терминал 2 — frontend, из корня того же клона:
cd apps/web
npm ci
npm run dev -- --host localhost --port 5173 --strictPort
Открыть http://localhost:5173/ в браузере и нажать кнопку помощника справа внизу. API работает на http://127.0.0.1:3001; Vite проксирует /api/*. Файл .env для этого запуска не нужен. В прототипе поиск по артикулу, корзина, условия и разбор документов работают без внешней модели.
Если порт занят, остановить старый dev-процесс или согласованно изменить порт frontend и WEB_ORIGIN backend. localhost и 127.0.0.1 — разные origin: адрес страницы должен точно совпадать с WEB_ORIGIN. Для другого порта API задать PORT и API_ORIGIN на сервере, а у frontend — VITE_API_PROXY_TARGET, например http://127.0.0.1:3002.
Демонстрация пяти must-have
Начать в новой сессии браузера; в этом каталоге все товары синтетические.
| Действие | Ожидаемый результат |
|---|---|
Есть ABC-123? | 4 единицы, артикул и технические характеристики; явная метка демо. Цена и сертификат в стандартных данных отсутствуют — интерфейс это сообщает. Если API передаёт сертификат, карточка показывает безопасную ссылку. |
Есть ABC-000? | Нулевой остаток, доступный аналог ABC-124 и причина совместимости по известным характеристикам. |
Какие оплата, доставка и минимальная партия? | Ответ по публичным условиям, ссылка на источник; минимальная партия и спорный порог бесплатной доставки не выдаются за подтверждённые факты. |
Добавь 2 шт. ABC-123 | Предложение с количеством; корзина ещё пуста. Только отдельная кнопка «Подтвердить и добавить» меняет её. Сервер повторно проверяет остаток. Повтор подтверждения с тем же ключом не дублирует товар. |
| Перейти по ссылке на корзину | /cart показывает ту же сессию, товар ABC-123 и количество 2. Попытка добавить ещё 3 при остатке 4 отклоняется. |
Сертификат присутствует в контракте и интерфейсе, но ни стандартный синтетический набор, ни подтверждённые сейчас поля live-каталога не дают реальную ссылку. Проверка с настоящим сертификатом остаётся зависимостью от данных партнёра.
Дополнительно проверить: режимы quick chat → половина экрана → полный экран без потери диалога; мобильный вид; переключение РУС/ҚАЗ; повтор запроса после ошибки сети; загрузку небольшого синтетического PDF/DOCX/XLSX/JPEG/PNG. Артикул и количество из документа необходимо проверить вручную; вложение само не меняет корзину.
Архитектура
Страница мокапа / сайт партнёра
└─ React-виджет в Shadow DOM
└─ same-origin /api/* proxy
└─ Fastify API
├─ каталог: синтетические данные / разрешённый live API
├─ проверенные публичные условия покупки
├─ ограниченный локальный разбор PDF/DOCX/XLSX
├─ опциональный OpenAI gateway
└─ сессия → предложение → явное подтверждение → корзина прототипа
apps/web: React/TypeScript/Vite, адаптивный виджет, RU/KZ, клиент API, ручная проверка вложений, подтверждение и страница корзины. Статические карточки мокапа служат оформлением и не являются актуальными фактами ассистента.apps/api: Fastify/TypeScript, каталог, проверка источников, сессии, CSRF, предложения и идемпотентное подтверждение. Модель не записывает в корзину напрямую.- Ввод, результаты и выбранные позиции сохраняются при смене режима виджета. Последние 40 сообщений могут восстанавливаться из
sessionStorageвкладки в течение 30 минут; действующие предложения и содержимое файлов там не сохраняются. Сервер удерживает ограниченный контекст товаров для уточняющих вопросов. - Для изменения корзины клиент сначала получает сессию и CSRF-токен через
GET /api/cart. Затем отдельные POST готовят предложение и подтверждают его. Сервер проверяет origin, CSRF, срок предложения, количество, актуальные товары и остатки.
Подробности: контракт API, backend, frontend и вставка виджета.
Данные и AI
Синтетические позиции ABC-123, ABC-000, ABC-124 покрывают наличие, отсутствие и аналог. В серверном каталоге есть дополнительные вымышленные кабель, розетка, светильник и выключатель для поиска по задаче. Они не являются готовым электротехническим проектом. Неизвестные цены, единицы измерения, сертификаты и остатки не дополняются догадками.
Условия оплаты и доставки основаны на публичных источниках. Условия без подтверждения помечаются как неизвестные.
Live-каталог и OpenAI включаются только локально на backend по его инструкции, после получения необходимых разрешений. API-ключи и Basic Auth не попадают во frontend. При разрешённом включении OpenAI помогает с неоднозначными запросами и фото; факты товара всё равно берутся из каталога. Есть ограничения числа вызовов и параллельности, при сбое работает детерминированный fallback. NVIDIA для запуска не требуется.
PDF с текстовым слоем и таблицы DOCX/XLSX разбираются локально с ограничениями размера, страниц, строк и распаковки. Допускается один файл до 2 МиБ. Распознанные позиции требуют проверки человеком. Для внешнего анализа JPEG/PNG требуется отдельное согласие клиента и разрешение в конфигурации сервера; без них используется ручной сценарий. Документы не отправляются внешней модели. Старые .doc/.xls и OCR сканированных PDF в текущую реализацию не входят.
Сборка и проверки
Backend, из apps/api:
npm run build
npm test
Frontend, из apps/web:
npm run build
npm run test:e2e
Браузерные тесты используют установленный Google Chrome на macOS; на другой машине предварительно установить тестовый браузер командой npx playwright install chromium из apps/web. npm run build создаёт dist/ для демонстрационной страницы и dist-widget/ekt-assistant.js для встраивания. Тесты интерфейса с подставленными ответами API не заменяют ручной совместный сценарий с настоящим сервером.
Совместная браузерная проверка с настоящим API, из apps/web после npm ci в обоих приложениях:
npx playwright test --config playwright.integration.config.ts
Конфигурация сама запускает изолированный API на порту 3010 и frontend на 5180, использует синтетический каталог и отключает внешние AI-вызовы. Порты должны быть свободны; ключи не нужны. Проверяются факты/аналог/условия, явное подтверждение и актуальная корзина, казахский мобильный сценарий с ограничением остатка, изменение количества нескольких позиций, PNG без согласия и ручная проверка PDF перед добавлением.
В интеграционном прогоне 23.09.2026 прошли 96 backend-тестов, 10 браузерных тестов frontend с подставленным API и 4 браузерных сценария с настоящим API. Обе сборки прошли. Тот же результат повторён из чистого общего клона коммита 158f8c9: npm ci в обоих приложениях, обе сборки и все 96 + 10 + 4 проверки прошли; подробности в листе приёмки. Этот прогон использовал синтетические данные без внешних OpenAI-вызовов.
Отдельная проверка с локальным ключом OpenAI прошла на двух синтетических запросах RU/KZ: HTTP 200, успешный ответ модели, 483 входных и 106 выходных токенов суммарно. Корзина не менялась. Учётные данные не сохранены в репозитории.
API-тесты проверяют серверные правила без реальных учётных данных. Отдельно проверены небольшие синтетические PDF/DOCX/XLSX/JPEG на настоящем API: документы вернули кандидатов для ручной проверки, фото без согласия — честный ручной fallback; корзина не изменялась. Итоговую интеграционную проверку выполнять по таблице выше с обеими частями из одного клона.
Встраивание и ограничения прототипа
<script src="/assets/ekt-assistant.js"></script>
<script>
EktAssistant.mount({ apiBase: '/api', locale: 'ru' });
</script>
Разместить после загрузки body. Для реального сайта требуется same-origin reverse proxy, HTTPS, корректные публичные origin и защищённые cookie; Vite proxy относится только к разработке. Подключение одного JS-файла даёт интерфейс, но не создаёт интеграцию с сессией и корзиной партнёра.
- API реальной корзины ekt.kz пока не подключён. Нет оплаты и оформления заказа; платёжные данные не запрашиваются.
- Сессии, корзины и бюджеты модели находятся в памяти процесса и сбрасываются при перезапуске. Для публичного использования нужны постоянное хранилище, согласование экземпляров сервера и ограничения на внешнем proxy.
- Live-поиск ограничен доступными полями, локальным индексом и лимитом запросов. Неполный поиск не означает, что товара точно нет. Неподтверждённые данные цены/сертификата остаются неизвестными.
- Изображение товара не включено в текущий контракт ассистента; используется нейтральная иконка. Скриншоты дизайна не служат источником технических фактов.
- Это демонстрационный прототип, а не завершённое внедрение в production ekt.kz.
Источники требований
ТЗ заказчика хранится отдельно от дополнений пользователя. AGENTS.md описывает правила совместной работы. Русский и казахский включены в интерфейс по указанию пользователя; английский исключён. Официальные правила HackAlem и уточнения партнёра имеют приоритет перед рабочими планами.
Авторы коммитов
История коммитов
- 2026-09-23 18:00fix(api): respond to greetings and clarify requests without requiring SKUKinKazuo
- 2026-09-23 17:50docs: record clean clone and live OpenAI smoke verificationKinKazuo
- 2026-09-23 17:47feat: integrate backend with embedded assistant and verify cart workflowsKinKazuo
- 2026-09-23 17:31docs: flag PNG gap in frontend acceptanceN0l4k
- 2026-09-23 17:30docs: add frontend integration promptN0l4k
- 2026-09-23 17:30docs: record cross-branch acceptance checkN0l4k
- 2026-09-23 17:23fix(web): make standalone widget production-ready and verify clean installKinKazuo
- 2026-09-23 17:19feat(web): embed bilingual EKT assistant with confirmed cart and attachmentsKinKazuo
Все коммиты (33)
- 2026-09-23 17:12fix(api): validate multi-item cart requests and demo catalog searchN0l4k
- 2026-09-23 16:49docs: add persistent HackAlem project briefN0l4k
- 2026-09-23 16:47docs: follow user scope and drop English from requirementsKinKazuo
- 2026-09-23 16:38feat(api): handle Kazakh product lists and harden quantity extractionN0l4k
- 2026-09-23 16:36docs: preserve original customer specification and project requirementsKinKazuo
- 2026-09-23 16:29feat(api): complete Kazakh attachment and cart responsesN0l4k
- 2026-09-23 16:23feat(api): use tiered flagship models and parse document attachmentsN0l4k
- 2026-09-23 16:01feat(api): index live catalog and add guarded photo AI assistanceN0l4k
- 2026-09-23 15:57fix(web): recover cart session after API restartKinKazuo
- 2026-09-23 15:52Revert "feat(web): integrate EKT storefront mockup and assistant"KinKazuo
- 2026-09-23 15:44feat(api): add bounded catalog candidate indexN0l4k
- 2026-09-23 15:38feat(web): integrate EKT storefront mockup and assistantKinKazuo
- 2026-09-23 15:22feat(web): add EKT visual mockup and assistant shellN0l4k
- 2026-09-23 15:20fix(api): honor canceled and expired cart consentN0l4k
- 2026-09-23 15:18fix(web): initialize CSRF session and match API responsesKinKazuo
- 2026-09-23 15:08fix(api): support current web CSRF flow and verify live adapterN0l4k
- 2026-09-23 15:01feat(api): add Kazakh replies and integration runbookN0l4k
- 2026-09-23 14:55fix(api): bound anonymous sessions and live catalog loadN0l4k
- 2026-09-23 14:48feat(web): build verified chat and explicit demo cart flowKinKazuo
- 2026-09-23 14:46feat(api): validate attachment uploads without mutating cartN0l4k
- 2026-09-23 14:31feat(api): add catalog chat and consent-gated demo cartN0l4k
- 2026-09-23 14:03docs: record verified catalog API shapeN0l4k
- 2026-09-23 14:01docs: source buying terms and refine shared design briefN0l4k
- 2026-09-23 13:58docs: add shared two-Codex mission and hourly checkpointsN0l4k
- 2026-09-23 13:55docs: add shared hackathon plan and API contractN0l4k
Структура репозитория (267 файлов)
.gitignore AGENTS.md CUSTOMER_SPEC.md PROJECT_REQUIREMENTS.md README.md apps/api/.env.example apps/api/README.md apps/api/package-lock.json apps/api/package.json apps/api/src/aiRouting.ts apps/api/src/attachments.ts apps/api/src/catalog.ts apps/api/src/catalogIndex.ts apps/api/src/catalogSnapshot.ts apps/api/src/catalogSync.ts apps/api/src/documentExtraction.ts apps/api/src/imageInput.ts apps/api/src/index.ts apps/api/src/modelGateway.ts apps/api/src/policy.ts apps/api/src/server.ts apps/api/test/advanced-chat.test.ts apps/api/test/ai-routing.test.ts apps/api/test/attachments.test.ts apps/api/test/catalog-index.test.ts apps/api/test/catalog-sync.test.ts apps/api/test/catalog.test.ts apps/api/test/conversation.test.ts apps/api/test/demo-categories.test.ts apps/api/test/document-extraction.test.ts apps/api/test/image-input.test.ts apps/api/test/model-gateway.test.ts apps/api/test/server.test.ts apps/api/tsconfig.json apps/web/.gitignore apps/web/README.md apps/web/index.html apps/web/package-lock.json apps/web/package.json apps/web/playwright.config.ts apps/web/playwright.integration.config.ts apps/web/public/assets/about-benefits.jpg apps/web/public/assets/about-clients.png apps/web/public/assets/about-partners.png apps/web/public/assets/about-production.png apps/web/public/assets/about.jpg apps/web/public/assets/category-0.png apps/web/public/assets/category-1.png apps/web/public/assets/category-10.png apps/web/public/assets/category-11.png apps/web/public/assets/category-2.png apps/web/public/assets/category-3.png apps/web/public/assets/category-4.png apps/web/public/assets/category-5.png apps/web/public/assets/category-6.png apps/web/public/assets/category-7.png apps/web/public/assets/category-8.png apps/web/public/assets/category-9.png apps/web/public/assets/hero-main.png apps/web/public/assets/hero-second.png apps/web/public/assets/hero-side.png apps/web/public/assets/low-0.png apps/web/public/assets/low-1.png apps/web/public/assets/low-10.png apps/web/public/assets/low-11.png apps/web/public/assets/low-12.png apps/web/public/assets/low-13.png apps/web/public/assets/low-14.png apps/web/public/assets/low-15.png apps/web/public/assets/low-16.png apps/web/public/assets/low-17.png apps/web/public/assets/low-2.png apps/web/public/assets/low-3.png apps/web/public/assets/low-4.png apps/web/public/assets/low-5.png apps/web/public/assets/low-6.png apps/web/public/assets/low-7.png apps/web/public/assets/low-8.png apps/web/public/assets/low-9.png apps/web/public/assets/news-0.jpg apps/web/public/assets/news-1.jpg apps/web/public/assets/news-2.jpg apps/web/public/assets/news-3.jpg apps/web/public/assets/news-4.jpg apps/web/public/assets/news-5.jpg apps/web/public/assets/news-6.jpg apps/web/public/assets/news-7.jpg apps/web/public/assets/product.jpg apps/web/public/assets/pt-sans-bold.ttf apps/web/public/assets/pt-sans-regular.ttf apps/web/public/assets/sample-product-0.jpg apps/web/public/assets/sample-product-1.jpg apps/web/public/assets/sample-product-2.jpg apps/web/public/assets/sample-product-3.jpg apps/web/public/assets/sample-product-4.jpg apps/web/public/assets/sample-product-5.jpg apps/web/public/assets/sample-product-6.jpg apps/web/public/assets/sample-product-7.jpg apps/web/public/assets/sub-0-0.png apps/web/public/assets/sub-0-1.png apps/web/public/assets/sub-0-2.png apps/web/public/assets/sub-0-3.png apps/web/public/assets/sub-0-4.png apps/web/public/assets/sub-0-5.png apps/web/public/assets/sub-1-0.png apps/web/public/assets/sub-1-1.png apps/web/public/assets/sub-1-10.png apps/web/public/assets/sub-1-2.png apps/web/public/assets/sub-1-3.png apps/web/public/assets/sub-1-4.png apps/web/public/assets/sub-1-5.png apps/web/public/assets/sub-1-6.png apps/web/public/assets/sub-1-7.png apps/web/public/assets/sub-1-8.png apps/web/public/assets/sub-1-9.png apps/web/public/assets/sub-10-0.png apps/web/public/assets/sub-10-1.png apps/web/public/assets/sub-10-2.png apps/web/public/assets/sub-10-3.png apps/web/public/assets/sub-10-4.png apps/web/public/assets/sub-11-0.png apps/web/public/assets/sub-11-1.png apps/web/public/assets/sub-11-2.png apps/web/public/assets/sub-11-3.png apps/web/public/assets/sub-11-4.png apps/web/public/assets/sub-11-5.png apps/web/public/assets/sub-11-6.png apps/web/public/assets/sub-11-7.png apps/web/public/assets/sub-2-0.png apps/web/public/assets/sub-2-1.png apps/web/public/assets/sub-2-10.png apps/web/public/assets/sub-2-11.png apps/web/public/assets/sub-2-12.png apps/web/public/assets/sub-2-13.png apps/web/public/assets/sub-2-14.png apps/web/public/assets/sub-2-15.png apps/web/public/assets/sub-2-16.png apps/web/public/assets/sub-2-17.png apps/web/public/assets/sub-2-18.png apps/web/public/assets/sub-2-19.png apps/web/public/assets/sub-2-2.png apps/web/public/assets/sub-2-20.png apps/web/public/assets/sub-2-3.png apps/web/public/assets/sub-2-4.png apps/web/public/assets/sub-2-5.png apps/web/public/assets/sub-2-6.png apps/web/public/assets/sub-2-7.png apps/web/public/assets/sub-2-8.png apps/web/public/assets/sub-2-9.png apps/web/public/assets/sub-3-0.png apps/web/public/assets/sub-3-1.png apps/web/public/assets/sub-3-2.png apps/web/public/assets/sub-3-3.png apps/web/public/assets/sub-3-4.png apps/web/public/assets/sub-3-5.png apps/web/public/assets/sub-3-6.png apps/web/public/assets/sub-3-7.png apps/web/public/assets/sub-3-8.png apps/web/public/assets/sub-3-9.png apps/web/public/assets/sub-4-0.png apps/web/public/assets/sub-4-1.png apps/web/public/assets/sub-4-10.png apps/web/public/assets/sub-4-11.png apps/web/public/assets/sub-4-12.png apps/web/public/assets/sub-4-13.png apps/web/public/assets/sub-4-14.png apps/web/public/assets/sub-4-15.png apps/web/public/assets/sub-4-16.png apps/web/public/assets/sub-4-17.png apps/web/public/assets/sub-4-18.png apps/web/public/assets/sub-4-2.png apps/web/public/assets/sub-4-3.png apps/web/public/assets/sub-4-4.png apps/web/public/assets/sub-4-5.png apps/web/public/assets/sub-4-6.png apps/web/public/assets/sub-4-7.png apps/web/public/assets/sub-4-8.png apps/web/public/assets/sub-4-9.png apps/web/public/assets/sub-5-0.png apps/web/public/assets/sub-5-1.png apps/web/public/assets/sub-5-2.png apps/web/public/assets/sub-5-3.png apps/web/public/assets/sub-5-4.png apps/web/public/assets/sub-6-0.png apps/web/public/assets/sub-6-1.png apps/web/public/assets/sub-6-2.png apps/web/public/assets/sub-6-3.png apps/web/public/assets/sub-6-4.png apps/web/public/assets/sub-6-5.png apps/web/public/assets/sub-6-6.png apps/web/public/assets/sub-6-7.png apps/web/public/assets/sub-7-0.png apps/web/public/assets/sub-7-1.png apps/web/public/assets/sub-7-10.png apps/web/public/assets/sub-7-11.png apps/web/public/assets/sub-7-12.png apps/web/public/assets/sub-7-13.png apps/web/public/assets/sub-7-2.png apps/web/public/assets/sub-7-3.png apps/web/public/assets/sub-7-4.png apps/web/public/assets/sub-7-5.png apps/web/public/assets/sub-7-6.png apps/web/public/assets/sub-7-7.png apps/web/public/assets/sub-7-8.png apps/web/public/assets/sub-7-9.png apps/web/public/assets/sub-8-0.png apps/web/public/assets/sub-8-1.png apps/web/public/assets/sub-8-10.png apps/web/public/assets/sub-8-11.png apps/web/public/assets/sub-8-12.png apps/web/public/assets/sub-8-13.png apps/web/public/assets/sub-8-2.png apps/web/public/assets/sub-8-3.png apps/web/public/assets/sub-8-4.png apps/web/public/assets/sub-8-5.png apps/web/public/assets/sub-8-6.png apps/web/public/assets/sub-8-7.png apps/web/public/assets/sub-8-8.png apps/web/public/assets/sub-8-9.png apps/web/public/assets/sub-9-0.png apps/web/public/assets/sub-9-1.png apps/web/public/assets/sub-9-10.png apps/web/public/assets/sub-9-11.png apps/web/public/assets/sub-9-12.png apps/web/public/assets/sub-9-2.png apps/web/public/assets/sub-9-3.png apps/web/public/assets/sub-9-4.png apps/web/public/assets/sub-9-5.png apps/web/public/assets/sub-9-6.png apps/web/public/assets/sub-9-7.png apps/web/public/assets/sub-9-8.png apps/web/public/assets/sub-9-9.png apps/web/src/CartPage.tsx apps/web/src/EktSite.tsx apps/web/src/api.ts apps/web/src/assistant/Assistant.tsx apps/web/src/assistant/AttachmentReview.tsx apps/web/src/assistant/Cards.tsx apps/web/src/assistant/i18n.ts apps/web/src/assistant/mount.tsx apps/web/src/assistant/widget.css apps/web/src/catalog.json apps/web/src/errors.ts apps/web/src/main.tsx apps/web/src/news.json apps/web/src/products.json apps/web/src/styles.css apps/web/src/types.ts apps/web/src/vite-env.d.ts apps/web/src/widget.ts apps/web/tests/integration/real-api.spec.ts apps/web/tests/standalone.spec.ts apps/web/tests/widget.spec.ts apps/web/tsconfig.json apps/web/vite.config.ts apps/web/vite.widget.config.ts docs/00_ПОЛНЫЙ_ПЛАН_HackAlem_ekt.md docs/01_ЗАДАНИЕ_BACKEND_Codex.md docs/02_ЗАДАНИЕ_FRONTEND_Codex.md docs/03_КОНТРАКТ_API.md docs/ACCEPTANCE_CHECK_2026-09-23.md docs/BUYING_TERMS_SOURCES.md docs/CATALOG_API_SHAPE.md docs/DESIGN_BRIEF.md docs/FRONTEND_INTEGRATION_PROMPT.md docs/PROJECT_BRIEF.md docs/TEAM_CODEX_PROMPT.md
Ветки (4)
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.