This commit is contained in:
369
docs/architecture/data-models.md
Normal file
369
docs/architecture/data-models.md
Normal file
@@ -0,0 +1,369 @@
|
||||
# 📊 Модели данных
|
||||
|
||||
Полное описание всех моделей и сущностей в ChatBot.
|
||||
|
||||
## 🗂️ Типы моделей
|
||||
|
||||
### 1. Domain Models (Доменные модели)
|
||||
- `ChatSession` - Основная модель сессии чата
|
||||
- `ChatMessage` - DTO для сообщений
|
||||
|
||||
### 2. Entity Models (Сущности БД)
|
||||
- `ChatSessionEntity` - Сущность сессии в БД
|
||||
- `ChatMessageEntity` - Сущность сообщения в БД
|
||||
|
||||
### 3. Configuration Models (Конфигурация)
|
||||
- `TelegramBotSettings`
|
||||
- `OllamaSettings`
|
||||
- `AISettings`
|
||||
- `DatabaseSettings`
|
||||
|
||||
## 📦 Domain Models
|
||||
|
||||
### ChatSession
|
||||
|
||||
Основная модель для работы с сессией чата.
|
||||
|
||||
```csharp
|
||||
public class ChatSession
|
||||
{
|
||||
public string SessionId { get; set; } // Уникальный ID
|
||||
public long ChatId { get; set; } // Telegram chat ID
|
||||
public string ChatType { get; set; } // Тип чата
|
||||
public string ChatTitle { get; set; } // Название
|
||||
public string Model { get; set; } // AI модель
|
||||
public DateTime CreatedAt { get; set; } // Создан
|
||||
public DateTime LastUpdatedAt { get; set; } // Обновлен
|
||||
public int MaxHistoryLength { get; set; } // Макс история
|
||||
}
|
||||
```
|
||||
|
||||
**Ключевые методы:**
|
||||
|
||||
#### Работа с сообщениями
|
||||
```csharp
|
||||
// Добавить сообщение (базовый)
|
||||
void AddMessage(ChatMessage message)
|
||||
|
||||
// Добавить с компрессией
|
||||
Task AddMessageWithCompressionAsync(ChatMessage message, int threshold, int target)
|
||||
|
||||
// Добавить user сообщение
|
||||
void AddUserMessage(string content, string username)
|
||||
Task AddUserMessageWithCompressionAsync(string content, string username, int threshold, int target)
|
||||
|
||||
// Добавить assistant сообщение
|
||||
void AddAssistantMessage(string content)
|
||||
Task AddAssistantMessageWithCompressionAsync(string content, int threshold, int target)
|
||||
|
||||
// Получить все сообщения
|
||||
List<ChatMessage> GetAllMessages()
|
||||
|
||||
// Количество сообщений
|
||||
int GetMessageCount()
|
||||
|
||||
// Очистить историю
|
||||
void ClearHistory()
|
||||
```
|
||||
|
||||
#### Управление компрессией
|
||||
```csharp
|
||||
void SetCompressionService(IHistoryCompressionService service)
|
||||
```
|
||||
|
||||
**Thread Safety:**
|
||||
Все операции с `_messageHistory` защищены `lock(_lock)`
|
||||
|
||||
**Управление историей:**
|
||||
- Автоматическое обрезание при превышении `MaxHistoryLength`
|
||||
- Сохранение system prompt при обрезке
|
||||
- Поддержка асинхронной компрессии
|
||||
|
||||
### ChatMessage (DTO)
|
||||
|
||||
```csharp
|
||||
public class ChatMessage
|
||||
{
|
||||
public ChatRole Role { get; set; } // user/assistant/system
|
||||
public string Content { get; set; } // Текст сообщения
|
||||
}
|
||||
```
|
||||
|
||||
**ChatRole enum:**
|
||||
```csharp
|
||||
public enum ChatRole
|
||||
{
|
||||
System, // Системный промпт
|
||||
User, // Сообщение пользователя
|
||||
Assistant // Ответ бота
|
||||
}
|
||||
```
|
||||
|
||||
## 💾 Entity Models
|
||||
|
||||
### ChatSessionEntity
|
||||
|
||||
Сущность для хранения в PostgreSQL.
|
||||
|
||||
```csharp
|
||||
public class ChatSessionEntity
|
||||
{
|
||||
public int Id { get; set; } // PK (auto-increment)
|
||||
public string SessionId { get; set; } // Unique, indexed
|
||||
public long ChatId { get; set; } // Indexed
|
||||
public string ChatType { get; set; } // Max 20 chars
|
||||
public string? ChatTitle { get; set; } // Max 200 chars
|
||||
public string Model { get; set; } // Max 100 chars
|
||||
public DateTime CreatedAt { get; set; } // Required
|
||||
public DateTime LastUpdatedAt { get; set; } // Required
|
||||
public List<ChatMessageEntity> Messages { get; set; } // Navigation property
|
||||
}
|
||||
```
|
||||
|
||||
**Индексы:**
|
||||
- `SessionId` - Unique index
|
||||
- `ChatId` - Index для быстрого поиска
|
||||
|
||||
**Constraints:**
|
||||
- `SessionId` - Required, MaxLength(50)
|
||||
- `ChatId` - Required
|
||||
- `ChatType` - Required, MaxLength(20)
|
||||
|
||||
**Relationships:**
|
||||
- One-to-Many с `ChatMessageEntity`
|
||||
- Cascade Delete - удаление сессии удаляет сообщения
|
||||
|
||||
### ChatMessageEntity
|
||||
|
||||
```csharp
|
||||
public class ChatMessageEntity
|
||||
{
|
||||
public int Id { get; set; } // PK
|
||||
public int SessionId { get; set; } // FK
|
||||
public string Content { get; set; } // Max 10000 chars
|
||||
public string Role { get; set; } // Max 20 chars
|
||||
public int MessageOrder { get; set; } // Порядок в диалоге
|
||||
public DateTime CreatedAt { get; set; } // Время создания
|
||||
|
||||
public ChatSessionEntity Session { get; set; } // Navigation property
|
||||
}
|
||||
```
|
||||
|
||||
**Индексы:**
|
||||
- `SessionId` - Index
|
||||
- `CreatedAt` - Index для сортировки
|
||||
- `(SessionId, MessageOrder)` - Composite index
|
||||
|
||||
**Constraints:**
|
||||
- `Content` - Required, MaxLength(10000)
|
||||
- `Role` - Required, MaxLength(20)
|
||||
|
||||
## ⚙️ Configuration Models
|
||||
|
||||
### TelegramBotSettings
|
||||
|
||||
```csharp
|
||||
public class TelegramBotSettings
|
||||
{
|
||||
public string BotToken { get; set; } = string.Empty;
|
||||
}
|
||||
```
|
||||
|
||||
**Validator:**
|
||||
```csharp
|
||||
RuleFor(x => x.BotToken)
|
||||
.NotEmpty()
|
||||
.MinimumLength(10);
|
||||
```
|
||||
|
||||
### OllamaSettings
|
||||
|
||||
```csharp
|
||||
public class OllamaSettings
|
||||
{
|
||||
public string Url { get; set; } = string.Empty;
|
||||
public string DefaultModel { get; set; } = string.Empty;
|
||||
}
|
||||
```
|
||||
|
||||
**Validator:**
|
||||
```csharp
|
||||
RuleFor(x => x.Url)
|
||||
.NotEmpty()
|
||||
.Must(BeValidUrl);
|
||||
|
||||
RuleFor(x => x.DefaultModel)
|
||||
.NotEmpty();
|
||||
```
|
||||
|
||||
### AISettings
|
||||
|
||||
```csharp
|
||||
public class AISettings
|
||||
{
|
||||
public double Temperature { get; set; } = 0.9;
|
||||
public string SystemPromptPath { get; set; } = "Prompts/system-prompt.txt";
|
||||
public int MaxRetryAttempts { get; set; } = 3;
|
||||
public int RetryDelayMs { get; set; } = 1000;
|
||||
public int RequestTimeoutSeconds { get; set; } = 180;
|
||||
|
||||
// Compression settings
|
||||
public bool EnableHistoryCompression { get; set; } = true;
|
||||
public int CompressionThreshold { get; set; } = 20;
|
||||
public int CompressionTarget { get; set; } = 10;
|
||||
public int MinMessageLengthForSummarization { get; set; } = 50;
|
||||
public int MaxSummarizedMessageLength { get; set; } = 200;
|
||||
|
||||
// Advanced
|
||||
public bool EnableExponentialBackoff { get; set; } = true;
|
||||
public int MaxRetryDelayMs { get; set; } = 30000;
|
||||
public int CompressionTimeoutSeconds { get; set; } = 30;
|
||||
public int StatusCheckTimeoutSeconds { get; set; } = 10;
|
||||
}
|
||||
```
|
||||
|
||||
**Validator:**
|
||||
```csharp
|
||||
RuleFor(x => x.Temperature)
|
||||
.GreaterThanOrEqualTo(0.0)
|
||||
.LessThanOrEqualTo(2.0);
|
||||
|
||||
RuleFor(x => x.MaxRetryAttempts)
|
||||
.GreaterThanOrEqualTo(1)
|
||||
.LessThanOrEqualTo(10);
|
||||
```
|
||||
|
||||
### DatabaseSettings
|
||||
|
||||
```csharp
|
||||
public class DatabaseSettings
|
||||
{
|
||||
public string ConnectionString { get; set; } = string.Empty;
|
||||
public bool EnableSensitiveDataLogging { get; set; } = false;
|
||||
public int CommandTimeout { get; set; } = 30;
|
||||
}
|
||||
```
|
||||
|
||||
**Validator:**
|
||||
```csharp
|
||||
RuleFor(x => x.ConnectionString)
|
||||
.NotEmpty();
|
||||
|
||||
RuleFor(x => x.CommandTimeout)
|
||||
.GreaterThanOrEqualTo(5)
|
||||
.LessThanOrEqualTo(300);
|
||||
```
|
||||
|
||||
## 🔄 Маппинг Entity ↔ Model
|
||||
|
||||
### Session Entity → Model
|
||||
|
||||
```csharp
|
||||
public ChatSession ToModel()
|
||||
{
|
||||
var session = new ChatSession
|
||||
{
|
||||
SessionId = this.SessionId,
|
||||
ChatId = this.ChatId,
|
||||
ChatType = this.ChatType,
|
||||
ChatTitle = this.ChatTitle ?? string.Empty,
|
||||
Model = this.Model,
|
||||
CreatedAt = this.CreatedAt,
|
||||
LastUpdatedAt = this.LastUpdatedAt
|
||||
};
|
||||
|
||||
// Восстановить сообщения
|
||||
foreach (var msg in Messages.OrderBy(m => m.MessageOrder))
|
||||
{
|
||||
session.AddMessage(new ChatMessage
|
||||
{
|
||||
Role = ParseRole(msg.Role),
|
||||
Content = msg.Content
|
||||
});
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
```
|
||||
|
||||
### Session Model → Entity
|
||||
|
||||
```csharp
|
||||
public ChatSessionEntity ToEntity()
|
||||
{
|
||||
return new ChatSessionEntity
|
||||
{
|
||||
SessionId = this.SessionId,
|
||||
ChatId = this.ChatId,
|
||||
ChatType = this.ChatType,
|
||||
ChatTitle = this.ChatTitle,
|
||||
Model = this.Model,
|
||||
CreatedAt = this.CreatedAt,
|
||||
LastUpdatedAt = this.LastUpdatedAt,
|
||||
Messages = this.GetAllMessages()
|
||||
.Select((msg, index) => new ChatMessageEntity
|
||||
{
|
||||
Content = msg.Content,
|
||||
Role = msg.Role.ToString(),
|
||||
MessageOrder = index,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
})
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 📐 Database Schema
|
||||
|
||||
```sql
|
||||
-- Таблица сессий
|
||||
CREATE TABLE chat_sessions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
session_id VARCHAR(50) UNIQUE NOT NULL,
|
||||
chat_id BIGINT NOT NULL,
|
||||
chat_type VARCHAR(20) NOT NULL,
|
||||
chat_title VARCHAR(200),
|
||||
model VARCHAR(100),
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
last_updated_at TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_chat_sessions_session_id ON chat_sessions(session_id);
|
||||
CREATE INDEX idx_chat_sessions_chat_id ON chat_sessions(chat_id);
|
||||
|
||||
-- Таблица сообщений
|
||||
CREATE TABLE chat_messages (
|
||||
id SERIAL PRIMARY KEY,
|
||||
session_id INTEGER NOT NULL REFERENCES chat_sessions(id) ON DELETE CASCADE,
|
||||
content VARCHAR(10000) NOT NULL,
|
||||
role VARCHAR(20) NOT NULL,
|
||||
message_order INTEGER NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_chat_messages_session_id ON chat_messages(session_id);
|
||||
CREATE INDEX idx_chat_messages_created_at ON chat_messages(created_at);
|
||||
CREATE INDEX idx_chat_messages_session_order ON chat_messages(session_id, message_order);
|
||||
```
|
||||
|
||||
## 🎯 Жизненный цикл Session
|
||||
|
||||
```
|
||||
1. Создание (GetOrCreate)
|
||||
↓
|
||||
2. Добавление сообщений (AddMessage)
|
||||
↓
|
||||
3. Проверка длины истории
|
||||
↓
|
||||
4. Компрессия (если нужно)
|
||||
↓
|
||||
5. Сохранение в БД (SaveSessionAsync)
|
||||
↓
|
||||
6. Обновление LastUpdatedAt
|
||||
```
|
||||
|
||||
## 📚 См. также
|
||||
|
||||
- [Архитектура слоев](./layers.md)
|
||||
- [База данных](./database.md)
|
||||
- [Сервисы](../development/services.md)
|
||||
351
docs/architecture/database.md
Normal file
351
docs/architecture/database.md
Normal file
@@ -0,0 +1,351 @@
|
||||
# 🗄️ База данных
|
||||
|
||||
Описание работы с PostgreSQL в ChatBot.
|
||||
|
||||
## 📊 Схема базы данных
|
||||
|
||||
### Таблицы
|
||||
|
||||
#### chat_sessions
|
||||
|
||||
Хранит информацию о сессиях чатов.
|
||||
|
||||
| Колонка | Тип | Constraints | Описание |
|
||||
|---------|-----|-------------|----------|
|
||||
| id | SERIAL | PRIMARY KEY | Auto-increment ID |
|
||||
| session_id | VARCHAR(50) | UNIQUE, NOT NULL | Уникальный идентификатор |
|
||||
| chat_id | BIGINT | NOT NULL, INDEXED | Telegram chat ID |
|
||||
| chat_type | VARCHAR(20) | NOT NULL | Тип чата |
|
||||
| chat_title | VARCHAR(200) | NULL | Название чата |
|
||||
| model | VARCHAR(100) | NULL | AI модель |
|
||||
| created_at | TIMESTAMP | NOT NULL | Дата создания |
|
||||
| last_updated_at | TIMESTAMP | NOT NULL | Последнее обновление |
|
||||
|
||||
**Индексы:**
|
||||
```sql
|
||||
CREATE UNIQUE INDEX idx_chat_sessions_session_id ON chat_sessions(session_id);
|
||||
CREATE INDEX idx_chat_sessions_chat_id ON chat_sessions(chat_id);
|
||||
```
|
||||
|
||||
#### chat_messages
|
||||
|
||||
Хранит историю сообщений.
|
||||
|
||||
| Колонка | Тип | Constraints | Описание |
|
||||
|---------|-----|-------------|----------|
|
||||
| id | SERIAL | PRIMARY KEY | Auto-increment ID |
|
||||
| session_id | INTEGER | FK, NOT NULL | Ссылка на сессию |
|
||||
| content | VARCHAR(10000) | NOT NULL | Текст сообщения |
|
||||
| role | VARCHAR(20) | NOT NULL | user/assistant/system |
|
||||
| message_order | INTEGER | NOT NULL | Порядок в диалоге |
|
||||
| created_at | TIMESTAMP | NOT NULL | Время создания |
|
||||
|
||||
**Foreign Keys:**
|
||||
```sql
|
||||
FOREIGN KEY (session_id) REFERENCES chat_sessions(id) ON DELETE CASCADE
|
||||
```
|
||||
|
||||
**Индексы:**
|
||||
```sql
|
||||
CREATE INDEX idx_chat_messages_session_id ON chat_messages(session_id);
|
||||
CREATE INDEX idx_chat_messages_created_at ON chat_messages(created_at);
|
||||
CREATE INDEX idx_chat_messages_session_order ON chat_messages(session_id, message_order);
|
||||
```
|
||||
|
||||
## 🔄 Entity Framework Core
|
||||
|
||||
### DbContext
|
||||
|
||||
```csharp
|
||||
public class ChatBotDbContext : DbContext
|
||||
{
|
||||
public DbSet<ChatSessionEntity> ChatSessions { get; set; }
|
||||
public DbSet<ChatMessageEntity> ChatMessages { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### Конфигурация моделей
|
||||
|
||||
```csharp
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
// ChatSessionEntity
|
||||
modelBuilder.Entity<ChatSessionEntity>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id);
|
||||
entity.Property(e => e.SessionId).IsRequired().HasMaxLength(50);
|
||||
entity.HasIndex(e => e.SessionId).IsUnique();
|
||||
entity.HasIndex(e => e.ChatId);
|
||||
|
||||
entity.HasMany(e => e.Messages)
|
||||
.WithOne(e => e.Session)
|
||||
.HasForeignKey(e => e.SessionId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
// ChatMessageEntity
|
||||
modelBuilder.Entity<ChatMessageEntity>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id);
|
||||
entity.Property(e => e.Content).IsRequired().HasMaxLength(10000);
|
||||
entity.HasIndex(e => e.SessionId);
|
||||
entity.HasIndex(e => new { e.SessionId, e.MessageOrder });
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Миграции
|
||||
|
||||
#### Создание миграции
|
||||
|
||||
```bash
|
||||
dotnet ef migrations add InitialCreate --project ChatBot
|
||||
```
|
||||
|
||||
#### Применение миграций
|
||||
|
||||
```bash
|
||||
# Вручную
|
||||
dotnet ef database update --project ChatBot
|
||||
|
||||
# Автоматически при запуске (DatabaseInitializationService)
|
||||
```
|
||||
|
||||
#### Откат миграции
|
||||
|
||||
```bash
|
||||
dotnet ef database update PreviousMigration --project ChatBot
|
||||
```
|
||||
|
||||
#### Удаление последней миграции
|
||||
|
||||
```bash
|
||||
dotnet ef migrations remove --project ChatBot
|
||||
```
|
||||
|
||||
## 🔌 Подключение к БД
|
||||
|
||||
### Connection String
|
||||
|
||||
```
|
||||
Host={host};Port={port};Database={name};Username={user};Password={password}
|
||||
```
|
||||
|
||||
**Пример:**
|
||||
```
|
||||
Host=localhost;Port=5432;Database=chatbot;Username=chatbot;Password=secret
|
||||
```
|
||||
|
||||
### Конфигурация в Program.cs
|
||||
|
||||
```csharp
|
||||
builder.Services.AddDbContext<ChatBotDbContext>(
|
||||
(serviceProvider, options) =>
|
||||
{
|
||||
var dbSettings = serviceProvider
|
||||
.GetRequiredService<IOptions<DatabaseSettings>>()
|
||||
.Value;
|
||||
|
||||
options.UseNpgsql(
|
||||
dbSettings.ConnectionString,
|
||||
npgsqlOptions =>
|
||||
{
|
||||
npgsqlOptions.CommandTimeout(dbSettings.CommandTimeout);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Connection Pooling
|
||||
|
||||
Npgsql автоматически использует connection pooling:
|
||||
|
||||
```
|
||||
Max Pool Size=100
|
||||
Min Pool Size=1
|
||||
Connection Lifetime=300
|
||||
Connection Idle Lifetime=300
|
||||
```
|
||||
|
||||
## 📝 Repository Pattern
|
||||
|
||||
### Interface
|
||||
|
||||
```csharp
|
||||
public interface IChatSessionRepository
|
||||
{
|
||||
Task<ChatSessionEntity?> GetByChatIdAsync(long chatId);
|
||||
Task<ChatSessionEntity> CreateAsync(ChatSessionEntity session);
|
||||
Task UpdateAsync(ChatSessionEntity session);
|
||||
Task DeleteAsync(int id);
|
||||
Task<List<ChatSessionEntity>> GetAllAsync();
|
||||
}
|
||||
```
|
||||
|
||||
### Implementation
|
||||
|
||||
```csharp
|
||||
public class ChatSessionRepository : IChatSessionRepository
|
||||
{
|
||||
private readonly ChatBotDbContext _context;
|
||||
|
||||
public async Task<ChatSessionEntity?> GetByChatIdAsync(long chatId)
|
||||
{
|
||||
return await _context.ChatSessions
|
||||
.Include(s => s.Messages)
|
||||
.FirstOrDefaultAsync(s => s.ChatId == chatId);
|
||||
}
|
||||
|
||||
public async Task<ChatSessionEntity> CreateAsync(ChatSessionEntity session)
|
||||
{
|
||||
_context.ChatSessions.Add(session);
|
||||
await _context.SaveChangesAsync();
|
||||
return session;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 Оптимизация запросов
|
||||
|
||||
### Eager Loading
|
||||
|
||||
```csharp
|
||||
// Загрузка с сообщениями
|
||||
var session = await _context.ChatSessions
|
||||
.Include(s => s.Messages)
|
||||
.FirstOrDefaultAsync(s => s.ChatId == chatId);
|
||||
```
|
||||
|
||||
### Projections
|
||||
|
||||
```csharp
|
||||
// Только нужные поля
|
||||
var sessionInfo = await _context.ChatSessions
|
||||
.Where(s => s.ChatId == chatId)
|
||||
.Select(s => new { s.SessionId, s.Model })
|
||||
.FirstOrDefaultAsync();
|
||||
```
|
||||
|
||||
### AsNoTracking
|
||||
|
||||
```csharp
|
||||
// Read-only запросы
|
||||
var sessions = await _context.ChatSessions
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
```
|
||||
|
||||
## 🔧 Обслуживание БД
|
||||
|
||||
### Vacuum (очистка)
|
||||
|
||||
```sql
|
||||
VACUUM ANALYZE chat_sessions;
|
||||
VACUUM ANALYZE chat_messages;
|
||||
```
|
||||
|
||||
### Статистика
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
schemaname,
|
||||
tablename,
|
||||
n_live_tup,
|
||||
n_dead_tup
|
||||
FROM pg_stat_user_tables
|
||||
WHERE tablename IN ('chat_sessions', 'chat_messages');
|
||||
```
|
||||
|
||||
### Размер таблиц
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
tablename,
|
||||
pg_size_pretty(pg_total_relation_size(tablename::regclass)) as size
|
||||
FROM pg_tables
|
||||
WHERE schemaname = 'public';
|
||||
```
|
||||
|
||||
## 🛡️ Безопасность
|
||||
|
||||
### SQL Injection Prevention
|
||||
|
||||
Entity Framework Core автоматически параметризует запросы:
|
||||
|
||||
```csharp
|
||||
// ✅ Безопасно
|
||||
var session = await _context.ChatSessions
|
||||
.Where(s => s.ChatId == chatId)
|
||||
.FirstOrDefaultAsync();
|
||||
```
|
||||
|
||||
### Права пользователя БД
|
||||
|
||||
```sql
|
||||
-- Создание пользователя
|
||||
CREATE USER chatbot WITH PASSWORD 'secure_password';
|
||||
|
||||
-- Выдача прав
|
||||
GRANT CONNECT ON DATABASE chatbot TO chatbot;
|
||||
GRANT USAGE ON SCHEMA public TO chatbot;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO chatbot;
|
||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO chatbot;
|
||||
```
|
||||
|
||||
## 📊 Мониторинг
|
||||
|
||||
### Active Connections
|
||||
|
||||
```sql
|
||||
SELECT count(*)
|
||||
FROM pg_stat_activity
|
||||
WHERE datname = 'chatbot';
|
||||
```
|
||||
|
||||
### Long Running Queries
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
pid,
|
||||
now() - pg_stat_activity.query_start AS duration,
|
||||
query
|
||||
FROM pg_stat_activity
|
||||
WHERE state = 'active'
|
||||
ORDER BY duration DESC;
|
||||
```
|
||||
|
||||
### Locks
|
||||
|
||||
```sql
|
||||
SELECT * FROM pg_locks
|
||||
WHERE NOT granted;
|
||||
```
|
||||
|
||||
## 🔄 Backup & Restore
|
||||
|
||||
### Backup
|
||||
|
||||
```bash
|
||||
# Полный backup
|
||||
pg_dump -U chatbot chatbot > backup.sql
|
||||
|
||||
# Только схема
|
||||
pg_dump -U chatbot --schema-only chatbot > schema.sql
|
||||
|
||||
# Только данные
|
||||
pg_dump -U chatbot --data-only chatbot > data.sql
|
||||
```
|
||||
|
||||
### Restore
|
||||
|
||||
```bash
|
||||
# Восстановление
|
||||
psql -U chatbot chatbot < backup.sql
|
||||
```
|
||||
|
||||
## 📚 См. также
|
||||
|
||||
- [Модели данных](./data-models.md)
|
||||
- [Конфигурация](../configuration.md)
|
||||
- [Установка](../installation.md)
|
||||
349
docs/architecture/layers.md
Normal file
349
docs/architecture/layers.md
Normal file
@@ -0,0 +1,349 @@
|
||||
# 🏛️ Слои приложения
|
||||
|
||||
Детальное описание каждого слоя архитектуры ChatBot.
|
||||
|
||||
## 1️⃣ Presentation Layer (Уровень представления)
|
||||
|
||||
### Telegram Bot Integration
|
||||
|
||||
Отвечает за взаимодействие с пользователями через Telegram.
|
||||
|
||||
#### Основные компоненты
|
||||
|
||||
**TelegramBotService**
|
||||
- Главный сервис, управляющий ботом
|
||||
- Запускается как `IHostedService`
|
||||
- Получает updates через Webhook или Long Polling
|
||||
- Координирует обработку сообщений
|
||||
|
||||
**TelegramMessageHandler**
|
||||
- Обработка входящих сообщений
|
||||
- Фильтрация по типу чата
|
||||
- Извлечение информации о пользователе
|
||||
- Передача в ChatService
|
||||
|
||||
**TelegramCommandProcessor**
|
||||
- Распознавание команд (`/start`, `/help`, и т.д.)
|
||||
- Routing к соответствующему обработчику
|
||||
- Валидация прав доступа
|
||||
|
||||
**Commands (Команды)**
|
||||
```
|
||||
StartCommand - /start
|
||||
HelpCommand - /help
|
||||
ClearCommand - /clear
|
||||
SettingsCommand - /settings
|
||||
StatusCommand - /status
|
||||
```
|
||||
|
||||
#### Паттерн Command
|
||||
|
||||
```csharp
|
||||
public interface ITelegramCommand
|
||||
{
|
||||
string Command { get; }
|
||||
string Description { get; }
|
||||
Task<ReplyInfo> ExecuteAsync(TelegramCommandContext context);
|
||||
}
|
||||
```
|
||||
|
||||
Каждая команда:
|
||||
- Изолирована
|
||||
- Легко тестируется
|
||||
- Независимо расширяема
|
||||
|
||||
## 2️⃣ Service Layer (Бизнес-логика)
|
||||
|
||||
### Core Services
|
||||
|
||||
#### ChatService
|
||||
|
||||
**Ответственность:**
|
||||
- Управление сессиями чатов
|
||||
- Координация между AI и storage
|
||||
- Обработка сообщений пользователей
|
||||
|
||||
**Методы:**
|
||||
```csharp
|
||||
GetOrCreateSession() // Получить/создать сессию
|
||||
ProcessMessageAsync() // Обработать сообщение
|
||||
ClearHistoryAsync() // Очистить историю
|
||||
UpdateSessionParameters() // Обновить параметры
|
||||
```
|
||||
|
||||
**Взаимодействия:**
|
||||
- IAIService → Генерация ответов
|
||||
- ISessionStorage → Хранение сессий
|
||||
- IHistoryCompressionService → Оптимизация истории
|
||||
|
||||
#### AIService
|
||||
|
||||
**Ответственность:**
|
||||
- Генерация ответов через Ollama
|
||||
- Управление retry логикой
|
||||
- Таймауты и error handling
|
||||
|
||||
**Методы:**
|
||||
```csharp
|
||||
GenerateChatCompletionAsync() // Базовая генерация
|
||||
GenerateChatCompletionWithCompressionAsync() // С сжатием
|
||||
```
|
||||
|
||||
**Особенности:**
|
||||
- Экспоненциальный backoff
|
||||
- Streaming responses
|
||||
- Timeout handling
|
||||
- System prompt injection
|
||||
|
||||
#### HistoryCompressionService
|
||||
|
||||
**Ответственность:**
|
||||
- Суммаризация длинной истории
|
||||
- Оптимизация контекста
|
||||
- Сохранение важной информации
|
||||
|
||||
**Алгоритм:**
|
||||
```
|
||||
1. Сохранить system prompt
|
||||
2. Сохранить последние N сообщений
|
||||
3. Суммаризировать старые сообщения
|
||||
4. Объединить результаты
|
||||
```
|
||||
|
||||
**Методы:**
|
||||
```csharp
|
||||
ShouldCompress() // Проверка необходимости
|
||||
CompressHistoryAsync() // Выполнить сжатие
|
||||
SummarizeMessageAsync() // Суммаризировать одно сообщение
|
||||
```
|
||||
|
||||
#### SystemPromptService
|
||||
|
||||
**Ответственность:**
|
||||
- Загрузка системного промпта
|
||||
- Кеширование промпта
|
||||
- Обработка ошибок чтения файла
|
||||
|
||||
#### ModelService
|
||||
|
||||
**Ответственность:**
|
||||
- Управление AI моделями
|
||||
- Получение списка доступных моделей
|
||||
- Переключение между моделями
|
||||
|
||||
### Storage Services
|
||||
|
||||
#### DatabaseSessionStorage
|
||||
|
||||
**Ответственность:**
|
||||
- Сохранение сессий в PostgreSQL
|
||||
- CRUD операции через репозиторий
|
||||
- Синхронизация с базой данных
|
||||
|
||||
**Методы:**
|
||||
```csharp
|
||||
GetOrCreate() // Получить или создать
|
||||
Get() // Получить по ID
|
||||
SaveSessionAsync() // Сохранить сессию
|
||||
Remove() // Удалить сессию
|
||||
CleanupOldSessions() // Очистка старых
|
||||
```
|
||||
|
||||
**Особенности:**
|
||||
- Автоматическая конвертация Entity ↔ Model
|
||||
- Lazy loading сессий
|
||||
- Кеширование в памяти
|
||||
|
||||
#### InMemorySessionStorage
|
||||
|
||||
**Ответственность:**
|
||||
- Хранение сессий в памяти
|
||||
- Быстрый доступ для тестов
|
||||
- Не требует БД
|
||||
|
||||
**Использование:**
|
||||
- Unit тесты
|
||||
- Development режим
|
||||
- Прототипирование
|
||||
|
||||
## 3️⃣ Data Access Layer (Доступ к данным)
|
||||
|
||||
### DbContext
|
||||
|
||||
**ChatBotDbContext**
|
||||
- Entity Framework Core контекст
|
||||
- Конфигурация таблиц
|
||||
- Отношения между сущностями
|
||||
|
||||
```csharp
|
||||
DbSet<ChatSessionEntity> ChatSessions
|
||||
DbSet<ChatMessageEntity> ChatMessages
|
||||
```
|
||||
|
||||
**Конфигурация:**
|
||||
- Индексы для оптимизации
|
||||
- Foreign Keys и Cascade Delete
|
||||
- Constraints и Validation
|
||||
|
||||
### Repositories
|
||||
|
||||
#### ChatSessionRepository
|
||||
|
||||
**Ответственность:**
|
||||
- Абстракция доступа к данным
|
||||
- CRUD операции с сессиями
|
||||
- Query оптимизация
|
||||
|
||||
**Методы:**
|
||||
```csharp
|
||||
GetByChatIdAsync() // По chat ID
|
||||
CreateAsync() // Создать
|
||||
UpdateAsync() // Обновить
|
||||
DeleteAsync() // Удалить
|
||||
GetAllAsync() // Все сессии
|
||||
```
|
||||
|
||||
**Преимущества паттерна Repository:**
|
||||
- Изоляция от EF Core
|
||||
- Легкое тестирование
|
||||
- Возможность смены ORM
|
||||
|
||||
### Entities (Сущности БД)
|
||||
|
||||
#### ChatSessionEntity
|
||||
|
||||
```csharp
|
||||
Id // PK
|
||||
SessionId // Unique identifier
|
||||
ChatId // Telegram chat ID
|
||||
ChatType // private/group/supergroup
|
||||
ChatTitle // Название чата
|
||||
Model // AI модель
|
||||
CreatedAt // Дата создания
|
||||
LastUpdatedAt // Последнее обновление
|
||||
Messages // Коллекция сообщений
|
||||
```
|
||||
|
||||
#### ChatMessageEntity
|
||||
|
||||
```csharp
|
||||
Id // PK
|
||||
SessionId // FK → ChatSessionEntity
|
||||
Content // Текст сообщения
|
||||
Role // user/assistant/system
|
||||
MessageOrder // Порядок в диалоге
|
||||
CreatedAt // Дата создания
|
||||
```
|
||||
|
||||
## 4️⃣ Infrastructure Layer (Инфраструктура)
|
||||
|
||||
### External Services
|
||||
|
||||
#### PostgreSQL
|
||||
|
||||
**Функции:**
|
||||
- Persistent storage сессий
|
||||
- Транзакционность
|
||||
- ACID гарантии
|
||||
|
||||
**Оптимизации:**
|
||||
- Индексы на ChatId, SessionId
|
||||
- Connection pooling
|
||||
- Query optimization
|
||||
|
||||
#### Ollama
|
||||
|
||||
**Функции:**
|
||||
- Локальные LLM модели
|
||||
- Streaming responses
|
||||
- Multiple models support
|
||||
|
||||
**Адаптер:**
|
||||
```csharp
|
||||
OllamaClientAdapter : IOllamaClient
|
||||
```
|
||||
|
||||
Абстрагирует от конкретной реализации OllamaSharp.
|
||||
|
||||
#### Telegram Bot API
|
||||
|
||||
**Функции:**
|
||||
- Получение updates
|
||||
- Отправка сообщений
|
||||
- Управление ботом
|
||||
|
||||
**Wrapper:**
|
||||
```csharp
|
||||
TelegramBotClientWrapper : ITelegramBotClientWrapper
|
||||
```
|
||||
|
||||
## 🔄 Взаимодействие слоев
|
||||
|
||||
### Правила взаимодействия
|
||||
|
||||
```
|
||||
Presentation → Service → Data → Infrastructure
|
||||
↓ ↓ ↓
|
||||
Interfaces Interfaces Repository
|
||||
```
|
||||
|
||||
**Принципы:**
|
||||
- Слои зависят только от интерфейсов
|
||||
- Вышестоящие слои не знают о нижестоящих
|
||||
- Dependency Injection связывает реализации
|
||||
|
||||
### Пример: Обработка сообщения
|
||||
|
||||
```
|
||||
1. TelegramBotService (Presentation)
|
||||
↓ вызывает
|
||||
2. TelegramMessageHandler (Presentation)
|
||||
↓ вызывает
|
||||
3. ChatService (Service)
|
||||
↓ использует
|
||||
4. ISessionStorage (Service Interface)
|
||||
↓ реализован как
|
||||
5. DatabaseSessionStorage (Service)
|
||||
↓ использует
|
||||
6. IChatSessionRepository (Data Interface)
|
||||
↓ реализован как
|
||||
7. ChatSessionRepository (Data)
|
||||
↓ использует
|
||||
8. ChatBotDbContext (Data)
|
||||
↓ обращается к
|
||||
9. PostgreSQL (Infrastructure)
|
||||
```
|
||||
|
||||
## 🎯 Разделение ответственности
|
||||
|
||||
### Presentation Layer
|
||||
- ✅ Обработка входящих запросов
|
||||
- ✅ Валидация команд
|
||||
- ✅ Форматирование ответов
|
||||
- ❌ Бизнес-логика
|
||||
- ❌ Доступ к данным
|
||||
|
||||
### Service Layer
|
||||
- ✅ Бизнес-логика
|
||||
- ✅ Координация сервисов
|
||||
- ✅ Валидация бизнес-правил
|
||||
- ❌ UI логика
|
||||
- ❌ SQL запросы
|
||||
|
||||
### Data Layer
|
||||
- ✅ CRUD операции
|
||||
- ✅ Query построение
|
||||
- ✅ Маппинг Entity ↔ Model
|
||||
- ❌ Бизнес-логика
|
||||
- ❌ UI логика
|
||||
|
||||
### Infrastructure Layer
|
||||
- ✅ Внешние интеграции
|
||||
- ✅ Конфигурация подключений
|
||||
- ❌ Бизнес-логика
|
||||
|
||||
## 📚 См. также
|
||||
|
||||
- [Архитектура - Обзор](./overview.md)
|
||||
- [Модели данных](./data-models.md)
|
||||
- [Структура проекта](../development/project-structure.md)
|
||||
210
docs/architecture/overview.md
Normal file
210
docs/architecture/overview.md
Normal file
@@ -0,0 +1,210 @@
|
||||
# 🏗️ Архитектура проекта
|
||||
|
||||
## 📐 Общая архитектура
|
||||
|
||||
ChatBot построен на принципах **Clean Architecture** с четким разделением ответственности.
|
||||
|
||||
## 🔄 Диаграмма слоев
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ Presentation Layer │
|
||||
│ (Telegram Bot, Commands, Handlers) │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Service Layer │
|
||||
│ (ChatService, AIService, Compression) │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Data Access Layer │
|
||||
│ (Repositories, DbContext, Entities) │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Infrastructure Layer │
|
||||
│ (PostgreSQL, Ollama, Telegram) │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 🎯 Принципы проектирования
|
||||
|
||||
### SOLID
|
||||
|
||||
- **S**ingle Responsibility - Каждый класс имеет одну ответственность
|
||||
- **O**pen/Closed - Открыт для расширения, закрыт для модификации
|
||||
- **L**iskov Substitution - Интерфейсы взаимозаменяемы
|
||||
- **I**nterface Segregation - Мелкие специализированные интерфейсы
|
||||
- **D**ependency Inversion - Зависимость от абстракций
|
||||
|
||||
### Design Patterns
|
||||
|
||||
- **Repository Pattern** - `IChatSessionRepository`
|
||||
- **Dependency Injection** - Microsoft.Extensions.DependencyInjection
|
||||
- **Strategy Pattern** - `ISessionStorage` (In-Memory/Database)
|
||||
- **Command Pattern** - Telegram команды
|
||||
- **Adapter Pattern** - `OllamaClientAdapter`
|
||||
|
||||
## 📦 Компоненты системы
|
||||
|
||||
### 1. Presentation Layer
|
||||
|
||||
**Telegram Bot Integration:**
|
||||
- `TelegramBotService` - Основной сервис бота
|
||||
- `TelegramMessageHandler` - Обработка сообщений
|
||||
- `TelegramCommandProcessor` - Обработка команд
|
||||
- `TelegramErrorHandler` - Обработка ошибок
|
||||
- Commands: `StartCommand`, `HelpCommand`, `ClearCommand`, etc.
|
||||
|
||||
### 2. Service Layer
|
||||
|
||||
**Core Services:**
|
||||
- `ChatService` - Управление диалогами
|
||||
- `AIService` - Генерация ответов AI
|
||||
- `HistoryCompressionService` - Сжатие истории
|
||||
- `SystemPromptService` - Загрузка системного промпта
|
||||
- `ModelService` - Управление AI моделями
|
||||
|
||||
**Storage Services:**
|
||||
- `DatabaseSessionStorage` - Хранение в БД
|
||||
- `InMemorySessionStorage` - Хранение в памяти
|
||||
|
||||
### 3. Data Access Layer
|
||||
|
||||
**Repositories:**
|
||||
- `ChatSessionRepository` - Работа с сессиями
|
||||
- `ChatBotDbContext` - EF Core контекст
|
||||
|
||||
**Entities:**
|
||||
- `ChatSessionEntity` - Сессия чата
|
||||
- `ChatMessageEntity` - Сообщение чата
|
||||
|
||||
### 4. Infrastructure
|
||||
|
||||
**External Services:**
|
||||
- PostgreSQL - База данных
|
||||
- Ollama - AI модели
|
||||
- Telegram Bot API - Telegram интеграция
|
||||
|
||||
## 🔌 Dependency Injection
|
||||
|
||||
```csharp
|
||||
// Telegram Services
|
||||
services.AddSingleton<ITelegramBotClient>
|
||||
services.AddSingleton<ITelegramBotService>
|
||||
services.AddSingleton<ITelegramMessageHandler>
|
||||
|
||||
// Core Services
|
||||
services.AddSingleton<IAIService, AIService>
|
||||
services.AddScoped<ChatService>
|
||||
services.AddScoped<ISessionStorage, DatabaseSessionStorage>
|
||||
|
||||
// Data Access
|
||||
services.AddDbContext<ChatBotDbContext>
|
||||
services.AddScoped<IChatSessionRepository, ChatSessionRepository>
|
||||
```
|
||||
|
||||
## 🔄 Data Flow
|
||||
|
||||
### Обработка сообщения пользователя
|
||||
|
||||
```
|
||||
User Message
|
||||
↓
|
||||
TelegramBotService (получение update)
|
||||
↓
|
||||
TelegramMessageHandler (валидация)
|
||||
↓
|
||||
TelegramCommandProcessor (проверка команды)
|
||||
↓ (если не команда)
|
||||
ChatService (обработка сообщения)
|
||||
↓
|
||||
SessionStorage (получение/создание сессии)
|
||||
↓
|
||||
AIService (генерация ответа)
|
||||
↓
|
||||
OllamaClient (запрос к AI)
|
||||
↓
|
||||
AIService (получение ответа)
|
||||
↓
|
||||
ChatService (сохранение в историю)
|
||||
↓
|
||||
SessionStorage (сохранение сессии)
|
||||
↓
|
||||
TelegramMessageSender (отправка ответа)
|
||||
↓
|
||||
User receives response
|
||||
```
|
||||
|
||||
## 🗂️ Структура проекта
|
||||
|
||||
```
|
||||
ChatBot/
|
||||
├── Common/ # Общие константы
|
||||
│ └── Constants/
|
||||
├── Data/ # Слой доступа к данным
|
||||
│ ├── Interfaces/
|
||||
│ ├── Repositories/
|
||||
│ └── ChatBotDbContext.cs
|
||||
├── Models/ # Модели и конфигурация
|
||||
│ ├── Configuration/
|
||||
│ ├── Dto/
|
||||
│ ├── Entities/
|
||||
│ └── ChatSession.cs
|
||||
├── Services/ # Бизнес-логика
|
||||
│ ├── HealthChecks/
|
||||
│ ├── Interfaces/
|
||||
│ ├── Telegram/
|
||||
│ └── *.cs
|
||||
├── Migrations/ # EF Core миграции
|
||||
├── Prompts/ # AI промпты
|
||||
└── Program.cs # Точка входа
|
||||
```
|
||||
|
||||
## 📊 Диаграмма классов (упрощенная)
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ ChatService │
|
||||
├─────────────────────┤
|
||||
│ + ProcessMessage() │
|
||||
│ + ClearHistory() │
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
├──> IAIService
|
||||
├──> ISessionStorage
|
||||
└──> IHistoryCompressionService
|
||||
|
||||
┌─────────────────────┐
|
||||
│ AIService │
|
||||
├─────────────────────┤
|
||||
│ + GenerateChat() │
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
└──> IOllamaClient
|
||||
```
|
||||
|
||||
## 🔐 Security Architecture
|
||||
|
||||
- Секреты в переменных окружения
|
||||
- Валидация входных данных
|
||||
- SQL инъекции предотвращены (EF Core)
|
||||
- Безопасное логирование (без секретов)
|
||||
|
||||
## 📈 Scalability
|
||||
|
||||
**Готовность к масштабированию:**
|
||||
- Stateless сервисы
|
||||
- Database session storage
|
||||
- Async/await везде
|
||||
- Connection pooling
|
||||
- Health checks
|
||||
|
||||
## 🎛️ Configuration Management
|
||||
|
||||
```
|
||||
Environment Variables → .env
|
||||
↓
|
||||
appsettings.json
|
||||
↓
|
||||
IOptions<T>
|
||||
↓
|
||||
Validation (FluentValidation)
|
||||
↓
|
||||
Services
|
||||
```
|
||||
Reference in New Issue
Block a user