This commit is contained in:
David Arranz 2025-02-03 14:12:36 +01:00
parent 350b8a8422
commit 7d8ca53495
48 changed files with 2145 additions and 382 deletions

48
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,48 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch firefox localhost",
"type": "firefox",
"request": "launch",
"reAttach": true,
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}/client"
},
{
"name": "Launch Chrome localhost",
"type": "chrome",
"request": "launch",
"reAttach": true,
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}/client"
},
{
"type": "msedge",
"request": "launch",
"name": "CLIENT: Launch Edge against localhost",
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}/client"
},
{
"type": "node",
"request": "attach",
"name": "SERVER: Attach to dev:debug",
"port": 4321,
"restart": true,
"cwd": "${workspaceRoot}"
},
{
"name": "Launch via YARN",
"request": "launch",
"runtimeArgs": ["run", "server"],
"runtimeExecutable": "yarn",
"skipFiles": ["<node_internals>/**", "client/**", "dist/**", "doc/**"],
"type": "node"
}
]
}

37
.vscode/settings.json vendored
View File

@ -1,20 +1,19 @@
{
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.fixAll.eslint": "explicit"
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.formatOnPaste": false,
"prettier.useEditorConfig": false,
"prettier.useTabs": false,
"prettier.configPath": ".prettierrc",
"asciidoc.antora.enableAntoraSupport": true,
// other vscode settings
"tailwindCSS.rootFontSize": 16,
"[handlebars]": {
"editor.defaultFormatter": "vscode.html-language-features"
} // <- your root font size here
}
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.fixAll.eslint": "explicit"
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.formatOnPaste": false,
"prettier.useEditorConfig": false,
"prettier.useTabs": false,
"prettier.configPath": ".prettierrc",
"asciidoc.antora.enableAntoraSupport": true,
// other vscode settings
"tailwindCSS.rootFontSize": 16,
"[handlebars]": {
"editor.defaultFormatter": "vscode.html-language-features"
} // <- your root font size here
}

View File

@ -0,0 +1,15 @@
{
"keep": {
"days": true,
"amount": 1
},
"auditLog": ".571b27c4f3dcc376d1f0ca8880ce87cfefd2f30d-audit.json",
"files": [
{
"date": 1738578708264,
"name": "debug-2025-02-03.log",
"hash": "48ca17f819e391cb5ae1909a6ee0fa4d9c8cdb6667ef893547acb004f4a79737"
}
],
"hashType": "sha256"
}

View File

@ -0,0 +1,15 @@
{
"keep": {
"days": true,
"amount": 1
},
"auditLog": ".e6616b1c93d5e50d48b909cd34375b545b447bc6-audit.json",
"files": [
{
"date": 1738578708262,
"name": "error-2025-02-03.log",
"hash": "a21f154f5c386a75eee98a35c2b100da7df1b8002cf99851b90bd12810f1fe8a"
}
],
"hashType": "sha256"
}

View File

@ -6,4 +6,7 @@ DB_DIALECT=mariadb
DB_PORT=3306
PORT=3002
JWT_SECRET=clave_secreta_para_tokens
JWT_SECRET=supersecretkey
JWT_ACCESS_EXPIRATION=1h
JWT_REFRESH_EXPIRATION=7d

View File

