"REFACTOR: API refatorada para se adequar a nova arquitetura baseada em Clean Architeture"

This commit is contained in:
Rafael Alves Lopes 2025-11-24 10:59:46 -03:00
parent 5adc1dba38
commit 038b9eb3d4
20 changed files with 1335 additions and 197 deletions

5
.gitignore vendored
View File

@ -1,2 +1,3 @@
.env
node_modules/
.env*
node_modules/
logs/

773
package-lock.json generated
View File

@ -1,20 +1,71 @@
{
"name": "sothiscontratacaoapi",
"name": "node-clean-architecture-starter",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sothiscontratacaoapi",
"name": "node-clean-architecture-starter",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"axios": "^1.6.0",
"cors": "^2.8.5",
"dotenv": "^17.2.3",
"express": "^5.1.0",
"qs": "^6.11.0"
"node-cron": "^4.2.1",
"qs": "^6.11.0",
"winston": "^3.18.3",
"winston-daily-rotate-file": "^5.0.0"
},
"devDependencies": {
"cross-env": "^10.1.0",
"nodemon": "^3.1.11"
}
},
"node_modules/@colors/colors": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
"integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
"license": "MIT",
"engines": {
"node": ">=0.1.90"
}
},
"node_modules/@dabh/diagnostics": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz",
"integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==",
"license": "MIT",
"dependencies": {
"@so-ric/colorspace": "^1.1.6",
"enabled": "2.0.x",
"kuler": "^2.0.0"
}
},
"node_modules/@epic-web/invariant": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
"integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
"dev": true,
"license": "MIT"
},
"node_modules/@so-ric/colorspace": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz",
"integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==",
"license": "MIT",
"dependencies": {
"color": "^5.0.2",
"text-hex": "1.0.x"
}
},
"node_modules/@types/triple-beam": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
"integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==",
"license": "MIT"
},
"node_modules/accepts": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
@ -28,6 +79,26 @@
"node": ">= 0.6"
}
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/async": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
"license": "MIT"
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -45,6 +116,26 @@
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true,
"license": "MIT"
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/body-parser": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
@ -65,6 +156,30 @@
"node": ">=18"
}
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -103,6 +218,77 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dev": true,
"license": "MIT",
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"engines": {
"node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/color": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz",
"integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==",
"license": "MIT",
"dependencies": {
"color-convert": "^3.1.3",
"color-string": "^2.1.3"
},
"engines": {
"node": ">=18"
}
},
"node_modules/color-convert": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz",
"integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==",
"license": "MIT",
"dependencies": {
"color-name": "^2.0.0"
},
"engines": {
"node": ">=14.6"
}
},
"node_modules/color-name": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz",
"integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==",
"license": "MIT",
"engines": {
"node": ">=12.20"
}
},
"node_modules/color-string": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz",
"integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==",
"license": "MIT",
"dependencies": {
"color-name": "^2.0.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -115,6 +301,13 @@
"node": ">= 0.8"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true,
"license": "MIT"
},
"node_modules/content-disposition": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
@ -167,6 +360,39 @@
"node": ">= 0.10"
}
},
"node_modules/cross-env": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz",
"integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@epic-web/invariant": "^1.0.0",
"cross-spawn": "^7.0.6"
},
"bin": {
"cross-env": "dist/bin/cross-env.js",
"cross-env-shell": "dist/bin/cross-env-shell.js"
},
"engines": {
"node": ">=20"
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@ -202,6 +428,18 @@
"node": ">= 0.8"
}
},
"node_modules/dotenv": {
"version": "17.2.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@ -222,6 +460,12 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"license": "MIT"
},
"node_modules/enabled": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
"license": "MIT"
},
"node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
@ -333,6 +577,34 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/fecha": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
"license": "MIT"
},
"node_modules/file-stream-rotator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz",
"integrity": "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==",
"license": "MIT",
"dependencies": {
"moment": "^2.29.1"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/finalhandler": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
@ -350,6 +622,12 @@
"node": ">= 0.8"
}
},
"node_modules/fn.name": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
"license": "MIT"
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
@ -425,6 +703,21 @@
"node": ">= 0.8"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@ -471,6 +764,19 @@
"node": ">= 0.4"
}
},
"node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@ -483,6 +789,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
@ -559,6 +875,13 @@
"node": ">=0.10.0"
}
},
"node_modules/ignore-by-default": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
"dev": true,
"license": "ISC"
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@ -574,12 +897,100 @@
"node": ">= 0.10"
}
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/is-promise": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT"
},
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true,
"license": "ISC"
},
"node_modules/kuler": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
"license": "MIT"
},
"node_modules/logform": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
"integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
"license": "MIT",
"dependencies": {
"@colors/colors": "1.6.0",
"@types/triple-beam": "^1.3.2",
"fecha": "^4.2.0",
"ms": "^2.1.1",
"safe-stable-stringify": "^2.3.1",
"triple-beam": "^1.3.0"
},
"engines": {
"node": ">= 12.0.0"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -631,6 +1042,28 @@
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@ -646,6 +1079,54 @@
"node": ">= 0.6"
}
},
"node_modules/node-cron": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-4.2.1.tgz",
"integrity": "sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg==",
"license": "ISC",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/nodemon": {
"version": "3.1.11",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz",
"integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"chokidar": "^3.5.2",
"debug": "^4",
"ignore-by-default": "^1.0.1",
"minimatch": "^3.1.2",
"pstree.remy": "^1.1.8",
"semver": "^7.5.3",
"simple-update-notifier": "^2.0.0",
"supports-color": "^5.5.0",
"touch": "^3.1.0",
"undefsafe": "^2.0.5"
},
"bin": {
"nodemon": "bin/nodemon.js"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/nodemon"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@ -655,6 +1136,15 @@
"node": ">=0.10.0"
}
},
"node_modules/object-hash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
"license": "MIT",
"engines": {
"node": ">= 6"
}
},
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
@ -688,6 +1178,15 @@
"wrappy": "1"
}
},
"node_modules/one-time": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
"integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
"license": "MIT",
"dependencies": {
"fn.name": "1.x.x"
}
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@ -697,6 +1196,16 @@
"node": ">= 0.8"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/path-to-regexp": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
@ -707,6 +1216,19 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@ -726,6 +1248,13 @@
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/pstree.remy": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
"dev": true,
"license": "MIT"
},
"node_modules/qs": {
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
@ -781,6 +1310,33 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/router": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
@ -817,12 +1373,34 @@
],
"license": "MIT"
},
"node_modules/safe-stable-stringify": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
"integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
"node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/send": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
@ -866,6 +1444,29 @@
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"license": "ISC"
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/side-channel": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
@ -938,6 +1539,28 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/simple-update-notifier": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
"integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
"dev": true,
"license": "MIT",
"dependencies": {
"semver": "^7.5.3"
},
"engines": {
"node": ">=10"
}
},
"node_modules/stack-trace": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/statuses": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
@ -947,6 +1570,47 @@
"node": ">= 0.8"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/text-hex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
"license": "MIT"
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@ -956,6 +1620,25 @@
"node": ">=0.6"
}
},
"node_modules/touch": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
"dev": true,
"license": "ISC",
"bin": {
"nodetouch": "bin/nodetouch.js"
}
},
"node_modules/triple-beam": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
"integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
"license": "MIT",
"engines": {
"node": ">= 14.0.0"
}
},
"node_modules/type-is": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
@ -970,6 +1653,13 @@
"node": ">= 0.6"
}
},
"node_modules/undefsafe": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
"dev": true,
"license": "MIT"
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@ -979,6 +1669,12 @@
"node": ">= 0.8"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@ -988,6 +1684,77 @@
"node": ">= 0.8"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"node-which": "bin/node-which"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/winston": {
"version": "3.18.3",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.18.3.tgz",
"integrity": "sha512-NoBZauFNNWENgsnC9YpgyYwOVrl2m58PpQ8lNHjV3kosGs7KJ7Npk9pCUE+WJlawVSe8mykWDKWFSVfs3QO9ww==",
"license": "MIT",
"peer": true,
"dependencies": {
"@colors/colors": "^1.6.0",
"@dabh/diagnostics": "^2.0.8",
"async": "^3.2.3",
"is-stream": "^2.0.0",
"logform": "^2.7.0",
"one-time": "^1.0.0",
"readable-stream": "^3.4.0",
"safe-stable-stringify": "^2.3.1",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
"winston-transport": "^4.9.0"
},
"engines": {
"node": ">= 12.0.0"
}
},
"node_modules/winston-daily-rotate-file": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-5.0.0.tgz",
"integrity": "sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw==",
"license": "MIT",
"dependencies": {
"file-stream-rotator": "^0.6.1",
"object-hash": "^3.0.0",
"triple-beam": "^1.4.1",
"winston-transport": "^4.7.0"
},
"engines": {
"node": ">=8"
},
"peerDependencies": {
"winston": "^3"
}
},
"node_modules/winston-transport": {
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
"integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
"license": "MIT",
"dependencies": {
"logform": "^2.7.0",
"readable-stream": "^3.6.2",
"triple-beam": "^1.3.0"
},
"engines": {
"node": ">= 12.0.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",

View File

@ -1,10 +1,13 @@
{
"name": "sothiscontratacaoapi",
"name": "node-clean-architecture-starter",
"version": "1.0.0",
"main": "server.js",
"main": "src/app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
"start:api": "cross-env NODE_ENV=production node src/app.js",
"dev:api": "cross-env NODE_ENV=development nodemon src/app.js",
"start:worker": "cross-env NODE_ENV=production node src/worker.js",
"dev:worker": "cross-env NODE_ENV=development nodemon src/worker.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
@ -13,12 +16,20 @@
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"description": "A robust and scalable Node.js project starter based on Clean Architecture principles.",
"dependencies": {
"axios": "^1.6.0",
"cors": "^2.8.5",
"dotenv": "^17.2.3",
"express": "^5.1.0",
"node-cron": "^4.2.1",
"qs": "^6.11.0",
"axios": "^1.6.0"
"winston": "^3.18.3",
"winston-daily-rotate-file": "^5.0.0"
},
"type": "commonjs",
"devDependencies": {
"cross-env": "^10.1.0",
"nodemon": "^3.1.11"
}
}
}

View File

@ -1,6 +0,0 @@
const app = require('./src/app.js');
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});

