Локально путь к сертификату вёл в ~/Downloads у каждого свой, а в контейнере
задавался двумя отдельными переменными. Теперь каталог один и подменяется
целиком через SECRETS_DIR: по умолчанию secrets/ в корне репозитория, в
контейнере /certs (смонтированный каталог с хоста, GRAPH_CERT_DIR не меняется).
Имена файлов внутри фиксированы, поэтому GRAPH_CERT_PATH и GRAPH_KEY_PATH
больше не нужны. Содержимое secrets/ в .gitignore, кроме README.
Отсутствие файлов теперь даёт понятную ошибку вместо ENOENT — на свежем
клоне это основной сценарий отказа.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Список юрлиц группы меняется без нашего участия, а две копии в репозитории
(COMPANY_OPTIONS во фронте и COMPANY_NAMES на сервере) неизбежно разошлись
бы с источником и между собой. Теперь единственный источник —
/Dictionary/Companies:
- GET /companies проксирует справочник, чтобы токен не утекал в браузер;
- имя компании для колонки Company резолвится по нему же, на сервере;
- в кэше 10 минут — новое юрлицо подхватится без перезапуска сервиса.
Пока список грузится, в select показывается «Загружаем…»; если не
загрузился — ошибка в слоте обязательного поля, а не пустой список.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Состав полей зависит от вида обращения и анонимности, поэтому часть строк
заведомо пустая. Пустая строка в списке выглядит как заполненное значение,
а не как отсутствующее поле — теперь такие поля выпадают из 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>