PWA-приложение для поиска транспортного средства на штрафстоянке. Работает как в браузере, так и устанавливается на мобильный телефон (требует HTTPS).
- Поиск ТС по ГРЗ - без авторизации, нормализация кириллицы (А123ВС77 = A123BC77)
- Профиль - данные пользователя и привязанное к нему транспортное средство со статусом
- Оффлайн-страница - через сервис-воркер (Serwist), только в продакшн-сборке
- Админ-панель - управление транспортными средствами через Bearer-токен
| Слой | Технология |
|---|---|
| Фреймворк | Next.js 16 (App Router, Turbopack) |
| БД | SQLite + Prisma 7 + @prisma/adapter-better-sqlite3 (WAL mode) |
| Сессии | iron-session v8 (зашифрованные cookie) |
| Валидация | Zod v4 |
| Стили | Tailwind CSS v4 |
| PWA | Serwist |
# 1. Установить зависимости
npm install
# 2. Скопировать пример и заполнить
cp .env.example .env.local
# 3. Применить схему БД
npx prisma db push
# 4. Заполнить тестовыми данными
npx tsx prisma/seed.ts
# 5. Запустить дев-сервер
npm run devОткрыть http://localhost:3000.
Создайте файл .env.local в корне проекта:
# Путь к SQLite-базе данных
DATABASE_URL="file:./dev.db"
# Секрет для шифрования сессий (минимум 32 символа, ОБЯЗАТЕЛЬНО сменить в проде!)
SESSION_SECRET="your-super-secret-32-plus-chars-here!!"
# Время жизни сессии в секундах (604800 = 7 дней)
SESSION_TTL_SECONDS="604800"
# Секрет для Bearer-токена в /api/admin/* (ОБЯЗАТЕЛЬНО сменить в проде!)
ADMIN_SECRET="your-admin-secret"
# Базовый URL приложения (используется для CSRF-проверки в проде)
APP_URL="http://localhost:3000"
# Rate limiting
RATE_LIMIT_LOGIN_PER_MINUTE="5"
RATE_LIMIT_LOGIN_PER_HOUR="20"
RATE_LIMIT_SEARCH_PER_MINUTE="30"Важно:
SESSION_SECRETиADMIN_SECRETобязательно сменить перед деплоем в продакшн.
После npx tsx prisma/seed.ts создаются:
| Логин | Пароль | Имя |
|---|---|---|
demo |
demo1234 |
Иван Петров |
alex |
alex1234 |
Александр Смирнов |
kate |
kate1234 |
Екатерина Волкова |
| ГРЗ | Авто | Статус | Владелец |
|---|---|---|---|
А123ВС77 |
Toyota Camry | На штрафстоянке | demo |
В456ЕК99 |
BMW X5 | Выдано | alex |
О777РР777 |
- | На штрафстоянке | kate |
Х001АА50 |
Lada Vesta | Неизвестно | - |
| Метод | URL | Описание |
|---|---|---|
POST |
/api/auth/login |
Вход (поле login, не email) |
POST |
/api/auth/logout |
Выход |
GET |
/api/vehicles/search?plate=А123ВС77 |
Поиск ТС по ГРЗ |
| Метод | URL | Описание |
|---|---|---|
GET |
/api/me |
Текущий пользователь |
| Метод | URL | Описание |
|---|---|---|
GET |
/api/admin/vehicles |
Список всех ТС |
POST |
/api/admin/vehicles |
Добавить ТС |
PUT |
/api/admin/vehicles/[id] |
Обновить ТС |
DELETE |
/api/admin/vehicles/[id] |
Удалить ТС |
src/
├── app/ # Next.js App Router страницы и API-роуты
│ ├── api/ # REST API
│ ├── admin/vehicles/ # Админ-панель
│ ├── login/ # Страница входа
│ ├── profile/ # Профиль пользователя
│ └── sw.ts # Service Worker (Serwist)
├── features/
│ └── auth/ # AuthProvider (клиентский контекст авторизации)
├── proxy.ts # Middleware авторизации (Next.js 16)
├── server/
│ ├── auth/ # Сессии, getCurrentUser
│ ├── config/env.ts # Zod-валидация env-переменных
│ ├── db/client.ts # Prisma singleton + WAL mode
│ ├── repositories/ # Запросы к БД
│ └── security/ # CSRF, rate limiter, admin auth
└── shared/
├── lib/normalize-plate.ts # Нормализация ГРЗ
└── ui/Navigation.tsx # Навигация
npm run build
npm run startnormalizedPlateиidТС никогда не возвращаются клиенту- CSRF-проверка в продакшн (сравнение
Origin/RefererсAPP_URL), в dev отключена - Rate limiting на логин и поиск (in-memory, сбрасывается при перезапуске)
- Сессия - зашифрованный cookie (AES-256-GCM), сервер не хранит состояние
Для разработки с телефона в локальной сети:
- Узнать IP машины:
ipconfig→ IPv4-адрес - Обновить
.env.local:APP_URL="http://192.168.x.x:3000" - Убедиться что в
next.config.tsпрописанallowedDevOrigins: ['192.168.x.x'] - Открыть
http://192.168.x.x:3000на телефоне
Для установки PWA на телефон требуется HTTPS (Let's Encrypt + VPS или белый IP с сертификатом).