AAYMA
RU
Войти

EKT AI-помощник

Витрина и AI-консультант по каталогу ekt.kz: чат ищет товары через реальный API магазина, показывает карточки с ценой и остатками по складам…

Рабочий MVP
Команда «Pozers» 2💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: Pozers
Кейс HackAlem.ai: Торговля — Электрокомплект · ekt.kz
Стадия: Рабочий MVP

Задача кейса: AI-консультант по каталогу ekt.kz: товары, аналоги, цены, остатки, корзина

Суть

Витрина и AI-консультант по каталогу ekt.kz: чат ищет товары через реальный API магазина, показывает карточки с ценой и остатками по складам, позволяет собрать серверную корзину; есть «ревизор закупки» для проверки списков.

Как устроено

Backend на Express проксирует ekt.kz/api/products (Basic Auth), ищет по первым 3 страницам каталога с приоритетом «точный артикул → подстрока артикула → название» и 3-минутным кэшем, отдельно получает detail (quantity, stores, properties). Чат на OpenAI Responses API с инструментами search_products и get_product_detail: модель по строгой JSON-схеме выбирает ID и поля, а русский текст ответа собирает сервер из реальных данных, чтобы AI не выдумывал цену или остаток. Корзина хранится в сессии backend и меняется только после подтверждения пользователя.

Ключевые решения

  • function calling
  • strict JSON schema
  • OpenAI Responses API
  • ранжирование поиска по артикулу
  • кэширование каталога
  • серверная сборка ответа из реальных полей

Особенности

Ответ пользователю собирает сервер из реальных полей API, а свободный текст модели наружу не попадает, поэтому AI не может подставить свою цену, остаток или название. В README честно описаны ограничения: поиск только по первым 3 страницам каталога, нет уменьшения количества в корзине, доставка не посчитана.

Стек

Node.js · Express · JavaScript · HTML/CSS · OpenAI SDK · node:test

Модели

gpt-5.6-luna (OpenAI)


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-ad95268c-pozers.

README

README.md

EKT — электротехника и AI-помощник

Командный проект Pozers для HackAlem AI. Основной сайт находится в frontend/, backend — в src/. Папка ekt-frontend/ содержит reference-версию; отдельно запускать её для общего сайта не нужно.

Быстрый запуск

Требуется Node.js 22+ и зависимости проекта. Из корня репозитория:

npm ci

Настройки доступа к EKT и OpenAI задаются только в локальном .env по .env.example. Не публикуйте ключи. Если .env уже есть, сохраняйте существующие настройки. Подробности переменных приведены в разделе backend ниже.

Запустите два процесса в разных терминалах:

npm run dev
npm run frontend

Откройте http://localhost:4173. Backend по умолчанию: http://localhost:3000. Открытие через file:// не поддерживается; используйте localhost для обоих процессов. В PowerShell при блокировке npm.ps1 замените npm на npm.cmd.

Текущая версия интерфейса

  • Главная-витрина с отдельными панелями AI-помощника и корзины. Чат по умолчанию закрыт, история и черновик сохраняются при открытии и закрытии.
  • Поиск по названию и артикулу среди уже загруженных товаров из ответов чата и текущей корзины: очистка, число результатов, фильтр наличия, пустое состояние. Ввод в поиск не вызывает AI. Загрузка всего каталога через API в этом интерфейсе ещё не подключена.
  • На карточках показано подтверждённое количество. Поле «Нужное количество в корзине» задаёт желаемый итог: при 2 уже добавленных выбор 3 подготавливает добавление 1. До подтверждения и успешного ответа сервера корзина не меняется.
  • Количество 0 предлагает удалить всю позицию через существующую серверную операцию и отдельное подтверждение. Уменьшение до ненулевого количества пока недоступно: существующий API не предоставляет такую операцию.
  • Ревизор закупки использует прежнюю проверку списков и общую серверную корзину.
  • Неизвестные цена, остаток, единица измерения и условия покупки не выдумываются. Сертификат выводится только при наличии ссылки в данных; текущий адаптер не передаёт сведения о сертификатах, единицах и характеристиках карточек.
  • Доставка не включена в подытог товаров. Её стоимость, сроки, способы оплаты и минимальная партия пока не подтверждены.

Корзина хранится в сессии backend проекта. Она не оформляет заказ, не резервирует товар и не изменяет корзину магазина ekt.kz.

