first commit
This commit is contained in:
505
lastochka-ui/README.md
Normal file
505
lastochka-ui/README.md
Normal file
@@ -0,0 +1,505 @@
|
||||
# 🕊️ Ласточка — Веб-кабинет
|
||||
|
||||
**Веб-кабинет** — браузерная версия мессенджера Ласточка.
|
||||
|
||||
## 📋 Содержание
|
||||
|
||||
- [Быстрый старт](#быстрый-старт)
|
||||
- [Структура](#структура)
|
||||
- [Аутентификация](#аутентификация)
|
||||
- [Чаты](#чаты)
|
||||
- [Группы и каналы](#группы-и-каналы)
|
||||
- [Админ-панель](#админ-панель)
|
||||
- [Настройки](#настройки)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Быстрый старт
|
||||
|
||||
```bash
|
||||
cd D:\Projects\Messenger\dev\lastochka-ui
|
||||
|
||||
# Установка
|
||||
npm install
|
||||
|
||||
# Запуск
|
||||
npm run dev
|
||||
|
||||
# Сборка
|
||||
npm run build
|
||||
```
|
||||
|
||||
**Адрес:** http://localhost:5173
|
||||
|
||||
---
|
||||
|
||||
## 📁 Структура
|
||||
|
||||
```
|
||||
src/
|
||||
├── components/
|
||||
│ ├── admin/ # Админ-панель
|
||||
│ │ ├── AdminPanel.tsx
|
||||
│ │ ├── Dashboard.tsx
|
||||
│ │ ├── Users.tsx
|
||||
│ │ ├── Settings.tsx
|
||||
│ │ └── Logs.tsx
|
||||
│ ├── auth/ # Аутентификация
|
||||
│ │ ├── LoginScreen.tsx
|
||||
│ │ ├── RegisterForm.tsx
|
||||
│ │ └── EmailVerification.tsx
|
||||
│ ├── chat/ # Чат
|
||||
│ │ ├── ChatWindow.tsx
|
||||
│ │ ├── ChatHeader.tsx
|
||||
│ │ ├── MessagesList.tsx
|
||||
│ │ └── MessageInput.tsx
|
||||
│ ├── layout/ # Layout
|
||||
│ │ └── Sidebar.tsx
|
||||
│ ├── sidebar/ # Боковая панель
|
||||
│ │ ├── ChatList.tsx
|
||||
│ │ └── ChatItem.tsx
|
||||
│ └── ui/ # UI компоненты
|
||||
│ ├── Avatar.tsx
|
||||
│ ├── UserSearch.tsx
|
||||
│ ├── CreateGroupModal.tsx
|
||||
│ ├── MembersPanel.tsx
|
||||
│ └── ProfileSettings.tsx
|
||||
├── lib/ # Утилиты
|
||||
│ ├── email-auth.ts
|
||||
│ ├── sms-auth.ts
|
||||
│ ├── phone-utils.ts
|
||||
│ └── tinode-client.ts
|
||||
├── store/ # Zustand store
|
||||
│ ├── auth.ts
|
||||
│ ├── chat.ts
|
||||
│ ├── groups.ts
|
||||
│ └── admin.ts
|
||||
├── types/ # TypeScript типы
|
||||
│ ├── index.ts
|
||||
│ └── admin.ts
|
||||
├── App.tsx
|
||||
├── main.tsx
|
||||
└── tinode.d.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Аутентификация
|
||||
|
||||
### Регистрация
|
||||
|
||||
**Поля:**
|
||||
- Логин (3-32 символа, буквы/цифры/подчёркивание)
|
||||
- Email (валидный формат)
|
||||
- Телефон (+7 XXX XXX-XX-XX)
|
||||
- Пароль (минимум 6 символов)
|
||||
- Подтверждение пароля
|
||||
- Отображаемое имя (необязательно)
|
||||
|
||||
**Проверки:**
|
||||
```typescript
|
||||
// Проверка логина на дубликат
|
||||
const result = await checkLoginAvailability(login)
|
||||
if (!result.available) {
|
||||
setError('Этот логин уже занят')
|
||||
}
|
||||
|
||||
// Проверка телефона на дубликат
|
||||
const result = await checkPhoneAvailability(phone)
|
||||
if (!result.available) {
|
||||
setError('Этот номер уже зарегистрирован')
|
||||
}
|
||||
```
|
||||
|
||||
### Вход
|
||||
|
||||
```typescript
|
||||
import { useAuthStore } from '@/store/auth'
|
||||
|
||||
const { login } = useAuthStore()
|
||||
await login('username', 'password')
|
||||
```
|
||||
|
||||
### Настройки профиля
|
||||
|
||||
**Вкладка Профиль:**
|
||||
- Аватар (загрузка файла, макс 5MB)
|
||||
- Отображаемое имя
|
||||
- Био/о себе
|
||||
|
||||
**Вкладка Безопасность:**
|
||||
- Текущий пароль
|
||||
- Новый пароль
|
||||
- Подтверждение пароля
|
||||
|
||||
---
|
||||
|
||||
## 💬 Чаты
|
||||
|
||||
### Типы чатов
|
||||
|
||||
| Тип | Описание | Макс. участников |
|
||||
|-----|----------|------------------|
|
||||
| **P2P** | Личная переписка | 2 |
|
||||
| **Группа** | Групповой чат | 200 000 |
|
||||
| **Канал** | Публикация контента | Неограниченно |
|
||||
|
||||
### Отправка сообщений
|
||||
|
||||
```typescript
|
||||
import { useChatStore } from '@/store/chat'
|
||||
|
||||
const { sendMessage } = useChatStore()
|
||||
await sendMessage('Привет, мир!')
|
||||
```
|
||||
|
||||
### Поиск пользователей
|
||||
|
||||
```typescript
|
||||
import UserSearch from '@/components/ui/UserSearch'
|
||||
|
||||
<UserSearch
|
||||
showStartChat
|
||||
onSelect={(user) => {
|
||||
console.log('Выбран пользователь:', user)
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 👥 Группы и каналы
|
||||
|
||||
### Создание группы
|
||||
|
||||
```typescript
|
||||
import { useGroupsStore } from '@/store/groups'
|
||||
|
||||
const { createGroup } = useGroupsStore()
|
||||
|
||||
const group = await createGroup({
|
||||
name: 'Моя группа',
|
||||
description: 'Описание',
|
||||
isChannel: false,
|
||||
isPublic: false,
|
||||
members: ['user1', 'user2'],
|
||||
})
|
||||
```
|
||||
|
||||
### Создание канала
|
||||
|
||||
```typescript
|
||||
const { createChannel } = useGroupsStore()
|
||||
|
||||
const channel = await createChannel({
|
||||
name: 'Мой канал',
|
||||
description: 'Новости проекта',
|
||||
isPublic: true,
|
||||
members: [],
|
||||
})
|
||||
```
|
||||
|
||||
### Управление участниками
|
||||
|
||||
```typescript
|
||||
const { addMember, removeMember, leaveGroup } = useGroupsStore()
|
||||
|
||||
// Добавить участника
|
||||
await addMember('group-id', 'user-id')
|
||||
|
||||
// Удалить участника
|
||||
await removeMember('group-id', 'user-id')
|
||||
|
||||
// Покинуть группу
|
||||
await leaveGroup('group-id')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Админ-панель
|
||||
|
||||
### Доступ
|
||||
|
||||
Только для пользователей с ролью `admin` или `superadmin`.
|
||||
|
||||
**Кнопка в Sidebar:**
|
||||
```tsx
|
||||
<button onClick={() => onOpenAdmin?.()}>
|
||||
<Shield size={20} />
|
||||
</button>
|
||||
```
|
||||
|
||||
### Дашборд
|
||||
|
||||
**Метрики:**
|
||||
- Пользователи (всего, активные, новые)
|
||||
- Сообщения (всего, сегодня)
|
||||
- Группы/каналы
|
||||
- Хранилище
|
||||
- API запросы
|
||||
- Ошибки
|
||||
|
||||
**Графики:**
|
||||
- Активность (день/неделя/месяц)
|
||||
- Прогресс-бары ресурсов (CPU, RAM, Disk)
|
||||
|
||||
### Пользователи
|
||||
|
||||
**Функции:**
|
||||
- Поиск по имени/email/телефону
|
||||
- Фильтры (роль, статус, сортировка)
|
||||
- Изменение роли
|
||||
- Блокировка/разблокировка
|
||||
- Удаление
|
||||
- Экспорт (CSV/JSON)
|
||||
|
||||
**Роли:**
|
||||
- `user` — обычный пользователь
|
||||
- `moderator` — модератор
|
||||
- `admin` — администратор
|
||||
- `superadmin` — супер-админ
|
||||
|
||||
**Статусы:**
|
||||
- `active` — активен
|
||||
- `banned` — заблокирован
|
||||
- `pending` — ожидание
|
||||
- `deleted` — удалён
|
||||
|
||||
### Логи
|
||||
|
||||
**Фильтры:**
|
||||
- Поиск по пользователю/действию/цели
|
||||
- Тип действия (14 типов)
|
||||
- Период дат
|
||||
- Сортировка
|
||||
|
||||
**Экспорт:**
|
||||
```typescript
|
||||
const handleExport = () => {
|
||||
const data = JSON.stringify(filteredLogs, null, 2)
|
||||
const blob = new Blob([data], { type: 'application/json' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `logs-${new Date().toISOString().split('T')[0]}.json`
|
||||
a.click()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Настройки
|
||||
|
||||
### Общие
|
||||
|
||||
- Режим обслуживания
|
||||
- Регистрация включена/выключена
|
||||
- Сообщение о техобслуживании
|
||||
|
||||
### Пользователи
|
||||
|
||||
- Требовать подтверждение email
|
||||
- Требовать подтверждение телефона
|
||||
- Разрешить несколько сессий
|
||||
- Минимальная длина пароля
|
||||
- Таймаут сессии
|
||||
|
||||
### Контент
|
||||
|
||||
- Макс. размер файла (50MB)
|
||||
- Макс. длина сообщения (4096 символов)
|
||||
- Макс. групп на пользователя (50)
|
||||
- Макс. каналов на пользователя (100)
|
||||
- Разрешённые типы файлов
|
||||
|
||||
### Безопасность
|
||||
|
||||
- Rate limiting (60 запросов/мин)
|
||||
- Защита от перебора (5 попыток)
|
||||
- Длительность блокировки (15 мин)
|
||||
|
||||
### Уведомления
|
||||
|
||||
- Email уведомления
|
||||
- Push уведомления
|
||||
- SMTP настройки
|
||||
|
||||
### Модерация
|
||||
|
||||
- Автомодерация
|
||||
- Запрещённые слова
|
||||
- Порог жалоб (10)
|
||||
|
||||
---
|
||||
|
||||
## 🎨 UI компоненты
|
||||
|
||||
### Avatar
|
||||
|
||||
```tsx
|
||||
import Avatar from '@/components/ui/Avatar'
|
||||
|
||||
<Avatar name="Иван Петров" size="md" online={true} />
|
||||
```
|
||||
|
||||
### UserSearch
|
||||
|
||||
```tsx
|
||||
import UserSearch from '@/components/ui/UserSearch'
|
||||
|
||||
<UserSearch
|
||||
showStartChat
|
||||
showAddToGroup
|
||||
groupId="grp123"
|
||||
onSelect={(user) => console.log(user)}
|
||||
/>
|
||||
```
|
||||
|
||||
### CreateGroupModal
|
||||
|
||||
```tsx
|
||||
import CreateGroupModal from '@/components/ui/CreateGroupModal'
|
||||
|
||||
<CreateGroupModal
|
||||
isOpen={showModal}
|
||||
onClose={() => setShowModal(false)}
|
||||
mode="group"
|
||||
/>
|
||||
```
|
||||
|
||||
### MembersPanel
|
||||
|
||||
```tsx
|
||||
import MembersPanel from '@/components/ui/MembersPanel'
|
||||
|
||||
<MembersPanel
|
||||
isOpen={showPanel}
|
||||
onClose={() => setShowPanel(false)}
|
||||
groupId="grp123"
|
||||
canAddMembers
|
||||
canRemoveMembers
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📡 API клиент
|
||||
|
||||
### Tinode Client
|
||||
|
||||
```typescript
|
||||
import { getTinode } from '@/lib/tinode-client'
|
||||
|
||||
const tn = getTinode()
|
||||
|
||||
// Подключение
|
||||
await tn.connect()
|
||||
|
||||
// Вход
|
||||
await tn.loginBasic('username', 'password')
|
||||
|
||||
// Получение темы
|
||||
const topic = tn.getTopic('grp123')
|
||||
|
||||
// Подписка
|
||||
await topic.subscribe(query)
|
||||
|
||||
// Отправка сообщения
|
||||
const draft = topic.createMessage('Привет!', false)
|
||||
await topic.publishMessage(draft)
|
||||
```
|
||||
|
||||
### Store
|
||||
|
||||
```typescript
|
||||
import { useAuthStore } from '@/store/auth'
|
||||
import { useChatStore } from '@/store/chat'
|
||||
import { useGroupsStore } from '@/store/groups'
|
||||
import { useAdminStore } from '@/store/admin'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Конфигурация
|
||||
|
||||
### Переменные окружения
|
||||
|
||||
Создайте файл `.env` в корне проекта:
|
||||
|
||||
```env
|
||||
VITE_TINODE_HOST=localhost:6060
|
||||
VITE_TINODE_API_KEY=AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K
|
||||
VITE_TINODE_SECURE=false
|
||||
VITE_APP_NAME=Ласточка
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"jsx": "react-jsx",
|
||||
"strict": false,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Сборка
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Production
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm run preview
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
```dockerfile
|
||||
FROM node:18-alpine
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
EXPOSE 4173
|
||||
CMD ["npm", "run", "preview"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Вклад
|
||||
|
||||
### Как помочь
|
||||
|
||||
1. Форкните репозиторий
|
||||
2. Создайте ветку (`git checkout -b feature/amazing-feature`)
|
||||
3. Закоммитьте изменения (`git commit -m 'Add amazing feature'`)
|
||||
4. Запушьте (`git push origin feature/amazing-feature`)
|
||||
5. Создайте Pull Request
|
||||
|
||||
### Стандарты кода
|
||||
|
||||
- **TypeScript:** strict mode выключен для совместимости
|
||||
- **Именование:** camelCase для переменных, PascalCase для компонентов
|
||||
- **Импорты:** сначала npm пакеты, потом локальные файлы
|
||||
|
||||
---
|
||||
|
||||
**Ласточка** — народный мессенджер с открытым кодом 🕊️
|
||||
|
||||
*Сделано с ❤️ для свободного общения*
|
||||
Reference in New Issue
Block a user