8.9 KiB
VikonPartialUpdates — Частичные обновления модулей VIKON
[S1] Проблема
Текущий модуль VikonIntegration поддерживает только полное обновление ядра модуля (UpdateCoreAction) и синхронизацию файлов через FM (SyncFilesAction). Частичные обновления (обновление отдельных частей модуля — common, struct, document...) не реализованы.
В vikon_core частичные обновления реализованы через 4-шаговый flow:
- Запрос генерации части на сервере
- Polling статуса генерации
- Проверка готовности
- Скачивание и применение
Нужно перенести эту логику в VikonIntegration с учётом архитектуры Porto.
[S2] Обзор решения
Backend-driven polling: фронт отправляет один запрос POST /update-part, backend выполняет всю цепочку синхронно (request → polling → download → apply), возвращает результат. HttpTask уже устанавливает set_time_limit(600), поэтому запрос может блокироваться до 10 минут — это достаточно для polling flow. Фронт показывает спиннер во время ожидания.
Полная поддержка: обычные части (atomic swap папки) + ABITUR (пофайловая синхронизация).
[S3] Backend компоненты
Новый Action: UpdatePartAction
Расположение: app/Containers/VikonIntegration/Actions/UpdatePartAction.php
Зависимости: HttpTask, FilesystemTask, PollPartStatusTask
Интерфейс:
public function run(int $moduleId, string $part, string $accessToken): array
Алгоритм:
- Валидация
moduleIdиpart(whitelist из конфига) - Запрос генерации:
POST pull_updates/requestGeneratePartByNewCoreJsonсpart - Получение
operation_identityиttl - Polling статуса через
PollPartStatusTask(GET pull_updates/getStatusPartGenerationByNewCoreJson) - Проверка готовности:
POST pull_updates/checkPartGenerationByNewCoreResultJson - Скачивание ZIP:
GET pull_updates/downloadPartByNewCoreResult?operation_identity=...&part=... - Распаковка во временную директорию
- Определение moduleId части (по
$allowedFoldersInCoreByModule) - Применение:
- Обычная часть: atomic swap всей папки
- ABITUR: пофайловая синхронизация всех entry
cleanUnitCoreс исключениями- Очистка temp файлов
Возвращаемое значение:
['success' => true, 'message' => '...', 'synced_count' => int]
Новый Task: PollPartStatusTask
Расположение: app/Containers/VikonIntegration/Tasks/PollPartStatusTask.php
Интерфейс:
public function run(string $operationIdentity, string $accessToken, int $ttl = 120): array
Алгоритм:
- Отправка GET
pull_updates/getStatusPartGenerationByNewCoreJsonсoperation_identity - Если
status === "completed"→ возврат['status' => 'completed'] - Если
status === "failed"→ возврат['status' => 'failed', 'error' => ...] - Если
status === "pending"и время <ttl→ sleep(3) и повтор - Если timeout → возврат
['status' => 'timeout']
Конфигурация:
- Интервал polling: 3 секунды (configurable через конфиг)
- Max attempts:
ceil(ttl / interval)+ 2 (запас)
Модификация FilesystemTask
Добавить метод atomicSwap():
public function atomicSwap(
string $newEntryPath,
string $currentEntryPath,
string $baseDir,
int $moduleId
): bool
Алгоритм:
- Если
$currentEntryPathсуществует:- Удалить
$currentEntryPath_newесли есть - Переместить
$newEntryPath→$currentEntryPath_new - Удалить
$currentEntryPath_oldесли есть - Переместить
$currentEntryPath→$currentEntryPath_old - Переместить
$currentEntryPath_new→$currentEntryPath
- Удалить
- Если не существует:
- Переместить
$newEntryPath→$currentEntryPath
- Переместить
Модификация VikonController
Добавить метод:
public function updatePart(UpdatePartRequest $request): JsonResponse
Маршрут: POST /dashboard/vikon-updates/update-part
Middleware: access-check, dashboard.auth, throttle:10,1, vikon.refresh
[S4] Frontend компоненты
Модификация Index.vue
Новые Props:
available_parts: объект с доступными частями по модулям
Новые UI-элементы:
- Выпадающий список частей для выбранного модуля
- Кнопка "Обновить часть" рядом с каждым модулем
- Прогресс-бар с логом во время обновления
- Индикатор загрузки (спиннер) во время polling
Data flow:
- Пользователь выбирает модуль → показываются доступные части
- Пользователь нажимает "Обновить" → отправляется
POST /update-part - Фронт показывает спиннер/прогресс-бар пока backend выполняет цепочку
- Получает ответ → показывает результат (успех/ошибка)
[S5] API эндпоинты
POST /dashboard/vikon-updates/update-part
Request:
{
"module_id": 1,
"part": "common"
}
Response (success):
{
"success": true,
"message": "Часть 'common' успешно обновлена.",
"operation_identity": "...",
"synced_count": 15
}
Response (error):
{
"success": false,
"message": "Ошибка при генерации части: timeout"
}
[S6] ABITUR special case
Для ABITUR (moduleId=2) в шаге 4 используется пофайловая синхронизация:
- Сканирует содержимое распакованного ZIP
- Для каждого entry (файл/папка) делает atomic swap через
FilesystemTask::atomicSwap() - Исключает
files/и.htaccessизcleanUnitCore - Не создаёт
sveden/update/index.phpredirect (это только для SVEDEN)
[S7] Ошибки и откат
| Шаг | Ошибка | Действие |
|---|---|---|
| Запрос генерации | HTTP ошибка | Возврат ошибки клиенту |
| Polling | Timeout (> ttl) | Возврат ошибки, очистка temp |
| Проверка готовности | Часть не готова | Возврат ошибки |
| Скачивание ZIP | HTTP ошибка | Возврат ошибки |
| Распаковка | Невалидный ZIP | Возврат ошибки |
| Atomic swap | Ошибка rename | restoreUnitCoreAfterFail() → откат через _old суффиксы |
| cleanUnitCore | Ошибка удаления | Логирование, продолжение |
[S8] Конфигурация
Добавить в config/vikon.php:
'parts' => [
1 => ['common', 'struct', 'document', 'education', 'managers', 'employees', 'objects', 'paid_edu', 'budget', 'vacant', 'grants', 'inter', 'catering', 'eduStandarts', 'corruption', 'antiterrorism'],
2 => ['abitur'],
6 => ['general', 'structure', 'faq', 'procedures', 'results-and-reports', 'plans', 'survey'],
],
'poll_interval' => 3,
'poll_max_attempts' => 50,
[S9] Зависимости
- Существующие:
HttpTask,FilesystemTask,ValidateTokenTask - Новые:
PollPartStatusTask,UpdatePartAction - Frontend: Vue 3 Composition API, Inertia.js
[S10] Тестирование
- Unit-тест
PollPartStatusTask: mock HTTP, проверка polling loop - Unit-тест
FilesystemTask::atomicSwap(): проверка 3-шагового flow - Integration-тест
UpdatePartAction: mock API responses, проверка полного flow - Manual test: подключение к реальному API VIKON, обновление одной части