# База знаний проекта DoSoap ## Назначение проекта DoSoap - это веб-приложение для расчета себестоимости продукции ручной работы. Пользователи могут: 1. Выбрать калькулятор (мыло, свечи и т.д.) 2. Ввести параметры продукта 3. Получить автоматический расчет себестоимости 4. Отправить результат в Telegram-бота ## Архитектура системы ### Frontend (Next.js) **Структура:** ``` frontend/ app/ # Next.js App Router page.tsx # Главная страница с меню layout.tsx # Общий layout calculators/ # Модули калькуляторов soap/ # Калькулятор мыла config.ts # Конфигурация calc.ts # Функции расчета candles/ # Калькулятор свечей config.ts calc.ts components/ # React компоненты CalculatorEngine.tsx # Универсальный движок CalculatorMenu.tsx # Меню выбора lib/ # Утилиты и типы calculator-types.ts # TypeScript типы calculator-registry.ts # Реестр калькуляторов docs/ # Документация calculator-creation-guide.md ``` **Технологии:** - Next.js 15.3.3 с App Router - React 19 - TypeScript 5 - Tailwind CSS 4 - Статический экспорт (`output: 'export'`) ### Backend (Express + Telegram) **Файлы:** - `backend/bot.js` - основной файл бэкенда **Функционал:** - Обработка POST запросов от фронтенда - Интеграция с Telegram Bot API - Загрузка и отправка фотографий - Форматирование сообщений для Telegram **API:** - `POST /api/submit` - принимает данные расчета и отправляет в Telegram - Команда `/myid` - возвращает chat_id пользователя ## Типы данных ### FieldConfig Определяет поле ввода в калькуляторе: ```typescript { id: string; // Уникальный ID type: 'text' | 'number' | 'file'; label: string; // Название поля defaultValue?: string; gridCols?: 1 | 2; // Ширина в grid required?: boolean; accept?: string; // Для файлов groupName?: string; // Группа для группировки showStepAfter?: string; // ID расчета после группы } ``` ### CalculationStep Шаг расчета (например, "Себестоимость основы"): ```typescript { id: string; name: string; formula: (values: Record) => number; formulaDescription?: string; } ``` ### SubtotalConfig Подитог (например, "Итого себестоимость"): ```typescript { id: string; name: string; formula: (values, steps) => number; highlight?: boolean; // Выделить визуально formulaDescription?: string; } ``` ### AdditionalCalculation Дополнительный расчет (например, "Цена за 100г"): ```typescript { id: string; name: string; formula: (values, steps, subtotals, additional?) => number; formulaDescription?: string; } ``` ## Поток работы калькулятора 1. **Выбор калькулятора**: Пользователь выбирает калькулятор в меню 2. **Загрузка конфигурации**: `CalculatorEngine` получает конфигурацию из реестра 3. **Рендеринг полей**: Динамически создаются поля на основе `fields` из конфигурации 4. **Ввод данных**: Пользователь заполняет поля 5. **Расчет**: При изменении полей автоматически пересчитываются все шаги, подитоги и дополнительные расчеты 6. **Отправка**: Данные отправляются на бэкенд через `/api/submit` 7. **Telegram**: Бэкенд отправляет форматированное сообщение в Telegram ## Группировка полей Поля можно группировать для правильного расположения блоков расчета: ```typescript { id: 'weight', groupName: 'base', // Группа "base" showStepAfter: 'base', // После группы показать расчет "base" } { id: 'price', groupName: 'base', // Тот же группа } // Блок расчета "Себестоимость основы" появится здесь ``` ## Форматирование Telegram сообщений Каждый калькулятор может иметь функцию `formatTelegramMessage`: ```typescript formatTelegramMessage: (values, steps, subtotals, additional) => { let text = `🧼 Расчёт мыла:\n\n`; text += `💵 Себестоимость: ${subtotals.total.toFixed(1)} ₽\n`; return text; } ``` Если функция не указана, используется универсальное форматирование. ## API интеграция ### Определение URL Фронтенд автоматически определяет URL API: ```typescript const isLocalhost = window.location.hostname === 'localhost'; const apiUrl = isLocalhost ? 'http://localhost:3001/api/submit' : 'https://api-dosoap.duckdns.org/api/submit'; ``` ### Формат запроса ```typescript FormData { chat_id: string; calculator_id: string; calculator_name: string; telegram_message: string; // Готовое сообщение photo?: File; // Опциональное фото // ... остальные поля } ``` ## Добавление нового калькулятора ### Шаг 1: Создать модуль ```bash mkdir frontend/calculators/my-calc touch frontend/calculators/my-calc/config.ts touch frontend/calculators/my-calc/calc.ts # опционально ``` ### Шаг 2: Создать конфигурацию См. `frontend/docs/calculator-creation-guide.md` ### Шаг 3: Зарегистрировать В `frontend/lib/calculator-registry.ts`: ```typescript import { myCalcConfig } from '@/calculators/my-calc/config'; registerCalculator(myCalcConfig); ``` ## Окружение разработки ### Платформы - **Разработка**: Windows с PowerShell - **Хостинг**: Ubuntu Linux ### Особенности разработки на Windows - PowerShell не поддерживает оператор `&&` для цепочки команд - Используйте `;` или выполняйте команды отдельно - Пути в Git и конфигах всегда используют `/`, даже на Windows - При работе через SSH используйте Linux команды ### Локальная разработка (Windows + PowerShell) ```powershell # Frontend - один терминал cd frontend npm install npm run dev # Backend - отдельный терминал cd backend node bot.js ``` ## Деплой ### Сервер - **ОС**: Ubuntu Linux - **IP**: 192.168.0.19 - **Пользователь**: dosai - **Путь**: ~/projects/DoSoapCalc - **Управление процессами**: PM2 ### Процессы PM2 - `dosoap-frontend` - Next.js приложение - `dosoap-backend` - Express сервер ### Команды деплоя **С локального Windows (PowerShell):** ```powershell # Отправить изменения git push origin dev # Подключиться и обновить сервер (Ubuntu команды через SSH) ssh dosai@192.168.0.19 "cd ~/projects/DoSoapCalc && git pull origin dev && cd frontend && npm run build && pm2 restart dosoap-frontend dosoap-backend" ``` **Или на сервере напрямую (Ubuntu):** ```bash cd ~/projects/DoSoapCalc git pull origin dev cd frontend && npm run build pm2 restart dosoap-frontend dosoap-backend ``` ## Обработка ошибок ### Расчеты Все формулы должны проверять: - Деление на ноль → вернуть 0 - Пустые значения → вернуть 0 - NaN → вернуть 0 Пример: ```typescript if (weight <= 0 || price <= 0) return 0; return (weight / 1000) * price; ``` ### API запросы ```typescript try { const res = await fetch(apiUrl, { method: 'POST', body: formData }); if (!res.ok) throw new Error('Server error'); } catch (err) { alert('Ошибка сети при отправке расчёта'); } ``` ## Известные особенности 1. **Статический экспорт**: Next.js собирается в статические файлы, нет серверного рендеринга 2. **Telegram Bot Token**: Хранится в переменных окружения на сервере 3. **Chat ID**: Передается через URL параметр `?chat_id=...` или через Telegram бота 4. **Фото**: Отправляются через FormData, обрабатываются multer на бэкенде