Файлы витрины: frontend/index.html, frontend/app.js, frontend/storefront.js, frontend/storefront.css. Базовые стили и ревизор сохранены. Слой запросов frontend/assistant-service.js, модель серверной корзины frontend/cart.js и backend при доработке витрины не менялись.

Проверки текущей доработки

  • Прошли 27 существующих frontend-проверок: node frontend/tests/run-tests.cjs.
  • Дополнительно выполнены 11 сценариев на временном DOM-стенде с подменёнными ответами: поиск, сохранение чата/черновика, отправка, подтверждение/отмена, итоговое количество, синхронизация, удаление, ошибка и повтор. Это не проверка живого backend или настоящего браузера.
  • Синтаксис изменённого JavaScript и согласованность идентификаторов разметки проверены.
  • Визуальная проверка desktop/390 px и живой сценарий после этой доработки не выполнены: локальный штатный запуск остановился из-за отсутствующего express. Зависимости и настройки окружения при работе над интерфейсом не менялись. Долгие тесты повторно не запускались.

Ниже сохранена техническая документация команды. Описанные там результаты прежних браузерных и backend-проверок относятся к соответствующим этапам, а не к новому прогону витрины.


Backend

Минимальный сервер на Node.js и Express. Нужен Node.js 22 или новее.

Установите зависимости:

npm install

Скопируйте .env.example в .env. В PowerShell:

Copy-Item .env.example .env

Переменная PORT задаёт порт сервера (по умолчанию 3000). Настоящие ключи в примере отсутствуют, а .env исключён из Git.

Запустите сервер:

npm start

Или запустите режим разработки с автоматическим перезапуском при изменении кода:

npm run dev

Используйте один режим запуска за раз. Для остановки нажмите Ctrl+C.

Откройте http://localhost:3000/api/health — сервер вернёт:

{ "ok": true }

Если PowerShell блокирует npm.ps1, используйте npm.cmd install, npm.cmd start и npm.cmd run dev вместо соответствующих команд npm.

Каталог ekt.kz

В локальном .env заполните выданные организаторами данные Basic Auth:

EKT_USERNAME=
EKT_PASSWORD=

Не публикуйте .env и не вставляйте пароль в исходный код. Если .env уже существует, добавьте строки вручную, не перезаписывая файл из примера. Значения с символом # заключайте в кавычки. После изменения .env перезапустите сервер.

Откройте http://localhost:3000/api/products или http://localhost:3000/api/products?page=2. Сервер обращается к https://ekt.kz/api/products с Basic Auth и передаёт параметр page, если он указан. Ответ JSON возвращается без переименования полей и изменения структуры. Страницы запрашиваются по одной; page должен быть целым положительным числом.

Ошибки возвращаются в объекте error с полями code и message:

  • HTTP 400: неверный page.
  • HTTP 503: не заполнены данные доступа.
  • HTTP 502: ошибка каталога, соединения или некорректный JSON. При получении HTTP-ответа каталога его статус доступен в error.upstreamStatus.
  • HTTP 504: время ожидания каталога превысило 15 секунд.

Тело ошибки внешнего API, пароль и заголовок авторизации не выводятся в ответ или в консоль. Структуру товаров нужно смотреть в успешном ответе с действующим доступом; предположений о полях каталога в коде нет.

Локальные тесты без обращения к ekt.kz: node --test.

Поиск и детали товаров (этап 3)

GET /api/products/search?q=Legrand возвращает { query, count, items }. count — количество найденных товаров в просмотренной части каталога. Объекты items сохраняют поля реального API, в том числе id, name, article, price, image, url, url_api_detail, offers.

Приоритет результатов: точный артикул, подстрока артикула, подстрока названия. Сравнение без учёта регистра. При отсутствии совпадений возвращаются count: 0 и items: []. Отсутствующий, пустой, повторённый q или запрос длиннее 200 символов даёт HTTP 400 с кодом INVALID_SEARCH_QUERY.

Ограничение прототипа: поиск проверяет только первые 3 страницы каталога. В проверенном ответе списка есть page, per_page, count, items, но нет общего количества страниц. count не трактуется как размер всего каталога. При пустой или неполной странице загрузка заканчивается раньше. Отсутствие совпадений не означает отсутствия товара во всём каталоге.