@ -0,0 +1,503 @@
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:31 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:31:48.326Z"}
{"label":"index.ts","level":"info","message":"Launched in: 58 ms","metadata":{},"timestamp":"2025-02-03T10:31:48.330Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:31:48.331Z"}
{"label":"index.ts","level":"info","message":"Process PID: 27291","metadata":{},"timestamp":"2025-02-03T10:31:48.331Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:31:48.332Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:31:48.332Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:31:54.022Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:31 CET","metadata":{},"timestamp":"2025-02-03T10:31:54.025Z"}
{"label":"index.ts","level":"info","message":"Closed out remaining connections.","metadata":{},"timestamp":"2025-02-03T10:31:54.026Z"}
{"label":"index.ts","level":"info","message":"Bye!","metadata":{},"timestamp":"2025-02-03T10:31:54.027Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:31:54.029Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:31 CET","metadata":{},"timestamp":"2025-02-03T10:31:54.030Z"}
{"label":"index.ts","level":"error","message":"Mon, 03 Feb 2025 10:31:54 GMT uncaughtException:","metadata":{"0":"S","1":"e","10":"n","11":"o","12":"t","13":" ","14":"r","15":"u","16":"n","17":"n","18":"i","19":"n","2":"r","20":"g","21":".","3":"v","4":"e","5":"r","6":" ","7":"i","8":"s","9":" "},"timestamp":"2025-02-03T10:31:54.031Z"}
{"label":"index.ts","level":"error","message":"Error [ERR_SERVER_NOT_RUNNING]: Server is not running.\n at Server.close (node:net:2356:12)\n at Object.onceWrapper (node:events:638:28)\n at Server.emit (node:events:536:35)\n at emitCloseNT (node:net:2416:8)\n at process.processTicksAndRejections (node:internal/process/task_queues:89:21)","metadata":{},"timestamp":"2025-02-03T10:31:54.034Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:33 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:33:04.048Z"}
{"label":"index.ts","level":"info","message":"Launched in: 72 ms","metadata":{},"timestamp":"2025-02-03T10:33:04.052Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:33:04.053Z"}
{"label":"index.ts","level":"info","message":"Process PID: 27486","metadata":{},"timestamp":"2025-02-03T10:33:04.053Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:33:04.054Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:33:04.054Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:33:04.888Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:33 CET","metadata":{},"timestamp":"2025-02-03T10:33:04.890Z"}
{"label":"index.ts","level":"info","message":"Closed out remaining connections.","metadata":{},"timestamp":"2025-02-03T10:33:04.891Z"}
{"label":"index.ts","level":"info","message":"Bye!","metadata":{},"timestamp":"2025-02-03T10:33:04.891Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:33:04.892Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:33 CET","metadata":{},"timestamp":"2025-02-03T10:33:04.893Z"}
{"label":"index.ts","level":"error","message":"Mon, 03 Feb 2025 10:33:04 GMT uncaughtException:","metadata":{"0":"S","1":"e","10":"n","11":"o","12":"t","13":" ","14":"r","15":"u","16":"n","17":"n","18":"i","19":"n","2":"r","20":"g","21":".","3":"v","4":"e","5":"r","6":" ","7":"i","8":"s","9":" "},"timestamp":"2025-02-03T10:33:04.894Z"}
{"label":"index.ts","level":"error","message":"Error [ERR_SERVER_NOT_RUNNING]: Server is not running.\n at Server.close (node:net:2356:12)\n at Object.onceWrapper (node:events:638:28)\n at Server.emit (node:events:536:35)\n at emitCloseNT (node:net:2416:8)\n at process.processTicksAndRejections (node:internal/process/task_queues:89:21)","metadata":{},"timestamp":"2025-02-03T10:33:04.896Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:33 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:33:46.916Z"}
{"label":"index.ts","level":"info","message":"Launched in: 57 ms","metadata":{},"timestamp":"2025-02-03T10:33:46.920Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:33:46.921Z"}
{"label":"index.ts","level":"info","message":"Process PID: 27632","metadata":{},"timestamp":"2025-02-03T10:33:46.922Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:33:46.922Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:33:46.922Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:33:49.225Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:33 CET","metadata":{},"timestamp":"2025-02-03T10:33:49.228Z"}
{"label":"index.ts","level":"info","message":"Closed out remaining connections.","metadata":{},"timestamp":"2025-02-03T10:33:49.228Z"}
{"label":"index.ts","level":"info","message":"Bye!","metadata":{},"timestamp":"2025-02-03T10:33:49.229Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:33:49.230Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:33 CET","metadata":{},"timestamp":"2025-02-03T10:33:49.231Z"}
{"label":"index.ts","level":"error","message":"Mon, 03 Feb 2025 10:33:49 GMT uncaughtException:","metadata":{"0":"S","1":"e","10":"n","11":"o","12":"t","13":" ","14":"r","15":"u","16":"n","17":"n","18":"i","19":"n","2":"r","20":"g","21":".","3":"v","4":"e","5":"r","6":" ","7":"i","8":"s","9":" "},"timestamp":"2025-02-03T10:33:49.232Z"}
{"label":"index.ts","level":"error","message":"Error [ERR_SERVER_NOT_RUNNING]: Server is not running.\n at Server.close (node:net:2356:12)\n at Object.onceWrapper (node:events:638:28)\n at Server.emit (node:events:536:35)\n at emitCloseNT (node:net:2416:8)\n at process.processTicksAndRejections (node:internal/process/task_queues:89:21)","metadata":{},"timestamp":"2025-02-03T10:33:49.233Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:35 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:35:48.079Z"}
{"label":"index.ts","level":"info","message":"Launched in: 59 ms","metadata":{},"timestamp":"2025-02-03T10:35:48.083Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:35:48.083Z"}
{"label":"index.ts","level":"info","message":"Process PID: 27747","metadata":{},"timestamp":"2025-02-03T10:35:48.084Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:35:48.084Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:35:48.084Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:37 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:37:13.858Z"}
{"label":"index.ts","level":"info","message":"Launched in: 79 ms","metadata":{},"timestamp":"2025-02-03T10:37:13.862Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:37:13.863Z"}
{"label":"index.ts","level":"info","message":"Process PID: 27943","metadata":{},"timestamp":"2025-02-03T10:37:13.863Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:37:13.864Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:37:13.864Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:37:14.746Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:37 CET","metadata":{},"timestamp":"2025-02-03T10:37:14.750Z"}
{"label":"index.ts","level":"info","message":"Closed out remaining connections.","metadata":{},"timestamp":"2025-02-03T10:37:14.751Z"}
{"label":"index.ts","level":"info","message":"Bye!","metadata":{},"timestamp":"2025-02-03T10:37:14.752Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:37:14.753Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:37 CET","metadata":{},"timestamp":"2025-02-03T10:37:14.754Z"}
{"label":"index.ts","level":"error","message":"Mon, 03 Feb 2025 10:37:14 GMT uncaughtException:","metadata":{"0":"S","1":"e","10":"n","11":"o","12":"t","13":" ","14":"r","15":"u","16":"n","17":"n","18":"i","19":"n","2":"r","20":"g","21":".","3":"v","4":"e","5":"r","6":" ","7":"i","8":"s","9":" "},"timestamp":"2025-02-03T10:37:14.756Z"}
{"label":"index.ts","level":"error","message":"Error [ERR_SERVER_NOT_RUNNING]: Server is not running.\n at Server.close (node:net:2356:12)\n at Object.onceWrapper (node:events:638:28)\n at Server.emit (node:events:536:35)\n at emitCloseNT (node:net:2416:8)\n at process.processTicksAndRejections (node:internal/process/task_queues:89:21)","metadata":{},"timestamp":"2025-02-03T10:37:14.758Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:47 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:47:16.343Z"}
{"label":"index.ts","level":"info","message":"Launched in: 63 ms","metadata":{},"timestamp":"2025-02-03T10:47:16.347Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:47:16.347Z"}
{"label":"index.ts","level":"info","message":"Process PID: 28264","metadata":{},"timestamp":"2025-02-03T10:47:16.348Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:47:16.348Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:47:16.349Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:47 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:47:24.661Z"}
{"label":"index.ts","level":"info","message":"Launched in: 60 ms","metadata":{},"timestamp":"2025-02-03T10:47:24.665Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:47:24.666Z"}
{"label":"index.ts","level":"info","message":"Process PID: 28355","metadata":{},"timestamp":"2025-02-03T10:47:24.667Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:47:24.667Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:47:24.667Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:47:26.385Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:47 CET","metadata":{},"timestamp":"2025-02-03T10:47:26.388Z"}
{"label":"index.ts","level":"info","message":"Closed out remaining connections.","metadata":{},"timestamp":"2025-02-03T10:47:26.389Z"}
{"label":"index.ts","level":"info","message":"Bye!","metadata":{},"timestamp":"2025-02-03T10:47:26.390Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:47:26.391Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:47 CET","metadata":{},"timestamp":"2025-02-03T10:47:26.392Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","code":"ERR_SERVER_NOT_RUNNING"},"timestamp":"2025-02-03T10:47:26.394Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:47 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:47:35.396Z"}
{"label":"index.ts","level":"info","message":"Launched in: 58 ms","metadata":{},"timestamp":"2025-02-03T10:47:35.400Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:47:35.400Z"}
{"label":"index.ts","level":"info","message":"Process PID: 28502","metadata":{},"timestamp":"2025-02-03T10:47:35.401Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:47:35.401Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:47:35.401Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:47:46.762Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:47 CET","metadata":{},"timestamp":"2025-02-03T10:47:46.765Z"}
{"label":"index.ts","level":"info","message":"Closed out remaining connections.","metadata":{},"timestamp":"2025-02-03T10:47:46.766Z"}
{"label":"index.ts","level":"info","message":"Bye!","metadata":{},"timestamp":"2025-02-03T10:47:46.767Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:47:46.767Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:47 CET","metadata":{},"timestamp":"2025-02-03T10:47:46.768Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","code":"ERR_SERVER_NOT_RUNNING"},"timestamp":"2025-02-03T10:47:46.769Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:51 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:51:55.876Z"}
{"label":"index.ts","level":"info","message":"Launched in: 57 ms","metadata":{},"timestamp":"2025-02-03T10:51:55.880Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:51:55.881Z"}
{"label":"index.ts","level":"info","message":"Process PID: 28711","metadata":{},"timestamp":"2025-02-03T10:51:55.881Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:51:55.882Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:51:55.882Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:53 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:53:58.189Z"}
{"label":"index.ts","level":"info","message":"Launched in: 62 ms","metadata":{},"timestamp":"2025-02-03T10:53:58.193Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:53:58.193Z"}
{"label":"index.ts","level":"info","message":"Process PID: 28911","metadata":{},"timestamp":"2025-02-03T10:53:58.194Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:53:58.194Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:53:58.195Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:54 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:54:05.950Z"}
{"label":"index.ts","level":"info","message":"Launched in: 71 ms","metadata":{},"timestamp":"2025-02-03T10:54:05.954Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:54:05.955Z"}
{"label":"index.ts","level":"info","message":"Process PID: 28989","metadata":{},"timestamp":"2025-02-03T10:54:05.955Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:54:05.956Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:54:05.957Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:55 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:55:06.572Z"}
{"label":"index.ts","level":"info","message":"Launched in: 62 ms","metadata":{},"timestamp":"2025-02-03T10:55:06.577Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:55:06.577Z"}
{"label":"index.ts","level":"info","message":"Process PID: 29110","metadata":{},"timestamp":"2025-02-03T10:55:06.577Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:55:06.578Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:55:06.578Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:55 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:55:12.694Z"}
{"label":"index.ts","level":"info","message":"Launched in: 71 ms","metadata":{},"timestamp":"2025-02-03T10:55:12.699Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:55:12.700Z"}
{"label":"index.ts","level":"info","message":"Process PID: 29161","metadata":{},"timestamp":"2025-02-03T10:55:12.700Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:55:12.701Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:55:12.702Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T10:55:17.083Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T10:55:28.369Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:56:00.604Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:56 CET","metadata":{},"timestamp":"2025-02-03T10:56:00.607Z"}
{"label":"index.ts","level":"info","message":"Closed out remaining connections.","metadata":{},"timestamp":"2025-02-03T10:56:00.608Z"}
{"label":"index.ts","level":"info","message":"Bye!","metadata":{},"timestamp":"2025-02-03T10:56:00.609Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T10:56:00.610Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 11:56 CET","metadata":{},"timestamp":"2025-02-03T10:56:00.611Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","code":"ERR_SERVER_NOT_RUNNING"},"timestamp":"2025-02-03T10:56:00.612Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:56 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:56:05.436Z"}
{"label":"index.ts","level":"info","message":"Launched in: 60 ms","metadata":{},"timestamp":"2025-02-03T10:56:05.440Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:56:05.440Z"}
{"label":"index.ts","level":"info","message":"Process PID: 29346","metadata":{},"timestamp":"2025-02-03T10:56:05.441Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:56:05.441Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:56:05.442Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T10:56:54.617Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:57 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:57:08.751Z"}
{"label":"index.ts","level":"info","message":"Launched in: 69 ms","metadata":{},"timestamp":"2025-02-03T10:57:08.756Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:57:08.756Z"}
{"label":"index.ts","level":"info","message":"Process PID: 29445","metadata":{},"timestamp":"2025-02-03T10:57:08.757Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:57:08.757Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:57:08.758Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:57 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:57:26.753Z"}
{"label":"index.ts","level":"info","message":"Launched in: 80 ms","metadata":{},"timestamp":"2025-02-03T10:57:26.758Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:57:26.758Z"}
{"label":"index.ts","level":"info","message":"Process PID: 29570","metadata":{},"timestamp":"2025-02-03T10:57:26.759Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:57:26.759Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:57:26.760Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T10:57:29.177Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:58 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:58:08.314Z"}
{"label":"index.ts","level":"info","message":"Launched in: 58 ms","metadata":{},"timestamp":"2025-02-03T10:58:08.318Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:58:08.318Z"}
{"label":"index.ts","level":"info","message":"Process PID: 29658","metadata":{},"timestamp":"2025-02-03T10:58:08.319Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:58:08.319Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:58:08.320Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 11:58 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T10:58:27.678Z"}
{"label":"index.ts","level":"info","message":"Launched in: 62 ms","metadata":{},"timestamp":"2025-02-03T10:58:27.682Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T10:58:27.682Z"}
{"label":"index.ts","level":"info","message":"Process PID: 29728","metadata":{},"timestamp":"2025-02-03T10:58:27.683Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T10:58:27.683Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T10:58:27.684Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:07 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:07:32.542Z"}
{"label":"index.ts","level":"info","message":"Launched in: 70 ms","metadata":{},"timestamp":"2025-02-03T11:07:32.546Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:07:32.547Z"}
{"label":"index.ts","level":"info","message":"Process PID: 30300","metadata":{},"timestamp":"2025-02-03T11:07:32.547Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:07:32.548Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:07:32.548Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:07 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:07:55.056Z"}
{"label":"index.ts","level":"info","message":"Launched in: 72 ms","metadata":{},"timestamp":"2025-02-03T11:07:55.060Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:07:55.061Z"}
{"label":"index.ts","level":"info","message":"Process PID: 30384","metadata":{},"timestamp":"2025-02-03T11:07:55.062Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:07:55.062Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:07:55.063Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:08:06.420Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:08:06.568Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:08:30.465Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:08:30.574Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T11:08:49.579Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T11:08:49.582Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:08 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:08:54.964Z"}
{"label":"index.ts","level":"info","message":"Launched in: 62 ms","metadata":{},"timestamp":"2025-02-03T11:08:54.968Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:08:54.968Z"}
{"label":"index.ts","level":"info","message":"Process PID: 30628","metadata":{},"timestamp":"2025-02-03T11:08:54.969Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:08:54.969Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:08:54.970Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T11:09:05.303Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 12:09 CET","metadata":{},"timestamp":"2025-02-03T11:09:05.306Z"}
{"label":"index.ts","level":"info","message":"Closed out remaining connections.","metadata":{},"timestamp":"2025-02-03T11:09:05.307Z"}
{"label":"index.ts","level":"info","message":"Bye!","metadata":{},"timestamp":"2025-02-03T11:09:05.308Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T11:09:05.309Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 12:09 CET","metadata":{},"timestamp":"2025-02-03T11:09:05.309Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","code":"ERR_SERVER_NOT_RUNNING"},"timestamp":"2025-02-03T11:09:05.310Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:13 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:13:50.071Z"}
{"label":"index.ts","level":"info","message":"Launched in: 63 ms","metadata":{},"timestamp":"2025-02-03T11:13:50.075Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:13:50.076Z"}
{"label":"index.ts","level":"info","message":"Process PID: 31564","metadata":{},"timestamp":"2025-02-03T11:13:50.077Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:13:50.077Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:13:50.078Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:14:03.058Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:14:03.193Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T11:14:19.007Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T11:14:19.010Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T11:14:19.132Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:20 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:20:36.249Z"}
{"label":"index.ts","level":"info","message":"Launched in: 64 ms","metadata":{},"timestamp":"2025-02-03T11:20:36.253Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:20:36.253Z"}
{"label":"index.ts","level":"info","message":"Process PID: 33993","metadata":{},"timestamp":"2025-02-03T11:20:36.254Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:20:36.254Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:20:36.255Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T11:20:39.531Z"}
{"label":"index.ts","level":"info","message":"Shut down at: 3 de febrero de 2025, 12:20 CET","metadata":{},"timestamp":"2025-02-03T11:20:39.534Z"}
{"label":"index.ts","level":"info","message":"Closed out remaining connections.","metadata":{},"timestamp":"2025-02-03T11:20:39.534Z"}
{"label":"index.ts","level":"info","message":"Bye!","metadata":{},"timestamp":"2025-02-03T11:20:39.536Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:20 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:20:43.979Z"}
{"label":"index.ts","level":"info","message":"Launched in: 61 ms","metadata":{},"timestamp":"2025-02-03T11:20:43.984Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:20:43.984Z"}
{"label":"index.ts","level":"info","message":"Process PID: 34099","metadata":{},"timestamp":"2025-02-03T11:20:43.985Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:20:43.985Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:20:43.986Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:20:46.872Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:20:47.049Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T11:20:50.520Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:20 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:20:53.818Z"}
{"label":"index.ts","level":"info","message":"Launched in: 60 ms","metadata":{},"timestamp":"2025-02-03T11:20:53.823Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:20:53.823Z"}
{"label":"index.ts","level":"info","message":"Process PID: 34196","metadata":{},"timestamp":"2025-02-03T11:20:53.824Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:20:53.824Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:20:53.825Z"}
{"label":"index.ts","level":"error","message":"Could not close connections in time, forcefully shutting down","metadata":{},"timestamp":"2025-02-03T11:21:20.528Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:21:42.752Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:22:22.098Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:22 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:22:42.651Z"}
{"label":"index.ts","level":"info","message":"Launched in: 63 ms","metadata":{},"timestamp":"2025-02-03T11:22:42.656Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:22:42.656Z"}
{"label":"index.ts","level":"info","message":"Process PID: 34476","metadata":{},"timestamp":"2025-02-03T11:22:42.657Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:22:42.657Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:22:42.658Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:22 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:22:48.049Z"}
{"label":"index.ts","level":"info","message":"Launched in: 62 ms","metadata":{},"timestamp":"2025-02-03T11:22:48.053Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:22:48.054Z"}
{"label":"index.ts","level":"info","message":"Process PID: 34516","metadata":{},"timestamp":"2025-02-03T11:22:48.054Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:22:48.055Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:22:48.055Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:22:51.754Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:24 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:24:57.165Z"}
{"label":"index.ts","level":"info","message":"Launched in: 69 ms","metadata":{},"timestamp":"2025-02-03T11:24:57.170Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:24:57.171Z"}
{"label":"index.ts","level":"info","message":"Process PID: 34710","metadata":{},"timestamp":"2025-02-03T11:24:57.171Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:24:57.172Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:24:57.172Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:25:01.961Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:28 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:28:08.745Z"}
{"label":"index.ts","level":"info","message":"Launched in: 61 ms","metadata":{},"timestamp":"2025-02-03T11:28:08.749Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:28:08.750Z"}
{"label":"index.ts","level":"info","message":"Process PID: 34895","metadata":{},"timestamp":"2025-02-03T11:28:08.750Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:28:08.751Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:28:08.752Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:28:15.111Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:28 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:28:33.351Z"}
{"label":"index.ts","level":"info","message":"Launched in: 61 ms","metadata":{},"timestamp":"2025-02-03T11:28:33.355Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:28:33.356Z"}
{"label":"index.ts","level":"info","message":"Process PID: 35002","metadata":{},"timestamp":"2025-02-03T11:28:33.356Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:28:33.357Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:28:33.357Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:28:39.509Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T11:28:52.885Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:28 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:28:56.892Z"}
{"label":"index.ts","level":"info","message":"Launched in: 63 ms","metadata":{},"timestamp":"2025-02-03T11:28:56.896Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:28:56.896Z"}
{"label":"index.ts","level":"info","message":"Process PID: 35142","metadata":{},"timestamp":"2025-02-03T11:28:56.897Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:28:56.897Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:28:56.898Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:29:12.361Z"}
{"label":"index.ts","level":"error","message":"Could not close connections in time, forcefully shutting down","metadata":{},"timestamp":"2025-02-03T11:29:22.891Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:29:34.887Z"}
{"label":"index.ts","level":"warn","message":"⚡️ Shutting down server","metadata":{},"timestamp":"2025-02-03T11:29:44.966Z"}
{"label":"index.ts","level":"error","message":"Could not close connections in time, forcefully shutting down","metadata":{},"timestamp":"2025-02-03T11:30:14.987Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:30 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:30:43.689Z"}
{"label":"index.ts","level":"info","message":"Launched in: 66 ms","metadata":{},"timestamp":"2025-02-03T11:30:43.693Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:30:43.694Z"}
{"label":"index.ts","level":"info","message":"Process PID: 35655","metadata":{},"timestamp":"2025-02-03T11:30:43.694Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:30:43.695Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:30:43.696Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:30:46.889Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:31:08.346Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:32 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:32:05.660Z"}
{"label":"index.ts","level":"info","message":"Launched in: 61 ms","metadata":{},"timestamp":"2025-02-03T11:32:05.664Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:32:05.665Z"}
{"label":"index.ts","level":"info","message":"Process PID: 35906","metadata":{},"timestamp":"2025-02-03T11:32:05.665Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:32:05.666Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:32:05.667Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:32:19.844Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:32 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:32:59.925Z"}
{"label":"index.ts","level":"info","message":"Launched in: 60 ms","metadata":{},"timestamp":"2025-02-03T11:32:59.929Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:32:59.930Z"}
{"label":"index.ts","level":"info","message":"Process PID: 36039","metadata":{},"timestamp":"2025-02-03T11:32:59.931Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:32:59.931Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:32:59.932Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:33:08.197Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:39:04.414Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 12:39 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T11:39:05.433Z"}
{"label":"index.ts","level":"info","message":"Launched in: 79 ms","metadata":{},"timestamp":"2025-02-03T11:39:05.437Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T11:39:05.438Z"}
{"label":"index.ts","level":"info","message":"Process PID: 36303","metadata":{},"timestamp":"2025-02-03T11:39:05.438Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T11:39:05.439Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T11:39:05.439Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T11:42:04.893Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:09 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:09:10.945Z"}
{"label":"index.ts","level":"info","message":"Launched in: 75 ms","metadata":{},"timestamp":"2025-02-03T12:09:10.950Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:09:10.950Z"}
{"label":"index.ts","level":"info","message":"Process PID: 36704","metadata":{},"timestamp":"2025-02-03T12:09:10.951Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:09:10.951Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:09:10.952Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:09 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:09:48.476Z"}
{"label":"index.ts","level":"info","message":"Launched in: 60 ms","metadata":{},"timestamp":"2025-02-03T12:09:48.480Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:09:48.480Z"}
{"label":"index.ts","level":"info","message":"Process PID: 36772","metadata":{},"timestamp":"2025-02-03T12:09:48.481Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:09:48.481Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:09:48.482Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:38 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:38:49.952Z"}
{"label":"index.ts","level":"info","message":"Launched in: 65 ms","metadata":{},"timestamp":"2025-02-03T12:38:49.956Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:38:49.957Z"}
{"label":"index.ts","level":"info","message":"Process PID: 36990","metadata":{},"timestamp":"2025-02-03T12:38:49.957Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:38:49.958Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:38:49.958Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:39 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:39:00.284Z"}
{"label":"index.ts","level":"info","message":"Launched in: 63 ms","metadata":{},"timestamp":"2025-02-03T12:39:00.288Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:39:00.288Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37060","metadata":{},"timestamp":"2025-02-03T12:39:00.289Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:39:00.289Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:39:00.290Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:39 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:39:19.498Z"}
{"label":"index.ts","level":"info","message":"Launched in: 62 ms","metadata":{},"timestamp":"2025-02-03T12:39:19.502Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:39:19.502Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37125","metadata":{},"timestamp":"2025-02-03T12:39:19.503Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:39:19.504Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:39:19.504Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:42 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:42:15.390Z"}
{"label":"index.ts","level":"info","message":"Launched in: 70 ms","metadata":{},"timestamp":"2025-02-03T12:42:15.395Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:42:15.395Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37257","metadata":{},"timestamp":"2025-02-03T12:42:15.396Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:42:15.397Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:42:15.397Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:43 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:43:12.245Z"}
{"label":"index.ts","level":"info","message":"Launched in: 74 ms","metadata":{},"timestamp":"2025-02-03T12:43:12.250Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:43:12.251Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37338","metadata":{},"timestamp":"2025-02-03T12:43:12.251Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:43:12.252Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:43:12.253Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:46 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:46:31.979Z"}
{"label":"index.ts","level":"info","message":"Launched in: 74 ms","metadata":{},"timestamp":"2025-02-03T12:46:31.984Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:46:31.985Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37459","metadata":{},"timestamp":"2025-02-03T12:46:31.985Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:46:31.986Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:46:31.986Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:46 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:46:40.345Z"}
{"label":"index.ts","level":"info","message":"Launched in: 63 ms","metadata":{},"timestamp":"2025-02-03T12:46:40.349Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:46:40.349Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37524","metadata":{},"timestamp":"2025-02-03T12:46:40.350Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:46:40.350Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:46:40.351Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:47 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:47:37.569Z"}
{"label":"index.ts","level":"info","message":"Launched in: 64 ms","metadata":{},"timestamp":"2025-02-03T12:47:37.574Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:47:37.574Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37567","metadata":{},"timestamp":"2025-02-03T12:47:37.574Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:47:37.575Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:47:37.576Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:48 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:48:43.576Z"}
{"label":"index.ts","level":"info","message":"Launched in: 73 ms","metadata":{},"timestamp":"2025-02-03T12:48:43.581Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:48:43.581Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37638","metadata":{},"timestamp":"2025-02-03T12:48:43.582Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:48:43.582Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:48:43.583Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:48 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:48:58.255Z"}
{"label":"index.ts","level":"info","message":"Launched in: 63 ms","metadata":{},"timestamp":"2025-02-03T12:48:58.259Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:48:58.260Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37703","metadata":{},"timestamp":"2025-02-03T12:48:58.260Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:48:58.261Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:48:58.262Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:49 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:49:54.186Z"}
{"label":"index.ts","level":"info","message":"Launched in: 64 ms","metadata":{},"timestamp":"2025-02-03T12:49:54.191Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:49:54.191Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37785","metadata":{},"timestamp":"2025-02-03T12:49:54.192Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:49:54.192Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:49:54.193Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:50 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:50:00.507Z"}
{"label":"index.ts","level":"info","message":"Launched in: 66 ms","metadata":{},"timestamp":"2025-02-03T12:50:00.512Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:50:00.512Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37839","metadata":{},"timestamp":"2025-02-03T12:50:00.513Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:50:00.513Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:50:00.514Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:50 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:50:13.018Z"}
{"label":"index.ts","level":"info","message":"Launched in: 67 ms","metadata":{},"timestamp":"2025-02-03T12:50:13.023Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:50:13.023Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37896","metadata":{},"timestamp":"2025-02-03T12:50:13.024Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:50:13.024Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:50:13.025Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:50 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:50:24.758Z"}
{"label":"index.ts","level":"info","message":"Launched in: 63 ms","metadata":{},"timestamp":"2025-02-03T12:50:24.762Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:50:24.762Z"}
{"label":"index.ts","level":"info","message":"Process PID: 37960","metadata":{},"timestamp":"2025-02-03T12:50:24.763Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:50:24.763Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:50:24.764Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T12:50:32.682Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T12:50:51.584Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:52 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:52:06.054Z"}
{"label":"index.ts","level":"info","message":"Launched in: 65 ms","metadata":{},"timestamp":"2025-02-03T12:52:06.059Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:52:06.059Z"}
{"label":"index.ts","level":"info","message":"Process PID: 38086","metadata":{},"timestamp":"2025-02-03T12:52:06.060Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:52:06.060Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:52:06.061Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:52 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:52:19.286Z"}
{"label":"index.ts","level":"info","message":"Launched in: 62 ms","metadata":{},"timestamp":"2025-02-03T12:52:19.290Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:52:19.290Z"}
{"label":"index.ts","level":"info","message":"Process PID: 38151","metadata":{},"timestamp":"2025-02-03T12:52:19.291Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:52:19.291Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:52:19.292Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 13:52 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T12:52:35.505Z"}
{"label":"index.ts","level":"info","message":"Launched in: 75 ms","metadata":{},"timestamp":"2025-02-03T12:52:35.510Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T12:52:35.511Z"}
{"label":"index.ts","level":"info","message":"Process PID: 38232","metadata":{},"timestamp":"2025-02-03T12:52:35.511Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T12:52:35.512Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T12:52:35.513Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T12:52:37.674Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T12:53:01.900Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T12:53:36.527Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 14:04 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T13:04:06.250Z"}
{"label":"index.ts","level":"info","message":"Launched in: 68 ms","metadata":{},"timestamp":"2025-02-03T13:04:06.255Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T13:04:06.255Z"}
{"label":"index.ts","level":"info","message":"Process PID: 38689","metadata":{},"timestamp":"2025-02-03T13:04:06.256Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T13:04:06.256Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T13:04:06.257Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T13:04:08.938Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T13:04:27.021Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T13:04:32.711Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T13:04:59.520Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 14:05 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T13:05:24.056Z"}
{"label":"index.ts","level":"info","message":"Launched in: 63 ms","metadata":{},"timestamp":"2025-02-03T13:05:24.060Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T13:05:24.060Z"}
{"label":"index.ts","level":"info","message":"Process PID: 38914","metadata":{},"timestamp":"2025-02-03T13:05:24.061Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T13:05:24.061Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T13:05:24.062Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T13:05:27.776Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":"},"timestamp":"2025-02-03T13:05:42.332Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 14:05 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T13:05:49.085Z"}
{"label":"index.ts","level":"info","message":"Launched in: 64 ms","metadata":{},"timestamp":"2025-02-03T13:05:49.089Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T13:05:49.090Z"}
{"label":"index.ts","level":"info","message":"Process PID: 39028","metadata":{},"timestamp":"2025-02-03T13:05:49.090Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T13:05:49.091Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T13:05:49.091Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 14:07 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T13:07:23.173Z"}
{"label":"index.ts","level":"info","message":"Launched in: 76 ms","metadata":{},"timestamp":"2025-02-03T13:07:23.178Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T13:07:23.178Z"}
{"label":"index.ts","level":"info","message":"Process PID: 39177","metadata":{},"timestamp":"2025-02-03T13:07:23.179Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T13:07:23.179Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T13:07:23.180Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 14:07 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T13:07:30.372Z"}
{"label":"index.ts","level":"info","message":"Launched in: 60 ms","metadata":{},"timestamp":"2025-02-03T13:07:30.377Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T13:07:30.377Z"}
{"label":"index.ts","level":"info","message":"Process PID: 39263","metadata":{},"timestamp":"2025-02-03T13:07:30.378Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T13:07:30.378Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T13:07:30.379Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 14:08 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T13:08:09.521Z"}
{"label":"index.ts","level":"info","message":"Launched in: 64 ms","metadata":{},"timestamp":"2025-02-03T13:08:09.525Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T13:08:09.526Z"}
{"label":"index.ts","level":"info","message":"Process PID: 39320","metadata":{},"timestamp":"2025-02-03T13:08:09.526Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T13:08:09.527Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T13:08:09.528Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 14:08 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T13:08:55.178Z"}
{"label":"index.ts","level":"info","message":"Launched in: 60 ms","metadata":{},"timestamp":"2025-02-03T13:08:55.182Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T13:08:55.182Z"}
{"label":"index.ts","level":"info","message":"Process PID: 39385","metadata":{},"timestamp":"2025-02-03T13:08:55.183Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T13:08:55.183Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T13:08:55.184Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 14:09 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T13:09:04.247Z"}
{"label":"index.ts","level":"info","message":"Launched in: 78 ms","metadata":{},"timestamp":"2025-02-03T13:09:04.252Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T13:09:04.253Z"}
{"label":"index.ts","level":"info","message":"Process PID: 39451","metadata":{},"timestamp":"2025-02-03T13:09:04.253Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T13:09:04.254Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T13:09:04.255Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 14:11 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T13:11:17.725Z"}
{"label":"index.ts","level":"info","message":"Launched in: 63 ms","metadata":{},"timestamp":"2025-02-03T13:11:17.729Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T13:11:17.730Z"}
{"label":"index.ts","level":"info","message":"Process PID: 39642","metadata":{},"timestamp":"2025-02-03T13:11:17.730Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T13:11:17.731Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T13:11:17.731Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 14:11 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T13:11:54.946Z"}
{"label":"index.ts","level":"info","message":"Launched in: 75 ms","metadata":{},"timestamp":"2025-02-03T13:11:54.951Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T13:11:54.951Z"}
{"label":"index.ts","level":"info","message":"Process PID: 39706","metadata":{},"timestamp":"2025-02-03T13:11:54.952Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T13:11:54.953Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T13:11:54.953Z"}
{"label":"index.ts","level":"info","message":"Time: 3 de febrero de 2025, 14:12 CET Europe/Madrid","metadata":{},"timestamp":"2025-02-03T13:12:00.002Z"}
{"label":"index.ts","level":"info","message":"Launched in: 60 ms","metadata":{},"timestamp":"2025-02-03T13:12:00.006Z"}
{"label":"index.ts","level":"info","message":"Environment: development","metadata":{},"timestamp":"2025-02-03T13:12:00.007Z"}
{"label":"index.ts","level":"info","message":"Process PID: 39743","metadata":{},"timestamp":"2025-02-03T13:12:00.007Z"}
{"label":"index.ts","level":"info","message":"To shut down your server, press <CTRL> + C at any time","metadata":{},"timestamp":"2025-02-03T13:12:00.008Z"}
{"label":"index.ts","level":"info","message":"⚡️ Server: http://localhost:3002","metadata":{},"timestamp":"2025-02-03T13:12:00.008Z"}
{"label":"index.ts","level":"info","message":"Incoming request POST to /api/v1/auth/register","metadata":{},"timestamp":"2025-02-03T13:12:30.183Z"}

View File

@ -0,0 +1,22 @@
{"label":"index.ts","level":"error","message":"Mon, 03 Feb 2025 10:31:54 GMT uncaughtException:","metadata":{"0":"S","1":"e","10":"n","11":"o","12":"t","13":" ","14":"r","15":"u","16":"n","17":"n","18":"i","19":"n","2":"r","20":"g","21":".","3":"v","4":"e","5":"r","6":" ","7":"i","8":"s","9":" "},"timestamp":"2025-02-03T10:31:54.031Z"}
{"label":"index.ts","level":"error","message":"Error [ERR_SERVER_NOT_RUNNING]: Server is not running.\n at Server.close (node:net:2356:12)\n at Object.onceWrapper (node:events:638:28)\n at Server.emit (node:events:536:35)\n at emitCloseNT (node:net:2416:8)\n at process.processTicksAndRejections (node:internal/process/task_queues:89:21)","metadata":{},"timestamp":"2025-02-03T10:31:54.034Z"}
{"label":"index.ts","level":"error","message":"Mon, 03 Feb 2025 10:33:04 GMT uncaughtException:","metadata":{"0":"S","1":"e","10":"n","11":"o","12":"t","13":" ","14":"r","15":"u","16":"n","17":"n","18":"i","19":"n","2":"r","20":"g","21":".","3":"v","4":"e","5":"r","6":" ","7":"i","8":"s","9":" "},"timestamp":"2025-02-03T10:33:04.894Z"}
{"label":"index.ts","level":"error","message":"Error [ERR_SERVER_NOT_RUNNING]: Server is not running.\n at Server.close (node:net:2356:12)\n at Object.onceWrapper (node:events:638:28)\n at Server.emit (node:events:536:35)\n at emitCloseNT (node:net:2416:8)\n at process.processTicksAndRejections (node:internal/process/task_queues:89:21)","metadata":{},"timestamp":"2025-02-03T10:33:04.896Z"}
{"label":"index.ts","level":"error","message":"Mon, 03 Feb 2025 10:33:49 GMT uncaughtException:","metadata":{"0":"S","1":"e","10":"n","11":"o","12":"t","13":" ","14":"r","15":"u","16":"n","17":"n","18":"i","19":"n","2":"r","20":"g","21":".","3":"v","4":"e","5":"r","6":" ","7":"i","8":"s","9":" "},"timestamp":"2025-02-03T10:33:49.232Z"}
{"label":"index.ts","level":"error","message":"Error [ERR_SERVER_NOT_RUNNING]: Server is not running.\n at Server.close (node:net:2356:12)\n at Object.onceWrapper (node:events:638:28)\n at Server.emit (node:events:536:35)\n at emitCloseNT (node:net:2416:8)\n at process.processTicksAndRejections (node:internal/process/task_queues:89:21)","metadata":{},"timestamp":"2025-02-03T10:33:49.233Z"}
{"label":"index.ts","level":"error","message":"Mon, 03 Feb 2025 10:37:14 GMT uncaughtException:","metadata":{"0":"S","1":"e","10":"n","11":"o","12":"t","13":" ","14":"r","15":"u","16":"n","17":"n","18":"i","19":"n","2":"r","20":"g","21":".","3":"v","4":"e","5":"r","6":" ","7":"i","8":"s","9":" "},"timestamp":"2025-02-03T10:37:14.756Z"}
{"label":"index.ts","level":"error","message":"Error [ERR_SERVER_NOT_RUNNING]: Server is not running.\n at Server.close (node:net:2356:12)\n at Object.onceWrapper (node:events:638:28)\n at Server.emit (node:events:536:35)\n at emitCloseNT (node:net:2416:8)\n at process.processTicksAndRejections (node:internal/process/task_queues:89:21)","metadata":{},"timestamp":"2025-02-03T10:37:14.758Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","code":"ERR_SERVER_NOT_RUNNING"},"timestamp":"2025-02-03T10:47:26.394Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","code":"ERR_SERVER_NOT_RUNNING"},"timestamp":"2025-02-03T10:47:46.769Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","code":"ERR_SERVER_NOT_RUNNING"},"timestamp":"2025-02-03T10:56:00.612Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:08:06.568Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:08:30.574Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","code":"ERR_SERVER_NOT_RUNNING"},"timestamp":"2025-02-03T11:09:05.310Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:14:03.193Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:20:47.049Z"}
{"label":"index.ts","level":"error","message":"Could not close connections in time, forcefully shutting down","metadata":{},"timestamp":"2025-02-03T11:21:20.528Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:22:22.098Z"}
{"label":"index.ts","level":"error","message":"Could not close connections in time, forcefully shutting down","metadata":{},"timestamp":"2025-02-03T11:29:22.891Z"}
{"label":"index.ts","level":"error","message":"Could not close connections in time, forcefully shutting down","metadata":{},"timestamp":"2025-02-03T11:30:14.987Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":","name":"SequelizeDatabaseError","original":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"parameters":{},"parent":{"code":"ER_NO_SUCH_TABLE","errno":1146,"fatal":false,"name":"SqlError","sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');","sqlMessage":"Table 'uecko_erp.users' doesn't exist","sqlState":"42S02"},"sql":"SELECT `id`, `username`, `email`, `password`, `roles`, `isActive`, `created_at`, `updated_at`, `deleted_at` FROM `users` AS `AuthUserModel` WHERE (`AuthUserModel`.`deleted_at` IS NULL AND `AuthUserModel`.`id` = 'email');"},"timestamp":"2025-02-03T11:39:04.414Z"}
{"label":"index.ts","level":"error","message":"Unhandled Rejection at:","metadata":{"0":"r","1":"e","2":"a","3":"s","4":"o","5":"n","6":":"},"timestamp":"2025-02-03T13:05:42.332Z"}

View File

@ -4,7 +4,8 @@
"description": "",
"main": "index.js",
"scripts": {
"dev": "tsx watch src/index.ts",
"dev": "ts-node-dev -r tsconfig-paths/register ./src/index.ts",
"dev:debug": "ts-node-dev --transpile-only --respawn --inspect=4321 -r tsconfig-paths/register ./src/index.ts",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"build": "npm run clean && npm run typecheck && esbuild src/index.ts --platform=node --format=cjs --bundle --sourcemap --minify --outdir=dist",
@ -19,9 +20,10 @@
"@repo/eslint-config": "workspace:*",
"@repo/typescript-config": "workspace:*",
"@types/bcrypt": "^5.0.2",
"@types/express": "^5.0.0",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.14",
"@types/jsonwebtoken": "^9.0.8",
"@types/luxon": "^3.4.2",
"@types/node": "^22.10.7",
"@types/passport": "^1.0.17",
"@types/passport-jwt": "^4.0.1",
@ -29,22 +31,32 @@
"@typescript-eslint/eslint-plugin": "^8.22.0",
"@typescript-eslint/parser": "^8.22.0",
"eslint": "^9.19.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-hexagonal-architecture": "^1.0.3",
"eslint-plugin-import": "^2.28.0",
"eslint-plugin-jest": "^27.4.2",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-sort-class-members": "^1.19.0",
"eslint-plugin-unused-imports": "^3.0.0",
"jest": "^29.7.0",
"nodemon": "^3.1.9",
"ts-jest": "^29.2.5",
"ts-node-dev": "^2.0.0",
"tsx": "^4.19.2",
"typescript": "^5.7.3"
},
"dependencies": {
"bcrypt": "^5.1.1",
"cls-rtracer": "^2.6.3",
"cors": "^2.8.5",
"dotenv": "^16.4.7",
"esbuild": "^0.24.0",
"express": "^4.21.2",
"express": "^4.18.2",
"helmet": "^8.0.0",
"http": "0.0.1-security",
"http-status": "^2.1.0",
"jsonwebtoken": "^9.0.2",
"luxon": "^3.5.0",
"mariadb": "^3.4.0",
"module-alias": "^2.2.3",
"mysql2": "^3.12.0",
@ -54,13 +66,18 @@
"response-time": "^2.3.3",
"sequelize": "^6.37.5",
"shallow-equal-object": "^1.1.1",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.2.0",
"uuid": "^11.0.5",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0",
"zod": "^3.24.1"
},
"engines": {
"node": ">=22"
},
"_moduleAliases": {
"@common": "./dist/common",
"@auth": "./dist/auth",
"@config": "./dist/config",
"@companies": "./dist/companies"
"@config": "./dist/config"
}
}

