Ver Fonte

Разделены пулы БД и изменен конфиг

Vadim há 6 meses atrás
pai
commit
991fd19ea2

+ 0 - 28
.env

@@ -1,28 +0,0 @@
-# BASIC
-PORT = "3000"
-LOGS_LEVEL = "info"
-API_URL = ""
-
-# DB
-DB_USER = ""
-DB_HOST = "localhost"
-DB_PORT = "5433"
-DB_NAME = ""
-DB_PASS = ""
-
-# MAIL
-SMTP_HOST = ""
-SMTP_PORT = ""
-SMTP_USER = ""
-SMTP_PASS = ""
-
-# AUTH
-JWT_ACCESS_SECRET= ""
-JWT_REFRESH_SECRET= ""
-PASSWORD_MAX_TRIES = "10"
-ACCESS_TOKEN_LIFETIME_MINS= "15"
-REFRESH_TOKEN_LIFETIME_DAYS= "90"
-
-# CONFIRM PINS
-CONFIRM_PIN_LIFETIME_MINS = "60"
-CONFIRM_PIN_MAX_TRIES = "5"

+ 4 - 2
.example.env

@@ -4,11 +4,13 @@ LOGS_LEVEL = "info"
 API_URL = ""
 
 # DB
-DB_USER = ""
 DB_HOST = "localhost"
 DB_PORT = "5433"
 DB_NAME = ""
-DB_PASS = ""
+DB_SELECT_USER = ""
+DB_SELECT_PASS = ""
+DB_UPDATE_USER = ""
+DB_UPDATE_PASS = ""
 
 # MAIL
 SMTP_HOST = ""

+ 4 - 402
package-lock.json

@@ -44,7 +44,7 @@
         "prettier": "^3.5.3",
         "rimraf": "^5.0.10",
         "tsx": "^4.19.3",
-        "typescript": "^5.8.2"
+        "typescript": "^5.3.3"
       }
     },
     "node_modules/@aashutoshrathi/word-wrap": {
@@ -76,390 +76,6 @@
         "kuler": "^2.0.0"
       }
     },