View File

@ -1,11 +1,36 @@
// Ponto de entrada para a API
const loadEnv = require('./shared/config/environment.js');
loadEnv();
const express = require('express');
const routes = require('./routes/routes.js');
const cors = require('cors');
const routes = require('./routes/routes.js');
const logger = require('./shared/utils/logger.js');
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.json());
app.use(cors());
app.use(express.json());
app.use('/api', routes);
module.exports = app;
app.listen(PORT, () => {
logger.info(`🚀 Servidor API rodando na porta ${PORT} em modo ${process.env.NODE_ENV}`);
});
/*
DESCRIÇÃO:
Este arquivo é o ponto de entrada principal (entry point) da aplicação. Ele é responsável por inicializar e configurar o servidor Express.
FLUXO:
1. Carrega as variáveis de ambiente a partir do arquivo `.env` utilizando a função `loadEnv`.
2. Importa as dependências necessárias, como o `express` para o servidor, `routes` para o roteamento e `logger` para os logs.
3. Cria uma instância do aplicativo Express.
4. Define a porta do servidor, utilizando a variável de ambiente `PORT` ou o valor padrão `3000`.
5. Configura o middleware `express.json()` para permitir que a API aceite e interprete corpos de requisição no formato JSON.
6. Associa as rotas importadas de `./routes/routes.js` ao prefixo `/api`. Todas as rotas definidas nesse arquivo serão acessíveis a partir de `/api/...`.
7. Inicia o servidor para escutar na porta definida.
8. Registra um log informativo quando o servidor é iniciado com sucesso, indicando a porta e o ambiente de execução (`development`, `production`, etc.).
Este arquivo é o coração da API, orquestrando a configuração inicial e o roteamento de todas as requisições recebidas.
*/

