feat(feedback): personal AI models, AI run tracking and profiles/options endpoint

- user_settings allowlist: feedback_models (up to 10 personal model configs)
- normalizeFeedbackModels() validation, UI block "Мои модели" in #fbPromptModal
- GET /api/ai/profiles/options for tutors (no api_key), used by feedback/shorts
- feedbacks columns ai_prompt/ai_model/ai_duration_ms + backup/restore support
- "ИИ-запрос" popover on feedback card with status, model, timing and prompt
- audit: feedback.update / feedback.ai.run / feedback.ai.error labels
This commit is contained in:
dev
2026-10-07 16:30:27 +03:00
parent a73b1b3f8c
commit a9fb7aaf77
13 changed files with 522 additions and 85 deletions
+4 -4
View File
@@ -110,9 +110,9 @@
- [ ] `GET /api/feedbacks/:id` — с JOIN `groups`, проверка филиала
- [ ] `POST /api/feedbacks` — валидация полей (дата `YYYY-MM-DD`, `resident` max 200, `topic` max 500, `text` max 5000, `group_id` int, `past_review` max 2000, `short_message_ids` массив int уникальные, `ai_check` boolean, `ai_profile` opt). Проверка доступа к группе. INSERT. Если `ai_check && feedback_ai_enabled!=='false'` → `ai_status='pending'`, `text=text||''`. **Пометить выбранные short_messages** `used=true, used_at=CURRENT_DATE` (только `deleted_at IS NULL`, можно `AND used=false`). `logAudit('feedback.create', {..., short_count})`. `invalidateFeedbacks()` + `invalidateShorts()`. Если `pending` → `wakeFeedbackWorker()`. 201
- [ ] `PUT /api/feedbacks/:id` — редактирование по образцу, без смены `ai_status` по умолчанию. `logAudit`, `invalidateFeedbacks()`
- [ ] `DELETE /api/feedbacks/:id` — мягкое удаление (`deleted_at`, `purge_at = now()+trash_purge_days`) по образцу `short_messages:2794–2810`
- [ ] `PUT /api/feedbacks/:id/restore` (requireAdmin) — снять `deleted_at`, `purge_at` (2811–2827)
- [ ] `DELETE /api/feedbacks/:id/permanent` (requireAdmin) — плановое удаление (2828–2843)
- [ ] `DELETE /api/feedbacks/:id` — мягкое удаление (`deleted_at`, `purge_at = now()+trash_purge_days`) по образцу `short_messages:2794–2810`, `feedbackById` (филиал), 404 если уже удалён, `logAudit('feedback.delete')`
- [ ] `PUT /api/feedbacks/:id/restore` (requireAuth + `feedbackById`) — снять `deleted_at`, `purge_at`, 404 если не удалён, `logAudit('feedback.restore')`
- [ ] `DELETE /api/feedbacks/:id/permanent` (requireAuth + `feedbackById`) — немедленный `DELETE FROM feedbacks WHERE deleted_at IS NOT NULL`, 404 если не удалён, `logAudit('feedback.permanent-delete')`. Мягко удалённые чистит `purgeScheduledDeletions()` по `purge_at`
- [ ] `POST /api/feedbacks/:id/ai/retry` (requireAuth) — `ai_status='error'→'pending'`, сброс `ai_error/ai_checked_at`, `wakeFeedbackWorker()`, `invalidateFeedbacks()`
- [ ] `POST /api/feedbacks/requeue-failed` (requireAuth, requireAdmin) — массовый перевод `error→pending`, wake + invalidate
- [ ] Хелпер `feedbackById(user,id)` по образцу `lessonReportById` (JOIN `groups g`, `branchScope`)
@@ -168,7 +168,7 @@
- [ ] `connectFeedbackLive()` — SSE `/api/events`, обработка `feedbacks_changed` (debounce) и `feedback_status` (обновить строку)
- [ ] Делегирование кликов `[data-edit]/[data-del]/[data-retry]`
- [ ] Фильтры с debounce 350мс, `page=1` при смене
- [ ] `initFeedback()` — `checkAuth()`, `buildSidebar('feedback')`, `loadGroups()`, загрузка профилей ИИ в `#fbModel` (`GET /api/ai/profiles`, первый `native`), `loadFeedbacks()`, `connectFeedbackLive()`, `lucide.createIcons()`
- [ ] `initFeedback()` — `checkAuth()`, `buildSidebar('feedback')`, `loadGroups()`, загрузка профилей ИИ в `#fbModel` (`GET /api/ai/profiles/options`, первый `native`), `loadFeedbacks()`, `connectFeedbackLive()`, `lucide.createIcons()`
---