Настройка запуска на Ubuntu + tmux и доступ извне (Арсен.)

- Добавлены инструкции `docs/UBUNTU_SETUP.md` и секции в README.
- Добавлены скрипты `scripts/setup-postgres-ubuntu.sh` и `scripts/start-tmux.sh` (tmux: front/back).
- Для доступа снаружи: Vite `allowedHosts: true`, бэкенд слушает `0.0.0.0`.
- Добавлен сид демо-пользователя портала `demo` / `demo123` с ролью DIRECTOR (как `its`).
- `.env` файлы добавлены в `.gitignore`, чтобы не коммитить секреты.

Выполнил: Арсен.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-02-10 11:55:20 +05:00
parent de94ad707b
commit 4993816a95
10 changed files with 305 additions and 9 deletions

View File

@@ -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 и др.)
*/

View File

@@ -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"
}

View File

@@ -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 проверена/создана'))