Загруженная часть каталога хранится в памяти 3 минуты; повторные и одновременные поиски используют общий кэш/общую загрузку. Первая загрузка и обновление делают максимум 3 запроса к ekt.kz. При ошибке возвращается ошибка API, а не пустой результат. Кэш теряется при перезапуске; цены могут отставать на время его действия. Эти ограничения относятся к новому GET-поиску.

GET /api/products/515279 возвращает исходный detail JSON из https://ekt.kz/api/products/detail?id=515279 без переименования полей. Детали запрашиваются напрямую, даже если товар не входит в первые 3 страницы. Неверный формат ID даёт HTTP 400; HTTP 404 ekt.kz преобразуется в HTTP 404 с кодом PRODUCT_NOT_FOUND. Другие ошибки ekt.kz возвращаются как 502/504 с безопасным описанием; HTTP-статус внешнего API, если получен, находится в error.upstreamStatus.

В реальном detail товара 515279 обнаружены поля: id, name, article, description, price, quantity, stores, image, url, offers, properties.

  • Характеристики: properties, например KOLICHESTVO_POLYUSOV, NOMINALNYY_TOK, NOMINALNOE_NAPRYAZHENIE; описание — description.
  • Количество: quantity (при проверке 36, значение может меняться).
  • Склады: stores, элементы с id, name, quantity.
  • В проверенном товаре сертификатов и ссылок на документы не обнаружено. Это не утверждение об отсутствии документов у всех товаров каталога.

Для проверки откройте:

Все тесты: node --test.

AI-ассистент (этап 4)

Добавьте в существующий локальный .env, сохранив настройки ekt.kz:

OPENAI_API_KEY=
OPENAI_MODEL=gpt-5.6-luna

Вставьте настоящий ключ только в .env. Файл исключён из Git. Модель читается из OPENAI_MODEL; если значение пустое — gpt-5.6-luna. Без ключа сервер и маршруты каталога работают, но чат отвечает HTTP 503 с кодом OPENAI_NOT_CONFIGURED. После заполнения перезапустите npm.cmd run dev. Установка зависимостей: npm.cmd install.

POST /api/chat, Content-Type: application/json:

{ "message": "Есть автомат Legrand 40A?" }

Успешный ответ содержит только message (русский текст) и products (карточки использованных товаров). Карточки собирает сервер из реальных полей id, name, article, price, quantity, image, url. Отсутствующие поля не добавляются. Пустой/неверный message или текст длиннее 2000 символов даёт HTTP 400. Слишком большой JSON — HTTP 413.

Используется официальный пакет openai и Responses API. Инструменты:

  • search_products({ query }) напрямую вызывает существующий поиск. GET-поиск и чат используют один кэш: первые 3 страницы, срок 3 минуты.
  • get_product_detail({ id }) напрямую вызывает getProductById. Допустим только ID из результатов поиска или сообщения пользователя.

Модель выбирает инструменты, подходящие ID и нужные поля ответа через строгую JSON-схему. Свободный текст модели не передаётся пользователю: сервер составляет русский ответ из реальных данных. Это ограничивает стиль ответов, зато AI не может подставить собственную цену, остаток или название. Факты из quantity, stores, properties, description требуют detail; если AI пропустил этот вызов, сервер получает detail перед ответом. Характеристики выводятся с исходными кодами свойств API. Валюта не угадывается. Несколько выбранных товаров сопровождаются просьбой уточнить артикул. Выбор релевантных вариантов делает модель; после добавления ключа его нужно проверить на реальных запросах. Ложный ID или ответ без каталога отклоняется.

Если товара нет: «Не удалось найти подходящий товар в доступной части каталога.» Если данных не хватает: «В полученных данных эта информация не указана.» Подтверждённого поля сертификатов пока нет — наличие сертификата не утверждается.

Один запрос ограничен 7 обращениями к модели и 10 вызовами инструментов; ожидание одного OpenAI-запроса — до 20 секунд, бюджет AI-цикла — 90 секунд (начатый запрос каталога может завершиться позже). Повторы SDK отключены. HTTP 502/503 сообщает об ошибке OpenAI безопасным текстом, без исходного тела ошибки, ключей и stack trace. Ошибки каталога сохраняют свой статус. В OpenAI отправляются текст запроса и данные товаров, без EKT-авторизации. Сохранение Responses отключено через store: false; логирование SDK отключено.

Чат обрабатывает каждый запрос отдельно, без истории и cookie-сессий. Старый чат по правилам и pending actions заменены новым API. Frontend подключён к этому API; серверная корзина изменяется только после явного подтверждения. Оплата, заказы и загрузка файлов не реализованы.

