Полноценное приложение для управления документами с аутентификацией, ролями пользователей и хранением файлов в MinIO.
Бэкенд написан на Java / Spring Boot, фронтенд — на Next.js / React.
Управление документами кажется простым, пока не приходится заниматься хранением файлов, предварительно подписанными URL-адресами, доступом на основе ролей и безопасностью токенов.
Ключевые инженерные решения:
- MinIO over S3 — самохостинговое хранилище объектов с генерацией предварительно подписанных URL-адресов для безопасного доступа к файлам с ограничением по времени
- Сохранение токенов обновления — хранение в БД с защитой от гонки , а не только в памяти или куки
- Доступ на основе ролей — детализированные аннотации @PreAuthorize, отдельные валидаторы для границ USER/ADMIN
- Аутентификация и авторизация
- Регистрация и вход пользователей (
/api/auth/register,/api/auth/login) - JWT access/refresh токены, хранение refresh‑токенов в БД
- Обновление access‑токена по refresh‑токену (
/api/auth/refresh)
- Регистрация и вход пользователей (
- Управление пользователями
- Роли:
USER,ADMIN - Просмотр списка пользователей (только ADMIN)
- Блокировка и активация пользователя (
/api/users/{id}/suspend,/api/users/{id}/activate) - Обновление данных профиля
- Роли:
- Управление документами
- Загрузка файлов с сохранением метаданных в PostgreSQL и содержимого в MinIO
- Статусы документа:
DRAFT,PUBLISHED,ARCHIVED - Получение списка документов по статусу (
/api/documents?status=...) - Просмотр метаданных и скачивание файла (
/api/documents/{id},/api/documents/{id}/download) - Архивация документа с удалением файла из MinIO (
/api/documents/{id}/archive) - Получение временной ссылки на файл (
/api/documents/{id}/url)
- Фронтенд‑интерфейс
- Экран авторизации (login/registration)
- Дашборд с сайдбаром и списком документов
- Отдельная страница просмотра документа с предпросмотром:
- PDF (через
iframe) - изображения, видео, аудио
- текстовые файлы (
.txt,.md,.jsonи др.)
- PDF (через
- Страница управления пользователями (для роли ADMIN)
- Язык: Java 22
- Фреймворк: Spring Boot 3.5.8
- Модули Spring:
spring-boot-starter-webspring-boot-starter-data-jpaspring-boot-starter-validationspring-boot-starter-security
- Хранение данных:
- PostgreSQL (JDBC‑драйвер
org.postgresql:postgresql) - Миграции БД через Flyway (
org.flywaydb:flyway-core)
- PostgreSQL (JDBC‑драйвер
- Хранение файлов:
- MinIO (
io.minio:minio) - Генерация presigned‑URL для доступа к файлам
- MinIO (
- Безопасность:
- JWT (библиотека
io.jsonwebtoken:jjwt-*) - Собственный
JwtAuthenticationFilter AuthServiceс хранением refresh‑токенов в таблицеrefresh_tokens
- JWT (библиотека
- Утилиты:
- Lombok (геттеры/сеттеры, билдеры)
- MapStruct (маппинг DTO ↔ Entity)
Основные пакеты бэкенда:
controller— REST‑контроллеры (AuthController,UserController,DocumentController)service— бизнес‑логика (AuthService,UserService,DocumentService,MinioServiceи др.)model.entity— JPA‑сущности (User,Document,RefreshToken, базовыйBaseEntity)model.dto.*— DTO‑объекты запросов и ответовrepository— Spring Data JPA репозиторииconfig— конфигурация Spring Security и интеграций (JWT, MinIO и пр.)
- Фреймворк: Next.js 14 (App Router)
- Ядро: React 18, TypeScript
- UI:
- TailwindCSS
- Собственный
Sidebarс навигацией по страницам - Таблицы и карточки на тёмной теме
- HTTP‑клиент:
- Axios с общим инстансом (
frontend/lib/api/client.ts) - Интерсепторы:
- автоматическое подставление
Authorization: Bearer <token> - повтор запроса после 401 с автоматическим
refresh
- автоматическое подставление
- Axios с общим инстансом (
- Состояние и контексты:
AuthContext— хранение и обновление токенов, текущего пользователяDocumentsContext— список документов, загрузка/обновление/архивация/скачиваниеUserContext— работа с конкретным пользователем
- Хранилище в браузере:
StorageService— обёртка надlocalStorageдля токенов и данных пользователя
-
Аутентификация
- Пользователь регистрируется или логинится через
/api/auth/registerили/api/auth/login - Бэкенд создаёт пользователя, генерирует access/refresh токены и сохраняет refresh‑токен в таблице
refresh_tokens - Фронтенд сохраняет токены и пользователя в
localStorageи в контекстеAuthContext - При истечении access‑токена фронтенд прозрачно вызывает
/api/auth/refreshчерез Axios‑интерсептор
- Пользователь регистрируется или логинится через
-
Документы
- Метаданные документа хранятся в таблице
documents(название, путь к файлу, MIME‑тип, размер, автор, статус) - Сам файл загружается в MinIO через
MinioServiceс уникальным именем (UUID + оригинальное имя) - Для отображения/скачивания документа используется:
- прямое скачивание файла (
/api/documents/{id}/download) - presigned‑URL (
/api/documents/{id}/url), который фронтенд использует для предпросмотра
- прямое скачивание файла (
- Метаданные документа хранятся в таблице
-
Права доступа
- Доступ к административным действиям ограничен ролями и аннотациями
@PreAuthorize - USER может работать со своими документами (валидируется в
DocumentValidatorиUserValidator) - ADMIN может просматривать всех пользователей, блокировать/активировать их и управлять пользователями
- Доступ к административным действиям ограничен ролями и аннотациями
Файл содержит конфигурацию для:
- PostgreSQL
spring.datasource.url=jdbc:postgresql://<host>:<port>/<db>spring.datasource.username=<username>spring.datasource.password=<password>spring.jpa.properties.hibernate.default_schema=knowledge_base
- Flyway
spring.flyway.schemas=knowledge_basespring.flyway.locations=classpath:db/migration
- MinIO
minio.url=http://localhost:9000minio.access-key=<MINIO_ACCESS_KEY>minio.secret-key=<MINIO_SECRET_KEY>minio.bucket-name=user-files
- JWT
jwt.access-secret,jwt.refresh-secretjwt.access-expiration,jwt.refresh-expiration
Рекомендация: вынести чувствительные данные (пароли, JWT‑секреты, MinIO‑ключи) в переменные окружения/
application-*.yaml, не хранить реальные значения в Git.
- В
next.config.mjsнастроенrewrite:- все запросы на
/api/*с фронтенда проксируются наhttp://localhost:8080/api/*
- все запросы на
- В
lib/api/client.ts:baseURLберётся изNEXT_PUBLIC_API_BASE_URLили пустая строка ('')
Варианты конфигурации:
- Через
rewrite(по умолчанию):- не указывать
NEXT_PUBLIC_API_BASE_URL - фронтенд делает запросы на
/api/..., Next.js проксирует их на бэкенд
- не указывать
- Через прямой baseURL:
- создать
.env.localвfrontend:NEXT_PUBLIC_API_BASE_URL=http://localhost:8080
- тогда запросы пойдут напрямую на бэкенд без прокси
- создать
- Установлен JDK 22+
- Установлен Node.js 18+ и npm
- Запущен сервер PostgreSQL
- Запущен MinIO (локально или в Docker)
cd backend
# Windows
gradlew.bat bootRun
# Unix-подобные системы
./gradlew bootRunПо умолчанию бэкенд стартует на http://localhost:8080.
cd frontend
npm install
npm run devПо умолчанию фронтенд будет доступен на http://localhost:3000.
POST /api/auth/register— регистрация пользователяPOST /api/auth/login— аутентификация пользователяPOST /api/auth/refresh— обновление access‑токена по refresh‑токену
POST /api/users— создание пользователя (ADMIN)GET /api/users— список всех пользователей (ADMIN)GET /api/users/{id}— получение пользователя по ID (аутентифицированный пользователь)PUT /api/users/{id}— обновление пользователя (ADMIN или владелец)POST /api/users/{id}/suspend— блокировка пользователя (ADMIN)POST /api/users/{id}/activate— активация пользователя (ADMIN)
POST /api/documents— загрузка документа (multipart/form-data,file)GET /api/documents?status=PUBLISHED— список документов по статусуGET /api/documents/{id}— подробная информация о документеPUT /api/documents/{id}— обновление метаданных/файлаPOST /api/documents/{id}/archive— архивирование документаGET /api/documents/{id}/download— скачивание файлаGET /api/documents/{id}/url— получение временной ссылки на файл