View File

@ -1,34 +0,0 @@
const dotenv = require("dotenv");
dotenv.config();
// Google API Key
const googleApiKey = process.env.GOOGLE_API_KEY;
// Geogrid API Configs
const geogridApiUrl = process.env.GEOGRID_API_URL;
const geogridApiKey = process.env.GEOGRID_API_KEY;
const geogridApiCookie = process.env.GEOGRID_API_COOKIE;
// Hubsoft API Configs
const hubsoftUrl = process.env.HUBSOFT_URL;
const hubsoftAuthUrl = `${process.env.HUBSOFT_URL}oauth/token`;
const hubsoftClientId = process.env.HUBSOFT_CLIENT_ID;
const hubsoftClientSecret = process.env.HUBSOFT_CLIENT_SECRET;
const hubsoftUsername = process.env.HUBSOFT_USERNAME;
const hubsoftPassword = process.env.HUBSOFT_PASSWORD;
const hubsoftGrantType = process.env.HUBSOFT_GRANT_TYPE;
module.exports = {
googleApiKey: googleApiKey,
geogridApiUrl: geogridApiUrl,
geogridApiKey: geogridApiKey,
geogridApiCookie: geogridApiCookie,
hubsoftUrl: hubsoftUrl,
hubsoftAuthUrl: hubsoftAuthUrl,
hubsoftClientId: hubsoftClientId,
hubsoftClientSecret: hubsoftClientSecret,
hubsoftUsername: hubsoftUsername,
hubsoftPassword: hubsoftPassword,
hubsoftGrantType: hubsoftGrantType
};

View File

@ -1,96 +0,0 @@
const geogridService = require("../services/geogridService.js");
const googleService = require("../services/googleService.js");
const cepRestService = require("../services/cepRestService.js");
const hubsoftService = require("../services/hubsoftService.js");
async function handleViabilidade(req, res) {
const rawCep = req.body.cep;
const rawNumero = req.body.numero;
try {
if (!rawCep && !rawNumero) return res.status(400).json({ error: 'cep e número são obrigatórios' });
if (!rawCep) return res.status(400).json({ error: 'cep é obrigatório' });
if (!rawNumero) return res.status(400).json({ error: 'número é obrigatório' });
// Consulta o endereço completo usando o serviço de CEP
const address = await cepRestService.getConsultaCep(rawCep, rawNumero);
if (!address) return res.status(404).json({ error: 'Endereço não encontrado para o CEP fornecido' });
const city = address.data[`cep:${rawCep}`].localidade;
const state = address.data[`cep:${rawCep}`].uf;
const numero = rawNumero;
const addressString = `${address.data[`cep:${rawCep}`].logradouro}, ${numero}, ${address.data[`cep:${rawCep}`].bairro}, ${city}, ${state}, ${address.data[`cep:${rawCep}`].cep}`;
// Obtém as coordenadas usando o serviço do Google
const coords = await googleService.geocodeWithGoogle(addressString);
if (!coords) return res.status(500).json({ error: 'Não foi possível obter as coordenadas do endereço' });
// Consulta a viabilidade no geogridService
const viabilidade = await geogridService.consultaViabilidade(coords.lat, coords.lon);
let naoDedicado;
let dedicado;
// Lógica para determinar os valores de naoDedicado e dedicado com base na distância
if (viabilidade.data) {
const distancia = viabilidade.data.distancia;
if (distancia <= 500) {
naoDedicado = true;
dedicado = true;
} else if (distancia <= 1000) {
naoDedicado = true;
dedicado = false;
} else {
naoDedicado = false;
dedicado = false;
} } else {
naoDedicado = false;
dedicado = false;
}
// Retorna a resposta com os dados necessários
return res.json({
bairro: address.data[`cep:${rawCep}`].bairro,
cidade: city,
estado: state,
logradouro: address.data[`cep:${rawCep}`].logradouro,
naoDedicado,
dedicado,
});
} catch (error) {
console.error("Erro ao processar a viabilidade:", error);
return res.status(500).json({ error: "Erro ao processar a viabilidade" });
}
}
async function handleCriarProspecto(req, res) {
const prospectData = req.body;
console.log("Dados recebidos para criação de prospecto:", prospectData);
try {
const resultado = await hubsoftService.criarProspectHubsoft(prospectData);
return res.json({ message: 'Prospecto criado com sucesso', data: resultado });
} catch (error) {
console.error("Erro ao criar prospecto:", error);
return res.status(500).json({ error: "Erro ao criar prospecto" });
}
}
// async function handleTeste(req, res) {
// console.log("Rota de teste acessada com sucesso.");
// return res.json({ message: "Rota de teste funcionando corretamente!" });
// }
module.exports = {
handleViabilidade,
handleCriarProspecto
};

View File

