From 8c772bf8ae9adf74fb0b6338b9644f4617d09daa Mon Sep 17 00:00:00 2001 From: andrei Date: Sun, 30 Nov 2025 13:08:45 +0500 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=80=D0=B8=D0=B4=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 286 +++++++++++++++++- web/Dockerfile | 2 +- .../ViewTaskModalForm/ViewTaskModal.jsx | 9 +- .../ViewTaskModalForm/useTaskLessonModal.js | 82 ++++- 4 files changed, 371 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b767e03..95982c7 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,286 @@ -# psb_hack +# ВНИМАНИЕ + +Просьба дочитать данный файл от начала и до КОНЦА, чтобы не упустить важную информацию касающуюся демонстрации проекта + +# Lectio + +**Lectio** — Система позволяет создавать курсы с лекциями и заданиями, записываться на них, отмечать прочитанные материалы, загружать решения с файлами любой сложности, а преподавателям — выставлять ручные оценки. Реализована ролевая модель (студент / преподаватель / администратор), автоматический подсчёт прогресса по курсу, детальный журнал успеваемости с максимальными оценками и статусом чтения лекций, а также личный кабинет студента, где он видит только свою успеваемость. + +## Наша команда Numerum + +Дувакин Андрей - фуллстак + дувопс +Лучевников Лев - фронтэнд-разработчик +Филимонов Михаил - бэкэнд-разработчик +Сотов Дмитрий - фронтэнд-разработчик + +## Технологический стек +* Backend: FastAPI (Python), SQLAlchemy 2.0, PostgreSQL, JWT-аутентификация +* Frontend: React + Vite + JavaScript + Ant Design + RTK Query +* Инфраструктура: Docker, Kubernetes (microk8s), Helm-чарт, cert-manager + Let’s Encrypt + +## Развернутый дистрибутив +WEB: https://lectio.numerum.team +API: https://api.lectio.numerum.team (с автоматической Swagger-документацией) +Хранение файлов: PersistentVolume с hostPath + +## Структура проекта +### API +Бэкенд построен на FastAPI с луковой архитектурой. +``` +app/ +├── controllers/ — FastAPI-роутеры (auth, courses, lessons, tasks, solutions и т.д.) +├── infrastructure/ — сервисы бизнес-логики (gradebook_service, solutions_service и др.) +├── application/ — репозитории (работа с БД через SQLAlchemy 2.0 async) +├── domain/ +│ ├── models/ — SQLAlchemy-модели (ORM) +│ └── entities/ — Pydantic-схемы для запросов/ответов +├── database/ — сессии, Alembic-миграции +├── core/ — константы, настройки +└── main.py, settings.py +``` +API спроектирован так, что добавление новых сущностей (например, сертификаты, тесты, группы) требует минимум изменений — достаточно добавить модель, репозиторий, сервис и роутер. + +### WEB +Фронтенд реализован на React + Vite + JavaScript с использованием UI-библиотеки Ant Design и state-менеджмента через RTK Query. +``` +src/ +├── Api/ — RTK Query API-слайсы (authApi, coursesApi, gradebookApi, solutionsApi и др.) +├── App/ — маршрутизация, PrivateRoute, AdminRoute, ErrorBoundary +├── Components/ +│ ├── Layouts/ — MainLayout (шапка, сайдбар, адаптивность) +│ ├── Pages/ — все страницы: CoursesPage, CourseDetailPage, GradebookPage, Login, Profile и др. +│ └── Widgets/ — переиспользуемые компоненты (модалки, лоадеры) +├── Redux/ — store + слайсы состояния (auth, courses, modals) +├── Core/ — константы, конфиги (VITE_BASE_URL, роли) +├── Hooks/ — кастомные хуки (useAuthUtils и др.) +└── Styles/ — глобальные стили +``` + +## Система ролей + +В системе реализована строгая ролевая модель с тремя ролями. Права проверяются как на бэкенде (зависимости FastAPI), так и на фронтенде (PrivateRoute / AdminRoute). + +### Администратор + +- Всё, что может преподаватель +- Управление пользователями (создание, редактирование, удаление, смена роли) +- Управление ролями и статусами +- Просмотр и редактирование всех курсов и их содержимого +- Доступ ко всем журналам успеваемости + + +### Преподаватель + +- Создавать, редактировать и удалять свои курсы +- Добавлять/редактировать лекции и задания +- Назначать себе и другим преподавателям курсы +- Просматривать полный журнал успеваемости по своим курсам +- Выставлять оценки и комментарии к решениям студентов +- Скачивать все файлы решений + + +### Студент + +- Просматривать список всех курсов и записываться на них +- Просматривать лекции и отмечать их как «прочитанные» +- Загружать решения заданий +- Видеть свой прогресс по каждому курсу +- Видеть свою успеваемость в журнале (только свою) +- Редактировать свой профиль (ФИО, фото и т.д.) + +## Развертывание проекта + +### API + +Бэкенд можно запустить тремя способами — от самого простого до полноценного production-деплоймента. + +#### 1. Локальный запуск (без Docker) + +```bash +# Клонируем репозиторий +git clone https://github.com/AndreiDuvakin/lectio.git +cd lectio/api + +# Создаём виртуальное окружение и устанавливаем зависимости +python -m venv .venv +source .venv/bin/activate # Windows: .venv\Scripts\activate +pip install -r req.txt + +# Создаём файл .env в корне api/ +cp .env.example .env +# Редактируем .env — обязательно заполняем: +DB_DRIVER=postgresql+asyncpg +DB_HOST=localhost +DB_PORT=5432 +DB_USER=postgres +DB_PASSWORD=your_password +DB_NAME=lectio +DB_SCHEMA=public +SECRET_KEY=your_very_strong_secret_key_here + +# Применяем миграции +alembic upgrade head + +# Запускаем сервер +uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 +``` +API: http://localhost:8000 + +#### 2. Запуск через Docker + +Обратите внимание, что для хранения файлов необходимо создавать хранилище. +**Вариант A — просто тянуть готовый образ** +```bash +docker run -d \ + --name lectio-api \ + -p 8000:8000 \ + -e DB_DRIVER=postgresql+asyncpg \ + -e DB_HOST=host.docker.internal \ + -e DB_PORT=5432 \ + -e DB_USER=postgres \ + -e DB_PASSWORD=your_password \ + -e DB_NAME=lectio \ + -e DB_SCHEMA=public \ + -e SECRET_KEY=supersecretkey123 \ + -v ./uploads:/app/uploads \ + andreiduvakin/lectio-api:latest +``` + +**Вариант B — собрать локально** +```bash +docker build -t lectio-api . +docker run -d --name lectio-api -p 8000:8000 lectio-api +``` + +#### 3. Production-развёртывание в Kubernetes +Используется Helm-чарт **k8s/helm/lectio-api**. +```bash +# Устанавливаем чарт (пример для нашего microk8s) +helm upgrade --install lectio-web k8s/helm/lectio-web --namespace lectio-web --create-namespace +``` +Что нужно настроить в **values.yaml**: +``` +env: + DB_DRIVER: postgresql+asyncpg + DB_HOST: db.numerum.team + DB_PORT: 30000 + DB_USER: lectio + DB_NAME: lectio + DB_SCHEMA: public +``` + +**Secret** с чувствительными данными: +``` +# k8s/helm/lectio-api/templates/secrets.yaml +apiVersion: v1 +kind: Secret +metadata: + name: lectio-api-secret +type: Opaque +data: + SECRET_KEY: base64_encoded_very_long_key== + DB_PASSWORD: base64_encoded_password== +``` + +**ОБРАТИТЕ ВНИМАНИЕ** +В настоящем решении не предоставлен действительный файл **k8s/helm/lectio-api/templates/secrets.yaml** - для предотвращения несанкционированного доступа к нашей базе данных. Для ВАШЕЙ конфигурации нужно создавать свой файл. + +PersistentVolume автоматически создаётся через pvc.yaml и монтирует папку /mnt/k8s_storage/lectio-api/uploads на хосте — все загруженные студентами файлы сохраняются между перезапусками. +После деплоя: + +API: https://api.lectio.numerum.team/ +Swagger/ReDoc: https://api.lectio.numerum.team/docs + +Именно так система работает в продакшене прямо сейчас — с HTTPS, Let’s Encrypt, персистентным хранилищем и автоматическим масштабированием. + +### WEB + +Фронтенд можно запустить тремя способами — от локальной разработки до production-развёртывания в Kubernetes. + +### 1. Локальный запуск + +```bash +git clone https://github.com/AndreiDuvakin/lectio.git +cd lectio/web + +# Устанавливаем зависимости +npm install + +# Создаём .env файл (в корне web/) +echo "VITE_BASE_URL=http://localhost:8000/api/v1 +VITE_ROOT_ROLE_NAME=root" > .env + +# Запускаем dev-сервер +npm run dev +``` +Приложение будет доступно по адресу: http://localhost:5173 + +### 2. Запуск через Docker + +**Вариант A — готовый образ** +Готовый образ уже собран с продакшен-настройками! +**VITE_BASE_URL** и **VITE_ROOT_ROLE_NAME** жёстко зашиты в образ на этапе сборки: +```Dockerfile +ENV VITE_BASE_URL=https://api.lectio.numerum.team/api/v1 +ENV VITE_ROOT_ROLE_NAME=root +``` +Поэтому запуск предельно прост: +```bash +docker run -d \ + --name lectio-web \ + -p 3000:3000 \ + andreiduvakin/lectio-web:latest +``` + +**Вариант B — сборка локально** +```bash +docker run -d \ + --name lectio-web \ + -p 3000:3000 \ + --build-arg VITE_BASE_URL=http://localhost:8000/api/v1 \ + andreiduvakin/lectio-web:latest +``` +Приложение доступно по адресу: http://localhost:3000 + +### 3. Production-развёртывание в Kubernetes + +Используется Helm-чарт k8s/helm/lectio-web. + +```bash +helm upgrade --install lectio-web k8s/helm/lectio-web --namespace lectio-web --create-namespace +``` + +Поскольку переменные окружения уже зашиты в образ на этапе **npm run build**, в **values.yaml** ничего передавать не нужно. + +После деплоя приложение доступно по адресу: +https://lectio.numerum.team +Именно так работает продакшен прямо сейчас. + + +## Демонстрация + +Видео УСТАНОВКИ и ДЕМОНСТРАЦИИ проекта достпуно по ссылке: https://disk.yandex.ru/i/sDi_GnOUBnpVaA + +Пожалуйста, досмотрите видео целиком. + +# ВНИМАНИЕ + +Для того, чтобы можно было протестировать систему в развернутом виде с разных ролей были подготовлены следующие авторизационные данные для проверки на: +https://lectio.numerum.team + +* Администратор: +Логин: admin +Пароль: Password1! + +* Студент: +Логин: student +Пароль: Password1! + +* Учитель: +Логин: teacher +Пароль: Password1! + +## Регистрация + +В системе можно зарегистрироваться перейдя на страницу регистрации из страницы авторизации, но по умолчанию вам будет выдана роль Студент без зачисления на курс \ No newline at end of file diff --git a/web/Dockerfile b/web/Dockerfile index e1bb99b..388a3e3 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -9,7 +9,7 @@ RUN npm install COPY . . ARG VITE_BASE_URL -ENV VITE_BASE_URL=http://localhost:8000/api/v1 +ENV VITE_BASE_URL=https://api.lectio.numerum.team/api/v1 ARG VITE_ROOT_ROLE_NAME ENV VITE_ROOT_ROLE_NAME=root RUN npm run build diff --git a/web/src/Components/Pages/CourseDetailPage/Components/ViewTaskModalForm/ViewTaskModal.jsx b/web/src/Components/Pages/CourseDetailPage/Components/ViewTaskModalForm/ViewTaskModal.jsx index a4a2180..d66dfd5 100644 --- a/web/src/Components/Pages/CourseDetailPage/Components/ViewTaskModalForm/ViewTaskModal.jsx +++ b/web/src/Components/Pages/CourseDetailPage/Components/ViewTaskModalForm/ViewTaskModal.jsx @@ -37,7 +37,7 @@ const ViewTaskModal = () => { currentTaskFiles, isCurrentTaskFilesLoading, isCurrentTaskFilesError, - downloadFile, + downloadTasksFile, downloadingFiles, currentUser, mySolutions, @@ -55,6 +55,7 @@ const ViewTaskModal = () => { commentForm, setComment, comment, + downloadSolutionFile, } = useViewTaskModal(); return ( @@ -126,7 +127,7 @@ const ViewTaskModal = () => { {file.filename || "Не указан"}