Проверка из PowerShell (UTF-8 сохраняет кириллицу):

$messages = @(
  'Есть Legrand 40A?',
  'Сколько осталось товара с артикулом 310100080_?',
  'Какие характеристики у товара 515279?',
  'Расскажи про несуществующий товар XYZ123NOTFOUND'
)
foreach ($message in $messages) {
  $body = @{ message = $message } | ConvertTo-Json
  Invoke-RestMethod http://localhost:3000/api/chat -Method Post -ContentType 'application/json; charset=utf-8' -Body ([Text.Encoding]::UTF8.GetBytes($body)) | ConvertTo-Json -Depth 10
}

Все автоматические тесты: npm.cmd test. OpenAI и ekt.kz в них замоканы; реальные API-кредиты не расходуются. Живая проверка AI требует ключа.

Реализация сверена с официальной документацией function calling, Structured Outputs и моделью GPT-5.6 Luna.

Запуск интеграции

Из корня проекта: npm.cmd install, затем npm.cmd run dev для backend. Во втором терминале: npm.cmd run frontend. Откройте http://localhost:4173.

CORS разрешает адрес из FRONTEND_ORIGIN (по умолчанию http://localhost:4173); порт frontend задаёт FRONTEND_PORT (по умолчанию 4173). При смене порта согласуйте обе настройки в .env и перезапустите серверы. Frontend отправляет сообщения на http://localhost:3000/api/chat.

Результаты AI и товары берутся из backend, без демо-подмены. Перед выбором количества серверное предложение обновляет detail товара. Добавление происходит только после кнопки «Да, добавить». Корзина хранится на backend в cookie-сессии, сохраняется при обновлении страницы, не связана с корзиной ekt.kz и не резервирует товары.

Тесты: npm.cmd test — 62 backend и 27 frontend-проверок без платных API. npm.cmd run test:browser — отдельная живая проверка в установленном Edge; требует запущенных серверов и расходует реальные OpenAI-кредиты. Подробности и результаты браузерного сценария — в frontend/README.md.

Ревизор закупки в едином интерфейсе

На http://localhost:4173 доступны вкладки «AI-чат» и «Ревизор закупки» с общей серверной корзиной. Каталог использует реальный API ekt.kz, AI-чат — OpenAI; Revisor обращается к ekt.kz через существующие функции backend, без вызова AI. Для запуска нужны только два процесса из корня проекта:

npm.cmd run dev

Во втором терминале:

npm.cmd run frontend

Папка ekt-frontend/ оставлена как reference-код второго участника; отдельно запускать её не нужно. В frontend/revisor.js перенесены структура проверки строк, выбор позиций, сводка суммы, сброс результата при редактировании и копирование вопросов для уточнения. Навигация и стили адаптированы из ekt-frontend/public/. Исходный server-demo.mjs, синтетический каталог, DEMO-артикулы, demo diagnostics и учебные ответы не используются основным приложением.

POST /api/audit принимает:

{ "text": "200300273_ ; 2\n310100080_ ; 5\nXYZ123NOTFOUND ; 3" }

Не более 10 непустых строк; формат — артикул или название ; количество. Количество — положительное безопасное целое число, без единиц измерения. Текст ограничен 6000 символами и общим лимитом JSON-запроса 8 КБ. Пустой список/превышение лимита строк даёт HTTP 400. Нераспознанная строка не мешает проверке других строк. Точный артикул имеет приоритет; при нескольких совпадениях нужно уточнение, случайный товар не выбирается.

Ответ { rows, data_mode: "live", message } содержит исходную строку raw, запрошенное quantity, товар product и массив alternatives. product.sku берётся из article, product.stock — из detail quantity. Неизвестные остаток/цена возвращаются как null, не как ноль. Единицы измерения и характеристики не додумываются.

Статус строкиЗначение
readyТовар найден, количества достаточно.
shortageОстаток меньше потребности.
out_of_stockРеальный остаток равен 0.
not_foundТовар не найден в просмотренной части каталога.
unparsedНеверный формат или неоднозначный поиск; нужно уточнение.
unknownТовар найден, но остаток не указан. Выбор запрещён.

Повторяющиеся товары проверяются по суммарной потребности списка. В detail каждый ID запрашивается один раз за проверку. Ошибка API возвращается как ошибка запроса, а не маскируется под отсутствие товара.

Ограничения поиска прежние: первые 3 страницы, кэш списка на 3 минуты; detail запрашивается заново. Для shortage/out_of_stock возможны до двух кандидатов на строку при совпадении реально указанных марки, номинального тока и числа полюсов; известное различие напряжения исключает кандидата. На весь список допускается не более четырёх дополнительных detail-запросов для кандидатов. Это ограниченный поиск, не подтверждение совместимости. Если оснований недостаточно — alternatives: []. Для добавления кандидата нужно проверить его характеристики и отдельно проверить его артикул.

Выбор доступен только для ready, по умолчанию ничего не выбрано. Проверка списка и выбор строк корзину не меняют. Кнопка «Подготовить добавление» заново получает detail и открывает одно групповое подтверждение с товарами, количествами и суммой. После нажатия «Да, добавить» остатки ещё раз проверяются, с учётом уже добавленного в корзину. Если хотя бы одной позиции не хватает — весь пакет блокируется. При изменении цены нужно подготовить предложение заново. Отмена и повторный клик не приводят к добавлению дублей.

Корзина хранится в памяти backend, отдельно для каждой сессии, сохраняется при обновлении страницы, не резервирует остатки, не оформляет заказ и не изменяет настоящую корзину ekt.kz. Остатки магазина могут измениться после запроса; атомарного резервирования во внешнем магазине нет.

Проверки выполнены: 62 backend + 27 frontend тестов основного проекта. Существующие тесты не удалены. Дополнительно прошли 28 тестов reference-проекта (npm.cmd --prefix ekt-frontend test) и его проверка синтаксиса. Отдельный legacy-стенд ekt-frontend/tests/browser-components.py не входит в основной запуск: перенесённый UI проверяется живым npm.cmd run test:browser. Браузерный сценарий проверил старый чат, оба раздела, реальные ready/not_found, отмену, явное подтверждение и запрет превышения остатка, а также ширину 390px. При проверке товара 515279 API вернул цену 26930 и остаток 36; эти данные могут измениться. .env игнорируется Git; секреты во frontend не передаются.

Серверная корзина

Новые маршруты работают через cookie ekt_cart_session (HttpOnly, SameSite=Strict, Secure при HTTPS). В браузере запросы корзины отправляются с credentials: 'include'. CORS разрешает cookie только точному FRONTEND_ORIGIN; настройки ключей не меняются. Открывайте frontend и backend через один hostname, например localhost.

МаршрутТело POST / результат
GET /api/cart{ items, totalCount, totalPrice } — текущая корзина.
POST /api/cart/proposals{ "productId": 515279, "quantity": 2 } → предложение с proposalId, items, status, expiresAt. Корзина не меняется.
POST /api/cart/confirm{ "proposalId": "..." } → подтверждение и корзина. Повтор того же ID не добавляет повторно.
POST /api/cart/cancel{ "proposalId": "..." } → отмена. Подтвердить отменённое предложение нельзя.
POST /api/cart/remove{ "productId": 515279 } → удаление для существующей кнопки «Удалить».

Групповое окно использует тот же /proposals с { "items": [{ "productId": 515279, "quantity": 2 }] } (до 10 позиций). Весь пакет подтверждается или отклоняется целиком. items[].quantity — количество в корзине/предложении; items[].product.quantity — последний полученный остаток ekt.kz. Данные карточки и цена берутся только из detail.

Остаток проверяется при создании предложения и повторно перед первым confirm, с учётом уже добавленного. Невалидное количество даёт HTTP 400; недостаточный или неизвестный остаток, изменение цены — HTTP 409. Ошибки ekt.kz не меняют корзину. Операции одной сессии выполняются последовательно, включая параллельные confirm. После подтверждения frontend отдельно загружает /api/cart; при неопределённом сетевом результате повторяет тот же proposalId.

Хранилище in-memory: перезапуск backend (включая watch-перезапуск при правке кода) очищает корзины. Сессия истекает через 24 часа без обращения к корзине, предложение — через 30 минут. Прототип рассчитан на один процесс backend: до 1000 сессий, 100 товаров в корзине и 100 предложений на сессию за 30 минут. Это не корзина ekt.kz и не резервирование товара во внешнем магазине.

Ручная проверка: запустите npm.cmd run dev и npm.cmd run frontend, откройте http://localhost:4173, найдите товар, выберите количество. До «Да, добавить» и после «Отмена» корзина не меняется. После подтверждения обновите страницу: товар остаётся. Количество больше остатка должно блокироваться; кнопка корзины загружает её актуальное состояние.

Проверка API в PowerShell (cookie сохраняется в объекте, его не нужно выводить):

$basket = Invoke-RestMethod http://localhost:3000/api/cart -SessionVariable cartSession
$proposal = Invoke-RestMethod http://localhost:3000/api/cart/proposals -Method Post -WebSession $cartSession -ContentType 'application/json' -Body '{"productId":515279,"quantity":2}'
Invoke-RestMethod http://localhost:3000/api/cart -WebSession $cartSession
$confirmation = @{ proposalId = $proposal.proposalId } | ConvertTo-Json
Invoke-RestMethod http://localhost:3000/api/cart/confirm -Method Post -WebSession $cartSession -ContentType 'application/json' -Body $confirmation
Invoke-RestMethod http://localhost:3000/api/cart -WebSession $cartSession

Повторите последний confirm: количество не увеличится. Для проверки отмены создайте новое предложение и вместо /confirm вызовите /cancel с его proposalId.

Звёзды
⭐ 0
Форки
0
Язык
—
Последний push
в прошлом месяце
Коммиты
12
Авторы
3
Файлы
58
Ветки
7

Авторы коммитов

SaidKA007 8aya0tto 3xxenchikk 1

История коммитов

  • 2026-09-23 17:56Document current storefront and local setupaya0tto
  • 2026-09-23 17:49Improve storefront UI and cart UXaya0tto
  • 2026-09-23 17:19finish server cart integrationSaidKA007
  • 2026-09-23 16:43Merge remote-tracking branch 'origin/frontend-ui-1' into integrationSaidKA007
  • 2026-09-23 16:29integrate frontend with backendSaidKA007
  • 2026-09-23 16:10Merge remote-tracking branch 'origin/frontend-ui' into integrationSaidKA007
  • 2026-09-23 15:49add ai product assistantSaidKA007
  • 2026-09-23 15:39Add files via uploadxxenchikk
Все коммиты (12)
  • 2026-09-23 15:32Add EKT AI Assistant frontendaya0tto
  • 2026-09-23 15:22add product search and detail endpointsSaidKA007
  • 2026-09-23 15:10feat: implement product chat backendSaidKA007
  • 2026-09-23 14:23add basic express backendSaidKA007
Структура репозитория (58 файлов)
.env.example
.gitignore
README.md
ekt-frontend/API.md
ekt-frontend/DEMO.md
ekt-frontend/QA.md
ekt-frontend/README.md
ekt-frontend/START_HERE.md
ekt-frontend/checks/run-checks.mjs
ekt-frontend/lib/revisor.mjs
ekt-frontend/package.json
ekt-frontend/previews/revisor-cart.png
ekt-frontend/previews/revisor-checks.png
ekt-frontend/previews/revisor-desktop.png
ekt-frontend/previews/revisor-mobile.png
ekt-frontend/public/api.js
ekt-frontend/public/app.js
ekt-frontend/public/evidence.js
ekt-frontend/public/favicon.svg
ekt-frontend/public/index.html
ekt-frontend/public/revisor.js
ekt-frontend/public/styles.css
ekt-frontend/reports/browser-components.json
ekt-frontend/reports/check-report.json
ekt-frontend/reports/node-tests.txt
ekt-frontend/reports/syntax-check.txt
ekt-frontend/server-demo.mjs
ekt-frontend/tests/browser-components.py
ekt-frontend/tests/revisor.test.mjs
ekt-frontend/tests/server.test.mjs
frontend/README.md
frontend/app.js
frontend/assistant-service.js
frontend/cart.js
frontend/demo-data.js
frontend/index.html
frontend/revisor.js
frontend/server.cjs
frontend/storefront.css
frontend/storefront.js
frontend/styles.css
frontend/tests/browser-smoke.cjs
frontend/tests/run-tests.cjs
package-lock.json
package.json
src/routes/cart.js
src/server.js
src/services/ai.js
src/services/audit.js
src/services/cart.js
src/services/ektApi.js
src/services/productSearch.js
test/audit.test.js
test/cart.test.js
test/chat.test.js
test/cors.test.js
test/ektApi.test.js
test/productSearch.test.js
Ветки (7)

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.