# Магазин изделий ручной работы Цель проекта — витрина и админка для магазина изделий ручного труда (игрушки, сувениры и т.п.) с простой загрузкой/редактированием данных через фронтенд‑админку. Проект сделан как **монорепозиторий**: - `client/` — фронтенд (витрина + админка) - `server/` — бэкенд API + БД ## Стек ### Фронтенд - **React** + **Vite** - **axios** - **@tanstack/react-query** - **MUI (@mui/material)** + emotion - **React Router** - **Архитектура**: **FSD (Feature-Sliced Design)** — слои `app/pages/widgets/features/entities/shared` - **Качество**: ESLint (flat config) + Prettier, границы FSD (`eslint-plugin-boundaries`) ### Бэкенд - **Node.js** - **Fastify** (+ CORS) - **Prisma** (миграции) - **SQLite** (локальная БД; легко сменить на Postgres через `DATABASE_URL`) ## Основные подходы и договорённости ### FSD на фронте - Импорты между слоями ограничены правилами `boundaries` (например `features` может импортировать `entities/shared`, но не наоборот). - Alias `@` указывает на `client/src` (см. `client/vite.config.ts` и `client/tsconfig.app.json`). ### Данные и админка - Данные загружаются/редактируются через **админку на фронте**. - Админ‑роуты бэкенда доступны только авторизованному пользователю с email из `ADMIN_EMAIL` в `server/.env`. ### Форматирование и линтинг (client) - Prettier конфиг: `client/.prettierrc.json` - Ignore: `client/.prettierignore` - EditorConfig: `client/.editorconfig` - Команды: - `npm run lint` / `npm run lint:fix` - `npm run format` / `npm run format:check` ## Запуск ### Бэкенд **Вариант A — типовой `.env`** ```bash cd server cp .env.example .env # укажите ADMIN_EMAIL npm install npx prisma migrate dev # если база ещё не создана npx prisma db seed # опционально: тестовые категории и товары npm run dev:classic # загрузка из `.env` ``` **Вариант B — файл [`server/.dev_env`](server/.dev_env)** (то, что уже лежит в репозитории для локального стенда; нужен **Node.js 20.6+** из‑за `node --env-file`): ```bash cd server npm install npm run dev # переменные из `.dev_env` ``` Очистка БД до «чистого» тестового состояния (SQLite + миграции + seed): в `server/` выполните `npm run db:reset:test`. Сервер: `http://127.0.0.1:3333`. Проверка: `GET /health`. Черновик деплоя на Proxmox: [docs/test-deploy-proxmox.md](docs/test-deploy-proxmox.md). Обновление уже развёрнутого стенда: [docs/deploy-changes.md](docs/deploy-changes.md). ### Фронтенд В другом терминале: ```bash cd client npm install npm run dev ``` Откройте `http://localhost:5173`. Запросы к `/api` проксируются на бэкенд (см. `client/vite.config.ts`). ## Админка Раздел админки доступен только по прямой ссылке `/admin` и только для пользователя с email из `ADMIN_EMAIL`. Если такого пользователя нет в БД, сервер создаёт его автоматически при старте. Для боевого размещения фронта и API на разных доменах задайте `VITE_API_URL` (например `https://api.example.com/api`) и **CORS_ORIGIN** на сервере. ### OAuth VK и Яндекс В `server/.env` задайте `VK_CLIENT_ID`, `VK_CLIENT_SECRET`, `YANDEX_CLIENT_ID`, `YANDEX_CLIENT_SECRET`, а также **точные** публичные адреса: - `SERVER_PUBLIC_URL` — базовый URL API (без завершающего `/`), например `https://api.example.com` или `http://127.0.0.1:3333`. - `CLIENT_PUBLIC_URL` — базовый URL витрины, куда бэкенд редиректит после входа с JWT в query: `/auth/callback?token=...`, например `http://127.0.0.1:5173`. **Redirect URI в кабинетах провайдеров** (должны совпадать с тем, что шлёт сервер при авторизации): - VK: `{SERVER_PUBLIC_URL}/api/auth/oauth/vk/callback` - Яндекс: `{SERVER_PUBLIC_URL}/api/auth/oauth/yandex/callback` Старт входа с витрины: кнопки на странице `/auth` ведут на `GET /api/auth/oauth/vk` и `GET /api/auth/oauth/yandex` (полный URL — тот же origin, что и API: при прокси Vite это `/api/...` относительно фронта; при отдельном домене API — из `VITE_API_URL`). ### Футер витрины (опционально) В `client/.env` можно задать `VITE_STORE_EMAIL`, `VITE_STORE_PHONE`, `VITE_STORE_SOCIAL_NOTE` для блока контактов в подвале. ## API (кратко) Публичные: - `GET /api/categories` - `GET /api/products?categorySlug=...` Админ: - `GET /api/admin/products` - `POST /api/admin/products` - `PATCH /api/admin/products/:id` - `DELETE /api/admin/products/:id` - `POST /api/admin/categories`