feat: changed get time logic to approvers

This commit is contained in:
Тимур Городецкий
2026-08-13 10:01:08 +05:00
parent 2e6e138e8d
commit 8578653c16
55 changed files with 2249 additions and 46 deletions
+105
View File
@@ -0,0 +1,105 @@
# План: обсуждение задачи
_Создано: 2026-08-12_
## Контекст
Пишем сюда идею, договорённости и шаги, чтобы ничего не забыть.
## Идея (со слов пользователя)
> Данные заявок лежат в списках SP Online. Т.к. рекомендуемый предел ~5000, а заявки
> копятся бесконечно, придумать механизм «архивации»/шардинга: при достижении 5000
> элементов заводить новый список с тем же именем + числовой постфикс (`— данные_2`),
> и фронт начинает писать новые заявки туда.
## Важный факт (уточнение)
- **5000 = List View Threshold** — лимит на строки, сканируемые ОДНИМ запросом, а НЕ на хранение.
- Список SPO хранит **до 30 млн** элементов. «Переполнения» по хранению не будет.
- Реальная проблема = запросы без индекса, сканирующие >5000 строк → throttling.
Лечится индексами + фильтрацией, а не разбиением списка.
## Цена шардинга по счётчику (что ломается в нашем коде)
- `myRequests.service` → чтение становится UNION по N шардам на каждый тип.
- `requestCode.ts` → код `type-YYMM-itemId`, itemId в новом списке снова с 1 → дубли кодов.
- Списки согласования растут ещё быстрее (строки маршрута) — их тоже шардить?
- Провижининг схемы/индексов/прав (Sites.Selected) для каждого нового списка на лету.
- Отчётность/поиск «за период» становятся кросс-списочными.
## Варианты (развилка)
- **A. Индексы + пагинация (рекомендую как базу)** — индексируем RequestStatus/Created/Author,
читаем через `.top()`+paging. Закрывает throughput-проблему полностью. Кода минимум.
- **B. Архивация по статусу/дате** — закрытые заявки переносим в `...— архив`, активный список
остаётся маленьким. Это «правильная» версия интуиции пользователя. Разгрузка без ломки кодов.
- **C. Шардинг по 5000 (исходная идея)** — крайний вариант, только если реально упрёмся в десятки млн.
## ВЫБРАННОЕ НАПРАВЛЕНИЕ (после обсуждения)
Причина тормозов подтверждена пользователем: слабый интернет (Казахстан) + список зависает.
Есть мандат «держать ≤5000 элементов в списке, плодить новые списки».
Решение = **C (шардинг) + обязательная пагинация**. Обе части нужны:
- **Шардинг** ≤5000 на список — выполняет мандат / снимает threshold-throttling (ops).
- **Пагинация + фильтр по индексу** — фронт НИКОГДА не качает весь список, только маленькую
страницу (`.top(50)`, фильтр по Author/RequestStatus). Именно это убирает зависания на
слабом канале. Без этой части шардинг сам по себе скорость НЕ спасёт (4999 строк грузятся
так же долго, как 5000).
## Кто что создаёт (решено)
- Создание шардов — **бэкенд-скрипт по расписанию** (НЕ фронт). Варианты хостинга:
Azure Function (timer) / Azure Automation runbook (PnP.PowerShell) / Power Automate /
cron на своём сервере (есть git.tnsu.kz → своя инфра). Auth: app-only (сертификат), Sites.Selected.
- Плюсы: права на создание списков не на фронте; тяжёлый провижининг мимо слабого канала юзера;
нет гонок (шард готовится заранее); переиспользуем существующий PnP-провижининг.
## Контракт бэк ↔ фронт: РЕЕСТР ШАРДОВ
Маленький SP-список / config-элемент. На каждый тип заявки:
`базовое имя`, `номер активного шарда`, `счётчик`, (для approval — свой активный/счётчик).
- Бэкенд-джоб ОБНОВЛЯЕТ (создал шард → новый активный номер).
- Фронт ЧИТАЕТ (активный список для записи + полный набор для чтения).
## Роли в коде фронта (обёртки, детали позже)
- `resolveActiveList(type)` → активный список для записи; все `submit.ts` зовут её вместо
хардкода `DATA_LIST_TITLE`.
- `resolveAllShards(type)` → все шарды для чтения; запрос по каждому с фильтром + `.top()`,
склейка маленьких кусков (быстро на слабом канале).
- Порог переключения — 4900 (запас до 5000).
- Коды: внести номер шарда (`type-YYMM-s2-itemId`), иначе itemId в новом списке снова с 1 → дубли.
- Списки согласования шардить по СВОЕМУ счётчику (растут в 3-5 раз быстрее) — проектируем после данных.
## Открытые вопросы (для следующего обсуждения)
1. Хостинг бэкенд-джоба: Azure Function / Automation / Power Automate / свой cron (git.tnsu.kz)? Что доступно и кто админит?
2. Реестр шардов — отдельный SP-список или один JSON config-элемент? (склоняюсь к маленькому списку — виден в админке)
3. ~~Формат кода с шардом?~~ РЕШЕНО: offset-схема (см. ниже).
4. Согласование: шардим сразу вместе с данными или сначала только данные, approval потом?
5. ~~Старые данные >5000 сейчас?~~ РЕШЕНО: таких списков нет, гринфилд. Разовая миграция НЕ нужна.
Текущие списки = «шард №1». Настоящая архивация (прятать старые из выдачи) — опционально, потом.
6. Прогноз объёма: заявок/месяц по каждому типу — чтобы понять реальную частоту переключений.
## Решения (зафиксировано)
- Направление: шардинг + обязательная пагинация (обе части).
- Создание шардов: бэкенд-скрипт по расписанию (app-only), НЕ фронт.
- Стык бэк↔фронт: реестр шардов.
- РЕЖИМ РАБОТЫ: сейчас ТОЛЬКО план и обсуждение. Код НЕ пишем без явного подтверждения пользователя.
### Код заявки: offset-схема (сквозная нумерация)
- ВАЖНО: SP-шный `ID` мы НЕ контролируем — в каждом новом списке он всегда с 1. Нельзя заставить
SP стартовать с 5001. Поэтому сквозную нумерацию делаем в НАШЕМ коде, не в SP ID.
- Код = `type-YYMM-{offset + itemId}`, offset = сумма финальных счётчиков всех предыдущих шардов.
- Шард 1: offset 0 → `hr-2608-1` … (совпадает с текущим форматом → обратная совместимость!)
- Шард 2: offset 5000 → `hr-2608-5001` …
- Уникальность гарантирована. Непрерывность не идеальна (удаления → дырки в SP ID), но это ок —
важна уникальность, а не отсутствие пропусков.
- Финальный счётчик закрытого шарда пишет бэкенд-джоб в реестр при переключении.
### «Мои заявки» — из ВСЕХ шардов
- `resolveAllShards(type)`: опрос всех шардов, каждый с фильтром по Author + `.top()`, склейка+сортировка.
- Трафик мал (с каждого шарда пара строк) → быстро на слабом канале.
- Оптимизация на потом: при большом числе шардов читать по умолчанию только свежие, старые — по кнопке «Показать ещё».
## Шаги (черновик, не выполняем)
- [ ] Закрыть открытые вопросы 1-6 (обсуждение)
- [ ] Спроектировать схему реестра шардов
- [ ] Спроектировать интерфейс `resolveActiveList` / `resolveAllShards` (без реализации)
- [ ] Спроектировать бэкенд-джоб (псевдокод/алгоритм)
- [ ] Только после «го» — реализация
## Заметки
- Паттерн доступа сегодня: у каждой формы свой `DATA_LIST_TITLE`, доступ через
`getSP().web.lists.getByTitle(...)` (см. `forms/*/submit.ts`, `load.ts`, `myRequests.service`).