wiki: Operations + User-Guide

Morozovka Admin 2026-10-21 07:13:11 +03:00
parent 3c92744163
commit d3b7c0d09c
2 changed files with 364 additions and 0 deletions

236
Operations.md Normal file

@ -0,0 +1,236 @@
# Эксплуатация
## Управление сервисами
```bash
# Портал
systemctl restart morozovka-portal
systemctl status morozovka-portal --no-pager
systemctl is-active morozovka-portal
# Gitea
systemctl restart gitea
systemctl status gitea --no-pager
# Nginx
systemctl reload nginx
nginx -t
# PostgreSQL
systemctl restart postgresql
# Google sync
systemctl list-timers morozovka-sync.timer
```
## Логи
```bash
# Портал (gunicorn + access log)
journalctl -u morozovka-portal -f --no-pager
journalctl -u morozovka-portal -n 100
# Gitea
journalctl -u gitea -f --no-pager
# Nginx
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
# PostgreSQL
journalctl -u postgresql -f --no-pager
tail -f /var/log/postgresql/postgresql-15-main.log
# Google sync
journalctl -u morozovka-sync.timer -n 20
journalctl -u morozovka-sync.service -n 50
```
## Проверка здоровья
```bash
# 1. Health портала
curl -sS http://127.0.0.1:8000/healthz
# → {"db":"ok","llm":"disabled","status":"ok"}
# 2. Все публичные роуты
for p in / /schedule /feed /projects /workshops /login; do
code=$(curl -sS -o /dev/null -w '%{http_code}' "http://127.0.0.1:8000$p")
printf '%-15s %s\n' "$p" "$code"
done
# 3. Полные смоук-тесты (94 проверки, 3 сек)
bash /opt/morozovka-portal/tests/run_smoke.sh
# 4. Миграции
cd /opt/morozovka-portal
export PATH=./venv/bin:$PATH
alembic current
# 5. Сервисы
systemctl is-active morozovka-portal gitea nginx postgresql
```
## Обновление кода
```bash
cd /opt/morozovka-portal
# 1. Бэкап
cp -r app /tmp/app_backup_$(date +%s)
PGPASSWORD='rf-slf-1945' pg_dump -h 127.0.0.1 -U morozovka morozovka_portal > /tmp/db_backup_$(date +%s).sql
# 2. Git pull
git fetch origin
git log HEAD..origin/main --oneline
git pull origin main
# 3. Зависимости (если requirements.txt изменился)
./venv/bin/pip install -r requirements.txt
# 4. Миграции
export PATH=./venv/bin:$PATH
alembic upgrade head
# 5. Синтаксис
python3 -c "import ast,glob; [ast.parse(open(f).read()) for f in glob.glob('app/*.py') + glob.glob('app/modules/*.py')]" && echo "OK"
# 6. Рестарт
systemctl restart morozovka-portal
sleep 3
# 7. Проверка
curl -sS http://127.0.0.1:8000/healthz
bash tests/run_smoke.sh
```
**Если что-то сломалось — откат:**
```bash
git reset --hard HEAD~1
alembic downgrade -1
systemctl restart morozovka-portal
```
## Troubleshooting
### Портал не запускается
```bash
systemctl status morozovka-portal --no-pager
journalctl -u morozovka-portal -n 100 --no-pager
```
Частые причины:
- `.env` не читается → проверь `EnvironmentFile=-/opt/morozovka-portal/.env` в systemd
- Синтаксическая ошибка в Python → `python3 -c "import ast,glob; [ast.parse(open(f).read()) for f in glob.glob('app/*.py')]"`
- Миграции не применены → `alembic current` и `alembic upgrade head`
- Порт 8000 занят → `ss -tlnp | grep 8000`
### /healthz → 503 (db:error)
- PostgreSQL не запущен → `systemctl restart postgresql`
- Неверный `DATABASE_URL` → проверь `.env`, `app/config.py`
- Пароль изменился → `ALTER USER morozovka WITH PASSWORD 'новый';` и `.env`
### Файлы не скачиваются
- Блоб отсутствует на диске → `ls -la /var/lib/gitea/portal-files/ | wc -l`
- `current_version_id` указывает на несуществующую версию → проверь в psql
- Права на папку → проверь `FileFolderACL`
### Webhook 401
- `GITEA_WEBHOOK_SECRET` не совпадает с настройкой в Gitea → проверь оба
### Webhook 200, но нет уведомлений
- У проекта нет `gitea_repo` → проверь в `/projects/<id>`
- У проекта нет подписчиков → проверь `projectsubscription`
- Push в ветку, которая не отслеживается → проверь `payload.ref`
### Gitea sync не работает
- `GOOGLE_CALENDAR_ID` неправильный → проверь в `.env`
- `google_credentials.json` отсутствует → положи в `/opt/morozovka-portal/`
- Календарь не расшарен на service account → Google Calendar → настройки → доступ
- Timer не запущен → `systemctl status morozovka-sync.timer`
### Email не приходит
- SMTP не настроен → письма идут в `journalctl`
- Проверка: `journalctl -u morozovka-portal | grep "EMAIL ДЛЯ"`
### LLM не работает
- `LLM_ENABLED=false` в `.env` (по умолчанию)
- Модель не загружена → `ollama list` (должна быть `qwen2.5:14b`)
- Ollama не запущена → `systemctl status ollama`
- Проверка: `curl -sS http://localhost:11434/v1/models`
## Обслуживание
### Очистка старых сессий
```bash
PGPASSWORD='rf-slf-1945' psql -h 127.0.0.1 -U morozovka -d morozovka_portal -c "
DELETE FROM usersession WHERE created_at < NOW() - INTERVAL '30 days';
"
```
### Очистка старых уведомлений
```bash
PGPASSWORD='rf-slf-1945' psql -h 127.0.0.1 -U morozovka -d morozovka_portal -c "
DELETE FROM notification WHERE is_read = true AND created_at < NOW() - INTERVAL '90 days';
"
```
### Проверка размера портала
```bash
# БД
PGPASSWORD='rf-slf-1945' psql -h 127.0.0.1 -U morozovka -d morozovka_portal -c "
SELECT pg_size_pretty(pg_database_size('morozovka_portal'));
"
# Файлы
du -sh /var/lib/gitea/portal-files/
# Топ-10 таблиц по размеру
PGPASSWORD='rf-slf-1945' psql -h 127.0.0.1 -U morozovka -d morozovka_portal -c "
SELECT relname, pg_size_pretty(pg_total_relation_size(relid))
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC LIMIT 10;
"
```
## Cron / systemd timers
| Timer | Что | Когда |
|---|---|---|
| `morozovka-sync.timer` | Google Calendar → Event | Каждые 15 мин |
| (TODO) `morozovka-backup.timer` | pg_dump + rsync | 3:00 |
## Emergency recovery
### Портал полностью лёг
1. Проверь `systemctl status morozovka-portal postgresql nginx`
2. Если БД умерла → `systemctl restart postgresql`
3. Если портал падает в цикле → `journalctl -u morozovka-portal -n 100`
4. Синтаксис → `python3 -c "import ast,glob; [ast.parse(open(f).read()) for f in glob.glob('app/*.py') + glob.glob('app/modules/*.py')]"`
5. Если миграция сломала → `alembic downgrade -1`
6. Worst case — восстановление из бэкапа (см. Database)
### Вебхук Gitea сломался
```bash
curl -X POST http://127.0.0.1:8000/webhooks/gitea \
-H "X-Gitea-Signature: DEADBEEF" -d '{}'
```
- `401` = защита работает, ок
- `200` = подпись не проверяется → `GITEA_WEBHOOK_SECRET` пустой
- `000` = портал не отвечает → см. выше

