diff --git a/.gitignore b/.gitignore index a547bf3..f942379 100755 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,13 @@ dist dist-ssr *.local +# Env files (never commit secrets) +.env +.env.* +!.env.example +!.env.production +backend/.env + # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/README.md b/README.md index fa0541e..80f28e9 100755 --- a/README.md +++ b/README.md @@ -86,7 +86,17 @@ VITE_DOMA_AI_PASSWORD=your-password **Для тестирования** можно использовать тестовый стенд: https://condo.d.doma.ai/ -### 3. Запуск в режиме разработки +### 3. (Ubuntu) Один раз настройте PostgreSQL + +Логин и пароль БД заданы в `backend/.env` (логин: **mkd_user**, пароль: **MkdUbuntu24Secure**). Выполните в терминале (введёте пароль sudo): + +```bash +sudo bash scripts/setup-postgres-ubuntu.sh +``` + +Затем в одном терминале: `cd backend && npm start`, в другом: `npm run dev`. + +### 4. Запуск в режиме разработки ```bash npm run dev @@ -94,13 +104,27 @@ npm run dev Приложение будет доступно по адресу: `http://localhost:3000` -### 4. Сборка для продакшена +### 4.1. Запуск в tmux (не зависит от SSH) + +Бэкенд и фронт в tmux-сессиях **back** и **front** — после отключения SSH процессы продолжают работать. + +```bash +bash scripts/start-tmux.sh +``` + +- Подключиться к логам: `tmux attach -t back` или `tmux attach -t front` +- Выйти из tmux без остановки: **Ctrl+B**, затем **D** +- Список сессий: `tmux ls` + +Доступ снаружи (если открыты порты в файрволе): **http://<IP-сервера>:3000** (фронт), **http://<IP-сервера>:4000/api** (API). На Ubuntu при необходимости: `sudo ufw allow 3000 && sudo ufw allow 4000 && sudo ufw reload` + +### 5. Сборка для продакшена ```bash npm run build ``` -### 5. Просмотр production сборки +### 6. Просмотр production сборки ```bash npm run preview diff --git a/backend/dbInit.js b/backend/dbInit.js index e6d233b..2b5b2b2 100755 --- a/backend/dbInit.js +++ b/backend/dbInit.js @@ -12,6 +12,13 @@ const DEFAULT_ADMIN_LOGIN = 'its'; const DEFAULT_ADMIN_PASSWORD = 'iiEasy348ax@'; const DEFAULT_ADMIN_ROLE = 'DIRECTOR'; +// Демо-пользователь с теми же правами, что и its (DIRECTOR) +const DEMO_EMPLOYEE_ID = 'e-demo'; +const DEMO_EMPLOYEE_NAME = 'Demo'; +const DEMO_LOGIN = 'demo'; +const DEMO_PASSWORD = 'demo123'; +const DEMO_ROLE = 'DIRECTOR'; + /** * Инициализация базы данных PostgreSQL * Создает БД при первом запуске и проверяет целостность при последующих запусках @@ -220,6 +227,9 @@ async function initializeDatabase() { // Администратор портала по умолчанию (логин its) — создаётся, если ещё нет await applyDefaultAdminSeed(client); + // Демо-пользователь (demo / demo123) с правами DIRECTOR — создаётся при каждом старте, если ещё нет + await applyDemoUserSeed(client); + return { success: true, initialized: !integrityCheck.isInitialized, @@ -2572,6 +2582,55 @@ async function applyDefaultAdminSeed(client) { } } +/** + * Демо-пользователь портала (логин demo, пароль demo123) с правами DIRECTOR, как у its. + */ +async function applyDemoUserSeed(client) { + try { + const existingUser = await client.query( + 'SELECT id FROM portal_users WHERE login = $1', + [DEMO_LOGIN] + ); + if (existingUser.rows.length > 0) { + return; + } + const employeeExists = await client.query( + 'SELECT id FROM employees WHERE id = $1', + [DEMO_EMPLOYEE_ID] + ); + if (employeeExists.rows.length === 0) { + await client.query( + `INSERT INTO employees (id, name, position, phone, status, salary, assigned_district_id) + VALUES ($1, $2, $3, $4, $5, $6, $7) + ON CONFLICT (id) DO NOTHING`, + [ + DEMO_EMPLOYEE_ID, + DEMO_EMPLOYEE_NAME, + 'Демо-пользователь', + '+70000000001', + 'active', + 0, + null, + ] + ); + console.log('[dbInit] Создан сотрудник для демо:', DEMO_EMPLOYEE_NAME); + } + const passwordHash = await bcrypt.hash(DEMO_PASSWORD, 10); + await client.query( + `INSERT INTO portal_users (employee_id, login, role, password_hash, is_active) + VALUES ($1, $2, $3, $4, true) + ON CONFLICT (login) DO NOTHING`, + [DEMO_EMPLOYEE_ID, DEMO_LOGIN, DEMO_ROLE, passwordHash] + ); + const check = await client.query('SELECT id FROM portal_users WHERE login = $1', [DEMO_LOGIN]); + if (check.rows.length > 0) { + console.log('[dbInit] Создан демо-пользователь портала: логин', DEMO_LOGIN, ', роль', DEMO_ROLE); + } + } catch (error) { + console.warn('[dbInit] Ошибка при создании демо-пользователя:', error.message); + } +} + /** * Таблица настроек интеграций (DaData и др.) */ diff --git a/backend/package-lock.json b/backend/package-lock.json index 3d1738d..f4de85d 100755 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -862,7 +862,8 @@ "version": "0.0.1551306", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1551306.tgz", "integrity": "sha512-CFx8QdSim8iIv+2ZcEOclBKTQY6BI1IEDa7Tm9YkwAXzEWFndTEzpTo5jAUhSnq24IC7xaDw0wvGcm96+Y3PEg==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/dom-serializer": { "version": "2.0.0", @@ -1929,7 +1930,6 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", - "peer": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -2330,6 +2330,7 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.17.2.tgz", "integrity": "sha512-vjbKdiBJRqzcYw1fNU5KuHyYvdJ1qpcQg1CeBrHFqV1pWgHeVR6j/+kX0E1AAXfyuLUGY1ICrN2ELKA/z2HWzw==", "license": "MIT", + "peer": true, "dependencies": { "pg-connection-string": "^2.10.1", "pg-pool": "^3.11.0", @@ -2806,7 +2807,6 @@ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" } diff --git a/backend/server.js b/backend/server.js index 1f7a936..cbfeeda 100755 --- a/backend/server.js +++ b/backend/server.js @@ -374,8 +374,8 @@ async function startServer() { process.exit(1); } } - app.listen(PORT, () => { - console.log(`Backend API running on http://localhost:${PORT}${API_PREFIX}`); + app.listen(PORT, '0.0.0.0', () => { + console.log(`Backend API running on http://0.0.0.0:${PORT}${API_PREFIX}`); if (DATABASE_URL) { ensureEmployeeResponsibilityTable() .then(() => console.log('[backend] Таблица employee_responsibility проверена/создана')) diff --git a/docs/UBUNTU_SETUP.md b/docs/UBUNTU_SETUP.md new file mode 100644 index 0000000..c1f4b53 --- /dev/null +++ b/docs/UBUNTU_SETUP.md @@ -0,0 +1,161 @@ +# Запуск проекта на Ubuntu 24.04 + +После переноса с Windows проект запускается на Ubuntu так же через Node.js и PostgreSQL. Ниже — пошаговая настройка. + +## 1. Установка Node.js (18+) + +```bash +# Через NodeSource (рекомендуется LTS) +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt-get install -y nodejs + +# Проверка +node -v # v20.x.x +npm -v +``` + +Либо через стандартный репозиторий Ubuntu: + +```bash +sudo apt update +sudo apt install -y nodejs npm +``` + +## 2. Установка PostgreSQL + +```bash +sudo apt update +sudo apt install -y postgresql postgresql-contrib +sudo systemctl start postgresql +sudo systemctl enable postgresql +``` + +Создание пользователя и базы (опционально, если ещё не созданы): + +```bash +sudo -u postgres psql -c "CREATE USER mkd_user WITH PASSWORD 'your_password';" +sudo -u postgres psql -c "CREATE DATABASE mkd_control_center OWNER mkd_user;" +``` + +Строка подключения для `.env` бэкенда: + +``` +postgres://mkd_user:your_password@localhost:5432/mkd_control_center +``` + +## 3. Зависимости для Puppeteer (бэкенд) + +Бэкенд использует Puppeteer. На Ubuntu нужны системные библиотеки: + +```bash +sudo apt install -y \ + ca-certificates fonts-liberation libasound2 libatk-bridge2.0-0 \ + libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 \ + libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 \ + libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 \ + libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 \ + libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 \ + libxtst6 lsb-release wget xdg-utils +``` + +## 4. Настройка проекта + +### 4.1 Клонирование / копирование + +Если репозиторий уже скопирован в каталог проекта (например, `/home/its/mkd`), переходите в него: + +```bash +cd /home/its/mkd +``` + +### 4.2 Установка зависимостей + +В корне (фронтенд) и в `backend`: + +```bash +npm install +cd backend && npm install && cd .. +``` + +### 4.3 Переменные окружения + +**Корень проекта** — для фронтенда. Создайте `.env` или `.env.local` на основе `.env.example`: + +```bash +cp .env.example .env.local +# Отредактируйте .env.local при необходимости (VITE_API_BASE_URL, Doma AI и т.д.) +``` + +**Бэкенд** — в `backend/.env` должны быть минимум: + +```env +# Обязательно для работы БД +DATABASE_URL=postgres://mkd_user:your_password@localhost:5432/mkd_control_center + +# Обязательно в production +JWT_SECRET=ваш-секретный-ключ-для-jwt +JWT_EXPIRES_IN=7d + +# Опционально: Doma AI, Turnstile и т.д. +# DOMA_API_URL=... +# DOMA_API_TOKEN=... +``` + +Пути в конфигах (например, `path.join(__dirname, 'uploads')`) на Linux не меняют — Node использует `/` и `path.join` корректно. + +## 5. Запуск + +Нужны два процесса: бэкенд (API) и фронтенд (Vite). + +### Вариант A: два терминала + +**Терминал 1 — бэкенд:** + +```bash +cd /home/its/mkd/backend +npm start +``` + +Должно появиться сообщение о запуске на порту 4000 (или вашем `PORT`). + +**Терминал 2 — фронтенд:** + +```bash +cd /home/its/mkd +npm run dev +``` + +Откройте в браузере: **http://localhost:3000**. Запросы к `/api` уйдут на бэкенд через прокси Vite (localhost:4000). + +### Вариант B: один терминал (фоновый бэкенд) + +```bash +cd /home/its/mkd/backend && npm start & +cd /home/its/mkd && npm run dev +``` + +### Сборка для production + +```bash +cd /home/its/mkd +npm run build +``` + +Статика окажется в `dist/`. Раздавать её можно nginx’ом, указав API и `uploads` на бэкенд (порт 4000). + +## 6. Проверка + +| Компонент | URL / проверка | +|------------|----------------| +| Фронтенд | http://localhost:3000 | +| API бэкенд | http://localhost:4000/api (например, health, если есть) | +| PostgreSQL | `sudo -u postgres psql -c "\l"` — список баз | + +## 7. Частые проблемы на Ubuntu + +- **«DATABASE_URL не задана»** — добавьте `DATABASE_URL` в `backend/.env` и перезапустите бэкенд. +- **Puppeteer/Chromium не запускается** — установите зависимости из пункта 3; при необходимости в `backend` можно задать `PUPPETEER_EXECUTABLE_PATH` на системный chromium. +- **Порт 3000 или 4000 занят** — смените в `.env`: фронт — `server.port` в `vite.config.ts` или переменные Vite; бэкенд — `PORT` в `backend/.env`. +- **Права на каталог uploads** — если бэкенд пишет файлы от другого пользователя: `chmod 755 backend/uploads` (или 775 при необходимости). + +После выполнения шагов 1–5 проект на Ubuntu 24.04 должен запускаться так же, как на Windows. diff --git a/package-lock.json b/package-lock.json index 89857e7..cc9f6dc 100755 --- a/package-lock.json +++ b/package-lock.json @@ -54,6 +54,7 @@ "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", @@ -1221,6 +1222,7 @@ "integrity": "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -1305,6 +1307,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -1719,6 +1722,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -1775,6 +1779,7 @@ "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", "license": "MIT", + "peer": true, "dependencies": { "fast-diff": "^1.3.0", "lodash.clonedeep": "^4.5.0", @@ -1799,6 +1804,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -1808,6 +1814,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -2041,6 +2048,7 @@ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", diff --git a/scripts/setup-postgres-ubuntu.sh b/scripts/setup-postgres-ubuntu.sh new file mode 100755 index 0000000..804e71e --- /dev/null +++ b/scripts/setup-postgres-ubuntu.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# Один раз выполните: sudo bash scripts/setup-postgres-ubuntu.sh +# Логин: mkd_user, пароль: MkdUbuntu24Secure +set -e +sudo -u postgres psql -c "DO \$\$ BEGIN CREATE USER mkd_user WITH PASSWORD 'MkdUbuntu24Secure'; EXCEPTION WHEN duplicate_object THEN ALTER USER mkd_user WITH PASSWORD 'MkdUbuntu24Secure'; END \$\$;" +sudo -u postgres psql -c "SELECT 1 FROM pg_database WHERE datname='mkd_control_center'" | grep -q 1 || sudo -u postgres psql -c "CREATE DATABASE mkd_control_center OWNER mkd_user;" +sudo -u postgres psql -d mkd_control_center -c "GRANT ALL ON SCHEMA public TO mkd_user; GRANT CREATE ON SCHEMA public TO mkd_user;" +echo "Готово. Логин: mkd_user, пароль: MkdUbuntu24Secure" diff --git a/scripts/start-tmux.sh b/scripts/start-tmux.sh new file mode 100755 index 0000000..143b162 --- /dev/null +++ b/scripts/start-tmux.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Запуск бэкенда и фронтенда в tmux (сессии back и front). +# После отключения SSH процессы продолжают работать. +# Подключиться: tmux attach -t back или tmux attach -t front +# Список сессий: tmux ls + +set -e +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +# Если порты заняты не tmux — освободите: kill процесс на 4000 и 3000, затем запустите скрипт снова. +echo "Останавливаем старые сессии tmux back/front..." +tmux kill-session -t back 2>/dev/null || true +tmux kill-session -t front 2>/dev/null || true + +# Backend в сессии "back" +tmux new-session -d -s back -c "$ROOT/backend" "npm start" + +# Frontend в сессии "front" +tmux new-session -d -s front -c "$ROOT" "npm run dev" + +echo "Tmux сессии запущены:" +echo " back — бэкенд (порт 4000)" +echo " front — фронтенд (порт 3000)" +echo "" +echo "Подключиться: tmux attach -t back или tmux attach -t front" +echo "Выйти из tmux без остановки: Ctrl+B, затем D" +echo "" +echo "Доступ снаружи: http://:3000 (фронт), :4000/api (API)" diff --git a/vite.config.ts b/vite.config.ts index a6159c7..24638e8 100755 --- a/vite.config.ts +++ b/vite.config.ts @@ -8,7 +8,7 @@ export default defineConfig(({ mode }) => { server: { port: 3000, host: '0.0.0.0', - allowedHosts: ['note.iieasy.ru'], + allowedHosts: true, proxy: { '/api': { target: process.env.API_PROXY_TARGET || 'http://localhost:4000',