@ -0,0 +1,56 @@
const contratacaoService = require('./contratacao.service.js');
async function handleViabilidade(req, res) {
const { cep, numero } = req.body;
try {
const resultadoViabilidade = await contratacaoService.verificarViabilidade(cep, numero);
return res.json(resultadoViabilidade);
} catch (error) {
console.error("Erro no controller ao processar viabilidade:", error.message);
const statusCode = error.statusCode || 500;
return res.status(statusCode).json({ error: error.message || "Erro interno ao processar a viabilidade." });
}
}
async function handleCriarProspecto(req, res) {
const prospectData = req.body;
try {
const resultado = await contratacaoService.criarProspecto(prospectData);
return res.json({ message: 'Prospecto criado com sucesso', data: resultado });
} catch (error) {
console.error("Erro no controller ao criar prospecto:", error.message);
const statusCode = error.statusCode || 500;
return res.status(statusCode).json({ error: error.message || "Erro interno ao criar o prospecto." });
}
}
module.exports = {
handleViabilidade,
handleCriarProspecto
};
/*
DESCRIÇÃO:
Este arquivo é o "Controller" do módulo de contratação. Ele atua como a camada intermediária que conecta as rotas da API com a lógica de negócio (serviços). Sua principal responsabilidade é receber as requisições HTTP, extrair os dados necessários (do corpo, parâmetros, etc.), chamar o serviço correspondente e formatar a resposta a ser enviada de volta ao cliente.
FUNÇÕES:
- handleViabilidade:
1. É acionado por uma rota (ex: POST /api/contratacao/viabilidade).
2. Extrai `cep` e `numero` do corpo da requisição (`req.body`).
3. Chama a função `verificarViabilidade` do `contratacao.service`, passando os dados recebidos.
4. Se a verificação for bem-sucedida, retorna o resultado como um JSON com status 200.
5. Se ocorrer um erro (lançado pelo serviço), captura o erro, loga a mensagem e retorna uma resposta de erro em JSON com o `statusCode` apropriado (ex: 400, 404, 500).
- handleCriarProspecto:
1. É acionado por uma rota (ex: POST /api/contratacao/prospecto).
2. Pega todos os dados do corpo da requisição (`req.body`), que representam os dados do prospecto.
3. Chama a função `criarProspecto` do `contratacao.service`.
4. Se a criação for bem-sucedida, retorna uma mensagem de sucesso com os dados do resultado.
5. Em caso de erro, segue um fluxo de tratamento de erro similar ao `handleViabilidade`.
Este controller garante que a lógica de negócio permaneça desacoplada do Express, focando apenas na orquestração do fluxo da requisição e resposta.
*/

View File

@ -0,0 +1,13 @@
/*
DESCRIÇÃO:
Este arquivo é destinado a definir o "Model" ou o esquema de dados para o módulo de contratação.
FLUXO:
- Em uma arquitetura com banco de dados, este arquivo normalmente conteria a definição de um modelo de dados usando um ORM (Object-Relational Mapper) como Sequelize (para SQL) ou Mongoose (para MongoDB).
- O modelo definiria os campos, tipos de dados, validações e relacionamentos para a entidade "contratação" ou "prospecto".
- Por exemplo, poderia definir que um prospecto deve ter campos como `nome` (String, obrigatório), `email` (String, formato de email), `cep` (String), etc.
- Este modelo seria então utilizado pelo `contratacao.repository.js` para realizar operações de CRUD (Create, Read, Update, Delete) no banco de dados de forma estruturada e segura.
ESTADO ATUAL:
Atualmente, o arquivo está como um placeholder e não contém uma implementação de modelo. A lógica de negócio não depende de uma estrutura de dados formalmente definida aqui.
*/

View File

@ -0,0 +1,18 @@
/*
DESCRIÇÃO:
Este arquivo implementa o padrão de "Repository" (Repositório) para o módulo de contratação. A camada de repositório é responsável por toda a comunicação com a fonte de dados, que geralmente é um banco de dados.
FLUXO:
1. Seria chamado pelo `contratacao.service.js` para persistir ou recuperar dados.
2. Utilizaria o `contratacao.model.js` para interagir com o banco de dados de forma estruturada. Por exemplo, usaria um modelo Sequelize ou Mongoose para executar queries.
3. Conteria métodos para operações de CRUD (Create, Read, Update, Delete), como:
- `create(prospectData)`: Para salvar um novo prospecto no banco de dados.
- `findById(id)`: Para buscar um prospecto pelo seu ID.
- `findAll()`: Para listar todos os prospectos.
- `update(id, newData)`: Para atualizar os dados de um prospecto.
- `delete(id)`: Para remover um prospecto.
4. Abstrairia os detalhes de implementação do banco de dados, permitindo que o serviço solicite os dados sem se preocupar em como eles são armazenados ou recuperados.
ESTADO ATUAL:
Atualmente, o arquivo é um placeholder. Como a lógica atual da aplicação se baseia em chamadas a APIs externas (Hubsoft) e não em um banco de dados local para prospectos, este repositório não tem uma implementação ativa. Se a aplicação precisasse armazenar dados localmente, este arquivo seria implementado.
*/

View File