128
User-Guide.md Normal file

@ -0,0 +1,128 @@
# Гайд для пользователей
## Регистрация
1. Открой `https://portal.morozovka.space`
2. Кнопка «Регистрация» в правом верхнем углу
3. Заполни: ФИО, организация (ННГУ / Неймарк / Ядро / внешний), логин, email, пароль (мин 6 символов)
4. После регистрации — можно войти
**Альтернатива:** войти через Gitea — кнопка «Войти через Gitea» на странице `/login`.
## Онбординг
При первой регистрации:
- В колокольчике уведомлений — «👋 Добро пожаловать!»
- Клик → страница `/onboarding` с туром по 6 разделам
- Отмечаешь, что освоил → прогресс-бар растёт
- «Отметить всё сразу» — если уже разобрался
**Повторно пройти** — ссылка «🎯 Тур» в футере или в `/profile`.
## Разделы
### 📅 Расписание (`/schedule`)
Публичная страница — видна без логина.
- **Статус-баннер сверху**: зелёный = на месте, жёлтый = опаздываю, красный = отменено/перенесено, серый = вне расписания
- **Календарь**: переключение День/Неделя/Месяц
- **Фильтры**: лекции / мастер-классы / встречи / личное
- **Клик по событию** — попап с деталями (место, аудитория, причина переноса)
- **Чат-ассистент** (кнопка 💬 справа снизу) — спроси «Где сейчас?», «Когда следующая пара?», «Что сегодня?», «Что на неделе?», «Как связаться?»
- **Подписка на уведомления** — блок под календарём (нужен логин)
### 🗂 Проекты (`/projects`)
- **Каталог** с фильтрами: по статусу (идея/в работе/завершён/заморожен), по тегам
- **Карточка проекта** — описание, участники с ролями, файлы, лента новостей, ссылка на Gitea
- **Канбан-доска** (`/projects/<id>/board`) — задачи со статусами backlog → todo → in_progress → review → done
- **Drag&drop** — перетаскивай задачи между колонками
- **Подписка** — получать уведомления о новых постах
**Создание** — только admin/professor/lead. Кнопка «+ Добавить проект».
### 🎓 Мастер-классы (`/workshops`)
- **Каталог** с фильтрами: по категории (пайка, embedded, Linux, творчество), по статусу
- **Карточка МК** — программа, ведущий, помощники, сессии, материалы, лента, участники
- **Записаться** — кнопка на странице МК (только для published)
- **Материалы** — доступны после записи (зависит от `visible_to`)
- **Подписка** — на новости
**Создание** — только admin. Кнопка «+ Создать мастер-класс».
### 📁 Файлы (`/files`)
- **Пространства** — верхний уровень (по проекту, направлению, тематике)
- **Папки** внутри пространства (можно вкладывать)
- **Файлы** с версиями (v1, v2, ...) и историей
- **Drag&drop** загрузка — перетащи файлы в зону или кликни
- **Мультизагрузка** — до 100 МБ суммарно за раз
- **Права** — на уровне пространства (viewer/editor/manager) и папки (4 флага)
- **Поиск** — по имени, описанию, тегам
- **Перемещение** — файл между пространствами через ↔
- **Версии** — загрузить новую версию, откатить к старой
### 📰 Лента (`/feed`)
- Все посты из проектов и МК в одном потоке
- Фильтры: источник (все/МК/проекты), поиск
- Закреплённые посты — сверху
### 🏠 Дашборд (`/dashboard`)
Персональный экран после входа:
- Ближайшие события
- Мои проекты и задачи
- Непрочитанные уведомления
- Новые материалы МК (где записан)
- Последние коммиты в Gitea (если есть)
- Быстрые ссылки
### 👤 Профиль (`/profile`)
- Личные данные
- Подписки на email-уведомления
- Активные сессии (можно выйти со всех устройств)
- Тур по платформе
## Уведомления
- **Колокольчик** в правом верхнем углу — счётчик непрочитанных
- **`/notifications`** — все уведомления
- **Триггеры**: новая запись на МК, материал, пост, задача, push в Gitea
- **Email-подписка** — через `/profile` (пока письма в `journalctl`, SMTP не настроен)
## Роли
| Роль | Что может |
|---|---|
| admin | Всё + `/admin/*` |
| professor | Управление расписанием |
| lead | Создавать проекты, пространства файлов |
| member | Участвовать в проектах, записываться на МК |
| student | Запись на МК, просмотр |
| guest | Только публичное |
## FAQ
**Q: Забыл пароль.**
A: `/forgot_password` → введи email → ссылка в `journalctl` (пока SMTP не настроен).
**Q: Не вижу проект.**
A: Возможно, он «внутренний» или «приватный». Спроси владельца добавить тебя.
**Q: Не могу загрузить файл.**
A: Проверь права на пространство/папку. Если не участник — попроси editor/manager.
**Q: Файл больше 100 МБ.**
A: Не пройдёт. Загрузи частями (архивы) или через Gitea LFS.
**Q: Как скачать старую версию файла?**
A: `/files/<id>/history` → «Скачать» напротив нужной версии.
**Q: Как связаться с админом?**
A: Напиши в Telegram / лично. В платформе пока нет чата с админом.