Состав полей зависит от вида обращения и анонимности, поэтому часть строк
заведомо пустая. Пустая строка в списке выглядит как заполненное значение,
а не как отсутствующее поле — теперь такие поля выпадают из payload.
Значения обрезаются, так что поле из одних пробелов тоже не уедет.
WantsFeedback остаётся всегда: false здесь осмысленно, а не пусто.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Локальное окружение требовало двух терминалов, а без запущенного
auth-сервиса форма отдаёт 500 от vite-прокси — это легко принять за баг
приложения. Теперь concurrently стартует оба процесса с метками
[web]/[auth]; только фронтенд — npm run dev:web.
Заодно поправлен README сервиса: GRAPH_SCOPE больше не нужно задавать
руками, дефолт уже указывает на App ID URI api.tnsu.kz.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
npm run dev читает server/.env через --env-file (нативно в Node 20+),
чтобы не передавать GRAPH_* руками при каждом старте. Без запущенного
сервиса на 3100 vite-прокси отдаёт 500, что легко принять за баг формы.
.env добавлен в .gitignore, в репозиторий положен только .env.example.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Токен с aud=graph.microsoft.com api.tnsu.kz отклонял с 401 — он проверяет
аудиторию входящего JWT. Меняем scope по умолчанию на App ID URI самого
api-tnsu-portal; наш сертификат для него уже авторизован, отдельный
client secret не нужен.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Убрал требование задавать их через .env на сервере — значения одни
и те же для единственного прод-окружения.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
POST /feedback собирает поля формы в столбцы списка (Company резолвится
в название по справочнику, Type/Title — по виду обращения) и создаёт
элемент через api.tnsu.kz /SharePoint/ListItem. Ошибки авторизации и
апстрима логируются в stdout и возвращаются клиенту как 502, чтобы сбой
на проде было видно явно.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>