@ -0,0 +1,96 @@
const geogridService = require("../../shared/apis/geogridService.js");
const googleService = require("../../shared/apis/googleService.js");
const cepRestService = require("../../shared/apis/cepRestService.js");
const hubsoftService = require("../../shared/apis/hubsoftService.js");
class ServiceError extends Error {
constructor(message, statusCode = 500) {
super(message);
this.name = 'ServiceError';
this.statusCode = statusCode;
}
}
async function verificarViabilidade(rawCep, rawNumero) {
if (!rawCep || !rawNumero) {
throw new ServiceError('CEP e número são obrigatórios.', 400);
}
const address = await cepRestService.getConsultaCep(rawCep, rawNumero);
if (!address || !address.success || !address.data) {
throw new ServiceError('Endereço não encontrado para o CEP fornecido.', 404);
}
const { logradouro, bairro, localidade: city, uf: state, cep } = address.data;
const addressString = `${logradouro}, ${rawNumero}, ${bairro}, ${city}, ${state}, ${cep}`;
const coords = await googleService.geocodeWithGoogle(addressString);
if (!coords) {
throw new ServiceError('Não foi possível obter as coordenadas do endereço.', 500);
}
const viabilidade = await geogridService.consultaViabilidade(coords.lat, coords.lon);
let naoDedicado = false;
let dedicado = false;
if (viabilidade.data) {
const distancia = viabilidade.data.distancia;
if (distancia <= 500) {
naoDedicado = true;
dedicado = true;
} else if (distancia <= 1000) {
naoDedicado = true;
dedicado = false;
}
}
return {
bairro,
cidade: city,
estado: state,
logradouro,
naoDedicado,
dedicado,
};
}
async function criarProspecto(prospectData) {
try {
console.log("Service: Dados recebidos para criação de prospecto:", prospectData);
const resultado = await hubsoftService.criarProspectHubsoft(prospectData);
return resultado;
} catch (error) {
throw new ServiceError(error.message || 'Erro ao comunicar com o serviço de prospectos.', 500);
}
}
module.exports = {
verificarViabilidade,
criarProspecto
};
/*
DESCRIÇÃO:
Este arquivo é a camada de "Serviço" para o módulo de contratação. Ele contém a lógica de negócio principal da aplicação, orquestrando chamadas a diferentes APIs externas e processando os dados para atender às solicitações do `contratacao.controller.js`.
A classe `ServiceError` é uma classe de erro personalizada para permitir que os serviços lancem exceções com `status codes` HTTP específicos, que podem ser capturados e tratados pelo controller.
FUNÇÕES:
- verificarViabilidade(rawCep, rawNumero):
1. É chamado pelo `contratacao.controller.js` com o CEP e o número do endereço.
2. Valida se o CEP e o número foram fornecidos, lançando um `ServiceError` (400) se não forem.
3. Chama o `cepRestService` para obter os dados do endereço a partir do CEP. Se não encontrar, lança um `ServiceError` (404).
4. Monta uma string de endereço completo e a utiliza para obter as coordenadas geográficas (latitude e longitude) através do `googleService`. Lança um erro (500) se não conseguir obter as coordenadas.
5. Com as coordenadas, chama o `geogridService` para consultar a viabilidade do serviço, que retorna a distância de um ponto de presença.
6. Com base na distância retornada pelo GeoGrid, define as flags `naoDedicado` e `dedicado` (ex: se a distância for menor que 500m, ambos são `true`).
7. Retorna um objeto contendo os dados do endereço e as flags de viabilidade para o controller.
- criarProspecto(prospectData):
1. Recebe os dados do prospecto do `contratacao.controller.js`.
2. Chama o `hubsoftService` para criar o prospecto no sistema Hubsoft.
3. Retorna o resultado da criação.
4. Em caso de erro na comunicação com o Hubsoft, lança um `ServiceError` (500).
Este serviço é o cérebro do módulo, conectando múltiplas fontes de dados externas para fornecer uma resposta unificada sobre a viabilidade e para registrar novos clientes.
*/

View File

@ -1,14 +1,35 @@
const express = require('express');
const router = express.Router();
const controller = require('../controllers/controller.js');
const contratacaoController = require('../modules/contratacao/contratacao.controller.js');
// Rota para consulta de viabilidade
router.post('/viabilidade', controller.handleViabilidade);
router.post('/viabilidade', contratacaoController.handleViabilidade);
// Rota para criação de prospecto no Hubsoft
router.post('/prospecto', controller.handleCriarProspecto);
router.post('/prospecto', contratacaoController.handleCriarProspecto);
// router.post('/teste', controller.handleTeste);
module.exports = router;
module.exports = router;
/*
DESCRIÇÃO:
Este arquivo é o roteador principal da aplicação. Ele é responsável por definir todos os endpoints (URLs) da API e associar cada um a uma função específica do controller correspondente.
FLUXO:
1. Este arquivo é carregado pelo `app.js`, que monta este roteador sob o prefixo `/api`. Isso significa que todas as rotas definidas aqui serão acessíveis a partir de `/api/...`.
2. Ele importa o `contratacao.controller.js`, que contém a lógica para manipular as requisições.
3. Define as seguintes rotas:
- `POST /viabilidade`:
- Quando uma requisição POST é feita para `/api/viabilidade`, o Express direciona a chamada para a função `handleViabilidade` no `contratacaoController`.
- Esta rota é usada para verificar a viabilidade de um serviço em um determinado endereço.
- `POST /prospecto`:
- Quando uma requisição POST é feita para `/api/prospecto`, a chamada é direcionada para a função `handleCriarProspecto` no `contratacaoController`.
- Esta rota é usada para criar um novo cliente potencial (prospecto) no sistema.
4. Finalmente, o objeto `router` configurado é exportado para ser usado pelo `app.js`.
Este arquivo centraliza a definição de todas as rotas da API, mantendo o código organizado e facilitando a visualização de todos os endpoints disponíveis.
*/

View File

@ -1,40 +0,0 @@
const apiConfig = require("../config/apiConfig.js")
const axios = require("axios");
// Geocodifica um endereço usando a API do Google Maps
async function geocodeWithGoogle(address) {
const key = apiConfig.googleApiKey;
if (!key) return null;
try {
const url = 'https://maps.googleapis.com/maps/api/geocode/json';
const r = await axios.get(url, {
params: { address, key },
timeout: 10000,
});
// Valida a resposta e extrai as coordenadas
if (!r || r.status !== 200) {
console.warn(`geocodeWithGoogle unexpected status for '${address}': ${r && r.status}`);
return null;
}
// Verifica se há resultados válidos
if (r.data && Array.isArray(r.data.results) && r.data.results.length > 0) {
const loc = r.data.results[0].geometry && r.data.results[0].geometry.location;
const lat = loc && (loc.lat !== undefined ? Number(loc.lat) : NaN);
const lng = loc && (loc.lng !== undefined ? Number(loc.lng) : NaN);
if (!Number.isNaN(lat) && !Number.isNaN(lng)) {
return { lat, lon: lng };
}
}
return null;
} catch (e) {
console.warn(`geocodeWithGoogle error for '${address}': ${e && e.message}`, e && e.stack);
return null;
}
}
module.exports = { geocodeWithGoogle };

