Relink — веб-приложение для сокращения URL, генерации QR-кодов и учёта переходов. Каждый пользователь работает в личном кабинете: создаёт ссылки, добавляет к ним заметки, смотрит статистику и удаляет ненужное.
Продакшен: https://linkshortener.ru
Репозиторий ориентирован на MVP: понятный стек, SQLite без отдельного сервера БД, развёртывание через Docker Compose.
- Что делает сервис
- Возможности
- Как это работает для пользователя
- Архитектура
- Стек технологий
- Структура репозитория
- Локальная разработка
- Запуск через Docker
- Продакшен-деплой
- Ограничения и планы
- Пользователь регистрируется или входит по email и паролю.
- На дашборде вставляет длинный URL — получает короткую ссылку вида
https://linkshortener.ru/Ab3xYz(6 символов, буквы и цифры). - Короткая ссылка редиректит на исходный адрес; при каждом переходе увеличивается счётчик кликов и обновляется время последнего клика.
- Для ссылки можно сгенерировать QR-код (внешний API) и скачать PNG.
- В таблице «Мои ссылки» — поиск, сортировка, редактирование описания, копирование URL, удаление.
Короткие коды обрабатывает backend (маршрут /{short_code}). Страницы React (/auth, /dashboard) отдаёт frontend через nginx-router.
| Область | Описание |
|---|---|
| Аутентификация | Регистрация (username, email, password), вход, JWT access + refresh, профиль /auth/me |
| Ссылки | Создание, список только своих, удаление, обновление описания (PUT) |
| Редирект | Публичный GET /{short_code} без авторизации |
| Статистика | clicks_count, last_clicked_at, дата создания (МСК) |
| Описание | Необязательное поле при создании и inline-редактирование в таблице |
| QR-коды | Генерация через QR Server API на клиенте, скачивание PNG |
| UI | Вкладки «Создать ссылку» / «Мои ссылки», светлая и тёмная тема, сохранение вкладки и темы в localStorage |
| Безопасность | Пароли — bcrypt; API защищён Bearer-токеном; чужие ссылки изменить/удалить нельзя |
| Маршрут | Назначение |
|---|---|
/ |
Редирект на /dashboard (если авторизован) или на /auth |
/auth |
Вход и регистрация |
/dashboard |
Личный кабинет (только для авторизованных) |
/{short_code} |
Редирект на оригинальный URL (не React-страница) |
- Создать ссылку — форма URL + описание; автоматически добавляется
https://, если протокол не указан; после создания — короткая ссылка, копирование, QR. - Мои ссылки — таблица: оригинал, короткая ссылка, описание, клики, даты; поиск по URL, коду и описанию; сортировка по дате создания, кликам, последнему переходу; удаление с подтверждением.
'''
flowchart TB
subgraph Client [Клиентская часть]
React[React SPA]
end
subgraph Router [nginx router]
R[Маршрутизация]
end
subgraph Services [Сервисы]
FE[Frontend nginx :80]
BE[FastAPI backend :8000]
end
DB[(SQLite)]
React -->|/api/*| R
React -->|/auth, /dashboard| R
R -->|/api/*| BE
R -->|статика, SPA| FE
R -->|/{code}| BE
BE --> DB
'''
Логика маршрутизации (dev и prod):
/api/*→ backend (REST API)/auth,/dashboard, статика (.js,.css, …) → frontend- всё остальное (
/abc123) → backend (редирект)
Файлы конфигурации: router/nginx.conf (разработка), router/nginx.prod.conf (HTTPS, linkshortener.ru).
- Python 3.12
- FastAPI — REST API и OpenAPI (
/docs) - SQLAlchemy 2 — асинхронный ORM
- PostgreSQL — основная реляционная СУБД
- Alembic — система контроля версий схемы базы данных (миграции)
- uv — сверхбыстрый пакетный менеджер для Python
- Pydantic v2 — схемы запросов/ответов
- python-jose — JWT (access + refresh)
- passlib[bcrypt] — хеши паролей
- Uvicorn — ASGI-сервер
- React 19 + React Router 7
- Vite 8 — сборка и dev-сервер
- Axios — HTTP-клиент с перехватчиками
- js-cookie — хранение токенов
- Docker / Docker Compose — локально и на сервере
- nginx — единая точка входа (router + статика frontend)
- GitHub Actions — линт, тесты, сборка образов
QR-коды не генерируются на backend: фронтенд обращается к https://api.qrserver.com/v1/create-qr-code/.
minions/
├── backend/ # FastAPI-приложение
│ ├── app/
│ │ ├── api/ # Роуты: v1 (auth, links), redirect
│ │ ├── core/ # config, database, security
│ │ ├── models/ # User, Link
│ │ ├── schemas/ # Pydantic-модели
│ │ ├── services/ # links_service, user_service
│ │ └── utils/ # short_link, logger
│ ├── data/ # SQLite (dev.db / links.db)
│ ├── Dockerfile # Dev-образ с --reload
│ ├── Dockerfile.prod # Продакшен-образ
│ └── requirements.txt
├── frontend/ # React SPA
│ ├── src/
│ │ ├── api/ # axios client
│ │ ├── components/ # CreateLink, LinkStatsTable, …
│ │ ├── contexts/ # AuthContext
│ │ └── pages/ # Auth, Dashboard
│ ├── Dockerfile / Dockerfile.prod
│ └── vite.config.js # proxy /api → localhost:8000
├── router/ # nginx: dev и prod конфиги
├── tests/ # pytest (API, сервисы, фильтр, e2e-сценарии)
├── .github/workflows/ # ci-cd.yml
├── docker-compose.yml # Локальный стек (dev)
├── docker-compose.prod.yml # Продакшен на сервере
├── pytest.ini
├── .env.example
└── README.md
- Python 3.12+
- Node.js 20+ и npm
- (опционально) Docker Desktop
- Менеджер пакетов uv
cd backend
python -m venv .venv
# Windows: .venv\Scripts\activate
# Linux/macOS: source .venv/bin/activate
pip install -r requirements.txt
# .env в корне репозитория или backend — см. .env.example
# DATABASE_URL для локали, например:
# sqlite:///./data/dev.db
mkdir -p data
uvicorn app.main:app --reload --host 127.0.0.1 --port 8000API: http://127.0.0.1:8000/docs
cd frontend
npm install
npm run devUI: http://localhost:5173 — Vite проксирует /api на http://127.0.0.1:8000 (vite.config.js).
Если база создана до добавления поля
description, выполните в SQLite:
ALTER TABLE links ADD COLUMN description VARCHAR;
В корне репозитория есть pyproject.toml — можно ставить зависимости через uv одним общим venv:
uv sync --extra dev
uv run uvicorn --app-dir backend app.main:app --reload --host 127.0.0.1 --port 8000Либо, если venv уже активирован:
uvicorn --app-dir backend app.main:app --reload --host 127.0.0.1 --port 8000docker compose up --build- Сайт: http://localhost (порт 80, сервис
router) - Backend с hot-reload: volume
./backend/app - БД:
./backend/data/dev.db
Остановка: docker compose down
docker compose -f docker-compose.prod.yml up -d --build- HTTPS и редирект HTTP→HTTPS:
router/nginx.prod.conf - SSL-сертификаты: каталог
./ssl(монтируется в контейнер router) - Образы backend/frontend собираются из
Dockerfile.prod - Переменная
SECRET_KEY— из.envна сервере
После обновления кода на сервере:
git pull
docker compose -f docker-compose.prod.yml up -d --buildАвтодеплой: push в main запускает job deploy в .github/workflows/ci-cd.yml — после прохождения тестов CI по SSH выполняет на сервере те же команды (git pull + docker compose -f docker-compose.prod.yml up -d --build). Миграции применяются автоматически при старте backend-контейнера.
Что нужно на сервере: репозиторий склонирован в /opt/minions (с доступом к git) и заполнен .env. Секреты в GitHub: DEPLOY_HOST, DEPLOY_USER, DEPLOY_SSH_KEY, DEPLOY_PORT (опц., по умолчанию 22).
Текущий MVP не включает:
- Alembic / версионирование схемы БД
- Rate limiting и отдельный health-check endpoint
- Детальную аналитику кликов (IP, User-Agent, гео)
- Собственный сервис генерации QR на backend
Возможные улучшения: PostgreSQL в prod, кастомные алиасы ссылок, срок жизни ссылки, админ-панель, единый язык сообщений об ошибках на русском.