From f40bcb84fde5987c0d4664cc72decbf38392be25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Tue, 9 Jun 2026 19:55:07 +0400 Subject: [PATCH] =?UTF-8?q?feat:=20ensureSchema=20=E2=80=94=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D1=91=D1=82=20?= =?UTF-8?q?=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=8B=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=20=D1=81=D1=82=D0=B0=D1=80=D1=82=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - db.js: ensureSchema() = CREATE TABLE IF NOT EXISTS для всех таблиц - server.js: вызов ensureSchema() после коннекта к БД - Больше не нужен ручной psql -f sql/schema.sql --- server.js | 4 ++-- src/db.js | 44 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/server.js b/server.js index cfa366d..52afd24 100644 --- a/server.js +++ b/server.js @@ -23,7 +23,7 @@ const path = require('path'); const helmet = require('helmet'); require('dotenv').config(); -const { checkConnection } = require('./src/db'); +const { checkConnection, ensureSchema } = require('./src/db'); const { initAuth } = require('./src/auth'); const q = require('./src/queries'); const { MOCK_USERS, APP_VERSION } = require('./src/config'); @@ -127,7 +127,7 @@ async function start() { // ── Старт сервера ───────────────────────────────────────────────────────────── checkConnection() - .then(() => console.log('DB connected')) + .then(() => { console.log('DB connected'); return ensureSchema(); }) .catch(e => console.error('DB not ready:', e.message)); return app; diff --git a/src/db.js b/src/db.js index 670e777..3c43c0c 100644 --- a/src/db.js +++ b/src/db.js @@ -21,4 +21,46 @@ async function checkConnection() { return rows[0].ok === 1; } -module.exports = { pool, checkConnection }; +async function ensureSchema() { + await pool.query(` + CREATE TABLE IF NOT EXISTS companies ( + id SERIAL PRIMARY KEY, + client_id VARCHAR(64) UNIQUE NOT NULL, + name VARCHAR(255), + custom_limit INTEGER DEFAULT NULL CHECK (custom_limit IS NULL OR custom_limit >= 0), + owner_email TEXT DEFAULT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ); + CREATE TABLE IF NOT EXISTS whitelist_entries ( + id SERIAL PRIMARY KEY, + company_id INTEGER NOT NULL REFERENCES companies(id) ON DELETE RESTRICT, + value_cidr VARCHAR(18) NOT NULL CHECK (value_cidr ~ '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'), + comment VARCHAR(255), + created_by VARCHAR(255) NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_by VARCHAR(255), + updated_at TIMESTAMPTZ, + deleted_by VARCHAR(255), + deleted_at TIMESTAMPTZ + ); + CREATE UNIQUE INDEX IF NOT EXISTS uq_entries_active_cidr + ON whitelist_entries(company_id, value_cidr) WHERE deleted_at IS NULL; + CREATE INDEX IF NOT EXISTS idx_entries_active + ON whitelist_entries(company_id, created_at DESC) WHERE deleted_at IS NULL; + CREATE TABLE IF NOT EXISTS audit_log ( + id SERIAL PRIMARY KEY, + user_email VARCHAR(255) NOT NULL, + company_id INTEGER NOT NULL, + action VARCHAR(32) NOT NULL CHECK (action IN ('CREATE','UPDATE','DELETE')), + old_value TEXT, + new_value TEXT, + entry_id INTEGER, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ); + CREATE INDEX IF NOT EXISTS idx_audit_company_time ON audit_log(company_id, created_at DESC); + `); + console.log('[db] Schema ensured'); +} + +module.exports = { pool, checkConnection, ensureSchema };