View File

@ -32,4 +32,22 @@ const getConsultaCep = async (rawCep, rawNumero) => {
}
};
module.exports = { getConsultaCep };
module.exports = { getConsultaCep };
/*
DESCRIÇÃO:
Este arquivo define um serviço para consultar endereços a partir de um CEP.
FLUXO:
1. É chamado principalmente pelo `contratacao.service.js`.
2. Recebe um CEP e um número.
3. Formata e valida o CEP.
4. Realiza uma requisição POST para a API externa `https://api.cep.rest/`.
5. Trata a resposta da API:
- Se o CEP não for encontrado (código 404), retorna `null`.
- Se houver outro erro na API, lança uma exceção.
- Se for bem-sucedido, anexa o número ao objeto de dados e retorna os dados do endereço.
6. Em caso de erro na comunicação, loga o erro e lança uma exceção genérica.
Este serviço abstrai a complexidade da comunicação com a API de CEP, fornecendo uma interface simples para outras partes da aplicação obterem dados de endereço.
*/

View File

@ -47,3 +47,27 @@ const consultaViabilidade = async (lat, lon) => {
};
module.exports = { consultaViabilidade };
/*
DESCRIÇÃO:
Este arquivo define um serviço para consultar a API "GeoGrid", que parece ser um sistema de geolocalização para verificar a viabilidade de serviço em um determinado local.
FLUXO:
1. É chamado pelo `contratacao.service.js`, recebendo coordenadas de latitude e longitude.
2. Busca as credenciais da API (URL, chave e cookie) a partir do `apiConfig`.
3. Monta um objeto de parâmetros para a requisição GET, incluindo:
- `raio`: um raio de busca de 5000 metros.
- `latitude` e `longitude`: as coordenadas do ponto de consulta.
- `itens[]`: especifica o que procurar (neste caso, "caixa").
- Parâmetros de ordenação e consulta.
4. Utiliza a biblioteca `qs` para serializar os parâmetros corretamente, especialmente o array `itens[]`.
5. Loga no console um comando `curl` equivalente, o que é uma excelente prática para depuração, permitindo replicar a requisição fora da aplicação.
6. Executa a requisição GET para a URL do GeoGrid usando `axios`, passando os parâmetros e os cabeçalhos de autenticação (`api-key` and `Cookie`).
7. Processa a resposta:
- Extrai o array `registros` da resposta.
- Pega apenas o primeiro item desse array.
- Retorna o primeiro registro encontrado, encapsulado em um objeto `{ data: primeiro }` para manter consistência com o que o `contratacao.service` espera (`viabilidade.data`).
8. Em caso de erro na requisição, loga a mensagem de erro e lança uma exceção.
Este serviço abstrai a interação com a API GeoGrid, expondo uma função simples (`consultaViabilidade`) para o resto da aplicação.
*/

View File

@ -0,0 +1,61 @@
const apiConfig = require("../config/apiConfig.js")
const axios = require("axios");
// Geocodifica um endereço usando a API do Google Maps
async function geocodeWithGoogle(address) {
const key = apiConfig.googleApiKey;
if (!key) return null;
try {
const url = 'https://maps.googleapis.com/maps/api/geocode/json';
const r = await axios.get(url, {
params: { address, key },
timeout: 10000,
});
// Valida a resposta e extrai as coordenadas
if (!r || r.status !== 200) {
console.warn(`geocodeWithGoogle unexpected status for '${address}': ${r && r.status}`);
return null;
}
// Verifica se há resultados válidos
if (r.data && Array.isArray(r.data.results) && r.data.results.length > 0) {
const loc = r.data.results[0].geometry && r.data.results[0].geometry.location;
const lat = loc && (loc.lat !== undefined ? Number(loc.lat) : NaN);
const lng = loc && (loc.lng !== undefined ? Number(loc.lng) : NaN);
if (!Number.isNaN(lat) && !Number.isNaN(lng)) {
return { lat, lon: lng };
}
}
return null;
} catch (e) {
console.warn(`geocodeWithGoogle error for '${address}': ${e && e.message}`, e && e.stack);
return null;
}
}
module.exports = { geocodeWithGoogle };
/*
DESCRIÇÃO:
Este arquivo define um serviço para interagir com a API de Geocodificação do Google Maps. Sua função é converter um endereço em formato de texto (string) para um par de coordenadas geográficas (latitude e longitude).
FLUXO:
1. É chamado pelo `contratacao.service.js`, recebendo uma string de endereço.
2. Obtém a chave da API do Google a partir do `apiConfig`. Se a chave não estiver configurada, a função retorna `null` imediatamente para evitar erros.
3. Define a URL da API de Geocodificação do Google.
4. Executa uma requisição GET usando `axios`, passando o endereço e a chave da API como parâmetros. Define um `timeout` de 10 segundos para evitar que a aplicação fique presa em requisições demoradas.
5. Realiza uma validação rigorosa da resposta:
- Verifica se a resposta foi recebida e se o status HTTP é 200.
- Verifica se o corpo da resposta (`r.data`) contém um array de `results` com pelo menos um item.
- Acessa a geometria do primeiro resultado para obter o objeto `location`.
- Extrai `lat` e `lng` do objeto de localização, convertendo-os para números.
- Se `lat` e `lng` forem números válidos, retorna um objeto no formato `{ lat, lon: lng }`. O `lon` é renomeado para se alinhar com o que o `geogridService` espera.
6. Se qualquer uma das validações falhar, a função retorna `null`, indicando que a geocodificação não foi bem-sucedida.
7. Em caso de erro na requisição (ex: timeout, erro de rede), o erro é capturado, uma mensagem de aviso é logada no console, e a função retorna `null`.
Este serviço é um componente crucial para a verificação de viabilidade, pois traduz um endereço textual em coordenadas precisas que podem ser usadas por outros serviços de geolocalização como o GeoGrid.
*/

