Phase 10: Per-User Rate Limits — messages + tokens, quota UI, admin usage

Backend:
- max_ai_messages_per_day + max_ai_tokens_per_day on User model (nullable, override)
- Migration 008: add columns + seed default settings (100 msgs, 500K tokens)
- usage_service: count today's messages + tokens, check quota, get limits
- GET /chats/quota returns usage vs limits + reset time
- POST /chats/{id}/messages checks quota before streaming (429 if exceeded)
- Admin user schemas expose both limit fields
- GET /admin/usage returns per-user daily message + token counts
- admin_user_service allows updating both limit fields

Frontend:
- Chat header shows "X/Y messages · XK/YK tokens" with red highlight at limit
- Quota refreshes every 30s via TanStack Query
- Admin usage page with table: user, messages today, tokens today
- Route + sidebar entry for admin usage
- English + Russian translations

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 15:44:51 +03:00
parent bb53eeee8e
commit d86d53f473
17 changed files with 390 additions and 17 deletions

View File

@@ -39,7 +39,8 @@
"skills": "Skills",
"personal_context": "My Context",
"pdf": "PDF Reports",
"pdf_templates": "Templates"
"pdf_templates": "Templates",
"usage": "Usage"
},
"dashboard": {
"welcome": "Welcome, {{name}}",
@@ -56,7 +57,9 @@
"unarchive": "Unarchive",
"delete_confirm": "Are you sure you want to delete this chat?",
"limit_reached": "Chat limit reached",
"streaming": "AI is thinking..."
"streaming": "AI is thinking...",
"quota_messages": "{{used}}/{{limit}} messages",
"quota_tokens": "{{used}}K/{{limit}}K tokens"
},
"admin": {
"context_editor": "Primary Context Editor",
@@ -197,6 +200,13 @@
"default_max_chats": "Default Max Chats",
"default_max_chats_desc": "Default chat limit for new users"
},
"admin_usage": {
"title": "Usage Statistics",
"user": "User",
"messages": "Messages Today",
"tokens": "Tokens Today",
"no_data": "No usage data available."
},
"common": {
"loading": "Loading...",
"error": "An error occurred",

View File

@@ -39,7 +39,8 @@
"skills": "Навыки",
"personal_context": "Мой контекст",
"pdf": "PDF отчёты",
"pdf_templates": "Шаблоны"
"pdf_templates": "Шаблоны",
"usage": "Использование"
},
"dashboard": {
"welcome": "Добро пожаловать, {{name}}",
@@ -56,7 +57,9 @@
"unarchive": "Разархивировать",
"delete_confirm": "Вы уверены, что хотите удалить этот чат?",
"limit_reached": "Достигнут лимит чатов",
"streaming": "ИИ думает..."
"streaming": "ИИ думает...",
"quota_messages": "{{used}}/{{limit}} сообщений",
"quota_tokens": "{{used}}K/{{limit}}K токенов"
},
"admin": {
"context_editor": "Редактор основного контекста",
@@ -197,6 +200,13 @@
"default_max_chats": "Лимит чатов по умолчанию",
"default_max_chats_desc": "Лимит чатов для новых пользователей"
},
"admin_usage": {
"title": "Статистика использования",
"user": "Пользователь",
"messages": "Сообщения сегодня",
"tokens": "Токены сегодня",
"no_data": "Данных пока нет."
},
"common": {
"loading": "Загрузка...",
"error": "Произошла ошибка",