|
@@ -1,6 +1,6 @@
|
|
|
# PhotoPlaces
|
|
# PhotoPlaces
|
|
|
|
|
|
|
|
-Сервис онлайн-карты с отметками мест для фотосъёмки, аренды фотостудий и найма фотографов.
|
|
|
|
|
|
|
+Маркетплейс фотолокаций: находите места и студии для фотосъёмок, бронируйте, общайтесь с фотографами.
|
|
|
|
|
|
|
|
## Стек
|
|
## Стек
|
|
|
|
|
|
|
@@ -9,34 +9,29 @@
|
|
|
| Фронтенд | Next.js 14, React 18, TypeScript, Tailwind CSS |
|
|
| Фронтенд | Next.js 14, React 18, TypeScript, Tailwind CSS |
|
|
|
| Бэкенд | Go 1.22, Chi router, pgx |
|
|
| Бэкенд | Go 1.22, Chi router, pgx |
|
|
|
| База данных | PostgreSQL 16 + PostGIS |
|
|
| База данных | PostgreSQL 16 + PostGIS |
|
|
|
-| Кеш | Redis 7 |
|
|
|
|
|
|
|
+| Кэш | Redis 7 |
|
|
|
| Файлы | MinIO (S3-совместимое хранилище) |
|
|
| Файлы | MinIO (S3-совместимое хранилище) |
|
|
|
-| Аутентификация | JWT (access + refresh токены) |
|
|
|
|
|
|
|
+| Авторизация | JWT (access + refresh токены) |
|
|
|
| Инфраструктура | Docker, docker-compose |
|
|
| Инфраструктура | Docker, docker-compose |
|
|
|
|
|
|
|
|
-## Быстрый старт
|
|
|
|
|
|
|
+## Быстрый старт (локальная разработка)
|
|
|
|
|
|
|
|
-### 1. Клонировать и перейти в проект
|
|
|
|
|
|
|
+### 1. Клонирование и запуск зависимостей
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
git clone http://192.168.88.96:10880/foxtime/photoplaces.git
|
|
git clone http://192.168.88.96:10880/foxtime/photoplaces.git
|
|
|
cd photoplaces
|
|
cd photoplaces
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-### 2. Запустить инфраструктуру (БД, Redis, MinIO)
|
|
|
|
|
-
|
|
|
|
|
-```bash
|
|
|
|
|
docker compose up -d postgres redis minio
|
|
docker compose up -d postgres redis minio
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### 3. Инициализировать переменные окружения
|
|
|
|
|
|
|
+### 2. Настройка окружения
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
cp backend/.env.example backend/.env
|
|
cp backend/.env.example backend/.env
|
|
|
cp frontend/.env.local.example frontend/.env.local
|
|
cp frontend/.env.local.example frontend/.env.local
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### 4. Запустить бэкенд
|
|
|
|
|
|
|
+### 3. Запуск бэкенда
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
cd backend
|
|
cd backend
|
|
@@ -45,7 +40,7 @@ go run ./cmd/api
|
|
|
|
|
|
|
|
Бэкенд будет доступен на `http://localhost:8080/api/v1`
|
|
Бэкенд будет доступен на `http://localhost:8080/api/v1`
|
|
|
|
|
|
|
|
-### 5. Запустить фронтенд (в другом терминале)
|
|
|
|
|
|
|
+### 4. Запуск фронтенда (в отдельном терминале)
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
cd frontend
|
|
cd frontend
|
|
@@ -55,10 +50,53 @@ npm run dev
|
|
|
|
|
|
|
|
Фронтенд будет доступен на `http://localhost:3000`
|
|
Фронтенд будет доступен на `http://localhost:3000`
|
|
|
|
|
|
|
|
-### Либо через Make
|
|
|
|
|
|
|
+### Через Make
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+make dev # docker compose + go run + npm run dev одновременно
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## Развёртывание на сервере (192.168.88.128)
|
|
|
|
|
+
|
|
|
|
|
+### Первичная настройка сервера
|
|
|
|
|
+
|
|
|
|
|
+Заходим на сервер по SSH и запускаем:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+ssh foxtime@192.168.88.128
|
|
|
|
|
+curl -fsSL http://192.168.88.96:10880/foxtime/photoplaces/raw/main/deploy/deploy-remote.sh | bash
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Скрипт автоматически:
|
|
|
|
|
+1. Проверит/установит Docker, Git, curl, openssl
|
|
|
|
|
+2. Склонирует репозиторий
|
|
|
|
|
+3. Сгенерирует секреты (пароли БД, JWT, S3)
|
|
|
|
|
+4. Запросит Yandex Maps API Key и домен
|
|
|
|
|
+5. Запустит docker-compose в production режиме
|
|
|
|
|
+
|
|
|
|
|
+### Ручной деплой (если автоматический не подошёл)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+ssh foxtime@192.168.88.128
|
|
|
|
|
+cd /home/foxtime/photoplaces
|
|
|
|
|
+docker compose --env-file deploy/env.prod -f deploy/docker-compose.prod.yml up -d --build
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Просмотр логов
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+ssh foxtime@192.168.88.128
|
|
|
|
|
+cd /home/foxtime/photoplaces
|
|
|
|
|
+docker compose -f deploy/docker-compose.prod.yml logs -f
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Обновление после изменений в репозитории
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-make dev # docker compose + go run + npm run dev одной командой
|
|
|
|
|
|
|
+ssh foxtime@192.168.88.128
|
|
|
|
|
+cd /home/foxtime/photoplaces
|
|
|
|
|
+git pull origin main
|
|
|
|
|
+docker compose --env-file deploy/env.prod -f deploy/docker-compose.prod.yml up -d --build --remove-orphans
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
## Структура проекта
|
|
## Структура проекта
|
|
@@ -66,107 +104,108 @@ make dev # docker compose + go run + npm run dev одной командой
|
|
|
```
|
|
```
|
|
|
photoplaces/
|
|
photoplaces/
|
|
|
├── backend/
|
|
├── backend/
|
|
|
-│ ├── cmd/api/main.go # точка входа API
|
|
|
|
|
|
|
+│ ├── cmd/api/main.go # Точка входа API
|
|
|
│ ├── internal/
|
|
│ ├── internal/
|
|
|
-│ │ ├── config/ # загрузка конфигурации из env
|
|
|
|
|
-│ │ ├── handlers/ # HTTP-обработчики (auth, places, services...)
|
|
|
|
|
-│ │ ├── middleware/ # JWT-аутентификация, rate limiter
|
|
|
|
|
-│ │ ├── models/ # структуры данных (User, Place, Booking…)
|
|
|
|
|
-│ │ ├── repository/ # работа с PostgreSQL
|
|
|
|
|
-│ │ └── services/ # бизнес-логика
|
|
|
|
|
-│ ├── migrations/ # SQL-миграции (golang-migrate)
|
|
|
|
|
-│ └── docs/ # документация
|
|
|
|
|
-│ ├── SPEC.md # техническое задание
|
|
|
|
|
-│ ├── API_CONTRACT.md # контракт API
|
|
|
|
|
-│ ├── DB_SCHEMA.md # схема базы данных
|
|
|
|
|
-│ ├── MAP_PROVIDERS.md # провайдеры карт
|
|
|
|
|
-│ └── PAYMENT_INTEGRATION.md
|
|
|
|
|
|
|
+│ │ ├── config/ # Загрузка конфига из env
|
|
|
|
|
+│ │ ├── handlers/ # HTTP-обработчики (auth, places, services...)
|
|
|
|
|
+│ │ ├── middleware/ # JWT-аутентификация, rate limiter
|
|
|
|
|
+│ │ ├── models/ # Модели данных (User, Place, Booking...)
|
|
|
|
|
+│ │ ├── repository/ # Запросы к PostgreSQL
|
|
|
|
|
+│ │ ├── services/ # Бизнес-логика
|
|
|
|
|
+│ │ ├── validator/ # Валидация (go-playground/validator)
|
|
|
|
|
+│ │ ├── pointer/ # Утилиты для указателей
|
|
|
|
|
+│ │ └── log/ # Структурированное логирование (slog)
|
|
|
|
|
+│ ├── migrations/ # SQL-миграции (golang-migrate)
|
|
|
|
|
+│ └── docs/ # Документация
|
|
|
├── frontend/
|
|
├── frontend/
|
|
|
│ ├── src/
|
|
│ ├── src/
|
|
|
-│ │ ├── app/ # страницы и layout (Next.js App Router)
|
|
|
|
|
-│ │ ├── components/ # React-компоненты
|
|
|
|
|
-│ │ ├── hooks/ # кастомные хуки (useAuth)
|
|
|
|
|
-│ │ ├── lib/ # утилиты (api, map)
|
|
|
|
|
-│ │ ├── styles/ # глобальные стили
|
|
|
|
|
-│ │ └── types/ # TypeScript-типы
|
|
|
|
|
|
|
+│ │ ├── app/ # Страницы (Next.js App Router)
|
|
|
|
|
+│ │ ├── components/ # React-компоненты
|
|
|
|
|
+│ │ ├── hooks/ # Пользовательские хуки (useAuth)
|
|
|
|
|
+│ │ ├── lib/ # Утилиты (api, map)
|
|
|
|
|
+│ │ ├── styles/ # Глобальные стили
|
|
|
|
|
+│ │ └── types/ # TypeScript-типы
|
|
|
│ └── public/
|
|
│ └── public/
|
|
|
-├── deploy/ # продакшен-окружение
|
|
|
|
|
|
|
+├── deploy/ # Инфраструктура продакшена
|
|
|
│ ├── docker-compose.prod.yml
|
|
│ ├── docker-compose.prod.yml
|
|
|
│ ├── env.prod
|
|
│ ├── env.prod
|
|
|
│ ├── deploy.sh
|
|
│ ├── deploy.sh
|
|
|
|
|
+│ ├── deploy-remote.sh
|
|
|
│ └── setup.sh
|
|
│ └── setup.sh
|
|
|
-├── docker-compose.yml # локальное окружение
|
|
|
|
|
-└── Makefile # вспомогательные команды
|
|
|
|
|
|
|
+├── docker-compose.yml # Локальная разработка
|
|
|
|
|
+└── Makefile # Автоматизация команд
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-## Доступные команды
|
|
|
|
|
|
|
+## Команды Make
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-make dev # локальная разработка
|
|
|
|
|
-make prod # продакшен-сборка
|
|
|
|
|
-make logs # логи продакшена
|
|
|
|
|
-make stop # остановка контейнеров
|
|
|
|
|
-make clean # остановка + удаление volume
|
|
|
|
|
-make ps # статус контейнеров
|
|
|
|
|
|
|
+make dev # Локальная разработка
|
|
|
|
|
+make prod # Продакшен-сборка
|
|
|
|
|
+make test # Запуск всех тестов
|
|
|
|
|
+make test-backend # Тесты бэкенда
|
|
|
|
|
+make test-frontend # Тесты фронтенда
|
|
|
|
|
+make logs # Просмотр логов
|
|
|
|
|
+make stop # Остановка контейнеров
|
|
|
|
|
+make migrate # Запуск миграций
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
## API
|
|
## API
|
|
|
|
|
|
|
|
-Документация: `backend/docs/API_CONTRACT.md`
|
|
|
|
|
|
|
+Полная спецификация: `backend/docs/API_CONTRACT.md`
|
|
|
|
|
|
|
|
Базовый URL: `http://localhost:8080/api/v1`
|
|
Базовый URL: `http://localhost:8080/api/v1`
|
|
|
|
|
|
|
|
### Основные эндпоинты
|
|
### Основные эндпоинты
|
|
|
|
|
|
|
|
-| Метод | Путь | Аутентификация |
|
|
|
|
|
-|-------|------|----------------|
|
|
|
|
|
-| POST | /auth/register | — |
|
|
|
|
|
-| POST | /auth/login | — |
|
|
|
|
|
-| POST | /auth/refresh | — |
|
|
|
|
|
|
|
+| Метод | Путь | Авторизация |
|
|
|
|
|
+|-------|------|-------------|
|
|
|
|
|
+| POST | /auth/register | Нет |
|
|
|
|
|
+| POST | /auth/login | Нет |
|
|
|
|
|
+| POST | /auth/refresh | Нет |
|
|
|
| POST | /auth/logout | + |
|
|
| POST | /auth/logout | + |
|
|
|
| GET | /auth/me | + |
|
|
| GET | /auth/me | + |
|
|
|
-| GET | /places | — |
|
|
|
|
|
-| GET | /places/:id | — |
|
|
|
|
|
|
|
+| GET | /places | Нет |
|
|
|
|
|
+| GET | /places/:id | Нет |
|
|
|
| POST | /places | + |
|
|
| POST | /places | + |
|
|
|
| PATCH | /places/:id | + |
|
|
| PATCH | /places/:id | + |
|
|
|
| DELETE | /places/:id | + |
|
|
| DELETE | /places/:id | + |
|
|
|
| POST | /places/:id/moderate | moderator+ |
|
|
| POST | /places/:id/moderate | moderator+ |
|
|
|
-| GET | /tags | — |
|
|
|
|
|
-| GET | /features | — |
|
|
|
|
|
-| GET | /services | — |
|
|
|
|
|
|
|
+| GET | /tags | Нет |
|
|
|
|
|
+| GET | /features | Нет |
|
|
|
|
|
+| GET | /services | Нет |
|
|
|
| POST | /services | + |
|
|
| POST | /services | + |
|
|
|
| PATCH | /services/:id | + |
|
|
| PATCH | /services/:id | + |
|
|
|
| DELETE | /services/:id | + |
|
|
| DELETE | /services/:id | + |
|
|
|
| POST | /bookings | + |
|
|
| POST | /bookings | + |
|
|
|
| GET | /bookings/me | + |
|
|
| GET | /bookings/me | + |
|
|
|
| PATCH | /bookings/:id/cancel | + |
|
|
| PATCH | /bookings/:id/cancel | + |
|
|
|
-| GET | /reviews | — |
|
|
|
|
|
|
|
+| GET | /reviews | Нет |
|
|
|
| POST | /reviews | + |
|
|
| POST | /reviews | + |
|
|
|
-| GET | /users/:id | — |
|
|
|
|
|
|
|
+| GET | /users/:id | Нет |
|
|
|
| PATCH | /users/me | + |
|
|
| PATCH | /users/me | + |
|
|
|
| GET | /admin/users | moderator+ |
|
|
| GET | /admin/users | moderator+ |
|
|
|
| PATCH | /admin/users/:id | moderator+ |
|
|
| PATCH | /admin/users/:id | moderator+ |
|
|
|
| POST | /upload/presigned-url | + |
|
|
| POST | /upload/presigned-url | + |
|
|
|
-| GET | /ws/visitors | — (WebSocket) |
|
|
|
|
|
|
|
+| GET | /ws/visitors | Нет (WebSocket) |
|
|
|
|
|
|
|
|
-## Переменные окружения
|
|
|
|
|
|
|
+## Конфигурация
|
|
|
|
|
|
|
|
### Бэкенд (`backend/.env`)
|
|
### Бэкенд (`backend/.env`)
|
|
|
|
|
|
|
|
-| Переменная | По умолчанию | Обязательная |
|
|
|
|
|
-|-----------|-------------|-------------|
|
|
|
|
|
-| APP_ENV | development | — |
|
|
|
|
|
-| SERVER_PORT | 8080 | — |
|
|
|
|
|
-| DATABASE_URL | postgres://photoplaces:photoplaces_dev@localhost:5432/photoplaces?sslmode=disable | да |
|
|
|
|
|
-| REDIS_URL | redis://localhost:6379/0 | да |
|
|
|
|
|
-| S3_ENDPOINT | http://localhost:9000 | да |
|
|
|
|
|
-| S3_PUBLIC_ENDPOINT | http://localhost:9000 | да |
|
|
|
|
|
-| S3_ACCESS_KEY | photoplaces | да |
|
|
|
|
|
-| S3_SECRET_KEY | photoplaces_dev | да |
|
|
|
|
|
-| S3_BUCKET | photoplaces | да |
|
|
|
|
|
-| JWT_SECRET | dev-secret | да |
|
|
|
|
|
-| JWT_REFRESH_SECRET | dev-refresh-secret | да |
|
|
|
|
|
-| ALLOWED_ORIGINS | http://localhost:3000 | — |
|
|
|
|
|
|
|
+| Переменная | По умолчанию | Описание |
|
|
|
|
|
+|-----------|-------------|---------|
|
|
|
|
|
+| APP_ENV | development | Среда |
|
|
|
|
|
+| SERVER_PORT | 8080 | Порт |
|
|
|
|
|
+| DATABASE_URL | postgres://... | Подключение к БД |
|
|
|
|
|
+| REDIS_URL | redis://... | Подключение к Redis |
|
|
|
|
|
+| S3_ENDPOINT | http://localhost:9000 | MinIO endpoint |
|
|
|
|
|
+| S3_PUBLIC_ENDPOINT | http://localhost:9000 | Публичный S3 endpoint |
|
|
|
|
|
+| S3_ACCESS_KEY | photoplaces | S3 Access Key |
|
|
|
|
|
+| S3_SECRET_KEY | photoplaces_dev | S3 Secret Key |
|
|
|
|
|
+| S3_BUCKET | photoplaces | S3 Bucket |
|
|
|
|
|
+| JWT_SECRET | dev-secret | JWT Secret |
|
|
|
|
|
+| JWT_REFRESH_SECRET | dev-refresh-secret | JWT Refresh Secret |
|
|
|
|
|
+| ALLOWED_ORIGINS | http://localhost:3000 | CORS origins |
|
|
|
|
|
|
|
|
### Фронтенд (`frontend/.env.local`)
|
|
### Фронтенд (`frontend/.env.local`)
|
|
|
|
|
|
|
@@ -174,34 +213,35 @@ make ps # статус контейнеров
|
|
|
|-----------|-------------|
|
|
|-----------|-------------|
|
|
|
| NEXT_PUBLIC_API_URL | http://localhost:8080/api/v1 |
|
|
| NEXT_PUBLIC_API_URL | http://localhost:8080/api/v1 |
|
|
|
| NEXT_PUBLIC_MAP_PROVIDER | yandex |
|
|
| NEXT_PUBLIC_MAP_PROVIDER | yandex |
|
|
|
-| NEXT_PUBLIC_YANDEX_MAPS_API_KEY | (пусто) |
|
|
|
|
|
|
|
+| NEXT_PUBLIC_YANDEX_MAPS_API_KEY | (задаётся) |
|
|
|
|
|
|
|
|
## Миграции
|
|
## Миграции
|
|
|
|
|
|
|
|
-Миграции накатываются автоматически в продакшене через `migrate/migrate` (см. `deploy/docker-compose.prod.yml`). Локально можно накатить вручную:
|
|
|
|
|
|
|
+Миграции запускаются автоматически через `docker-entrypoint.sh` при старте бэкенда, либо отдельно:
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-docker compose run --rm migrations
|
|
|
|
|
|
|
+docker compose run --rm migrate
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
Файлы миграций: `backend/migrations/`
|
|
Файлы миграций: `backend/migrations/`
|
|
|
|
|
|
|
|
## Роли пользователей
|
|
## Роли пользователей
|
|
|
|
|
|
|
|
-| Роль | Описание |
|
|
|
|
|
-|------|----------|
|
|
|
|
|
|
|
+| Роль | Права |
|
|
|
|
|
+|------|-------|
|
|
|
| superadmin | Полный доступ |
|
|
| superadmin | Полный доступ |
|
|
|
| moderator | Модерация мест, управление пользователями |
|
|
| moderator | Модерация мест, управление пользователями |
|
|
|
-| landlord | Добавление и управление своими студиями |
|
|
|
|
|
-| executor | Добавление услуг фото/видеосъёмки |
|
|
|
|
|
-| customer | Добавление мест для съёмки |
|
|
|
|
|
|
|
+| landlord | Создание и управление студиями |
|
|
|
|
|
+| executor | Создание и управление услугами |
|
|
|
|
|
+| customer | Поиск и бронирование |
|
|
|
|
|
|
|
|
## Безопасность
|
|
## Безопасность
|
|
|
|
|
|
|
|
- JWT-аутентификация: access token (15 мин) + refresh token (30 дней)
|
|
- JWT-аутентификация: access token (15 мин) + refresh token (30 дней)
|
|
|
-- Rate limiting: in-memory, 60 запр/мин на IP
|
|
|
|
|
-- CORS: настроен для разрешённых доменов
|
|
|
|
|
-- Параметризованные SQL-запросы (pgx)
|
|
|
|
|
-- Валидация загружаемых файлов (тип, размер)
|
|
|
|
|
-- Мягкое удаление (deleted_at)
|
|
|
|
|
-- Проверка владельца ресурса при изменении/удалении
|
|
|
|
|
|
|
+- Rate limiting: Redis-based, настраивается для каждой группы эндпоинтов
|
|
|
|
|
+- CORS: только разрешённые origins
|
|
|
|
|
+- Защита от SQL-инъекций: pgx с параметризованными запросами
|
|
|
|
|
+- Валидация ввода: go-playground/validator
|
|
|
|
|
+- Мягкое удаление (soft delete: deleted_at)
|
|
|
|
|
+- Content Security Policy (CSP) через Caddy
|
|
|
|
|
+- WebSocket origin check: только разрешённые домены
|