-    "node_modules/@esbuild/aix-ppc64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
-      "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "aix"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-arm": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
-      "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
-      "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
-      "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
-      "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/darwin-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
-      "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
-      "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
-      "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-arm": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
-      "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
-      "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-ia32": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
-      "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-loong64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
-      "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
-      "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
-      "cpu": [
-        "mips64el"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
-      "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
-      "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-s390x": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
-      "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
-      "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/netbsd-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
-      "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
-      "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/openbsd-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
-      "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
-      "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/sunos-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
-      "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "sunos"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/win32-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
-      "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/win32-ia32": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
-      "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
     "node_modules/@esbuild/win32-x64": {
       "version": "0.25.0",
       "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
@@ -2487,20 +2103,6 @@
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
       "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
     },
-    "node_modules/fsevents": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
-      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
-      "dev": true,
-      "hasInstallScript": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
-      }
-    },
     "node_modules/function-bind": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -4781,9 +4383,9 @@
       "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
     },
     "node_modules/typescript": {
-      "version": "5.8.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
-      "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
+      "version": "5.3.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
+      "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
       "dev": true,
       "bin": {
         "tsc": "bin/tsc",

+ 2 - 2
package.json

@@ -12,7 +12,7 @@
     "#exceptions": "./src/exceptions/",
     "#logger": "./src/plugins/logger.ts",
     "#dayjs": "./src/plugins/dayjs.ts",
-    "#config": "./config/config.ts"
+    "#config": "./src/config/config.ts"
   },
   "husky": {
     "hooks": {
@@ -63,6 +63,6 @@
     "prettier": "^3.5.3",
     "rimraf": "^5.0.10",
     "tsx": "^4.19.3",
-    "typescript": "^5.8.2"
+    "typescript": "^5.3.3"
   }
 }

+ 13 - 9
config/config.ts → src/config/config.ts

@@ -1,6 +1,9 @@
-import "../src/plugins/dotenv.js";
+import { logger } from "#plugins/logger.js";
+import "../plugins/dotenv.js";
 import { z } from "zod";
 
+logger.info("Валидация env...");
+
 // Функция для обязательных строковых переменных
 const requiredString = (envVar: string, defaultValue?: string) => {
   return z.preprocess(
@@ -53,11 +56,13 @@ const ConfigSchema = z.object({
   API_URL: requiredString("API_URL"),
 
   // DB
-  DB_USER: requiredString("DB_USER"),
   DB_HOST: requiredString("DB_HOST"),
   DB_PORT: requiredNumber("DB_PORT"),
   DB_NAME: requiredString("DB_NAME"),
-  DB_PASS: requiredString("DB_PASS"),
+  DB_SELECT_USER: requiredString("DB_SELECT_USER"),
+  DB_SELECT_PASS: requiredString("DB_SELECT_PASS"),
+  DB_UPDATE_USER: requiredString("DB_UPDATE_USER"),
+  DB_UPDATE_PASS: requiredString("DB_UPDATE_PASS"),
 
   // MAIL
   SMTP_HOST: requiredString("SMTP_HOST"),
@@ -81,10 +86,7 @@ const ConfigSchema = z.object({
 const result = ConfigSchema.safeParse(process.env);
 
 if (!result.success) {
-  console.error(
-    "❌ Невалидные переменные окружения:\n",
-    JSON.stringify(result.error.format(), null, 2),
-  );
+  logger.error("❌ Невалидные переменные окружения:\n", result.error);
   process.exit(1);
 }
 
@@ -96,9 +98,11 @@ export type Config = z.infer<typeof ConfigSchema>;
 // Логируем успешную валидацию без чувствительных данных
 const safeConfig = {
   ...config,
-  DB_PASS: "********",
+  DB_SELECT_PASS: "********",
+  DB_UPDATE_PASS: "********",
   SMTP_PASS: "********",
   JWT_ACCESS_SECRET: "********",
   JWT_REFRESH_SECRET: "********",
 };
-console.debug("✅ Валидация env прошла успешно:", safeConfig);
+logger.info("✅ Валидация env прошла успешно!");
+logger.silly("env:", safeConfig);

+ 6 - 2
src/db/db-service.ts

@@ -1,4 +1,4 @@
-import { db } from "#db";
+import { selPool } from "#db";
 
 import { sql } from "slonik";
 import { z } from "zod";
@@ -12,7 +12,9 @@ function camelToSnake(str: string) {
 // база данных
 class DbService {
   async checkDbShema() {
-    const dbColumns = await db.any(sql.type(
+    logger.info("Проверка схемы БД...");
+
+    const dbColumns = await selPool.any(sql.type(
       z.object({
         table_schema: z.string(),
         table_name: z.string(),
@@ -62,6 +64,8 @@ class DbService {
         }
       }
     }
+
+    logger.info("✅ БД корректная");
   }
 }
 

+ 31 - 26
src/db/db.ts

@@ -5,39 +5,44 @@ import {
   createLoggerInterceptor,
 } from "./db-interrceptors.js";
 import { config } from "#config";
-import dayjs from "dayjs";
 
 const host = config.DB_HOST;
 const port = config.DB_PORT;
-const user = config.DB_USER;
-const password = config.DB_PASS;
 const databaseName = config.DB_NAME;
+const selUser = config.DB_SELECT_USER;
+const selPass = config.DB_SELECT_PASS;
+const updUser = config.DB_UPDATE_USER;
+const updPass = config.DB_UPDATE_PASS;
 
-const pool = await createPool(
-  `postgres://${user}:${password}@${host}:${port}/${databaseName}`,
+const interceptors = [
+  createLoggerInterceptor(),
+  createResultParserInterceptor(),
+  createErrorLoggingInterceptor(),
+];
+
+const typeParsers = [
   {
-    interceptors: [
-      createLoggerInterceptor(),
-      createResultParserInterceptor(),
-      createErrorLoggingInterceptor(),
-    ],
-    typeParsers: [
-      {
-        name: "int8",
-        parse: (value) => {
-          return value === null ? value : Number(value);
-        },
-      },
-      {
-        name: "timestamp",
-        parse: (value) => {
-          return value === null ? value : dayjs.utc(value).toISOString();
-        },
-      },
-    ],
+    name: "int8",
+    parse: (value: unknown) => {
+      return value === null ? value : Number(value);
+    },
   },
-).then((p) => {
+];
+
+const selConnectString = `postgres://${selUser}:${selPass}@${host}:${port}/${databaseName}`;
+const selPool = await createPool(selConnectString, {
+  interceptors: interceptors,
+  typeParsers: typeParsers,
+}).then((p) => {
+  return p;
+});
+
+const updConnectString = `postgres://${updUser}:${updPass}@${host}:${port}/${databaseName}`;
+const updPool = await createPool(updConnectString, {
+  interceptors: interceptors,
+  typeParsers: typeParsers,
+}).then((p) => {
   return p;
 });
 
-export const db = pool;
+export { selPool, updPool };

+ 2 - 2
src/main.ts

@@ -1,5 +1,3 @@
-logger.info("Start server");
-
 import { config } from "#config";
 
 import express from "express";
@@ -71,6 +69,8 @@ app.use(errorMiddleware);
 
 const start = async () => {
   try {
+    logger.info("Запуск сервиса...");
+
     // проверка схемы БД
     await DbService.checkDbShema();
 

+ 3 - 3
src/modules/companies-management/companies-router.ts

@@ -4,7 +4,7 @@ const router = express.Router();
 export default router;
 
 // db
-import { db } from "#db";
+import { selPool, updPool } from "#db";
 import { DbShema } from "#db-shema";
 import { sql } from "slonik";
 
@@ -44,7 +44,7 @@ router.post("/company", async (req, res, next) => {
     const companyId = uuidv7();
 
     // company
-    await db.query(
+    await updPool.query(
       sql.unsafe`
       insert into usr.companies
         (company_id, name, owner_id, timezone)
@@ -64,7 +64,7 @@ router.get("/user-companies", async (req, res, next) => {
   try {
     const userId = UserUtils.getUserFromReq(req).userId;
 
-    const companies = await db.any(
+    const companies = await selPool.any(
       sql.type(
         z.object({
           companyId: DbShema.usr.companies.companyId,

+ 4 - 4
src/modules/companies-management/companies-service.ts

@@ -1,6 +1,6 @@
 // types
 
-import { db } from "#db";
+import { selPool } from "#db";
 import { sql } from "slonik";
 import { z } from "zod";
 import { DbShema } from "#db/db-shema.js";
@@ -8,7 +8,7 @@ import { ApiError } from "#exceptions/api-error.js";
 
 class companiesService {
   async checkCompanyAccess(userId: string, companyId: string) {
-    const companyData = await db.maybeOne(
+    const companyData = await selPool.maybeOne(
       sql.type(
         z.object({
           name: DbShema.usr.companies.name,
@@ -40,7 +40,7 @@ class companiesService {
   }
 
   async getCompanyEvents(companyId: string) {
-    const events = await db.any(
+    const events = await selPool.any(
       sql.type(
         z.object({
           eventId: DbShema.ev.events.eventId,
@@ -76,7 +76,7 @@ class companiesService {
   }
 
   async getCompanyById(companyId: string) {
-    const company = await db.maybeOne(
+    const company = await selPool.maybeOne(
       sql.type(
         z.object({
           companyId: DbShema.usr.companies.companyId,

+ 17 - 17
src/modules/events-management/events-router.ts

@@ -4,7 +4,7 @@ const router = express.Router();
 export default router;
 
 // db
-import { db } from "#db";
+import { selPool, updPool } from "#db";
 import { DbShema } from "#db-shema";
 import { sql } from "slonik";
 
@@ -56,7 +56,7 @@ router.post("/event", async (req, res, next) => {
     const eventId = uuidv7();
 
     // создаём ивент
-    await db.query(
+    await updPool.query(
       sql.unsafe`
       insert into ev.events 
         (event_id, local_name, timezone, company_id) 
@@ -66,7 +66,7 @@ router.post("/event", async (req, res, next) => {
 
     // вставляем даты ивента
     for (const date of dates) {
-      await db.query(
+      await updPool.query(
         sql.unsafe`
         insert into ev.event_dates 
           (event_id, date) 
@@ -76,7 +76,7 @@ router.post("/event", async (req, res, next) => {
     }
 
     // менеджер
-    await db.query(
+    await updPool.query(
       sql.unsafe`
       insert into ev.event_managers 
         (event_id, user_id) 
@@ -102,7 +102,7 @@ router.get("/event/:eventId", async (req, res, next) => {
     await EventsService.checkEventAccess(userId, eventId);
 
     // event
-    const event = await db.maybeOne(
+    const event = await selPool.maybeOne(
       sql.type(
         z.object({
           eventId: DbShema.ev.events.eventId,
@@ -132,7 +132,7 @@ router.get("/event/:eventId", async (req, res, next) => {
 
     // points
     const DbPointsType = DbShema.ev.programPoints;
-    const programPoints = await db.any(
+    const programPoints = await selPool.any(
       sql.type(
         z.object({
           programPointId: DbPointsType.programPointId,
@@ -158,7 +158,7 @@ router.get("/event/:eventId", async (req, res, next) => {
     );
 
     // rooms
-    const rooms = await db.any(
+    const rooms = await selPool.any(
       sql.type(
         z.object({
           roomId: DbShema.ev.rooms.roomId,
@@ -181,7 +181,7 @@ router.get("/event/:eventId", async (req, res, next) => {
 
     // task-blocks
     // TODO: вынести
-    const taskBlocks = await db.any(
+    const taskBlocks = await selPool.any(
       sql.type(
         z.object({
           taskBlockId: DbShema.ev.taskBlocks.taskBlockId,
@@ -198,7 +198,7 @@ router.get("/event/:eventId", async (req, res, next) => {
         `,
     );
 
-    const managers = await db.any(
+    const managers = await selPool.any(
       sql.type(
         z.object({
           userId: DbShema.ev.eventManagers.userId,
@@ -220,7 +220,7 @@ router.get("/event/:eventId", async (req, res, next) => {
         `,
     );
 
-    const roles = await db.any(
+    const roles = await selPool.any(
       sql.type(
         z.object({
           roleId: DbShema.ev.roles.roleId,
@@ -267,7 +267,7 @@ router.post("/program-point", async (req, res, next) => {
 
     const programPointId = uuidv7();
 
-    await db.query(
+    await updPool.query(
       sql.unsafe`
         insert into ev.program_points
           (program_point_id, name, start_date, end_date, room_id, event_id, is_internal)
@@ -298,7 +298,7 @@ router.patch("/event", async (req, res, next) => {
     await EventsService.checkEventAccess(userId, eventId);
 
     // change localName, timezone
-    await db.query(
+    await updPool.query(
       sql.unsafe`
     update ev.events
     set
@@ -320,7 +320,7 @@ router.patch("/event", async (req, res, next) => {
 
     // change dates
     if (dates) {
-      await db.query(
+      await updPool.query(
         sql.unsafe`
         delete from ev.event_dates
         where
@@ -328,7 +328,7 @@ router.patch("/event", async (req, res, next) => {
       );
 
       for (const date of dates) {
-        await db.query(
+        await updPool.query(
           sql.unsafe`
           insert into ev.event_dates 
             (event_id, date) 
@@ -340,7 +340,7 @@ router.patch("/event", async (req, res, next) => {
 
     // TODO: преверить безопасность pp и roles
     if (programPoint) {
-      await db.query(
+      await updPool.query(
         sql.unsafe`
         update ev.program_points
         set
@@ -354,7 +354,7 @@ router.patch("/event", async (req, res, next) => {
     }
 
     if (role) {
-      await db.query(
+      await updPool.query(
         sql.unsafe`
         update ev.roles
         set
@@ -385,7 +385,7 @@ router.post("/role", async (req, res, next) => {
     const roleId = uuidv7();
 
     // create role
-    await db.query(
+    await updPool.query(
       sql.unsafe`
       insert into ev.roles
         (role_id, name, event_id)

+ 4 - 4
src/modules/events-management/events-service.ts

@@ -1,6 +1,6 @@
 // types
 
-import { db } from "#db";
+import { selPool } from "#db";
 import { sql } from "slonik";
 import { ApiError } from "#exceptions/api-error.js";
 import { DbShema } from "#db/db-shema.js";
@@ -8,7 +8,7 @@ import { z } from "zod";
 
 class eventsService {
   async checkEventAccess(userId: string, eventId: string) {
-    const isExist = await db.exists(
+    const isExist = await selPool.exists(
       sql.unsafe`
       select 
         1 
@@ -35,7 +35,7 @@ class eventsService {
     taskId?: string;
   }): Promise<string> {
     if (taskBlockId) {
-      const eventId = await db.maybeOneFirst(
+      const eventId = await selPool.maybeOneFirst(
         sql.type(z.object({ eventId: DbShema.ev.taskBlocks.eventId }))`
         select
           event_id as "eventId"
@@ -54,7 +54,7 @@ class eventsService {
     }
 
     if (taskId) {
-      const taskBlockId = await db.maybeOneFirst(
+      const taskBlockId = await selPool.maybeOneFirst(
         sql.type(z.object({ taskBlockId: DbShema.ev.taskBlocks.taskBlockId }))`
         select
           task_block_id as "taskBlockId"

+ 4 - 4
src/modules/locations-management/locations-router.ts

@@ -4,7 +4,7 @@ const router = express.Router();
 export default router;
 
 // db
-import { db } from "#db";
+import { selPool, updPool } from "#db";
 import { DbShema } from "#db-shema";
 import { sql } from "slonik";
 
@@ -43,7 +43,7 @@ router.post("/location", async (req, res, next) => {
     const locationId = uuidv7();
 
     // location
-    await db.query(
+    await updPool.query(
       sql.unsafe`
          insert into ev.locations
            (location_id, name, event_id)
@@ -54,7 +54,7 @@ router.post("/location", async (req, res, next) => {
     // rooms
     for (const room of rooms) {
       const roomId = uuidv7();
-      await db.query(
+      await updPool.query(
         sql.unsafe`
           insert into ev.rooms
             (room_id, location_id, name, parent_id)
@@ -88,7 +88,7 @@ router.get("/event-locations/:eventId", async (req, res, next) => {
 
     await EventsService.checkEventAccess(userId, eventId);
 
-    const locations = await db.any(
+    const locations = await selPool.any(
       sql.type(
         z.object({
           locationId: DbShema.ev.locations.locationId,

+ 5 - 5
src/modules/tasks-management/task-blocks-router.ts

@@ -4,7 +4,7 @@ const router = express.Router();
 export default router;
 
 // db
-import { db } from "#db";
+import { selPool, updPool } from "#db";
 import { sql } from "slonik";
 
 // api
@@ -46,7 +46,7 @@ router.post("/task-block", async (req, res, next) => {
     const blockId = uuidv7();
 
     // create block
-    await db.query(
+    await updPool.query(
       sql.unsafe`
       insert into ev.task_blocks
         (task_block_id, name, event_id)
@@ -77,7 +77,7 @@ router.patch("/task-block", async (req, res, next) => {
 
     await EventsService.checkEventAccess(userId, eventId);
 
-    await db.query(
+    await updPool.query(
       sql.unsafe`
       update ev.task_blocks
       set
@@ -109,7 +109,7 @@ router.get("/task-block/:taskBlockId", async (req, res, next) => {
 
     await EventsService.checkEventAccess(userId, eventId);
 
-    const taskBlock = await db.maybeOne(
+    const taskBlock = await selPool.maybeOne(
       sql.type(
         z.object({
           taskBlockId: DbShema.ev.taskBlocks.taskBlockId,
@@ -129,7 +129,7 @@ router.get("/task-block/:taskBlockId", async (req, res, next) => {
     }
 
     const ZDbTasks = DbShema.ev.tasks;
-    const tasks = await db.any(
+    const tasks = await selPool.any(
       sql.type(
         z.object({
           taskId: ZDbTasks.taskId,

+ 6 - 6
src/modules/tasks-management/tasks-router.ts

@@ -4,7 +4,7 @@ const router = express.Router();
 export default router;
 
 // db
-import { db } from "#db";
+import { updPool } from "#db";
 import { sql } from "slonik";
 
 // api
@@ -53,7 +53,7 @@ router.post("/task", async (req, res, next) => {
     const taskId = uuidv7();
 
     // create task
-    await db.query(
+    await updPool.query(
       sql.unsafe`
       insert into ev.tasks
         (task_id, name, start_date, end_date, accountable_id, is_todo, task_block_id, program_point_id, room_id)
@@ -63,7 +63,7 @@ router.post("/task", async (req, res, next) => {
 
     // add executors
     for (const executorId of executors) {
-      await db.query(
+      await updPool.query(
         sql.unsafe`
         insert into ev.task_executors
           (task_id, role)
@@ -102,7 +102,7 @@ router.patch("/task", async (req, res, next) => {
     await EventsService.checkEventAccess(userId, eventId);
 
     // edit task
-    await db.query(
+    await updPool.query(
       sql.unsafe`
       UPDATE ev.tasks
       SET
@@ -138,7 +138,7 @@ router.patch("/task", async (req, res, next) => {
 
     if (executors && executors.length) {
       // del executors
-      await db.query(
+      await updPool.query(
         sql.unsafe`
       delete from ev.task_executors
       where
@@ -148,7 +148,7 @@ router.patch("/task", async (req, res, next) => {
       // add executors
       // TODO: вынести и слить с event-block
       for (const executorId of executors) {
-        await db.query(
+        await updPool.query(
           sql.unsafe`
         insert into ev.task_executors
           (task_id, role_id)

+ 5 - 5
src/modules/users-management/auth/routers/auth-router.ts

@@ -4,7 +4,7 @@ const router = express.Router();
 export default router;
 
 // db
-import { db } from "#db";
+import { selPool, updPool } from "#db";
 import { DbShema } from "#db-shema";
 import { sql } from "slonik";
 
@@ -38,7 +38,7 @@ router.post("/registration", async (req, res, next) => {
     const { email } = AuthApi.POST_Registration.req.parse(req.body);
 
     // проверка на существование пользователя
-    const isUserExist = await db.exists(
+    const isUserExist = await selPool.exists(
       sql.unsafe`select email from usr.users where email = ${email}`,
     );
 
@@ -131,7 +131,7 @@ router.post("/confirm-registration", async (req, res, next) => {
     // регистрация
     const hashPassword = await bcript.hash(password, 3);
     const userId = uuidv7();
-    await db.query(
+    await updPool.query(
       sql.unsafe`
       insert into usr.users 
         (user_id, email, name, password) 
@@ -176,7 +176,7 @@ router.post("/login", async (req, res, next) => {
     const { email, password } = AuthApi.POST_Login.req.parse(req.body);
 
     // поиск юзера
-    const user = await db.maybeOne(
+    const user = await selPool.maybeOne(
       sql.type(
         z.object({
           userId: DbShema.usr.users.userId,
@@ -320,7 +320,7 @@ router.get("/refresh", async (req, res, next) => {
     }
 
     // обновляем токены
-    const newUserData = await db.maybeOne(
+    const newUserData = await selPool.maybeOne(
       sql.type(
         z.object({
           email: DbShema.usr.users.email,

+ 6 - 6
src/modules/users-management/auth/services/token-service.ts

@@ -3,7 +3,7 @@ import { config } from "#config";
 import jwt from "jsonwebtoken";
 
 // база данных
-import { db } from "#db";
+import { selPool, updPool } from "#db";
 import { sql } from "slonik";
 
 // types
@@ -46,7 +46,7 @@ class TokenService {
    * @param refreshToken - токен, который будет вставлен
    */
   async insertRefreshToken(userId: string, refreshToken: string) {
-    await db.query(
+    await updPool.query(
       sql.unsafe`
       insert into usr.user_refresh_tokens
         (user_id, refresh_token)
@@ -67,7 +67,7 @@ class TokenService {
     oldRefreshToken: string,
     newRefreshToken: string,
   ) {
-    await db.query(
+    await updPool.query(
       sql.unsafe`
       update
         usr.user_refresh_tokens
@@ -86,7 +86,7 @@ class TokenService {
    * @param refreshToken - токен, который будет удален
    */
   async removeToken(userId: string, refreshToken: string) {
-    await db.query(sql.unsafe`
+    await updPool.query(sql.unsafe`
       delete from
         usr.user_refresh_tokens
       where
@@ -99,7 +99,7 @@ class TokenService {
    * @param userId - id пользователя
    */
   async removeAllUserTokens(userId: string) {
-    await db.query(sql.unsafe`
+    await updPool.query(sql.unsafe`
     delete from
       usr.user_refresh_tokens
     where
@@ -139,7 +139,7 @@ class TokenService {
     userId: string,
     refreshToken: string,
   ): Promise<boolean> {
-    const tokenIsExist = await db.exists(
+    const tokenIsExist = await selPool.exists(
       sql.unsafe`
       select 
         user_id 

+ 3 - 3
src/modules/users-management/auth/services/user-auth-service.ts

@@ -1,10 +1,10 @@
 // db
-import { db } from "#db/db.js";
+import { updPool } from "#db/db.js";
 import { sql } from "slonik";
 
 class userAuthService {
   async authTriesIncrement(userId: string) {
-    await db.any(
+    await updPool.query(
       sql.unsafe`
       update 
         usr.users 
@@ -16,7 +16,7 @@ class userAuthService {
   }
 
   async resetAuthTries(userId: string) {
-    await db.any(
+    await updPool.query(
       sql.unsafe`
       update 
         usr.users 

+ 5 - 5
src/modules/users-management/confirm-pins/confirm-pins-service.ts

@@ -1,6 +1,6 @@
 import { MailService } from "#services/mail-service.js";
 import { logger } from "#logger";
-import { db } from "#db";
+import { selPool, updPool } from "#db";
 import { sql } from "slonik";
 
 import { DbShema } from "#db-shema";
@@ -17,7 +17,7 @@ class confirmPinsService {
   }
 
   private async deleteConfirmPin(transactionId: string) {
-    await db.any(
+    await updPool.query(
       sql.unsafe`
       delete from 
         usr.confirm_pins 
@@ -27,7 +27,7 @@ class confirmPinsService {
   }
 
   private async pinTriesIncrement(transactionId: string) {
-    await db.any(
+    await updPool.query(
       sql.unsafe`
       update 
         usr.confirm_pins 
@@ -53,7 +53,7 @@ class confirmPinsService {
 `;
     await MailService.sendMail(email, "Ваш код для EVENT", mailBody);
     // бд
-    await db.any(
+    await updPool.query(
       sql.unsafe`
       insert into usr.confirm_pins (
         transaction_id,
@@ -84,7 +84,7 @@ class confirmPinsService {
         triesRemained: number;
       }
   > {
-    const pinInfo = await db.maybeOne(
+    const pinInfo = await selPool.maybeOne(
       sql.type(
         z.object({
           confirmPin: DbShema.usr.confirmPins.confirmPin,

+ 12 - 6
src/plugins/logger.ts

@@ -1,6 +1,5 @@
 import { createLogger, format, transports } from "winston";
 import path from "path";
-import { config } from "#config";
 
 const __dirname = path.resolve();
 
@@ -24,7 +23,7 @@ const customFormat = format.combine(
     // Приведение stack к строке или undefined
     const stackString = typeof stack === "string" ? stack : undefined;
 
-    // Форматирование вложенных объектов
+    //  Форматирование вложенных объектов
     const additionalData = Object.keys(rest).length
       ? `\nAdditional Info:\n${formatNestedObjects(rest)}`
       : "";
@@ -36,9 +35,10 @@ const customFormat = format.combine(
   }),
 );
 
+const LOGS_LEVEL = process.env.LOGS_LEVEL || "info";
+
 // Логгер Winston
 export const logger = createLogger({
-  level: config.LOGS_LEVEL, // Уровень логирования
   format: customFormat, // Формат логов
   transports: [
     new transports.Console({
@@ -47,11 +47,17 @@ export const logger = createLogger({
         format.colorize({ all: true }), // Цветные логи для консоли
         customFormat,
       ),
+      level: LOGS_LEVEL,
+    }),
+    new transports.File({
+      // Логирование в файл ошибок
+      filename: path.join(__dirname, "logs", "all.log"),
+      level: LOGS_LEVEL,
     }),
     new transports.File({
-      // Логирование в файл
-      filename: path.join(__dirname, "logs", "app.log"), // Путь к файлу логов
-      level: "error", // Логировать только ошибки
+      // Логирование в файл ошибок
+      filename: path.join(__dirname, "logs", "panic.log"),
+      level: "error",
     }),
   ],
 });