Files
WhatIDo/README.md
T
dev 6844d659fc harden security and add public TLS scaffold
- require ADMIN_PASSWORD (no default), remove CORS
- close public DB port, move DB credentials to .env (DB_PASSWORD)
- fix HTML escaping, add helmet + sec headers (no CSP due to inline scripts)
- rate limit public routes by IP (express-rate-limit)
- validate restore data and confine file unlinking to uploads/
- block dangerous upload extensions, 30MB per-entry limit, SVG not served inline
- return 400 on unknown group_id in POST /api/entries
- add commented Caddy/Let's Encrypt reverse-proxy scaffold + Caddyfile.example
- update README
2026-09-07 11:27:04 +03:00

9.8 KiB
Raw Blame History

WhatIDo

Учётная система для образовательного центра: журнал посещений, проектные работы воспитанников, галерея групп, откреплённые файлы и публичные страницы-витрины (share-ссылки).

Возможности

  • Журнал записей — отметки о занятиях с фото и прикреплёнными файлами (проектные работы), мягкое удаление и корзина
  • Файлы — централизованный раздел со всеми загруженными файлами, фильтры (имя воспитанника, группа, даты, поиск) и вкладка «Откреплённые»
  • Группы — учебные группы, расписание (день недели, время), фотохроника группы
  • Воспитанники — справочник с привязкой к группам
  • Share-ссылки — публичные страницы-витрины с выбором группы / воспитанника / диапазона дат
  • Дашборд — статистика, активные группы, активность за 14 дней, последние записи, топ воспитанников
  • Резервное копирование — экспорт/импорт полного дампа (БД + файлы) в tar.gz
  • Настройки — научные тексты футера, анти-спам интервал
  • HTTPS — самоподписанный TLS-сертификат по умолчанию + готовая заготовка reverse-proxy (Caddy / Let's Encrypt) для публичного запуска

Технологии

  • Node.js + Express
  • PostgreSQL (pg)
  • Multer (загрузка файлов), Tar (бэкапы)
  • Docker / Docker Compose

Быстрый старт

Требования

  • Docker + Docker Compose

Запуск

# создайте .env с паролем администратора и БД (см. раздел «Конфигурация»)
docker compose up -d --build

После старта:

  • HTTP http://localhost:3000 — редирект на HTTPS
  • HTTPS https://localhost:3443 — приложение (самоподписанный сертификат, принимайте предупреждение браузера)
  • PostgreSQL — доступен только внутри docker-сети (порт 5432 наружу не публикуется)

Управление:

docker compose ps        # статус
docker compose logs -f app
docker compose down      # остановка (данные сохраняются)

Приложение не запустится без ADMIN_PASSWORD (защита от пароля по умолчанию). DB_PASSWORD задаёт пароль пользователя app в PostgreSQL.

Конфигурация

Переменные окружения (.env):

Переменная По умолчанию Назначение
ADMIN_PASSWORD — (обязательно) Пароль администратора (X-Admin-Token). Без него сервер не стартует
DB_PASSWORD — (обязательно) Пароль пользователя app в PostgreSQL

Пример .env:

ADMIN_PASSWORD=сложный-пароль
DB_PASSWORD=случайная-строка

DB_PASSWORD подставляется в docker-compose.yml в POSTGRES_PASSWORD и DATABASE_URL. Если БД уже была инициализирована ранее, значение DB_PASSWORD должно совпадать с фактическим паролем пользователя app в БД (иначе приложение не подключится).

Структура данных

  • groups — группы, расписание (day_of_week, time_start, time_end)
  • students — воспитанники
  • entries — записи журнала (фото photo_path, описание, мягкое удаление deleted_at)
  • project_files — файлы записей (token, path, привязка entry_id, отметка detached_at)
  • group_photos — фотохроника групп
  • share_links — публичные ссылки-витрины
  • settings — пары ключ/значение (анти-спам интервал, футер)

Схема инициализируется при первом запуске из db/init.sql; миграции существующей БД — в db/migration.sql.

Хранилище файлов

Загруженные фото и файлы хранятся в каталоге uploads/ на хосте и монтируются в контейнер (./uploads:/app/uploads). Это даёт прямой доступ к данным из-под хост-системы. Данные БД хранятся в именованном томе pgdata.

Бэкапы

В админке (Настройки → Бэкап) можно:

  • Скачать полный бэкап — tar.gz, содержащий data.json (все таблицы) и uploads/
  • Восстановить из файла бэкапа

Также доступны скрипты на хосте:

./scripts/backup.sh    # дамп БД + фото в backups/whatido-backup-<дата>.tar.gz
./scripts/restore.sh   # восстановление из архива

Безопасность

  • Пароль администратора обязателен (ADMIN_PASSWORD); фолбэка на admin нет.
  • CORS отключён — кросс-доменные запросы к API запрещены.
  • Rate limiting по IP на публичные роуты: POST /api/entries — 10 запросов / 15 мин, загрузка файлов и share-ссылки — 300 / 15 мин.
  • Загрузки ограничены: 30 МБ суммарно на запись, 10 МБ на файл; заблокированы опасные расширения (.html, .js, .svg, .xml, .exe и др.); SVG иным способом не отдаётся inline.
  • Restore проходит полную валидацию данных бэкапа; удаление файлов ограничено каталогом uploads/.
  • Заголовки: helmet — X-Frame-Options, nosniff, HSTS, Referrer-Policy.
  • Порт БД 5432 наружу не публикуется (доступ только внутри docker-сети).
  • TLS: по умолчанию самоподписанный сертификат. Для публикации включите reverse-proxy Caddy с Let's Encrypt — заготовка закомментирована в docker-compose.yml, конфиг в Caddyfile.example.

Публичный запуск (TLS)

cp Caddyfile.example Caddyfile          # подставить реальный домен
# расскомментировать сервис caddy и перевести ports сервиса app в expose (следуйте комментариям в docker-compose.yml)
docker compose up -d --build

Caddy автоматически получит Let's Encrypt сертификат на 80/443.

Основные API

Метод Путь Назначение
GET /api/entries Записи журнала (с фильтрами)
POST /api/entries Создать запись (photo + files)
PUT/DELETE /api/entries/:id Обновить / мягко удалить
GET /api/files Все файлы (фильтры)
GET /api/files/detached Откреплённые файлы
POST /api/files/:id/detach Открепить файл от записи
GET /api/files/:token Скачать/показать файл по токену (публично)
GET /api/groups Список групп
POST/PUT/DELETE /api/groups/:id(?) CRUD групп
GET/POST /api/groups/:id/photos Фотохроника группы
GET/POST/PUT/DELETE /api/share/..., /api/links Публичные ссылки
GET /api/backup Скачать бэкап
POST /api/restore Восстановить из бэкапа
GET /api/dashboard, /api/stats Статистика

Защищённые админ-маршруты требуют заголовок X-Admin-Token с ADMIN_PASSWORD.

Структура проекта

├── docker-compose.yml   # сервисы app + db (+ закомментированный caddy)
├── Dockerfile           # сборка образа (Node 20, генерация TLS-сертификата)
├── Caddyfile.example    # шаблон reverse-proxy с Let's Encrypt (домен заменить)
├── server.js            # Express-приложение
├── db/
│   ├── init.sql         # схема при первом запуске
│   └── migration.sql    # миграции существующей БД
├── public/              # статика (HTML/CSS/JS админки и витрин)
├── scripts/             # вспомогательные скрипты
├── uploads/             # загруженные файлы (bind-монт, вне git)
└── backups/             # локальные бэкапы