15 KiB
Team Board — Frontend спецификация
Общие сведения
Технологии:
- React 19.2.0
- TypeScript (~5.9.3)
- Vite 7.3.1 (bundler + dev server)
- React Router DOM 7.13.1 (роутинг)
- Tailwind CSS 4.2.1 (стили)
Файл конфигурации: package.json
Архитектура: SPA (Single Page Application)
Структура проекта
src/
├── App.tsx # Главный компонент с роутингом
├── pages/ # Страницы приложения
│ ├── HomePage.tsx # Главная страница (список проектов)
│ ├── LoginPage.tsx # Страница входа
│ ├── ProjectPage.tsx # Страница проекта (канбан + чат)
│ ├── CreateProjectPage.tsx # Создание проекта
│ └── settings/ # Настройки
│ ├── SettingsLayout.tsx # Layout для настроек
│ ├── SettingsPage.tsx # Общие настройки
│ ├── LabelsPage.tsx # Управление лейблами
│ └── AgentsPage.tsx # Управление агентами
├── components/ # Переиспользуемые компоненты
│ ├── AuthGuard.tsx # Защита роутов авторизацией
│ ├── Sidebar.tsx # Боковая панель навигации
│ ├── KanbanBoard.tsx # Канбан доска задач
│ ├── TaskModal.tsx # Модальное окно задачи
│ ├── CreateTaskModal.tsx # Создание задачи
│ ├── CreateProjectModal.tsx # Создание проекта
│ ├── CreateAgentModal.tsx # Создание агента
│ ├── AgentModal.tsx # Просмотр/редактирование агента
│ ├── ProjectSettings.tsx # Настройки проекта
│ ├── ProjectFiles.tsx # Файлы проекта
│ └── ChatPanel.tsx # Панель чата
├── lib/ # Библиотеки и утилиты
│ ├── api.ts # REST API клиент
│ ├── ws.ts # WebSocket клиент
│ └── auth-client.ts # Авторизация
└── assets/ # Статические ресурсы
Роуты и страницы
Публичные роуты:
/login— LoginPage — вход в систему
Защищённые роуты (AuthGuard):
/— HomePage — список проектов/projects/:id— ProjectPage — страница проекта с канбаном и чатом/projects/new— CreateProjectPage — создание нового проекта/settings— SettingsLayout — настройки (nested routes)/settings— SettingsPage — общие настройки/settings/labels— LabelsPage — управление лейблами/settings/agents— AgentsPage — управление агентами
Роутинг:
<BrowserRouter>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/" element={<AuthGuard><HomePage /></AuthGuard>} />
<Route path="/projects/:id" element={<AuthGuard><ProjectPage /></AuthGuard>} />
<Route path="/projects/new" element={<AuthGuard><CreateProjectPage /></AuthGuard>} />
<Route path="/settings" element={<AuthGuard><SettingsLayout /></AuthGuard>}>
<Route index element={<SettingsPage />} />
<Route path="labels" element={<LabelsPage />} />
<Route path="agents" element={<AgentsPage />} />
</Route>
</Routes>
</BrowserRouter>
Основные компоненты
AuthGuard
Файл: components/AuthGuard.tsx
Назначение: проверяет авторизацию, перенаправляет на /login если токена нет
KanbanBoard
Файл: components/KanbanBoard.tsx
Назначение: канбан доска с drag & drop задач между колонками
Колонки:
- Backlog (#737373)
- TODO (#3b82f6)
- In Progress (#f59e0b)
- Review (#a855f7)
- Done (#22c55e)
Функции:
- Drag & drop задач между статусами
- Фильтрация по исполнителю/лейблам
- Real-time обновления через WebSocket
- Создание задач в определённой колонке
TaskModal
Файл: components/TaskModal.tsx
Назначение: полное отображение и редактирование задачи
Секции:
- Заголовок и описание
- Метаданные (статус, приоритет, лейблы, исполнитель)
- Steps (чеклист этапов)
- Комментарии и обсуждения
- Файловые вложения
ChatPanel
Файл: components/ChatPanel.tsx
Назначение: панель чата проекта с real-time сообщениями
Функции:
- Отправка сообщений
- Упоминания участников (@username)
- Загрузка файлов
- Real-time обновления через WebSocket
Sidebar
Файл: components/Sidebar.tsx
Назначение: боковая панель навигации
Элементы:
- Список проектов
- Общий чат (Lobby)
- Настройки
- Онлайн участники
State Management
Подход: Локальный state с React hooks
Глобального стора нет — каждый компонент управляет своим состоянием
Паттерны управления состоянием:
Загрузка данных:
const [data, setData] = useState<T[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function load() {
try {
const result = await apiCall();
setData(result);
} finally {
setLoading(false);
}
}
load();
}, [dependency]);
Real-time обновления:
useEffect(() => {
const unsubscribe = wsClient.on("event.type", (data) => {
setItems(prev => prev.map(item =>
item.id === data.id ? data : item
));
});
return unsubscribe;
}, []);
Оптимистичные обновления:
const handleUpdate = async (id: string, changes: Partial<T>) => {
// Оптимистично обновляем UI
setItems(prev => prev.map(item =>
item.id === id ? {...item, ...changes} : item
));
try {
await updateItem(id, changes);
} catch {
// Откат в случае ошибки
loadItems();
}
};
API интеграция
Файл: lib/api.ts
Базовый URL: определяется через VITE_API_URL environment variable
HTTP клиент:
async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
const token = getToken();
const headers = {
"Content-Type": "application/json",
...(token && { "Authorization": `Bearer ${token}` })
};
const res = await fetch(`${API_BASE}${path}`, { ...options, headers });
if (!res.ok) {
if (res.status === 401) {
localStorage.removeItem("tb_token");
window.location.href = "/login";
}
throw new Error(await res.json().error);
}
return res.json();
}
API методы по категориям:
Auth:
login(login, password)— вход в систему
Projects:
getProjects()— список проектовgetProject(id)— получить проектcreateProject(data)— создать проектupdateProject(id, data)— обновить проектdeleteProject(id)— удалить проект
Tasks:
getTasks(projectId)— задачи проектаgetTask(id)— получить задачуcreateTask(projectId, data)— создать задачуupdateTask(id, data)— обновить задачуdeleteTask(id)— удалить задачуtakeTask(id)— взять задачу (для агентов)rejectTask(id, reason)— отклонить задачуassignTask(id, assigneeId)— назначить задачуwatchTask(id)/unwatchTask(id)— подписки на задачу
Steps:
getTaskSteps(taskId)— этапы задачиcreateTaskStep(taskId, data)— создать этапupdateTaskStep(taskId, stepId, data)— обновить этапdeleteTaskStep(taskId, stepId)— удалить этап
Messages:
getMessages(params)— сообщения чата/задачиcreateMessage(data)— отправить сообщение
Members:
getMembers()— список участниковgetMember(id)— получить участникаcreateMember(data)— создать участника/агентаupdateMember(id, data)— обновить участникаregenerateMemberToken(id)— новый токен агентаrevokeMemberToken(id)— отозвать токен
Labels:
getLabels()— глобальные лейблыcreateLabel(data)— создать лейблupdateLabel(id, data)— обновить лейблdeleteLabel(id)— удалить лейбл
Files:
uploadFile(file)— загрузить временный файлdownloadAttachment(id)— скачать вложениеgetProjectFiles(projectId)— файлы проектаuploadProjectFile(projectId, file, description)— загрузить файл проектаdeleteProjectFile(projectId, fileId)— удалить файл проекта
WebSocket интеграция
Файл: lib/ws.ts
URL: определяется через VITE_WS_URL environment variable
WSClient класс:
class WSClient {
connect() // подключение с токеном из localStorage
disconnect() // отключение
on(type, handler) // подписка на события
send(data) // отправка сообщения
// Convenience методы:
subscribeProject(projectId)
unsubscribeProject(projectId)
sendChat(chatId, content, mentions)
sendTaskComment(taskId, content, mentions)
heartbeat(status)
}
Обработка событий:
useEffect(() => {
const unsubscribe = wsClient.on("message.new", (message) => {
setMessages(prev => [...prev, message]);
});
return unsubscribe;
}, []);
Поддерживаемые события:
auth.ok— успешная авторизацияauth.error— ошибка авторизацииmessage.new— новое сообщениеtask.created— задача созданаtask.updated— задача обновленаtask.assigned— задача назначенаtask.deleted— задача удаленаagent.status— изменение статуса участникаagent.stream.*— streaming от агентов
Auto-reconnect:
- При разрыве соединения автоматический переподключение через 3 секунды
- Heartbeat каждые 30 секунд для поддержания соединения
- Очередь сообщений до подключения и авторизации
Авторизация
Файл: lib/auth-client.ts
Токены:
- Хранение:
localStorage.getItem("tb_token") - Формат: JWT токен
- Автоматическое добавление в заголовки API запросов
- Автоматический redirect на /login при 401 ошибке
AuthGuard компонент:
function AuthGuard({ children }: { children: React.ReactNode }) {
const token = localStorage.getItem("tb_token");
if (!token) return <Navigate to="/login" />;
return <>{children}</>;
}
Стили и UI
Tailwind CSS 4.2.1:
- Utility-first подход
- CSS переменные для темизации
- Responsive дизайн
Цветовая схема:
:root {
--background: #ffffff;
--foreground: #0f0f0f;
--muted: #6b7280;
--border: #e5e7eb;
--primary: #3b82f6;
--destructive: #ef4444;
}
Компоненты UI:
- Модальные окна
- Drag & drop интерфейсы
- Kanban колонки
- Формы с валидацией
- Файл загрузчики
- Chat интерфейс
Environment переменные
Файл: .env
VITE_API_URL=http://localhost:8100 # Базовый URL REST API
VITE_WS_URL=ws://localhost:8100 # Базовый URL WebSocket
Использование:
const API_BASE = import.meta.env.VITE_API_URL!;
const WS_BASE = import.meta.env.VITE_WS_URL!;
Типизация
TypeScript конфигурация:
- Строгий режим
- Path mapping (
@/→src/) - DOM типы
API типы:
Все типы синхронизированы с backend Pydantic схемами:
Member,AgentConfig,MemberBriefProject,ProjectMemberTask,Step,SubtaskBriefMessage,AttachmentLabel
Производительность
Оптимизации:
- Lazy loading компонентов
- Мемоизация через React.memo для тяжёлых компонентов
- Дебаунсинг поисковых запросов
- Пагинация сообщений чата
- Оптимистичные обновления UI
Bundle размер:
- Tree shaking неиспользуемого кода
- Code splitting по роутам
- Минификация в production
Особенности архитектуры
Real-time синхронизация:
- WebSocket для мгновенных обновлений
- Оптимистичные обновления с откатом при ошибках
- Автоматическая подписка на события проекта
Drag & Drop:
- Нативный HTML5 drag & drop API
- Визуальная обратная связь при перетаскивании
- Оптимистичное обновление с откатом
Файловая система:
- Поддержка загрузки файлов через drag & drop
- Preview для изображений
- Скачивание файлов через API
Offline-first:
- Кэширование в localStorage (токен авторизации)
- Graceful degradation при отсутствии сети
- Очередь WebSocket сообщений
Этот документ описывает фронтенд на основе исходного кода в /root/projects/team-board/web-client-vite/src/ на дату создания спецификации.