# Findings: Аудит проекта PhotoPlaces Дата аудита: 2026-06-13 --- ## 1. Безопасность ### 🔴 P0: `websocket.go` — CheckOrigin всегда true `backend/internal/handlers/websocket.go:13` — WebSocket принимает соединения с любых источников. В production должен проверять `AllowedOrigins`. ```go CheckOrigin: func(r *http.Request) bool { return true } ``` ### 🔴 P0: `places.go` — ошибка авторизации не типизирована `backend/internal/services/places.go:118` — использует `fmt.Errorf("not your place")` вместо sentinel error. Вызывающий код не может отличить "не ваше место" от других ошибок. ### 🔴 P0: Dev-секреты в `docker-compose.yml` Локальный `docker-compose.yml` содержит: - `POSTGRES_PASSWORD: photoplaces_dev` - `REDIS_PASSWORD: photoplaces_dev` - `MINIO_ROOT_PASSWORD: photoplaces_dev` - `JWT_SECRET: dev-secret-change-in-production` **Риск:** если запустить `docker compose up` без переопределения секретов, они уходят в production. ### 🔴 P0: env.prod с placeholder-секретами `deploy/env.prod`: - `DB_PASSWORD=CHANGE_ME_STRONG_PASSWORD` - `REDIS_PASSWORD=CHANGE_ME_REDIS_PASSWORD` - `JWT_SECRET=CHANGE_ME_JWT_SECRET_32_HEX` - `S3_SECRET_KEY=CHANGE_ME_MINIO_PASSWORD` - `YANDEX_MAPS_API_KEY=ВАШ_КЛЮЧ_ЯНДЕКС_КАРТ` **Риск:** деплой с этими значениями провалится, но если кто-то скопирует env.prod на другой сервер — будет дыра. ### 🟡 P1: `backend/cmd/api/main.go` — rate limiter in-memory активен Несмотря на наличие `ratelimit_redis.go`, в `main.go` используется in-memory rate limiter. Redis-версия не подключена. --- ## 2. Баги ### 🔴 P0: `log.go:114` — `string(rune(line))` вместо `strconv.Itoa(line)` **Исправлено.** Функция `callerInfo` конвертировала номер строки в символ Unicode, а не в строку. ### 🟡 P1: `strPtr` дублируется Определена дважды: - `backend/internal/handlers/helpers.go:7` - `backend/internal/services/auth.go:252` **Риск:** при изменении одной копии вторая рассинхронизируется. ### 🟡 P1: `reviews.go` — самописные утилиты вместо стандартных `backend/internal/handlers/reviews.go:88-103`: - `isUniqueViolation` — ручной парсинг ошибки pgx, когда есть `pgconn.PgError` - `contains`, `searchString` — дубликат `strings.Contains` --- ## 3. Тесты ### 🔴 P0: 0 тестов во всём проекте - `make test-backend` → `go test ./...` ничего не найдёт - `make test-frontend` → `npm run test` упадёт (нет скрипта в `package.json`) - `frontend/package.json` не содержит `"test"` скрипта Стратегия тестирования описана в `obsidian_data/Photoplaces_data/decision-test-strategy.md`, но не реализована. --- ## 4. Архитектура / Незавершённое ### 🟡 P1: Только Яндекс.Карты `frontend/src/lib/map.ts` — интерфейс `MapProvider` есть, но реализован только Yandex Maps. MapLibre/OSM (из docs/MAP_PROVIDERS.md) не реализованы. ### 🟡 P1: Redis rate limiter не подключён `backend/cmd/api/main.go` использует in-memory `ratelimit.go`. `ratelimit_redis.go` написан, но не включён. Решение в Obsidian (`decision-rate-limiter-redis.md`) помечено как "Accepted (needs implementation)". ### 🟡 P2: `env.prod` с хардкодом IP `S3_PUBLIC_ENDPOINT=http://192.168.88.128:9000` — IP зашит, а не домен. При смене сервера требует ручного редактирования. --- ## 5. Документация (исправлено) ### ✅ Go package-level docs Добавлены во все 8 пакетов: - `main`, `config`, `log`, `validator`, `models`, `handlers`, `middleware`, `repository`, `services` ### ✅ Frontend JSDoc Добавлены ко всем экспортам: 18 файлов, все компоненты, хуки, типы, утилиты. ### ✅ CONTRIBUTING.md Создан. ### ✅ README.md Уже был, полный и актуальный. --- ## 6. Рекомендации ### Приоритет 0 (немедленно) 1. Заменить `CheckOrigin: return true` на проверку `ALLOWED_ORIGINS` 2. Заменить `fmt.Errorf("not your place")` на sentinel error `ErrNotYourPlace` 3. Написать хотя бы 1 smoke-тест для health endpoint 4. Заменить placeholder-секреты в `deploy/env.prod` на сгенерированные 5. Убрать dev-секреты из `docker-compose.yml` (вынести в `.env`) ### Приоритет 1 (до production) 6. Удалить дубликат `strPtr` из `services/auth.go`, использовать из `helpers.go` 7. Заменить самописные `contains`/`searchString` на `strings.Contains` 8. Подключить Redis rate limiter вместо in-memory 9. Заменить IP в `env.prod` на доменное имя ### Приоритет 2 (улучшения) 10. Реализовать MapLibre/OSM провайдер для карт 11. Настроить `"test"` скрипт в `frontend/package.json` 12. Добавить `npm run test` в CI