View File

@ -65,3 +65,30 @@ const criarProspectHubsoft = async (prospectData) => {
}
module.exports = { criarProspectHubsoft };
/*
DESCRIÇÃO:
Este arquivo contém os serviços para interagir com a API do Hubsoft, um sistema de gestão. As funções aqui são responsáveis pela autenticação e pela criação de "prospectos" (clientes potenciais).
FUNÇÕES:
- hubsoftToken():
1. É uma função interna, não exportada, usada para obter um token de autenticação OAuth 2.0.
2. Busca as credenciais do Hubsoft (client_id, client_secret, username, password, etc.) a partir do `apiConfig`.
3. Monta o corpo da requisição de autenticação.
4. Usa a biblioteca `qs` para serializar o corpo no formato `application/x-www-form-urlencoded`, que é o padrão para fluxos OAuth.
5. Realiza uma requisição POST para a URL de autenticação do Hubsoft.
6. Se a autenticação for bem-sucedida, extrai e retorna o `access_token` da resposta.
7. Em caso de erro, loga a resposta de erro do Hubsoft (se disponível) e lança uma exceção.
- criarProspectHubsoft(prospectData):
1. É a função principal exportada, chamada pelo `contratacao.service.js`.
2. Primeiro, chama a função `hubsoftToken()` para obter um token de acesso válido.
3. Monta o `payload` (corpo da requisição) para a criação do prospecto, mapeando os dados recebidos (`prospectData`) para o formato esperado pela API do Hubsoft.
4. Realiza uma requisição POST para o endpoint de criação de prospecto do Hubsoft (`/api/v1/integracao/prospecto`).
5. Inclui o token de acesso no cabeçalho `Authorization` como um "Bearer token".
6. Define o `Content-Type` como `application/json` para enviar o payload.
7. Se a criação for bem-sucedida, loga a resposta e a retorna para o serviço.
8. Em caso de erro (ex: token inválido, dados do prospecto incorretos), loga o erro e lança uma exceção.
Este serviço encapsula toda a complexidade da comunicação com a API do Hubsoft, desde a autenticação até a criação de registros.
*/

View File

@ -0,0 +1,52 @@
const dotenv = require("dotenv");
dotenv.config();
// Google API Key
const googleApiKey = process.env.GOOGLE_API_KEY;
// Geogrid API Configs
const geogridApiUrl = process.env.GEOGRID_API_URL;
const geogridApiKey = process.env.GEOGRID_API_KEY;
const geogridApiCookie = process.env.GEOGRID_API_COOKIE;
// Hubsoft API Configs
const hubsoftUrl = process.env.HUBSOFT_URL;
const hubsoftAuthUrl = `${process.env.HUBSOFT_URL}oauth/token`;
const hubsoftClientId = process.env.HUBSOFT_CLIENT_ID;
const hubsoftClientSecret = process.env.HUBSOFT_CLIENT_SECRET;
const hubsoftUsername = process.env.HUBSOFT_USERNAME;
const hubsoftPassword = process.env.HUBSOFT_PASSWORD;
const hubsoftGrantType = process.env.HUBSOFT_GRANT_TYPE;
module.exports = {
googleApiKey: googleApiKey,
geogridApiUrl: geogridApiUrl,
geogridApiKey: geogridApiKey,
geogridApiCookie: geogridApiCookie,
hubsoftUrl: hubsoftUrl,
hubsoftAuthUrl: hubsoftAuthUrl,
hubsoftClientId: hubsoftClientId,
hubsoftClientSecret: hubsoftClientSecret,
hubsoftUsername: hubsoftUsername,
hubsoftPassword: hubsoftPassword,
hubsoftGrantType: hubsoftGrantType
};
/*
DESCRIÇÃO:
Este arquivo é o ponto central de configuração para todas as APIs externas utilizadas pela aplicação. Ele é responsável por carregar as variáveis de ambiente (a partir de um arquivo `.env`) e exportá-las em um único objeto para serem consumidas por outros módulos, principalmente os serviços em `src/shared/apis/`.
FLUXO:
1. Utiliza o pacote `dotenv` para carregar as variáveis definidas em um arquivo `.env` no diretório raiz do projeto para dentro do `process.env` do Node.js.
2. as variáveis de ambiente específicas para cada API:
- `GOOGLE_API_KEY` para a API do Google.
- `GEOGRID_API_URL`, `GEOGRID_API_KEY`, `GEOGRID_API_COOKIE` para a API do GeoGrid.
- `HUBSOFT_URL`, `HUBSOFT_CLIENT_ID`, `HUBSOFT_CLIENT_SECRET`, etc., para a API do Hubsoft.
3. A URL de autenticação do Hubsoft (`hubsoftAuthUrl`) é construída dinamicamente a partir da URL base.
4. Exporta um objeto contendo todas essas variáveis, fornecendo um acesso limpo e centralizado para outras partes do código.
OBJETIVO:
- **Centralização:** Manter todas as chaves de API e URLs em um lugar, facilitando a manutenção.
- **Segurança:** Abstrair o acesso direto ao `process.env` e evitar que segredos (como API keys) sejam espalhados por todo o código. Ao usar variáveis de ambiente, o código pode ser compartilhado em repositórios de forma segura, sem expor as credenciais, que permanecem apenas no arquivo local `.env` (que não deve ser versionado).
*/

