30 KiB
🚀 План реализации нового Frontend (Material UI 3 + Next.js 16)
Дата создания: 26 января 2026
Проект: Uchill Platform - Frontend Material
Цель: Создать новый frontend с Material UI 3, iOS 24+ дизайном и панелью управления снизу
📋 Общая информация
Технологический стек:
- Framework: Next.js 16.1+ (с Turbopack)
- UI Library: Material Web Components 3 (
@material/web) - ТОЛЬКО Material компоненты! - Layout System: Material Design 3 Grid System
- Styling: CSS Variables (Material Theme)
- TypeScript: Да
- State Management: React Context API
- API Client: Axios
- Real-time: WebSocket (чат, доска), WebRTC (видеозвонки)
- Icons: Material Symbols (Google Fonts)
Дизайн-система:
- Цвета: Из
landing_site(см. ниже) - Стиль: iOS 24+ (rounded corners, blur effects, glassmorphism)
- Навигация: Bottom Navigation Bar (iOS-style, Material Navigation)
- Компоненты: ТОЛЬКО Material Web Components 3 (
@material/web) - Layout: Material Design 3 Grid System
- Styling: Чистый CSS с CSS Variables (БЕЗ Tailwind CSS)
🎨 Цветовая палитра из landing_site
:root {
--theme: #7444FD; /* Основной фиолетовый */
--theme2: #F9F3EF; /* Бежевый фон */
--theme3: #FAF8FF; /* Светло-фиолетовый фон */
--title: #282C32; /* Темно-серый для заголовков */
--text: #858585; /* Серый для текста */
--text2: #cbcbcb; /* Светло-серый */
--border: #E6E6E6; /* Границы */
--border-2: #F1F1F1; /* Светлые границы */
--bg-1: #161921; /* Темный фон */
--bg-2: #F6F7FF; /* Светлый фон */
--white: #fff;
--black: #000;
--orange: #e78c45;
}
Адаптация для iOS 24+ стиля:
- Использовать blur effects (backdrop-filter)
- Rounded corners (16px, 20px, 24px)
- Glassmorphism для панелей
- Soft shadows
- Smooth animations
📦 Этап 1: Подготовка проекта и инфраструктуры
Задача 1.1: Инициализация Next.js 16 проекта
- Создать новый Next.js проект в
front_material/ - Настроить TypeScript конфигурацию
- Настроить ESLint и Prettier
- Настроить пути импортов (
@/components,@/utils, и т.д.) - Создать базовую структуру папок
Команды:
cd front_material
npx create-next-app@latest . --typescript --no-tailwind --app --no-src-dir
npm install @material/web
npm install axios date-fns livekit-client
npm install -D @types/node @types/react @types/react-dom
⚠️ Важно: Создаем проект БЕЗ Tailwind CSS (--no-tailwind)!
Задача 1.2: Настройка Docker
- Создать
Dockerfileдля Next.js 16 - Создать
.dockerignore - Настроить multi-stage build (development, production)
- Обновить
docker-compose.yml(отключить старый frontend, добавить новый) - Настроить hot reload в Docker
Dockerfile структура:
# Development stage
FROM node:20-alpine AS development
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
# Production stage
FROM node:20-alpine AS production
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
Задача 1.3: Настройка переменных окружения
- Создать
.env.example - Настроить
NEXT_PUBLIC_API_URL - Настроить
NEXT_PUBLIC_WS_URL - Настроить другие переменные окружения
Файл .env.example:
NEXT_PUBLIC_API_URL=http://localhost:8123/api
NEXT_PUBLIC_WS_URL=ws://localhost:8123/ws
NEXT_PUBLIC_LIVEKIT_URL=ws://localhost:7880
NODE_ENV=development
Задача 1.4: Настройка Material Web Components
- Установить
@material/web - Настроить импорт компонентов
- Создать wrapper компоненты для React
- Настроить темизацию (цвета из landing_site)
- Создать базовые стили
Структура:
front_material/
├── src/
│ ├── components/
│ │ ├── material/ # Wrapper компоненты для Material UI
│ │ │ ├── Button.tsx
│ │ │ ├── TextField.tsx
│ │ │ ├── Card.tsx
│ │ │ └── ...
│ │ └── ...
│ ├── styles/
│ │ ├── material-theme.css # Кастомная тема Material UI
│ │ └── globals.css # Глобальные стили
🎨 Этап 2: Дизайн-система и базовые компоненты
Задача 2.1: Создание цветовой темы
- Создать CSS переменные на основе цветов landing_site
- Адаптировать цвета для iOS 24+ стиля
- Создать темную тему (dark mode)
- Настроить Material UI тему с кастомными цветами
Файл src/styles/theme.css:
:root {
/* Основные цвета из landing_site */
--md-sys-color-primary: #7444FD;
--md-sys-color-on-primary: #FFFFFF;
--md-sys-color-primary-container: #FAF8FF;
--md-sys-color-on-primary-container: #282C32;
/* iOS 24+ адаптация */
--ios-blur-background: rgba(255, 255, 255, 0.8);
--ios-blur-background-dark: rgba(0, 0, 0, 0.6);
--ios-border-radius: 20px;
--ios-border-radius-small: 16px;
--ios-border-radius-large: 24px;
--ios-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
[data-theme="dark"] {
--md-sys-color-primary: #9D6AFF;
--ios-blur-background: rgba(0, 0, 0, 0.8);
}
Задача 2.2: Использование Material Web Components (напрямую)
- Импортировать все нужные Material компоненты
- Настроить типизацию для Web Components в TypeScript
- Создать глобальный импорт всех Material компонентов
Важно: Используем Material Web Components напрямую в JSX/TSX, без wrapper компонентов!
Файл src/lib/material-components.ts:
// Импортируем все нужные Material компоненты
import '@material/web/button/filled-button.js';
import '@material/web/button/outlined-button.js';
import '@material/web/button/text-button.js';
import '@material/web/button/elevated-button.js';
import '@material/web/button/tonal-button.js';
import '@material/web/textfield/filled-text-field.js';
import '@material/web/textfield/outlined-text-field.js';
import '@material/web/card/filled-card.js';
import '@material/web/card/elevated-card.js';
import '@material/web/card/outlined-card.js';
import '@material/web/list/list.js';
import '@material/web/list/list-item.js';
import '@material/web/dialog/dialog.js';
import '@material/web/chip/chip-set.js';
import '@material/web/chip/assist-chip.js';
import '@material/web/chip/filter-chip.js';
import '@material/web/icon/icon.js';
import '@material/web/iconbutton/icon-button.js';
import '@material/web/checkbox/checkbox.js';
import '@material/web/radio/radio.js';
import '@material/web/switch/switch.js';
import '@material/web/select/filled-select.js';
import '@material/web/select/outlined-select.js';
// И другие по необходимости
Использование в компонентах:
'use client';
export default function LoginPage() {
return (
<div>
<md-outlined-text-field
label="Email"
type="email"
></md-outlined-text-field>
<md-filled-button>Войти</md-filled-button>
</div>
);
}
Задача 2.3: Настройка TypeScript для Web Components
- Создать типы для Material Web Components
- Настроить JSX для использования Web Components
Файл src/types/material-web.d.ts:
declare namespace JSX {
interface IntrinsicElements {
'md-filled-button': any;
'md-outlined-button': any;
'md-text-button': any;
'md-elevated-button': any;
'md-tonal-button': any;
'md-filled-text-field': any;
'md-outlined-text-field': any;
'md-filled-card': any;
'md-elevated-card': any;
'md-outlined-card': any;
'md-list': any;
'md-list-item': any;
'md-dialog': any;
'md-chip-set': any;
'md-assist-chip': any;
'md-filter-chip': any;
'md-icon': any;
'md-icon-button': any;
'md-checkbox': any;
'md-radio': any;
'md-switch': any;
'md-filled-select': any;
'md-outlined-select': any;
// ... другие компоненты
}
}
Задача 2.4: Настройка Material Grid System
- Использовать CSS Grid из Material Design 3
- Настроить responsive breakpoints
- Создать Layout Grid компоненты
Material Design 3 Grid:
/* src/styles/material-grid.css */
/* Material Design 3 Grid System */
.md-grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 16px;
padding: 0 16px;
}
/* Responsive breakpoints (Material Design 3) */
@media (min-width: 600px) { /* Tablet */
.md-grid {
gap: 24px;
padding: 0 24px;
}
}
@media (min-width: 840px) { /* Desktop */
.md-grid {
gap: 24px;
padding: 0 24px;
}
}
@media (min-width: 1240px) { /* Large Desktop */
.md-grid {
gap: 24px;
max-width: 1200px;
margin: 0 auto;
}
}
/* Grid column classes */
.md-col-1 { grid-column: span 1; }
.md-col-2 { grid-column: span 2; }
.md-col-3 { grid-column: span 3; }
.md-col-4 { grid-column: span 4; }
.md-col-6 { grid-column: span 6; }
.md-col-8 { grid-column: span 8; }
.md-col-12 { grid-column: span 12; }
/* Responsive columns */
@media (max-width: 599px) {
.md-col-sm-12 { grid-column: span 12; }
}
@media (min-width: 600px) and (max-width: 839px) {
.md-col-md-6 { grid-column: span 6; }
.md-col-md-12 { grid-column: span 12; }
}
@media (min-width: 840px) {
.md-col-lg-4 { grid-column: span 4; }
.md-col-lg-6 { grid-column: span 6; }
.md-col-lg-8 { grid-column: span 8; }
}
Задача 2.5: Создание Bottom Navigation Bar (iOS-style + Material)
- Компонент
BottomNavigationBarс использованием Material компонентов - Использовать
md-navigation-barиmd-navigation-tab - Кастомизация под iOS 24+ стиль
- Badge для уведомлений (Material Badge)
- Адаптация под разные роли (mentor, client, parent)
Использование Material Navigation:
'use client';
import '@material/web/labs/navigationbar/navigation-bar.js';
import '@material/web/labs/navigationtab/navigation-tab.js';
import '@material/web/icon/icon.js';
import '@material/web/badge/badge.js';
export function BottomNavigationBar({ userRole }: { userRole: string }) {
return (
<md-navigation-bar className="ios-bottom-bar">
<md-navigation-tab label="Главная" active>
<md-icon slot="inactive-icon">home</md-icon>
<md-icon slot="active-icon">home</md-icon>
</md-navigation-tab>
<md-navigation-tab label="Расписание">
<md-icon slot="inactive-icon">calendar_month</md-icon>
<md-icon slot="active-icon">calendar_month</md-icon>
</md-navigation-tab>
<md-navigation-tab label="Чат">
<md-icon slot="inactive-icon">chat</md-icon>
<md-icon slot="active-icon">chat</md-icon>
<md-badge value="3"></md-badge>
</md-navigation-tab>
{userRole === 'mentor' && (
<md-navigation-tab label="Студенты">
<md-icon slot="inactive-icon">group</md-icon>
<md-icon slot="active-icon">group</md-icon>
</md-navigation-tab>
)}
</md-navigation-bar>
);
}
Кастомизация под iOS стиль:
/* src/styles/ios-navigation.css */
md-navigation-bar.ios-bottom-bar {
--md-navigation-bar-container-color: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-top: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.05);
border-radius: 24px 24px 0 0;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
}
[data-theme="dark"] md-navigation-bar.ios-bottom-bar {
--md-navigation-bar-container-color: rgba(0, 0, 0, 0.8);
border-top-color: rgba(255, 255, 255, 0.1);
}
🏗️ Этап 3: Архитектура и структура приложения
Задача 3.1: Настройка роутинга Next.js App Router
- Создать структуру папок для маршрутов
- Настроить Route Groups:
(auth),(protected) - Создать layout для защищенных страниц
- Создать layout для публичных страниц
- Настроить middleware для проверки авторизации
Структура:
src/app/
├── (auth)/
│ ├── login/
│ ├── register/
│ └── layout.tsx
├── (protected)/
│ ├── dashboard/
│ ├── schedule/
│ ├── chat/
│ └── layout.tsx
├── layout.tsx
└── page.tsx
Задача 3.2: Создание системы аутентификации
- Context для хранения пользователя (
AuthContext) - Хуки для работы с API (
useAuth,useLogin,useLogout) - Хранение токенов (localStorage)
- Автоматическое обновление токенов
- Защита маршрутов через middleware
Файл src/contexts/AuthContext.tsx:
'use client';
import { createContext, useContext, useState, useEffect } from 'react';
import { getCurrentUser } from '@/api/auth';
interface User {
id: number;
email: string;
role: 'mentor' | 'client' | 'parent';
// ...
}
interface AuthContextType {
user: User | null;
loading: boolean;
login: (token: string) => Promise<void>;
logout: () => void;
}
const AuthContext = createContext<AuthContextType | null>(null);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
// Загрузка пользователя при монтировании
useEffect(() => {
loadUser();
}, []);
const loadUser = async () => {
try {
const token = localStorage.getItem('access_token');
if (token) {
const userData = await getCurrentUser();
setUser(userData);
}
} catch (error) {
localStorage.removeItem('access_token');
} finally {
setLoading(false);
}
};
const login = async (token: string) => {
localStorage.setItem('access_token', token);
await loadUser();
};
const logout = () => {
localStorage.removeItem('access_token');
setUser(null);
};
return (
<AuthContext.Provider value={{ user, loading, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (!context) throw new Error('useAuth must be used within AuthProvider');
return context;
}
Задача 3.3: Создание API клиента
- Настроить Axios с базовым URL
- Добавить interceptors для токенов
- Обработка ошибок
- Типизация API ответов
- Создать модули API (auth, schedule, chat, и т.д.)
Файл src/lib/api-client.ts:
import axios from 'axios';
const apiClient = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8123/api',
headers: {
'Content-Type': 'application/json',
},
});
// Добавление токена к запросам
apiClient.interceptors.request.use((config) => {
const token = localStorage.getItem('access_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Обработка ошибок
apiClient.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem('access_token');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
export default apiClient;
Задача 3.4: Создание системы управления состоянием
- Настроить React Context для глобального состояния
- Опционально: добавить Zustand для сложного состояния
- Создать stores (userStore, notificationStore, и т.д.)
📱 Этап 4: Основные страницы и компоненты
Задача 4.1: Страницы аутентификации
/login- страница входа- Material UI TextField для email/password
- Material UI Button
- iOS-стиль дизайн
- Валидация форм
/register- страница регистрации- Форма с выбором роли
- Material UI компоненты
- Валидация
/forgot-password- восстановление пароля/verify-email- подтверждение email
Задача 4.2: Главный Layout (защищенные страницы)
- Создать
ProtectedLayout - Верхняя панель навигации (iOS-style)
- Нижняя панель навигации (Bottom Navigation Bar)
- Контентная область с padding
- Обработка разных ролей
Компонент ProtectedLayout.tsx:
'use client';
import { useAuth } from '@/contexts/AuthContext';
import { BottomNavigationBar } from '@/components/navigation/BottomNavigationBar';
import { TopNavigationBar } from '@/components/navigation/TopNavigationBar';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';
export default function ProtectedLayout({ children }: { children: React.ReactNode }) {
const { user, loading } = useAuth();
const router = useRouter();
useEffect(() => {
if (!loading && !user) {
router.push('/login');
}
}, [user, loading, router]);
if (loading) {
return <LoadingScreen />;
}
if (!user) {
return null;
}
return (
<div className="flex flex-col h-screen bg-gray-50 dark:bg-gray-900">
<TopNavigationBar user={user} />
<main className="flex-1 overflow-y-auto pb-20">
{children}
</main>
<BottomNavigationBar user={user} />
</div>
);
}
Задача 4.3: Дашборды для каждой роли
/dashboard/mentor- дашборд ментора- Статистика студентов
- Ближайшие занятия
- Графики доходов
- Material UI Cards
/dashboard/client- дашборд клиента- Календарь занятий
- Прогресс обучения
- Статистика
/dashboard/parent- дашборд родителя- Выбор ребенка
- Статистика детей
Задача 4.4: Страница расписания
- Календарь (Material UI или кастомный)
- Создание занятия
- Редактирование занятия
- Список занятий
- Фильтры
Задача 4.5: Страница чата
- Список чатов (Material UI List)
- Окно чата
- WebSocket интеграция
- Отправка сообщений
- Файлы и медиа
Задача 4.6: Страница видеозвонков
- Интеграция с LiveKit
- Видео компоненты
- Управление микрофоном/камерой
- Интерактивная доска
- Чат во время звонка
🎨 Этап 5: Стилизация и анимации
Задача 5.1: Настройка стилей (только CSS, без Tailwind)
- Создать CSS переменные для всей платформы
- Использовать Material Design 3 Grid System
- Настроить iOS 24+ эффекты (blur, rounded corners)
- Настроить dark mode через CSS
⚠️ Важно: НЕ используем Tailwind CSS! Только чистый CSS и CSS Variables.
Файл src/styles/globals.css:
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Roboto', -apple-system, BlinkMacSystemFont, sans-serif;
color: var(--md-sys-color-on-surface);
background-color: var(--md-sys-color-surface);
}
/* iOS 24+ эффекты */
.ios-blur {
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
}
.ios-card {
border-radius: 20px;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
[data-theme="dark"] .ios-card {
background: rgba(0, 0, 0, 0.6);
}
Задача 5.2: Создание анимаций
- Переходы между страницами
- Анимация Bottom Navigation Bar
- Анимация модальных окон
- Skeleton loaders
- Pull-to-refresh (опционально)
Задача 5.3: Адаптивный дизайн
- Mobile-first подход
- Breakpoints для планшетов и десктопов
- Адаптация Bottom Navigation Bar для разных экранов
- Оптимизация для touch устройств
🔌 Этап 6: Интеграция с Backend
Задача 6.1: Интеграция API
- Модуль
src/api/auth.ts- аутентификация - Модуль
src/api/schedule.ts- расписание - Модуль
src/api/chat.ts- чат - Модуль
src/api/materials.ts- материалы - Модуль
src/api/homework.ts- домашние задания - Модуль
src/api/students.ts- студенты - Модуль
src/api/payment.ts- оплата - И другие модули по необходимости
Задача 6.2: WebSocket интеграция
- Хук
useChatWebSocketдля чата - Хук
useBoardWebSocketдля доски - Хук
useVideoWebSocketдля видеозвонков - Обработка переподключений
- Обработка ошибок
Задача 6.3: Интеграция видеозвонков
- LiveKit клиент
- Компоненты видео
- Управление медиа
- Screen sharing
- Интерактивная доска во время звонка
🐳 Этап 7: Docker и деплой
Задача 7.1: Обновление docker-compose.yml
- Отключить старый frontend сервис
- Добавить новый
front_materialсервис - Настроить порты
- Настроить volumes
- Настроить environment variables
Изменения в docker-compose.yml:
# Старый frontend - закомментировать или удалить
# frontend:
# ...
# Новый frontend
front_material:
build:
context: ./front_material
dockerfile: Dockerfile
target: development
container_name: platform_front_material
restart: unless-stopped
command: npm run dev
environment:
- NODE_ENV=development
- NEXT_PUBLIC_API_URL=http://web:8000/api
- NEXT_PUBLIC_WS_URL=ws://web:8000/ws
ports:
- "3000:3000"
volumes:
- ./front_material:/app
- /app/node_modules
- /app/.next
networks:
- app_network
depends_on:
- web
Задача 7.2: Production сборка
- Настроить production Dockerfile
- Оптимизация bundle size
- Настройка кеширования
- Настройка статических файлов
📝 Этап 8: Документация и тестирование
Задача 8.1: Документация
- README.md с инструкциями по установке
- Документация компонентов
- Документация API интеграции
- Документация стилей и темизации
Задача 8.2: Тестирование
- Unit тесты для утилит
- Integration тесты для API
- E2E тесты для критичных flow
- Тестирование на разных устройствах
✅ Чеклист миграции со старого frontend
Подготовка:
- Создать backup старого frontend
- Экспортировать важные данные/конфигурации
- Документировать текущие API endpoints
Миграция:
- Постепенно переносить функциональность
- Тестировать каждую страницу
- Проверять интеграцию с backend
- Проверять WebSocket соединения
Завершение:
- Отключить старый frontend в docker-compose.yml
- Обновить документацию
- Обновить CI/CD (если есть)
- Уведомить команду о изменениях
🎯 Приоритеты реализации
Фаза 1 (MVP - 2-3 недели):
- ✅ Этап 1: Подготовка проекта
- ✅ Этап 2: Базовые компоненты
- ✅ Этап 3: Архитектура
- ✅ Этап 4.1-4.3: Аутентификация и дашборды
Фаза 2 (Основной функционал - 3-4 недели):
- ✅ Этап 4.4-4.6: Основные страницы
- ✅ Этап 5: Стилизация
- ✅ Этап 6: Интеграция с Backend
Фаза 3 (Полировка - 1-2 недели):
- ✅ Этап 7: Docker и деплой
- ✅ Этап 8: Документация и тестирование
📚 Полезные ресурсы
Material Web Components:
Next.js 16:
iOS 24+ Design Guidelines:
⚠️ Важные замечания
-
Vite vs Turbopack:
- Next.js 16 уже использует Turbopack, который быстрее Vite
- Рекомендуется использовать Turbopack (встроен в Next.js)
- Если нужен чистый Vite, можно использовать Vite + React, но потеряете SSR
-
Material UI 3 Web Components:
- Это Web Components, не React компоненты
- Нужны wrapper компоненты для использования в React
- Альтернатива: использовать React версию Material UI, но она не Material 3
-
Bottom Navigation:
- На десктопе можно показывать sidebar вместо bottom bar
- Адаптация под разные экраны обязательна
-
Цвета:
- Использовать цвета из landing_site как основу
- Адаптировать под iOS 24+ стиль (blur, rounded corners)
Дата начала: _______________
Ожидаемая дата завершения: _______________
Ответственный: _______________