View File

@ -1,11 +1,14 @@
import { initLogger } from "@common/infrastructure/logger";
import { errorHandler } from "@common/presentation";
import dotenv from "dotenv";
import express, { Application } from "express";
import helmet from "helmet";
import passport from "passport";
import responseTime from "response-time";
import { v1Routes } from "./routes";
dotenv.config();
const logger = initLogger();
export function createApp(): Application {
const app = express();
@ -25,6 +28,11 @@ export function createApp(): Application {
// Inicializar Passport
app.use(passport.initialize());
app.use((req, _, next) => {
logger.info(`Incoming request ${req.method} to ${req.path}`);
next();
});
// Registrar rutas de la API
app.use("/api/v1", v1Routes());

View File

@ -1,8 +1 @@
import { Result } from "./result";
export interface IAggregateRootRepository<T> {
findById(id: string): Promise<Result<T, Error>>;
create(entity: T): Promise<Result<void, Error>>;
update(entity: T): Promise<Result<void, Error>>;
delete(id: string): Promise<Result<void, Error>>;
}
export interface IAggregateRootRepository<T> {}

View File

@ -4,8 +4,8 @@ describe("Result", () => {
it("should create a successful result", () => {
const result = Result.ok("Success Data");
expect(result.isOk()).toBe(true);
expect(result.isError()).toBe(false);
expect(result.isSuccess).toBe(true);
expect(result.isSuccess).toBe(false);
expect(result.data).toBe("Success Data");
});
@ -13,8 +13,8 @@ describe("Result", () => {
const error = new Error("Test error");
const result = Result.fail(error);
expect(result.isOk()).toBe(false);
expect(result.isError()).toBe(true);
expect(result.isSuccess).toBe(false);
expect(result.isSuccess).toBe(true);
expect(result.error).toBe(error);
});

View File

@ -1,6 +1,5 @@
export class Result<T, E extends Error = Error> {
private readonly isSuccess: boolean;
private readonly _isSuccess: boolean;
private readonly _data?: T;
private readonly _error?: E;
@ -13,7 +12,7 @@ export class Result<T, E extends Error = Error> {
throw new Error(`InvalidOperation: A failing result needs to contain an error message`);
}
this.isSuccess = isSuccess;
this._isSuccess = isSuccess;
this._error = error;
this._data = data;
@ -30,7 +29,7 @@ export class Result<T, E extends Error = Error> {
static combine(results: Result<any, any>[]): Result<any, any> {
for (const result of results) {
if (result.isError()) {
if (result.isFailure) {
return result;
}
}
@ -38,23 +37,23 @@ export class Result<T, E extends Error = Error> {
return Result.ok<any>();
}
isOk(): boolean {
return this.isSuccess;
get isSuccess(): boolean {
return this._isSuccess;
}
isError(): boolean {
return !this.isSuccess;
get isFailure(): boolean {
return !this._isSuccess;
}
get data(): T {
if (!this.isSuccess) {
if (!this._isSuccess) {
throw new Error("Cannot get value data from a failed result.");
}
return this._data as T;
}
get error(): E {
if (this.isSuccess) {
if (this._isSuccess) {
throw new Error("Cannot get error from a successful result.");
}
return this._error as E;
@ -65,7 +64,7 @@ export class Result<T, E extends Error = Error> {
* Si el `Result` es un `ok`, devuelve `data`, de lo contrario, devuelve `defaultValue`.
*/
getOrElse(defaultValue: any): T | any {
return this.isSuccess ? this.data : defaultValue;
return this._isSuccess ? this.data : defaultValue;
}
/**
@ -73,6 +72,6 @@ export class Result<T, E extends Error = Error> {
* Evalúa el `Result`: ejecuta `onOk()` si es `ok` o `onError()` si es `fail`.
*/
match<R>(onOk: (data: T) => R, onError: (error: E) => R): R {
return this.isSuccess ? onOk(this.data) : onError(this.error);
return this._isSuccess ? onOk(this.data) : onError(this.error);
}
}

View File

@ -4,7 +4,7 @@ describe("UniqueID Value Object", () => {
it("should generate a new UUID using generateNewID()", () => {
const result = UniqueID.generateNewID();
expect(result.isOk()).toBe(true);
expect(result.isSuccess).toBe(true);
expect(result.data.getValue()).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
);
@ -13,7 +13,7 @@ describe("UniqueID Value Object", () => {
it("should return an error for an invalid UUID", () => {
const result = UniqueID.create("invalid-uuid");
expect(result.isError()).toBe(true);
expect(result.isSuccess).toBe(true);
expect(result.error.message).toBe("Invalid UUID format");
});
@ -21,7 +21,7 @@ describe("UniqueID Value Object", () => {
const validUUID = "550e8400-e29b-41d4-a716-446655440000";
const result = UniqueID.create(validUUID);
expect(result.isOk()).toBe(true);
expect(result.isSuccess).toBe(true);
expect(result.data.getValue()).toBe(validUUID);
});
@ -29,7 +29,7 @@ describe("UniqueID Value Object", () => {
const validUUID = "550e8400-e29b-41d4-a716-446655440000";
const result = UniqueID.create(validUUID);
expect(result.isOk()).toBe(true);
expect(result.isSuccess).toBe(true);
expect(result.data.toString()).toBe(validUUID);
});
});

View File

@ -13,7 +13,7 @@ export interface ITransactionManager {
* 🔹 Ejecuta un bloque de código dentro de una transacción
* Si algo falla, se hace rollback automáticamente.
*/
execute<T>(work: (transaction: any) => Promise<T>): Promise<T>;
complete<T>(work: (transaction: any) => Promise<T>): Promise<T>;
/**
* 🔹 Confirma la transacción

View File

@ -25,7 +25,7 @@ export abstract class TransactionManager implements ITransactionManager {
/**
* 🔹 Ejecuta una función dentro de una transacción
*/
async execute<T>(work: (transaction: any) => Promise<T>): Promise<T> {
async complete<T>(work: (transaction: any) => Promise<T>): Promise<T> {
await this.start();
try {
const result = await work(this.getTransaction());

View File

@ -0,0 +1,91 @@
import rTracer from "cls-rtracer";
import dotenv from "dotenv";
import path from "path";
import { createLogger, format, transports } from "winston";
import DailyRotateFile from "winston-daily-rotate-file";
dotenv.config();
export const initLogger = () => {
const isProduction = process.env.NODE_ENV === "production";
const consoleFormat = format.combine(
format.colorize(),
format.timestamp(),
format.align(),
format.splat(),
format.printf((info) => {
const rid = rTracer.id();
let out =
isProduction && rid
? `${info.timestamp} [request-id:${rid}] - ${info.level}: [${info.label}]: ${info.message}`
: `${info.timestamp} - ${info.level}: [${info.label}]: ${info.message}`;
if (info.metadata?.error) {
out = `${out} ${info.metadata.error}`;
if (info.metadata?.error?.stack) {
out = `${out} ${info.metadata.error.stack}`;
}
}
return out;
})
);
const fileFormat = format.combine(
format.timestamp(),
format.splat(),
format.label({ label: path.basename(String(require.main?.filename)) }),
//format.metadata(),
format.metadata({ fillExcept: ["message", "level", "timestamp", "label"] }),
format.simple(),
format.json()
);
const logger = createLogger({
level: isProduction ? "debug" : "debug",
format: fileFormat,
transports: [
new DailyRotateFile({
dirname: isProduction ? "/logs" : ".",
filename: "error-%DATE%.log",
datePattern: "YYYY-MM-DD",
utc: true,
level: "error",
maxSize: "5m",
maxFiles: "1d",
}),
new DailyRotateFile({
dirname: isProduction ? "/logs" : ".",
filename: "debug-%DATE%.log",
datePattern: "YYYY-MM-DD",
utc: true,
level: "debug",
maxSize: "5m",
maxFiles: "1d",
}),
],
});
//
// If we're not in production then log to the `console` with the format:
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
//
//if (!config.isProduction) {
logger.add(
new transports.Console({
format: consoleFormat,
level: "debug",
})
);
//}
return logger;
};
export const logger = () => {
return initLogger();
};

View File

@ -14,7 +14,7 @@ passport.use(
new JwtStrategy(jwtOptions, async (payload, done) => {
try {
const userResult = await authUserRepository.findById(payload.userId);
if (userResult.isError()) {
if (userResult.isFailure) {
return done(null, false);
}
return done(null, userResult.data);

View File

@ -1 +1,2 @@
export * from "./sequelize-repository";
export * from "./sequelize-transaction-manager";

View File

@ -1,66 +1,102 @@
import { IAggregateRootRepository, Result } from "@common/domain";
import { Transaction } from "sequelize";
import { IAggregateRootRepository, Result, UniqueID } from "@common/domain";
import { ModelDefined, Transaction } from "sequelize";
export abstract class SequelizeRepository<T> implements IAggregateRootRepository<T> {
/**
* 🔹 Convertir un modelo de Sequelize en un agregado del dominio
* Cada repositorio concreto debe implementar este método.
*/
protected abstract toDomain(entity: any): Result<T, Error>;
protected _findById(
model: ModelDefined<any, any>,
id: string,
params: any = {},
transaction?: Transaction
): Promise<any> {
return model.findByPk(id.toString(), {
transaction,
...params,
});
}
/**
* 🔹 Convertir un agregado del dominio en datos listos para persistir
*/
protected abstract toPersistence(aggregate: T): any;
protected async _exists(
model: ModelDefined<any, any>,
field: string,
value: any,
transaction?: Transaction
): Promise<boolean> {
const where: { [key: string]: any } = {};
where[field] = value;
/**
* 🔹 Buscar por ID y devolver el agregado
*/
async findById(id: string, transaction?: Transaction): Promise<Result<T, Error>> {
const entity = await this._findById(id, transaction);
if (!entity) {
return Result.fail(new Error("Entity not found"));
const count: number = await model.count({
where,
transaction,
});
return Promise.resolve(Boolean(count !== 0));
}
protected async _save(
model: ModelDefined<any, any>,
id: UniqueID,
data: any,
params: any = {},
transaction?: Transaction
): Promise<void> {
if (await this._exists(model, "id", id.toString())) {
await model.update(
{
...data,
id: undefined,
},
{
where: { id: id.toString() },
transaction: transaction,
...params,
}
);
} else {
await model.create(
{
...data,
id: id.toString(),
},
{
include: [{ all: true }],
transaction: transaction,
...params,
}
);
}
return this.toDomain(entity);
}
protected async _deleteById(
model: ModelDefined<any, any>,
id: UniqueID,
force: boolean = false,
transaction?: Transaction
) {
await model.destroy({
where: {
id: id.toString(),
},
transaction,
force,
});
}
/**
* 🔹 Crear un nuevo agregado en la BD
* 🔹 Manejo de errores de la base de datos
*/
async create(aggregate: T, transaction?: Transaction): Promise<Result<void, Error>> {
const data = this.toPersistence(aggregate);
await this._create(data, transaction);
return Result.ok();
}
/**
* 🔹 Actualizar un agregado en la BD
*/
async update(aggregate: T, transaction?: Transaction): Promise<Result<void, Error>> {
const data = this.toPersistence(aggregate);
const updated = await this._update(data.id, data, transaction);
if (!updated) {
return Result.fail(new Error("Failed to update entity"));
protected _handleDatabaseError(error: unknown): Result<never, Error> {
const _error = error as Error;
if (_error.name === "SequelizeUniqueConstraintError") {
return Result.fail(new Error("User with this email already exists"));
}
return Result.ok();
}
/**
* 🔹 Eliminar un agregado de la BD
*/
async delete(id: string, transaction?: Transaction): Promise<Result<void, Error>> {
const deleted = await this._delete(id, transaction);
if (!deleted) {
return Result.fail(new Error("Failed to delete entity"));
if (_error.name === "SequelizeConnectionError") {
return Result.fail(new Error("Database connection lost"));
}
return Result.ok();
}
/**
* 🔹 Métodos privados que deben ser implementados en la infraestructura
*/
protected abstract _findById(id: string, transaction?: Transaction): Promise<any>;
protected abstract _create(data: any, transaction?: Transaction): Promise<void>;
protected abstract _update(id: string, data: any, transaction?: Transaction): Promise<boolean>;
protected abstract _delete(id: string, transaction?: Transaction): Promise<boolean>;
if (_error.name === "SequelizeTimeoutError") {
return Result.fail(new Error("Database request timed out"));
}
return Result.fail(new Error("Unexpected database error"));
}
}

View File

@ -19,3 +19,7 @@ export class SequelizeTransactionManager extends TransactionManager {
}
}
}
export const createSequelizeTransactionManager = () => {
return new SequelizeTransactionManager();
};

View File

@ -1,5 +1,6 @@
import { NextFunction, Request, Response } from "express";
import httpStatus from "http-status";
import { ApiError } from "./api-error";
export abstract class ExpressController {
protected req!: Request;
@ -8,25 +9,10 @@ export abstract class ExpressController {
protected abstract executeImpl(): Promise<void | any>;
public execute(req: Request, res: Response, next: NextFunction): void {
this.req = req;
this.res = res;
this.next = next;
this.executeImpl();
}
protected ok<T>(dto?: T) {
return dto ? this.res.status(httpStatus.OK).json(dto) : this.res.status(httpStatus.OK).send();
}
protected fail(error: string | Error) {
console.error("ExpressController FAIL:", error);
return this.res
.status(httpStatus.INTERNAL_SERVER_ERROR)
.json({ message: error instanceof Error ? error.message : error });
}
protected created<T>(dto?: T) {
return dto
? this.res.status(httpStatus.CREATED).json(dto)
@ -37,27 +23,128 @@ export abstract class ExpressController {
return this.res.status(httpStatus.NO_CONTENT).send();
}
protected clientError(message?: string) {
return this.res.status(httpStatus.BAD_REQUEST).json({ message });
protected errorResponse(apiError: ApiError) {
return this.res.status(apiError.status).json(apiError);
}
/**
* 🔹 Respuesta para errores de cliente (400 Bad Request)
*/
protected clientError(message: string, errors?: any[]) {
return this.errorResponse(
new ApiError({
status: 400,
title: "Bad Request",
detail: message,
errors,
})
);
}
/**
* 🔹 Respuesta para errores de autenticación (401 Unauthorized)
*/
protected unauthorizedError(message?: string) {
return this.res.status(httpStatus.UNAUTHORIZED).json({ message });
return this.errorResponse(
new ApiError({
status: 401,
title: "Unauthorized",
detail: message ?? "You are not authorized to access this resource.",
})
);
}
/**
* 🔹 Respuesta para errores de autorización (403 Forbidden)
*/
protected forbiddenError(message?: string) {
return this.res.status(httpStatus.FORBIDDEN).json({ message });
return this.errorResponse(
new ApiError({
status: 403,
title: "Forbidden",
detail: message ?? "You do not have permission to perform this action.",
})
);
}
protected notFoundError(message?: string) {
return this.res.status(httpStatus.NOT_FOUND).json({ message });
/**
* 🔹 Respuesta para recursos no encontrados (404 Not Found)
*/
protected notFoundError(message: string) {
return this.errorResponse(
new ApiError({
status: 404,
title: "Not Found",
detail: message,
})
);
}
protected conflictError(message?: string) {
return this.res.status(httpStatus.CONFLICT).json({ message });
/**
* 🔹 Respuesta para conflictos (409 Conflict)
*/
protected conflictError(message: string, errors?: any[]) {
return this.errorResponse(
new ApiError({
status: 409,
title: "Conflict",
detail: message,
errors,
})
);
}
protected invalidInputError(message?: string) {
return this.res.status(httpStatus.UNPROCESSABLE_ENTITY).json({ message });
/**
* 🔹 Respuesta para errores de validación de entrada (422 Unprocessable Entity)
*/
protected invalidInputError(message: string, errors?: any[]) {
return this.errorResponse(
new ApiError({
status: 422,
title: "Invalid Input",
detail: message,
errors,
})
);
}
/**
* Respuesta para errores de servidor no disponible (503 Service Unavailable)
* @param message
* @returns
*/
protected unavailableError(message?: string) {
return this.errorResponse(
new ApiError({
status: 503,
title: "Service Unavailable",
detail: message ?? "The service is currently unavailable. Please try again later.",
})
);
}
/**
* 🔹 Respuesta para errores internos del servidor (500 Internal Server Error)
*/
protected internalServerError(message?: string) {
return this.errorResponse(
new ApiError({
status: 500,
title: "Internal Server Error",
detail: message ?? "An unexpected error occurred. Please try again later.",
})
);
}
public execute(req: Request, res: Response, next: NextFunction): void {
this.req = req;
this.res = res;
this.next = next;
try {
this.executeImpl();
} catch (error) {
this.internalServerError((error as Error).message);
}
}
}

View File

@ -1 +1,12 @@
import dotenv from "dotenv";
export * from "./database";
// Carga variables de entorno desde el archivo .env
dotenv.config();
// Exporta una configuración centralizada, aplicando valores por defecto donde sea necesario
export const ENV = {
HOST: process.env.HOST || process.env.HOSTNAME || "localhost",
PORT: process.env.PORT || "18888",
NODE_ENV: process.env.NODE_ENV || "development",
};

View File

@ -0,0 +1,9 @@
export interface IAuthProvider {
generateAccessToken(payload: any): string;
generateRefreshToken(payload: any): string;
/**
* 🔹 Verifica la validez de un token JWT y devuelve su payload
*/
verifyToken(token: string): any;
}

View File

@ -6,9 +6,9 @@ export interface IAuthService {
* 🔹 Registra un nuevo usuario en el sistema.
* Si el email ya existe, devuelve un error.
*/
registerUser(
username: Username,
email: EmailAddress,
password: PasswordHash
): Promise<Result<AuthenticatedUser, Error>>;
registerUser(params: {
username: Username;
email: EmailAddress;
passwordHash: PasswordHash;
}): Promise<Result<AuthenticatedUser, Error>>;
}

View File

@ -1,20 +1,28 @@
import { Result, UniqueID } from "@common/domain";
import { ITransactionManager } from "@common/infrastructure/database";
import {
AuthenticatedUser,
EmailAddress,
IAuthenticatedUserRepository,
PasswordHash,
Username,
} from "@contexts/auth/domain";
import { IAuthProvider } from "./auth-provider.interface";
import { IAuthService } from "./auth-service.interface";
export class AuthService implements IAuthService {
private _respository!: IAuthenticatedUserRepository;
private readonly _transactionManager!: ITransactionManager;
private readonly _authProvider: IAuthProvider;
constructor(repository: IAuthenticatedUserRepository, transactionManager: ITransactionManager) {
constructor(
repository: IAuthenticatedUserRepository,
transactionManager: ITransactionManager,
authProvider: IAuthProvider
) {
this._respository = repository;
this._transactionManager = transactionManager;
this._authProvider = authProvider;
}
/**
@ -24,49 +32,79 @@ export class AuthService implements IAuthService {
async registerUser(params: {
username: Username;
email: EmailAddress;
password: PasswordHash;
}): Promise<Result<{ userId: string }, Error>> {
return await this._transactionManager.execute(async (transaction) => {
const { username, email, password } = params;
const userIdResult = UniqueID.generateNewID();
passwordHash: PasswordHash;
}): Promise<Result<AuthenticatedUser, Error>> {
try {
return await this._transactionManager.complete(async (transaction) => {
const { username, email, passwordHash } = params;
// Verificar si el usuario ya existe
const userExists = await this._respository.userExists(email.toString(), transaction);
if (userExists) {
return Result.fail(new Error("Email is already registered"));
}
// Verificar si el usuario ya existe
const userExists = await this._respository.findUserByEmail(email, transaction);
if (userExists.isSuccess && userExists.data) {
return Result.fail(new Error("Email is already registered"));
}
const user = await this._respository.createUser(
{
id: userIdResult,
username: username,
email: email,
password: password,
isActive: true,
},
transaction
);
if (userExists.isFailure) {
return Result.fail(userExists.error);
}
return Result.ok({ userId: user.id });
});
const newUserId = UniqueID.generateNewID().data;
// 🔹 Generar Access Token y Refresh Token
const accessToken = this._authProvider.generateAccessToken({
userId: newUserId.toString(),
email: email.toString(),
roles: ["USER"],
});
const refreshToken = this._authProvider.generateRefreshToken({
userId: newUserId.toString(),
});
const userOrError = AuthenticatedUser.create(
{
username,
email,
passwordHash,
roles: ["USER"],
token: accessToken,
},
newUserId
);
if (userOrError.isFailure) {
return Result.fail(userOrError.error);
}
const createdResult = await this._respository.createUser(userOrError.data, transaction);
if (createdResult.isFailure) {
return Result.fail(createdResult.error);
}
return Result.ok(userOrError.data);
});
} catch (error: unknown) {
return Result.fail(error as Error);
}
}
/**
* 🔹 `login`
* Autentica un usuario y genera un token JWT bajo transacción.
*/
static async login(
/*static async login(
email: string,
password: string
): Promise<Result<{ token: string; userId: string }, Error>> {
return await authUserRepository.executeTransaction(async (transaction) => {
const emailResult = EmailAddress.create(email);
if (emailResult.isError()) {
if (emailResult.isFailure) {
return Result.fail(emailResult.error);
}
const user = await authUserRepository.findByEmail(emailResult.data.getValue(), transaction);
if (user.isError()) {
if (user.isFailure) {
return Result.fail(new Error("Invalid email or password"));
}
@ -79,19 +117,19 @@ export class AuthService implements IAuthService {
return Result.ok({ token, userId: user.data.getUserID() });
});
}
}*/
/**
* 🔹 `selectCompany`
* Permite a un usuario seleccionar una empresa activa en la sesión bajo transacción.
*/
static async selectCompany(
/*static async selectCompany(
userId: string,
companyId: string
): Promise<Result<{ message: string }, Error>> {
return await authUserRepository.executeTransaction(async (transaction) => {
const user = await authUserRepository.findById(userId, transaction);
if (user.isError()) {
if (user.isFailure) {
return Result.fail(new Error("User not found"));
}
@ -106,13 +144,13 @@ export class AuthService implements IAuthService {
return Result.ok({ message: "Company selected successfully" });
});
}
}*/
/**
* 🔹 `logout`
* Simula el cierre de sesión de un usuario. No requiere transacción.
*/
static logout(): Result<{ message: string }, never> {
/*static logout(): Result<{ message: string }, never> {
return Result.ok({ message: "Logged out successfully" });
}
}*/
}

View File

@ -1,11 +1,17 @@
export * from "./auth-service.interface";
import { ITransactionManager } from "@common/infrastructure/database";
import { SequelizeTransactionManager } from "@common/infrastructure/sequelize/sequelize-transaction-manager";
import { AuthenticatedUserRepository } from "../infraestructure";
import { createSequelizeTransactionManager } from "@common/infrastructure";
import { createAuthenticatedUserRepository } from "../infraestructure";
import { createPassportAuthProvider } from "../infraestructure/passport/passport-auth-provider";
import { IAuthProvider } from "./auth-provider.interface";
import { IAuthService } from "./auth-service.interface";
import { AuthService } from "./auth.service";
const transactionManager: ITransactionManager = new SequelizeTransactionManager();
const authenticatedUserRepository = new AuthenticatedUserRepository();
const authService = new AuthService(authenticatedUserRepository, transactionManager);
export * from "./auth-provider.interface";
export * from "./auth-service.interface";
export { authService };
export const createAuthService = (): IAuthService => {
const transactionManager = createSequelizeTransactionManager();
const authenticatedUserRepository = createAuthenticatedUserRepository();
const authProvider: IAuthProvider = createPassportAuthProvider();
return new AuthService(authenticatedUserRepository, transactionManager, authProvider);
};

View File

@ -1,25 +1,21 @@
import { AggregateRoot, Result, UniqueID } from "@common/domain";
import { UserAuthenticatedEvent } from "../events";
import { EmailAddress, Username } from "../value-objects";
import { EmailAddress, PasswordHash, Username } from "../value-objects";
export interface IAuthenticatedUserProps {
username: Username;
email: EmailAddress;
passwordHash: PasswordHash;
roles: string[];
token: string;
}
export class AuthenticatedUser extends AggregateRoot<IAuthenticatedUserProps> {
static create(props: IAuthenticatedUserProps, id?: UniqueID): Result<AuthenticatedUser, Error> {
const { username, email, roles, token } = props;
if (!id || !username || !email || !token) {
return Result.fail(new Error("Invalid authenticated user data"));
}
const user = new AuthenticatedUser({ username, email, roles, token }, id);
static create(props: IAuthenticatedUserProps, id: UniqueID): Result<AuthenticatedUser, Error> {
const user = new AuthenticatedUser(props, id);
// 🔹 Disparar evento de dominio "UserAuthenticatedEvent"
const { email } = props;
user.addDomainEvent(new UserAuthenticatedEvent(id, email.toString()));
return Result.ok(user);
@ -28,11 +24,12 @@ export class AuthenticatedUser extends AggregateRoot<IAuthenticatedUserProps> {
/**
* 🔹 Devuelve una representación lista para persistencia
*/
public toPersistenceData(): any {
toPersistenceData(): any {
return {
id: this._id.toString(),
username: this._props.username.toString(),
email: this._props.email.toString(),
password: this._props.passwordHash.toString(),
roles: JSON.stringify(this._props.roles),
token: this._props.token,
};

View File

@ -1,5 +1,4 @@
export * from "./aggregates/authenticated-user";
export * from "./auth-user.entity";
export * from "./events/user-authenticated.event";
export * from "./repositories";
export * from "./value-objects";

View File

@ -1 +1,12 @@
export interface IAuthenticatedUserRepository {}
import { Result } from "@common/domain";
import { AuthenticatedUser } from "../aggregates";
import { EmailAddress } from "../value-objects";
export interface IAuthenticatedUserRepository {
findUserByEmail(
email: EmailAddress,
transaction?: any
): Promise<Result<AuthenticatedUser | null, Error>>;
createUser(user: AuthenticatedUser, transaction?: any): Promise<Result<void, Error>>;
}

View File

@ -4,28 +4,28 @@ describe("EmailAddress Value Object", () => {
it("should create a valid email", () => {
const result = EmailAddress.create("user@example.com");
expect(result.isOk()).toBe(true);
expect(result.isSuccess).toBe(true);
expect(result.data.getValue()).toBe("user@example.com");
});
it("should return an error for invalid email format", () => {
const result = EmailAddress.create("invalid-email");
expect(result.isError()).toBe(true);
expect(result.isSuccess).toBe(true);
expect(result.error.message).toBe("Invalid email format");
});
it("should allow null email", () => {
const result = EmailAddress.create(null);
expect(result.isOk()).toBe(true);
expect(result.isSuccess).toBe(true);
expect(result.data.getValue()).toBe(null);
});
it("should convert empty string to null", () => {
const result = EmailAddress.create("");
expect(result.isOk()).toBe(true);
expect(result.isSuccess).toBe(true);
expect(result.data.getValue()).toBe(null);
});
@ -33,8 +33,8 @@ describe("EmailAddress Value Object", () => {
const email1 = EmailAddress.create("test@example.com");
const email2 = EmailAddress.create("test@example.com");
expect(email1.isOk()).toBe(true);
expect(email2.isOk()).toBe(true);
expect(email1.isSuccess).toBe(true);
expect(email2.isSuccess).toBe(true);
expect(email1.data.equals(email2.data)).toBe(true);
});
@ -42,22 +42,22 @@ describe("EmailAddress Value Object", () => {
const email1 = EmailAddress.create("test@example.com");
const email2 = EmailAddress.create("other@example.com");
expect(email1.isOk()).toBe(true);
expect(email2.isOk()).toBe(true);
expect(email1.isSuccess).toBe(true);
expect(email2.isSuccess).toBe(true);
expect(email1.data.equals(email2.data)).toBe(false);
});
it("should detect empty email correctly", () => {
const email = EmailAddress.create(null);
expect(email.isOk()).toBe(true);
expect(email.isSuccess).toBe(true);
expect(email.data.isEmpty()).toBe(true);
});
it("should detect non-empty email correctly", () => {
const email = EmailAddress.create("test@example.com");
expect(email.isOk()).toBe(true);
expect(email.isSuccess).toBe(true);
expect(email.data.isEmpty()).toBe(false);
});
});

View File

@ -4,20 +4,20 @@ describe("PasswordHash Value Object", () => {
it("should hash a valid password", async () => {
const result = await PasswordHash.create("StrongPass123");
expect(result.isOk()).toBe(true);
expect(result.isSuccess).toBe(true);
expect(result.data.getValue()).not.toBe("StrongPass123"); // Should be hashed
});
it("should return an error for short password", async () => {
const result = await PasswordHash.create("12345");
expect(result.isError()).toBe(true);
expect(result.error.message).toBe("Password must be at least 8 characters long");
expect(result.isSuccess).toBe(true);
expect(result.error.message).toBe("Password must be at least 6 characters long");
});
it("should validate password comparison correctly", async () => {
const result = await PasswordHash.create("SecurePass123");
expect(result.isOk()).toBe(true);
expect(result.isSuccess).toBe(true);
const isValid = await result.data.compare("SecurePass123");
expect(isValid).toBe(true);
@ -25,7 +25,7 @@ describe("PasswordHash Value Object", () => {
it("should fail password comparison for incorrect passwords", async () => {
const result = await PasswordHash.create("SecurePass123");
expect(result.isOk()).toBe(true);
expect(result.isSuccess).toBe(true);
const isValid = await result.data.compare("WrongPassword");
expect(isValid).toBe(false);

View File

@ -2,26 +2,22 @@ import { Result, ValueObject } from "@common/domain";
import bcrypt from "bcrypt";
import { z } from "zod";
const PasswordSchema = z
.string()
.min(8, { message: "Password must be at least 8 characters long" });
export class PasswordHash extends ValueObject<string> {
private static readonly SALT_ROUNDS = 10;
static async create(plainPassword: string): Promise<Result<PasswordHash, Error>> {
static create(plainPassword: string): Result<PasswordHash, Error> {
const result = PasswordHash.validate(plainPassword);
if (!result.success) {
return Result.fail(new Error(result.error.errors[0].message));
}
const hashed = await bcrypt.hash(result.data, this.SALT_ROUNDS);
const hashed = bcrypt.hashSync(result.data, this.SALT_ROUNDS);
return Result.ok(new PasswordHash(hashed));
}
private static validate(password: string) {
const schema = z.string().min(8, { message: "Password must be at least 8 characters long" });
const schema = z.string().min(6, { message: "Password must be at least 6 characters long" });
return schema.safeParse(password);
}

View File

@ -1,3 +1,4 @@
export * from "./jwt.helper";
export * from "./mappers";
export * from "./passport";
export * from "./sequelize";
12;

View File

@ -1,11 +1,12 @@
import { Result, UniqueID } from "@common/domain";
import { AuthenticatedUser, EmailAddress, Username } from "@contexts/auth/domain";
import { AuthenticatedUser, EmailAddress, PasswordHash, Username } from "@contexts/auth/domain";
import { IAuthenticatedUserMapper } from "./authenticated-user-mapper.interface";
export class AuthenticatedUserMapper {
export class AuthenticatedUserMapper implements IAuthenticatedUserMapper {
/**
* 🔹 Convierte una entidad de la base de datos en un agregado de dominio `AuthenticatedUser`
*/
static toDomain(entity: any): Result<AuthenticatedUser, Error> {
toDomain(entity: any): Result<AuthenticatedUser, Error> {
if (!entity) {
return Result.fail(new Error("Entity not found"));
}
@ -13,12 +14,18 @@ export class AuthenticatedUserMapper {
// Crear Value Objects asegurando que sean válidos
const uniqueIdResult = UniqueID.create(entity.id);
const usernameResult = Username.create(entity.username);
const passwordHashResult = PasswordHash.create(entity.passwordHash);
const emailResult = EmailAddress.create(entity.email);
1;
// Validar que no haya errores en la creación de los Value Objects
const okOrError = Result.combine([uniqueIdResult, usernameResult, emailResult]);
if (okOrError.isError()) {
return okOrError;
const okOrError = Result.combine([
uniqueIdResult,
usernameResult,
passwordHashResult,
emailResult,
]);
if (okOrError.isFailure) {
return Result.fail(okOrError.error.message);
}
// Crear el agregado de dominio
@ -26,6 +33,7 @@ export class AuthenticatedUserMapper {
{
username: usernameResult.data!,
email: emailResult.data!,
passwordHash: passwordHashResult.data!,
roles: entity.roles || [],
token: entity.token,
},
@ -36,7 +44,10 @@ export class AuthenticatedUserMapper {
/**
* 🔹 Convierte un agregado `AuthenticatedUser` en un objeto listo para persistencia
*/
static toPersistence(authenticatedUser: AuthenticatedUser): any {
toPersistence(authenticatedUser: AuthenticatedUser): any {
return authenticatedUser.toPersistenceData();
}
}
export const createAuthenticatedUserMapper = (): IAuthenticatedUserMapper =>
new AuthenticatedUserMapper();

View File

@ -0,0 +1 @@
export * from "./passport-auth-provider";

View File

@ -0,0 +1,48 @@
import { IAuthProvider } from "@contexts/auth/application";
import jwt from "jsonwebtoken";
import passport from "passport";
import { ExtractJwt, Strategy as JwtStrategy } from "passport-jwt";
const SECRET_KEY = process.env.JWT_SECRET || "supersecretkey";
const ACCESS_EXPIRATION = process.env.JWT_ACCESS_EXPIRATION || "1h";
const REFRESH_EXPIRATION = process.env.JWT_REFRESH_EXPIRATION || "7d";
export class PassportAuthProvider implements IAuthProvider {
constructor() {
this.initializePassport();
}
generateAccessToken(payload: any): string {
return jwt.sign(payload, SECRET_KEY, { expiresIn: ACCESS_EXPIRATION });
}
generateRefreshToken(payload: any): string {
return jwt.sign(payload, SECRET_KEY, { expiresIn: REFRESH_EXPIRATION });
}
verifyToken(token: string): any {
return jwt.verify(token, SECRET_KEY);
}
/**
* 🔹 Configura PassportJS con la estrategia JWT
*/
private initializePassport(): void {
const jwtOptions = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: SECRET_KEY,
};
passport.use(
new JwtStrategy(jwtOptions, (payload, done) => {
try {
return done(null, payload);
} catch (error) {
return done(error, false);
}
})
);
}
}
export const createPassportAuthProvider = () => new PassportAuthProvider();

View File

@ -1,13 +1,12 @@
import { Result, UniqueID } from "@common/domain";
import { Result } from "@common/domain";
import { SequelizeRepository } from "@common/infrastructure";
import {
AuthenticatedUser,
EmailAddress,
IAuthenticatedUserRepository,
Username,
} from "@contexts/auth/domain";
import { Transaction } from "sequelize";
import { IAuthenticatedUserMapper } from "../mappers";
import { createAuthenticatedUserMapper, IAuthenticatedUserMapper } from "../mappers";
import { AuthUserModel } from "./auth-user.model";
export class AuthenticatedUserRepository
@ -21,56 +20,61 @@ export class AuthenticatedUserRepository
this._mapper = mapper;
}
protected async _findById(id: string, transaction?: Transaction): Promise<any> {
return await AuthUserModel.findByPk(id, { transaction });
}
async userExists(
email: EmailAddress,
transaction?: Transaction
): Promise<Result<boolean, Error>> {
try {
const rawUser: any = await this._findById(
AuthUserModel,
"email",
email.toString(),
transaction
);
async create(user: AuthenticatedUser, transaction?: Transaction): Promise<Result<void, Error>> {
const persistenceData = this._mapper.toPersistence(user);
await AuthUserModel.create(persistenceData, { transaction });
return Result.ok();
}
protected async _update(id: string, data: any, transaction?: Transaction): Promise<boolean> {
const [updated] = await AuthUserModel.update(data, { where: { id }, transaction });
return updated > 0;
}
protected async _delete(id: string, transaction?: Transaction): Promise<boolean> {
const deleted = await AuthUserModel.destroy({ where: { id }, transaction });
return deleted > 0;
}
protected toDomain(entity: any): Result<AuthenticatedUser, Error> {
if (!entity) {
return Result.fail(new Error("Entity not found"));
return Result.ok(Boolean(rawUser));
} catch (error: any) {
return this._handleDatabaseError(error);
}
}
// 🔹 Crear los Value Objects manejando errores correctamente
const idOrError = UniqueID.create(entity.id);
const usernameOrError = Username.create(entity.username);
const emailOrError = EmailAddress.create(entity.email);
async findUserByEmail(
email: EmailAddress,
transaction?: Transaction
): Promise<Result<AuthenticatedUser | null, Error>> {
try {
const rawUser: any = await this._findById(
AuthUserModel,
"email",
email.toString(),
transaction
);
// 🔹 Si algún Value Object es inválido, devolver el error inmediatamente
const combinedResults = [idOrError, usernameOrError, emailOrError];
for (const result of combinedResults) {
if (result.isError()) {
return Result.fail(result.error);
if (!rawUser === true) {
return Result.ok(null);
}
return this._mapper.toDomain(rawUser);
} catch (error: any) {
return this._handleDatabaseError(error);
}
// 🔹 Crear las propiedades validadas del agregado
const props = {
username: usernameOrError.data!,
email: emailOrError.data!,
roles: entity.roles || [],
token: entity.token,
};
// 🔹 Crear el agregado manejando errores
return AuthenticatedUser.create(props, idOrError.data!);
}
protected toPersistence(authenticatedUser: AuthenticatedUser): any {
this._mapper.toPersistence(authenticatedUser);
async createUser(
user: AuthenticatedUser,
transaction?: Transaction
): Promise<Result<void, Error>> {
try {
const persistenceData = this._mapper.toPersistence(user);
await AuthUserModel.create(persistenceData, { transaction });
return Result.ok();
} catch (error: any) {
return this._handleDatabaseError(error);
}
}
}
export const createAuthenticatedUserRepository = (): IAuthenticatedUserRepository => {
const authenticatedUserMapper = createAuthenticatedUserMapper();
return new AuthenticatedUserRepository(authenticatedUserMapper);
};

View File

@ -1,57 +0,0 @@
import { ExpressController } from "@common/presentation/express/express-controller";
import { Request, Response } from "express";
import { AuthService } from "../application";
import { EmailAddress, PasswordHash, Username } from "../domain";
import { IRegisterUserRequestDTO } from "./dto";
class AuthController extends ExpressController {
protected async executeImpl(): Promise<void> {
this.clientError("Method not implemented");
}
async register(req: Request, res: Response) {
const { username, email, password }: IRegisterUserRequestDTO = req.body;
const emailVO = EmailAddress.create(email);
const usernameVO = Username.create(username);
const passwordVO = await PasswordHash.create(password);
const combined = [emailVO, usernameVO, passwordVO].every((r) => r.isOk());
if (!combined) {
return this.clientError("Invalid input data");
}
const result = await AuthService.registerUser({
username: usernameVO.data,
email: emailVO.data,
password: passwordVO.data,
});
return result.isError()
? this.clientError(result.error.message)
: this.created({ userId: result.data.userId });
}
async login(req: Request, res: Response) {
const { email, password } = req.body;
const result = await AuthService.login(email, password);
return result.isError() ? this.unauthorizedError(result.error.message) : this.ok(result.data);
}
async selectCompany(req: Request, res: Response) {
const userId = (req as any).user.userId;
const { companyId } = req.body;
const result = await AuthService.selectCompany(userId, companyId);
return result.isError() ? this.forbiddenError(result.error.message) : this.ok(result.data);
}
async logout(req: Request, res: Response) {
return this.ok(AuthService.logout());
}
}
export const authController = new AuthController();

View File

@ -1,8 +1,6 @@
import { authController } from "./auth.controller";
import { validateRequest } from "@common/presentation";
import { NextFunction, Request, Response, Router } from "express";
import { registerController } from "./controllers";
import { createRegisterController } from "./controllers";
import { RegisterUserSchema } from "./dto";
const loggerMiddleware = () => (req: Request, res: Response, next: NextFunction) => {
@ -27,7 +25,9 @@ export const authRouter = (appRouter: Router) => {
*
* @apiError (400) {String} message Error message.
*/
authRoutes.post("/register", validateRequest(RegisterUserSchema), registerController.execute);
authRoutes.post("/register", validateRequest(RegisterUserSchema), (req, res, next) => {
createRegisterController().execute(req, res, next);
});
/**
* @api {post} /api/auth/login Authenticate a user
@ -43,7 +43,7 @@ export const authRouter = (appRouter: Router) => {
*
* @apiError (401) {String} message Invalid email or password.
*/
authRoutes.post("/login", authController.login);
//authRoutes.post("/login", authController.login);
/**
* @api {post} /api/auth/select-company Select an active company
@ -59,7 +59,7 @@ export const authRouter = (appRouter: Router) => {
*
* @apiError (403) {String} message Unauthorized or invalid company selection.
*/
authRoutes.post("/select-company", authMiddleware, authController.selectCompany);
//authRoutes.post("/select-company", authMiddleware, authController.selectCompany);
/**
* @api {post} /api/auth/logout Logout user
@ -71,7 +71,7 @@ export const authRouter = (appRouter: Router) => {
*
* @apiSuccess (200) {String} message Success message.
*/
authRoutes.post("/logout", authMiddleware, authController.logout);
//authRoutes.post("/logout", authMiddleware, authController.logout);
appRouter.use("/auth", authRoutes);
};

View File

@ -1,12 +1,11 @@
import { ExpressController } from "@common/presentation";
import { authService } from "@contexts/auth/application";
import { AuthService } from "@contexts/auth/application/auth.service";
import { createAuthService, IAuthService } from "@contexts/auth/application";
import { EmailAddress, PasswordHash, Username } from "@contexts/auth/domain";
class RegisterController extends ExpressController {
private readonly _authService!: AuthService;
private readonly _authService!: IAuthService;
constructor(authService: AuthService) {
public constructor(authService: IAuthService) {
super();
this._authService = authService;
}
@ -14,22 +13,47 @@ class RegisterController extends ExpressController {
async executeImpl() {
const emailVO = EmailAddress.create(this.req.body.email);
const usernameVO = Username.create(this.req.body.username);
const passwordVO = await PasswordHash.create(this.req.body.password);
const passwordHashVO = await PasswordHash.create(this.req.body.password);
if ([emailVO, usernameVO, passwordVO].some((r) => r.isError())) {
if ([emailVO, usernameVO, passwordHashVO].some((r) => r.isFailure)) {
return this.clientError("Invalid input data");
}
const result = await this._authService.registerUser({
username: usernameVO.data,
email: emailVO.data,
password: passwordVO.data,
passwordHash: passwordHashVO.data,
});
return result.isError()
? this.clientError(result.error.message)
: this.created({ userId: result.data.userId });
if (result.isFailure) {
console.log(result.error);
const message = result.error.message;
if (message.includes("User with this email already exists")) {
return this.conflictError(message);
}
if (
message.includes("Database connection lost") ||
message.includes("Database request timed out")
) {
return this.unavailableError(
"Database service is currently unavailable. Please try again later."
);
}
return this.internalServerError(message);
}
return this.created({
accessToken: result.data.accessToken,
refreshToken: result.data.refreshToken,
userId: result.data.user.getID(),
});
}
}
export const registerController = new RegisterController(authService);
export const createRegisterController = () => {
const authService = createAuthService();
return new RegisterController(authService);
};

View File

@ -3,12 +3,12 @@ import { z } from "zod";
export const RegisterUserSchema = z.object({
username: z.string().min(3, "Username must be at least 3 characters long"),
email: z.string().email("Invalid email format"),
password: z.string().min(8, "Password must be at least 8 characters long"),
password: z.string().min(6, "Password must be at least 6 characters long"),
});
export const LoginUserSchema = z.object({
email: z.string().email("Invalid email format"),
password: z.string().min(8, "Password must be at least 8 characters long"),
password: z.string().min(6, "Password must be at least 6 characters long"),
});
export const SelectCompanySchema = z.object({

View File

@ -1 +1,4 @@
export * from "./auth.controller";
export * from "./auth.routes";
export * from "./controllers";
export * from "./dto";
export * from "./middleware";

View File

@ -0,0 +1 @@
export * from "./passport-auth";

View File

@ -0,0 +1,12 @@
import { NextFunction, Request, Response } from "express";
import passport from "passport";
export function authenticateJWT(req: Request, res: Response, next: NextFunction) {
passport.authenticate("jwt", { session: false }, (err, user) => {
if (err || !user) {
return res.status(401).json({ message: "Unauthorized: Invalid token" });
}
(req as any).user = user;
next();
})(req, res, next);
}

View File

@ -1,16 +1,128 @@
import { createApp } from "./app";
import { connectToDatabase } from "./config/database";
import { initLogger } from "@common/infrastructure/logger";
import { connectToDatabase } from "@config/database";
import { createApp } from "app";
import http from "http";
import { DateTime } from "luxon";
import { ENV } from "./config";
const PORT = process.env.PORT || 3000;
const logger = initLogger();
(async () => {
// Conexión a la base de datos
await connectToDatabase();
// Guardamos información del estado del servidor
export const currentState = {
launchedAt: DateTime.now(),
appPath: process.cwd(),
host: ENV.HOST,
port: ENV.PORT,
environment: ENV.NODE_ENV,
connections: {} as Record<string, any>,
};
// Inicializar la aplicación
const app = createApp();
// Manejo de cierre forzado del servidor (graceful shutdown)
const serverStop = (server: http.Server) => {
const forceTimeout = 30000;
app.listen(PORT, () => {
console.log(`Servidor escuchando en http://localhost:${PORT}`);
return new Promise<void>((resolve, reject) => {
logger.warn("⚡️ Shutting down server");
setTimeout(() => {
logger.error("Could not close connections in time, forcefully shutting down");
resolve();
}, forceTimeout).unref();
server.close((err) => {
if (err) {
return reject(err);
}
logger.info("Closed out remaining connections.");
logger.info("Bye!");
resolve();
});
});
};
// Manejo de errores al iniciar el servidor
const serverError = (error: NodeJS.ErrnoException) => {
logger.debug(`⛔️ Server wasn't able to start properly.`);
if (error.code === "EADDRINUSE") {
logger.error(`The port ${error.port} is already used by another application.`);
} else {
logger.error(error);
}
// Dependiendo de la criticidad, podrías forzar el proceso a salir
// process.exit(1);
};
// Almacena en "connections" cada nueva conexión (descomentar si se quiere seguimiento)
const serverConnection = (conn: any) => {
const key = `${conn.remoteAddress}:${conn.remotePort}`;
currentState.connections[key] = conn;
conn.on("close", () => {
delete currentState.connections[key];
});
};
//const sequelizeConn = createSequelizeAdapter();
//const firebirdConn = createFirebirdAdapter();
// Crea el servidor HTTP
const server = http
.createServer(createApp())
.once("listening", () =>
process.on("SIGINT", async () => {
// Por ejemplo, podrías desconectar la base de datos aquí:
// firebirdConn.disconnect();
// O forzar desconexión en adapters
// sequelizeConn.close();
await serverStop(server);
})
)
.on("close", () =>
logger.info(`Shut down at: ${DateTime.now().toLocaleString(DateTime.DATETIME_FULL)}`)
)
.on("connection", serverConnection)
.on("error", serverError);
// Ejemplo de adapters de base de datos (descoméntalos si los necesitas)
// const sequelizeConn = createSequelizeAdapter();
// const firebirdConn = createFirebirdAdapter();
// Manejo de promesas no capturadas
process.on("unhandledRejection", (reason: any, promise: Promise<any>) => {
logger.error("Unhandled Rejection at:", promise, "reason:", reason);
// Dependiendo de la aplicación, podrías desear una salida total o un cierre controlado
// process.exit(1);
});
// Manejo de excepciones no controladas
process.on("uncaughtException", (error: Error) => {
// firebirdConn.disconnect();
logger.error(`${new Date().toUTCString()} uncaughtException:`, error.message);
logger.error(error.stack);
// process.exit(1);
});
// Arranca el servidor si la conexión a la base de datos va bien
(async () => {
try {
await connectToDatabase();
// Lógica de inicialización de DB, si procede:
// initStructure(sequelizeConn.connection);
// insertUsers();
server.listen(currentState.port, () => {
const now = DateTime.now();
logger.info(`Time: ${now.toLocaleString(DateTime.DATETIME_FULL)} ${now.zoneName}`);
logger.info(`Launched in: ${now.diff(currentState.launchedAt).toMillis()} ms`);
logger.info(`Environment: ${currentState.environment}`);
logger.info(`Process PID: ${process.pid}`);
logger.info("To shut down your server, press <CTRL> + C at any time");
logger.info(`⚡️ Server: http://${currentState.host}:${currentState.port}`);
});
} catch (error) {
serverError(error as NodeJS.ErrnoException);
}
})();

View File

@ -8,13 +8,6 @@ export const v1Routes = () => {
res.send("Hello world!");
});
routes.use((req, res, next) => {
console.log(
`[${new Date().toLocaleTimeString()}] Incoming request ${req.method} to ${req.path}`
);
next();
});
authRouter(routes);
return routes;

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,12 @@
{
"compilerOptions": {
"target": "ES6",
"target": "ES2022",
"module": "CommonJS",
"outDir": "./dist",
"sourceMap": true,
"strict": true,
"pretty": true,
"removeComments": true /* Do not emit comments to output. */,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,