View File

@ -0,0 +1,36 @@
const path = require('path');
const dotenv = require('dotenv');
function loadEnv() {
// Define 'development' como padrão se NODE_ENV não estiver setado
const nodeEnv = process.env.NODE_ENV || 'development';
const envFile = `.env.${nodeEnv}`;
const envPath = path.resolve(process.cwd(), envFile);
const result = dotenv.config({ path: envPath });
if (result.error) {
console.warn(`Atenção: Não foi possível carregar o arquivo ${envFile}. Certifique-se de que ele existe.`);
}
}
module.exports = loadEnv;
/*
DESCRIÇÃO:
Este arquivo é responsável por carregar variáveis de ambiente de arquivos `.env` específicos para cada ambiente de execução (development, production, test, etc.). Isso permite que a aplicação tenha configurações diferentes dependendo de onde está rodando.
FLUXO:
1. Exporta uma única função, `loadEnv`.
2. Esta função é chamada no início do ciclo de vida da aplicação, dentro do `app.js`.
3. A função `loadEnv` verifica a variável de ambiente `process.env.NODE_ENV`. Se não estiver definida, assume `'development'` como padrão.
4. Com base no ambiente (`nodeEnv`), ele constrói o nome do arquivo de configuração esperado (ex: `.env.development`).
5. Usa o `path.resolve` para criar o caminho absoluto para esse arquivo, garantindo que ele seja encontrado corretamente a partir do diretório raiz do projeto.
6. Chama `dotenv.config({ path: envPath })` para carregar as variáveis do arquivo `.env` específico para o `process.env`.
7. Se o arquivo `.env` específico do ambiente não for encontrado, `dotenv.config` retorna um erro. O código captura isso e exibe um aviso (`console.warn`) em vez de quebrar a aplicação, o que é uma abordagem robusta.
OBJETIVO:
- Permitir configurações diferentes para desenvolvimento e produção (e outros ambientes). Por exemplo, a URL do banco de dados ou as chaves de API podem ser diferentes.
- Manter a configuração do ambiente separada da lógica principal, tornando o código mais limpo e portável.
- Centralizar a lógica de carregamento de ambiente em um único local.
*/

View File

@ -0,0 +1,88 @@
const winston = require('winston');
const path = require('path');
require('winston-daily-rotate-file');
// O diretório de logs é criado pelo script de inicialização, mas garantimos aqui também.
const logsDir = path.resolve(process.cwd(), 'logs');
// Configuração do logger com winston
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss'
}),
winston.format.errors({ stack: true }), // Mostra stack trace de erros
winston.format.json()
),
transports: [
// Log geral da aplicação
new winston.transports.DailyRotateFile({
filename: path.join(logsDir, 'app-%DATE%.log'),
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '5m',
maxFiles: '10d',
}),
// Log de erros
new winston.transports.DailyRotateFile({
filename: path.join(logsDir, 'error-%DATE%.log'),
level: 'error',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '5m',
maxFiles: '10d',
})
],
});
// Log no console em desenvolvimento
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.printf((info) => {
const { timestamp, level, message, stack, ...meta } = info;
let logMessage = `${timestamp} [${level}]: ${stack || message}`;
if (Object.keys(meta).length) {
logMessage += ` ${JSON.stringify(meta, null, 2)}`;
}
return logMessage;
})
)
}));
}
module.exports = logger;
/*
DESCRIÇÃO:
Este arquivo configura e exporta uma instância de logger centralizada para toda a aplicação, utilizando a biblioteca `winston`. O objetivo é ter um sistema de logging robusto, que armazena logs em arquivos e se comporta de maneira diferente em ambientes de desenvolvimento e produção.
FLUXO E CONFIGURAÇÃO:
1. Importa as bibliotecas `winston` e `winston-daily-rotate-file`. A segunda é uma extensão para rotacionar arquivos de log automaticamente (por data, tamanho, etc.).
2. Define o diretório de logs (`logs/`) na raiz do projeto.
3. Cria a instância do logger com `winston.createLogger()`:
- `level: 'info'`: Define o nível mínimo de log a ser registrado. Logs com severidade menor (como `debug` ou `verbose`) serão ignorados.
- `format`: Define o formato das mensagens de log.
- `timestamp`: Adiciona um timestamp a cada log.
- `errors({ stack: true })`: Garante que, ao logar um objeto de erro, sua stack trace seja incluída.
- `json()`: Formata a saída do log como JSON, o que é ideal para parseamento por sistemas de monitoramento.
4. Configura os "Transports" (saídas de log):
- **DailyRotateFile (app)**:
- Salva todos os logs de nível `info` e acima em arquivos diários (ex: `app-2023-10-27.log`).
- `zippedArchive: true`: Compacta os arquivos de log antigos.
- `maxSize: '5m'`: Rotaciona o arquivo se ele atingir 5MB.
- `maxFiles: '10d'`: Mantém os logs dos últimos 10 dias.
- **DailyRotateFile (error)**:
- Salva apenas logs de nível `error` em arquivos separados (ex: `error-2023-10-27.log`), facilitando a análise de falhas.
5. **Log de Console (Apenas em Desenvolvimento)**:
- Se a variável `NODE_ENV` não for `'production'`, um transport adicional é adicionado para exibir logs no console.
- O formato para o console é mais amigável para leitura humana, usando `colorize()` para cores e `printf` para um formato de string personalizado que exibe a stack trace de erros de forma legível.
UTILIZAÇÃO:
- Em qualquer outro arquivo, o logger pode ser importado e usado assim:
`const logger = require('./shared/utils/logger');`
`logger.info('Mensagem informativa');`
`logger.error('Ocorreu um erro', new Error('detalhes'));`
*/