From 13b5df541682bbb6eb145d60282e310f42ec1c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:16:58 -0300 Subject: [PATCH 01/60] chore: implement initial structure --- .gitignore | 28 ++++++++++++++++++++++++++++ go.mod | 3 +++ 2 files changed, 31 insertions(+) create mode 100644 .gitignore create mode 100644 go.mod diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4dea56d --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Created by https://www.toptal.com/developers/gitignore/api/go +# Edit at https://www.toptal.com/developers/gitignore?templates=go + +### Go ### +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +# End of https://www.toptal.com/developers/gitignore/api/go +.env \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a22225e --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/jpeccia/go-backend-test + +go 1.23.4 From c6c6f33592aeea90e655d4a7379fb2272f55a7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:19:16 -0300 Subject: [PATCH 02/60] build: install gin framework --- go.mod | 30 ++++++++++++++++++++++ go.sum | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 go.sum diff --git a/go.mod b/go.mod index a22225e..a06deca 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,33 @@ module github.com/jpeccia/go-backend-test go 1.23.4 + +require ( + github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/gin-contrib/sse v1.0.0 // indirect + github.com/gin-gonic/gin v1.10.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.26.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.15.0 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..0e8fcbc --- /dev/null +++ b/go.sum @@ -0,0 +1,78 @@ +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= +github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= +github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= +golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= From 4c923a3075b284c7f17e2a52f3a0da7600da6b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:20:57 -0300 Subject: [PATCH 03/60] build: install gorm --- go.mod | 3 +++ go.sum | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/go.mod b/go.mod index a06deca..7803e38 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,8 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/goccy/go-json v0.10.5 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -30,4 +32,5 @@ require ( golang.org/x/text v0.23.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/gorm v1.25.12 // indirect ) diff --git a/go.sum b/go.sum index 0e8fcbc..6e17a3b 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,10 @@ github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAu github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -74,5 +78,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= From 605018a8f9be66d26a0eac5c32496dcede6cd7e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:21:33 -0300 Subject: [PATCH 04/60] build: install postgres driver --- go.mod | 6 ++++++ go.sum | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/go.mod b/go.mod index 7803e38..3cb1aa2 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,10 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/goccy/go-json v0.10.5 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.4 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -28,9 +32,11 @@ require ( golang.org/x/arch v0.15.0 // indirect golang.org/x/crypto v0.36.0 // indirect golang.org/x/net v0.38.0 // indirect + golang.org/x/sync v0.12.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/text v0.23.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/postgres v1.5.11 // indirect gorm.io/gorm v1.25.12 // indirect ) diff --git a/go.sum b/go.sum index 6e17a3b..fa82e1c 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,14 @@ github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAu github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg= +github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= @@ -67,6 +75,8 @@ golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= @@ -78,6 +88,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= +gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= From 7d8645b893904330c4ed5de8da24205c39aea2cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:22:57 -0300 Subject: [PATCH 05/60] build: install godot env --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index 3cb1aa2..c9b64a6 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/leodido/go-urn v1.4.0 // indirect diff --git a/go.sum b/go.sum index fa82e1c..15574e0 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= From 71415ce9a204ebc24e62f27bec9472caa7cffa9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:25:48 -0300 Subject: [PATCH 06/60] chore: create .env.example --- .env.example | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..9695fda --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +DB_HOST= +DB_USER= +DB_PASS= +DB_NAME= +DB_PORT= \ No newline at end of file From 73f77f1af056caa73d5903d6c544f579172202ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:28:11 -0300 Subject: [PATCH 07/60] feat: create main.go initial structure with gin run and loading env vars --- main.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 main.go diff --git a/main.go b/main.go new file mode 100644 index 0000000..aaecaf7 --- /dev/null +++ b/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "log" + + "github.com/gin-gonic/gin" + "github.com/joho/godotenv" +) + +func main() { + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } + + r := gin.Default() + r.Run(":8080") +} \ No newline at end of file From 42ecb1510d02fa007eb76ebeeafec62a651fc498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:39:03 -0300 Subject: [PATCH 08/60] ops: create a docker-compose file to run db in dev env --- docker-compose.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..325c7d5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +version: "3.8" + +services: + db: + image: postgres:latest + container_name: postgres_competition + restart: always + environment: + POSTGRES_USER: ${DB_USER} + POSTGRES_PASSWORD: ${DB_PASS} + POSTGRES_DB: ${DB_NAME} + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: \ No newline at end of file From 8b771a870da72b5f3c773d1e790cc66685434059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:43:21 -0300 Subject: [PATCH 09/60] feat: create connection database config file --- config/database.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 config/database.go diff --git a/config/database.go b/config/database.go new file mode 100644 index 0000000..778f8df --- /dev/null +++ b/config/database.go @@ -0,0 +1,31 @@ +package config + +import ( + "fmt" + "log" + "os" + + "gorm.io/driver/postgres" + "gorm.io/gorm" +) + +var DB *gorm.DB + +func ConnectDatabase() { + dsn := fmt.Sprintf( + "host=%s user=%s password=%s dbname=%s port=%s sslmode=disable", + os.Getenv("DB_HOST"), + os.Getenv("DB_USER"), + os.Getenv("DB_PASS"), + os.Getenv("DB_NAME"), + os.Getenv("DB_PORT"), + ) + + database, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + log.Fatal("Failed to connect to database:", err) + } + + DB = database + fmt.Println("Database connected successfully") +} From 910341db2999cfa171dc7d40a074c3d9b875c321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:45:10 -0300 Subject: [PATCH 10/60] feat: add ConnectDatabase function starts in main.go --- main.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main.go b/main.go index aaecaf7..a3ff0ac 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "github.com/gin-gonic/gin" "github.com/joho/godotenv" + "github.com/jpeccia/go-backend-test/config" ) func main() { @@ -13,6 +14,8 @@ func main() { log.Fatal("Error loading .env file") } + config.ConnectDatabase() + r := gin.Default() r.Run(":8080") } \ No newline at end of file From 14919b7d412eb02d961cc3b7ec0a951b29cdec6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:45:45 -0300 Subject: [PATCH 11/60] chore: update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4dea56d..acca4bf 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,5 @@ go.work # End of https://www.toptal.com/developers/gitignore/api/go -.env \ No newline at end of file +.env +.air.toml \ No newline at end of file From 592abc35eb5d2aa13dfbe06176f46471f41614f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:50:34 -0300 Subject: [PATCH 12/60] feat: create User Entity Model --- internal/models/user.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 internal/models/user.go diff --git a/internal/models/user.go b/internal/models/user.go new file mode 100644 index 0000000..d42581b --- /dev/null +++ b/internal/models/user.go @@ -0,0 +1,13 @@ +package models + +import "gorm.io/gorm" + +type User struct { + gorm.Model + Name string `json:"name"` + Email string `json:"email"` + PhoneNumber string `json"phone_number"` + ReferralCode string `json:"referral_code" gorm:"unique"` + ReferredBy string `json:"referred_by"` + Points int `json:"points"` +} From f416b5bf0b13f4ba954ac8e461647b1b72f65bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:52:20 -0300 Subject: [PATCH 13/60] style: adding a gorm unique missing in email --- internal/models/user.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/models/user.go b/internal/models/user.go index d42581b..e13a9f9 100644 --- a/internal/models/user.go +++ b/internal/models/user.go @@ -5,8 +5,8 @@ import "gorm.io/gorm" type User struct { gorm.Model Name string `json:"name"` - Email string `json:"email"` - PhoneNumber string `json"phone_number"` + Email string `json:"email" gorm:"unique"` + PhoneNumber string `json:"phone_number"` ReferralCode string `json:"referral_code" gorm:"unique"` ReferredBy string `json:"referred_by"` Points int `json:"points"` From 973c0dc46418df89158752e126ac70212e0b653f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 10:56:54 -0300 Subject: [PATCH 14/60] feat: create RegisterUserDTO to validate data input --- internal/dto/user_dto.go | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 internal/dto/user_dto.go diff --git a/internal/dto/user_dto.go b/internal/dto/user_dto.go new file mode 100644 index 0000000..3aef727 --- /dev/null +++ b/internal/dto/user_dto.go @@ -0,0 +1,8 @@ +package dto + +type RegisterUserDTO struct { + Name string `json:"name" binding:"required"` + Email string `json:"email" binding:"required,email"` + PhoneNumber string `json:"phone_number" binding:"required"` + ReferredBy string `json:"referred_by,omitempty"` +} \ No newline at end of file From f6b95272e283a6f121e9697438aee2f3f5f48023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 11:01:41 -0300 Subject: [PATCH 15/60] feat: create User Repository and Create User e FindUserByEmail functions --- internal/repositories/user_repository.go | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 internal/repositories/user_repository.go diff --git a/internal/repositories/user_repository.go b/internal/repositories/user_repository.go new file mode 100644 index 0000000..778eb06 --- /dev/null +++ b/internal/repositories/user_repository.go @@ -0,0 +1,30 @@ +package repositories + +import ( + "github.com/jpeccia/go-backend-test/internal/models" + "gorm.io/gorm" +) + +type UserRepository interface { + CreateUser(user *models.User) error + FindUserByEmail(email string) (*models.User, error) +} + +type userRepository struct { + db *gorm.DB +} + +func NewUserRepository(db *gorm.DB) UserRepository { + return &userRepository{db} +} + +func (u *userRepository) CreateUser(user *models.User) error { + return u.db.Create(user).Error +} + +func (u *userRepository) FindUserByEmail(email string) (*models.User, error) { + var user models.User + err := u.db.Where("email= ?", email).First(&user).Error + return &user, err +} + From 35bda7dd452da9fd27ab2ddb871d651da0327fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 11:08:59 -0300 Subject: [PATCH 16/60] build: install google uuid --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index c9b64a6..5c8113e 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/goccy/go-json v0.10.5 // indirect + github.com/google/uuid v1.6.0 github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgx/v5 v5.7.4 // indirect diff --git a/go.sum b/go.sum index 15574e0..320f73d 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,8 @@ github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAu github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= From fa17805f33083ffc8cb1eb9fe65aeb01e05adb13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 11:09:58 -0300 Subject: [PATCH 17/60] feat: create User Service and Register User with reference points functions --- internal/services/user_service.go | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 internal/services/user_service.go diff --git a/internal/services/user_service.go b/internal/services/user_service.go new file mode 100644 index 0000000..c20be9f --- /dev/null +++ b/internal/services/user_service.go @@ -0,0 +1,48 @@ +package services + +import ( + "github.com/google/uuid" + "github.com/jpeccia/go-backend-test/internal/dto" + "github.com/jpeccia/go-backend-test/internal/models" + "github.com/jpeccia/go-backend-test/internal/repositories" +) + +type UserService interface { + RegisterUser(dto dto.RegisterUserDTO) (*models.User, error) +} + +type userService struct { + userRepo repositories.UserRepository +} + +func NewUserService(userRepo repositories.UserRepository) UserService { + return &userService{userRepo} +} + +func (u *userService) RegisterUser(dto dto.RegisterUserDTO) (*models.User, error) { + referralCode := uuid.New().String() + + user := models.User{ + Name: dto.Name, + Email: dto.Email, + PhoneNumber: dto.PhoneNumber, + ReferralCode: referralCode, + Points: 1, + } + + if dto.ReferredBy != "" { + referredUser, err := u.userRepo.FindUserByEmail(dto.ReferredBy) + if err == nil { + referredUser.Points++ + u.userRepo.CreateUser(referredUser) + } + } + + err := u.userRepo.CreateUser(&user) + if err != nil { + return nil, err + } + + return &user, nil +} + From 1e39b8ebff5147fd22decb98324bda745a55f289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 11:16:31 -0300 Subject: [PATCH 18/60] feat: create User Handler --- internal/handlers/user_handler.go | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 internal/handlers/user_handler.go diff --git a/internal/handlers/user_handler.go b/internal/handlers/user_handler.go new file mode 100644 index 0000000..bbf5041 --- /dev/null +++ b/internal/handlers/user_handler.go @@ -0,0 +1,36 @@ +package handlers + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/jpeccia/go-backend-test/internal/dto" + "github.com/jpeccia/go-backend-test/internal/services" +) + +type UserHandler struct { + userService services.UserService +} + +func NewUserHandler(userService services.UserService) *UserHandler { + return &UserHandler{userService} +} + +func (u *UserHandler) RegisterUser(c *gin.Context) { + var input dto.RegisterUserDTO + if err := c.ShouldBindJSON(&input); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + user, err := u.userService.RegisterUser(input) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to register user"}) + return + } + + c.JSON(http.StatusCreated, gin.H{ + "message": "User registered successfully", + "referral_code": user.ReferralCode, + }) +} \ No newline at end of file From 3621833c37a484dc7274ffc3b04dcd443ec19504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 11:19:30 -0300 Subject: [PATCH 19/60] feat: create routes and add POST signup to Register User --- internal/routes/routes.go | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 internal/routes/routes.go diff --git a/internal/routes/routes.go b/internal/routes/routes.go new file mode 100644 index 0000000..4071fbd --- /dev/null +++ b/internal/routes/routes.go @@ -0,0 +1,10 @@ +package routes + +import ( + "github.com/gin-gonic/gin" + "github.com/jpeccia/go-backend-test/internal/handlers" +) + +func SetupRoutes(r *gin.Engine, userHandler *handlers.UserHandler) { + r.POST("/signup", userHandler.RegisterUser) +} \ No newline at end of file From 2a2ca42d42007351aad5ba5bf4b44193a3a59435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 11:32:07 -0300 Subject: [PATCH 20/60] feat: add setup routes in main.go --- main.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index a3ff0ac..94ca755 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,10 @@ import ( "github.com/gin-gonic/gin" "github.com/joho/godotenv" "github.com/jpeccia/go-backend-test/config" + "github.com/jpeccia/go-backend-test/internal/handlers" + "github.com/jpeccia/go-backend-test/internal/repositories" + "github.com/jpeccia/go-backend-test/internal/routes" + "github.com/jpeccia/go-backend-test/internal/services" ) func main() { @@ -13,9 +17,15 @@ func main() { if err != nil { log.Fatal("Error loading .env file") } - config.ConnectDatabase() - + r := gin.Default() + + userRepo := repositories.NewUserRepository(config.DB) + userService := services.NewUserService(userRepo) + userHandler := handlers.NewUserHandler(userService) + + routes.SetupRoutes(r, userHandler) + r.Run(":8080") } \ No newline at end of file From 92b25105b6aad91ca09f70a2b7b35e1199e6b2ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 11:37:21 -0300 Subject: [PATCH 21/60] feat: create database migrations --- internal/database/migrations/migrate.go | 21 +++++++++++++++++++++ main.go | 2 ++ 2 files changed, 23 insertions(+) create mode 100644 internal/database/migrations/migrate.go diff --git a/internal/database/migrations/migrate.go b/internal/database/migrations/migrate.go new file mode 100644 index 0000000..40ed003 --- /dev/null +++ b/internal/database/migrations/migrate.go @@ -0,0 +1,21 @@ +package migrations + +import ( + "log" + + "github.com/jpeccia/go-backend-test/config" + "github.com/jpeccia/go-backend-test/internal/models" +) + +func Migrate() { + db := config.DB + + log.Println("Running database migrations...") + + err := db.AutoMigrate(&models.User{}) + if err != nil { + log.Fatalf("Migration failed: %v", err) + } + + log.Println("Database migrated successfully!") +} \ No newline at end of file diff --git a/main.go b/main.go index 94ca755..9fad374 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "github.com/gin-gonic/gin" "github.com/joho/godotenv" "github.com/jpeccia/go-backend-test/config" + "github.com/jpeccia/go-backend-test/internal/database/migrations" "github.com/jpeccia/go-backend-test/internal/handlers" "github.com/jpeccia/go-backend-test/internal/repositories" "github.com/jpeccia/go-backend-test/internal/routes" @@ -18,6 +19,7 @@ func main() { log.Fatal("Error loading .env file") } config.ConnectDatabase() + migrations.Migrate() r := gin.Default() From fbcb62b8a4884dd8de3554700433646a01280d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 11:45:01 -0300 Subject: [PATCH 22/60] feat: add FindUserByReferralCode and UpdateUser functions in UserRepository --- internal/repositories/user_repository.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/repositories/user_repository.go b/internal/repositories/user_repository.go index 778eb06..37d31a6 100644 --- a/internal/repositories/user_repository.go +++ b/internal/repositories/user_repository.go @@ -28,3 +28,12 @@ func (u *userRepository) FindUserByEmail(email string) (*models.User, error) { return &user, err } +func (r *userRepository) FindUserByReferralCode(code string) (*models.User, error) { + var user models.User + err := r.db.Where("referral_code = ?", code).First(&user).Error + return &user, err +} + +func (r *userRepository) UpdateUser(user *models.User) error { + return r.db.Save(user).Error +} From 62b6ab98cb7dbaa813e8db7815b4161d9e1facb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 16:11:21 -0300 Subject: [PATCH 23/60] feat: add function FindUserByReferralCode in interface --- internal/repositories/user_repository.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/repositories/user_repository.go b/internal/repositories/user_repository.go index 37d31a6..234ef8c 100644 --- a/internal/repositories/user_repository.go +++ b/internal/repositories/user_repository.go @@ -8,6 +8,7 @@ import ( type UserRepository interface { CreateUser(user *models.User) error FindUserByEmail(email string) (*models.User, error) + FindUserByReferralCode(code string) (*models.User, error) } type userRepository struct { @@ -28,12 +29,12 @@ func (u *userRepository) FindUserByEmail(email string) (*models.User, error) { return &user, err } -func (r *userRepository) FindUserByReferralCode(code string) (*models.User, error) { +func (u *userRepository) FindUserByReferralCode(code string) (*models.User, error) { var user models.User - err := r.db.Where("referral_code = ?", code).First(&user).Error + err := u.db.Where("referral_code = ?", code).First(&user).Error return &user, err } -func (r *userRepository) UpdateUser(user *models.User) error { - return r.db.Save(user).Error +func (u *userRepository) UpdateUser(user *models.User) error { + return u.db.Save(user).Error } From c228625d59898b8d640003158fc84f7dc33317af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 16:11:52 -0300 Subject: [PATCH 24/60] feat: switch find user by email to find user by referralcode --- internal/services/user_service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/user_service.go b/internal/services/user_service.go index c20be9f..7e0da58 100644 --- a/internal/services/user_service.go +++ b/internal/services/user_service.go @@ -31,7 +31,7 @@ func (u *userService) RegisterUser(dto dto.RegisterUserDTO) (*models.User, error } if dto.ReferredBy != "" { - referredUser, err := u.userRepo.FindUserByEmail(dto.ReferredBy) + referredUser, err := u.userRepo.FindUserByReferralCode(dto.ReferredBy) if err == nil { referredUser.Points++ u.userRepo.CreateUser(referredUser) From e932bf20276e2bc6fdc07c94f808da3318dcc927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 16:13:10 -0300 Subject: [PATCH 25/60] feat: add share link in register response in user handler --- internal/handlers/user_handler.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/handlers/user_handler.go b/internal/handlers/user_handler.go index bbf5041..2b91318 100644 --- a/internal/handlers/user_handler.go +++ b/internal/handlers/user_handler.go @@ -1,6 +1,7 @@ package handlers import ( + "fmt" "net/http" "github.com/gin-gonic/gin" @@ -32,5 +33,6 @@ func (u *UserHandler) RegisterUser(c *gin.Context) { c.JSON(http.StatusCreated, gin.H{ "message": "User registered successfully", "referral_code": user.ReferralCode, + "share_link": fmt.Sprintf("https://test.com/signup?ref=%s", user.ReferralCode), }) } \ No newline at end of file From 28911255e1984ae0fb7dc0ac78fe703303d8d173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 16:16:07 -0300 Subject: [PATCH 26/60] feat: create config file with load env function --- config/config.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 config/config.go diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..1035fab --- /dev/null +++ b/config/config.go @@ -0,0 +1,14 @@ +package config + +import ( + "log" + + "github.com/joho/godotenv" +) + +func LoadEnv() { + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } +} \ No newline at end of file From 34570191a1d1e9d57133214b7fb02bc45a9131ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 16:16:26 -0300 Subject: [PATCH 27/60] feat: add call function Load env in main --- main.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/main.go b/main.go index 9fad374..2400caa 100644 --- a/main.go +++ b/main.go @@ -1,10 +1,8 @@ package main import ( - "log" "github.com/gin-gonic/gin" - "github.com/joho/godotenv" "github.com/jpeccia/go-backend-test/config" "github.com/jpeccia/go-backend-test/internal/database/migrations" "github.com/jpeccia/go-backend-test/internal/handlers" @@ -14,10 +12,7 @@ import ( ) func main() { - err := godotenv.Load() - if err != nil { - log.Fatal("Error loading .env file") - } + config.LoadEnv() config.ConnectDatabase() migrations.Migrate() From d5d1f3a1af5f378e78f61c730edfbfd904c3a981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 16:37:08 -0300 Subject: [PATCH 28/60] feat: create email service to send emails --- internal/services/email_service.go | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 internal/services/email_service.go diff --git a/internal/services/email_service.go b/internal/services/email_service.go new file mode 100644 index 0000000..5c1f2c0 --- /dev/null +++ b/internal/services/email_service.go @@ -0,0 +1,37 @@ +package services + +import ( + "fmt" + "net/smtp" + "os" +) + +type EmailService interface { + SendEmail(to string, subject string, body string) error +} + +type emailService struct { + smtpHost string + smtpPort string + sender string + password string +} + +func NewEmailService() EmailService { + return &emailService{ + smtpHost: os.Getenv("SMTP_HOST"), + smtpPort: os.Getenv("SMTP_PORT"), + sender: os.Getenv("SMTP_EMAIL"), + password: os.Getenv("SMTP_PASSWORD"), + } +} + +func (e *emailService) SendEmail(to string, subject string, body string) error { + auth := smtp.PlainAuth("", e.sender, e.password, e.smtpHost) + + msg := []byte(fmt.Sprintf("Subject: %s\n\n%s", subject, body)) + + err := smtp.SendMail(e.smtpHost+":"+e.smtpPort, auth, e.sender, []string{to}, msg) + return err +} + From 0147e6e9b80ff8ce59270e34fee935dfd590c754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 16:37:41 -0300 Subject: [PATCH 29/60] feat: add send email after register --- internal/services/user_service.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/internal/services/user_service.go b/internal/services/user_service.go index 7e0da58..34e8850 100644 --- a/internal/services/user_service.go +++ b/internal/services/user_service.go @@ -1,6 +1,8 @@ package services import ( + "fmt" + "github.com/google/uuid" "github.com/jpeccia/go-backend-test/internal/dto" "github.com/jpeccia/go-backend-test/internal/models" @@ -30,11 +32,19 @@ func (u *userService) RegisterUser(dto dto.RegisterUserDTO) (*models.User, error Points: 1, } + emailService := NewEmailService() + if dto.ReferredBy != "" { referredUser, err := u.userRepo.FindUserByReferralCode(dto.ReferredBy) if err == nil { referredUser.Points++ u.userRepo.CreateUser(referredUser) + + emailService.SendEmail( + referredUser.Email, + "Congratulations! You earned an extra point!", + fmt.Sprintf("A new person signed up using your referral link! You now have %d points.", referredUser.Points), + ) } } @@ -43,6 +53,12 @@ func (u *userService) RegisterUser(dto dto.RegisterUserDTO) (*models.User, error return nil, err } + emailService.SendEmail( + user.Email, + "Welcome to the competition!", + fmt.Sprintf("Hi %s :), you have successfully registered! Share your link to earn points: https://test.com/signup?ref=%s", user.Name, user.ReferralCode), + ) + return &user, nil } From d736f441f9c6d573e69d8f00c62d23a1b6884bb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 16:54:23 -0300 Subject: [PATCH 30/60] feat: create competition handler and get winners function --- internal/handlers/competition_handler.go | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 internal/handlers/competition_handler.go diff --git a/internal/handlers/competition_handler.go b/internal/handlers/competition_handler.go new file mode 100644 index 0000000..dfc3883 --- /dev/null +++ b/internal/handlers/competition_handler.go @@ -0,0 +1,26 @@ +package handlers + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/jpeccia/go-backend-test/internal/services" +) + +type CompetitionHandler struct { + competitionService services.CompetitionService +} + +func NewCompetitionHandler(service services.CompetitionService) *CompetitionHandler { + return &CompetitionHandler{competitionService: service} +} + +func (h *CompetitionHandler) GetWinners(c *gin.Context) { + winners, err := h.competitionService.GetTopWinners(10) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve winners"}) + return + } + + c.JSON(http.StatusOK, winners) +} \ No newline at end of file From 50d792b7448f8b19d419cbcc2a7d596b5ede97d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 16:54:49 -0300 Subject: [PATCH 31/60] feat: create competition service and get top winners function --- internal/services/competition_service.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 internal/services/competition_service.go diff --git a/internal/services/competition_service.go b/internal/services/competition_service.go new file mode 100644 index 0000000..6bbd5b2 --- /dev/null +++ b/internal/services/competition_service.go @@ -0,0 +1,22 @@ +package services + +import ( + "github.com/jpeccia/go-backend-test/internal/models" + "github.com/jpeccia/go-backend-test/internal/repositories" +) + +type CompetitionService interface { + GetTopWinners(limit int) ([]models.User, error) +} + +type competitionService struct { + userRepo repositories.UserRepository +} + +func NewCompetitionService(userRepo repositories.UserRepository) CompetitionService { + return &competitionService{userRepo: userRepo} +} + +func (s *competitionService) GetTopWinners(limit int) ([]models.User, error) { + return s.userRepo.FindTopUsersByPoints(limit) +} \ No newline at end of file From 4cab58090be8be1c146645c0c98db1ef41c25b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 16:55:22 -0300 Subject: [PATCH 32/60] feat: add FindTopUsersByPoints function --- internal/repositories/user_repository.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/repositories/user_repository.go b/internal/repositories/user_repository.go index 234ef8c..d511c42 100644 --- a/internal/repositories/user_repository.go +++ b/internal/repositories/user_repository.go @@ -9,6 +9,7 @@ type UserRepository interface { CreateUser(user *models.User) error FindUserByEmail(email string) (*models.User, error) FindUserByReferralCode(code string) (*models.User, error) + FindTopUsersByPoints(limit int) ([]models.User, error) } type userRepository struct { @@ -35,6 +36,12 @@ func (u *userRepository) FindUserByReferralCode(code string) (*models.User, erro return &user, err } +func (u *userRepository) FindTopUsersByPoints(limit int) ([]models.User, error) { + var users []models.User + err := u.db.Order("points DESC").Limit(limit).Find(&users).Error + return users, err +} + func (u *userRepository) UpdateUser(user *models.User) error { return u.db.Save(user).Error } From f2c4cd994d5da009dce9ce96886307fff2ca6541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 16:55:43 -0300 Subject: [PATCH 33/60] feat: configure routes and add winners get route --- internal/routes/routes.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/routes/routes.go b/internal/routes/routes.go index 4071fbd..9ada713 100644 --- a/internal/routes/routes.go +++ b/internal/routes/routes.go @@ -5,6 +5,10 @@ import ( "github.com/jpeccia/go-backend-test/internal/handlers" ) -func SetupRoutes(r *gin.Engine, userHandler *handlers.UserHandler) { - r.POST("/signup", userHandler.RegisterUser) -} \ No newline at end of file +func SetupRoutes(r *gin.Engine, userHandler *handlers.UserHandler, competitionHandler *handlers.CompetitionHandler) { + api := r.Group("/api") + { + api.POST("/signup", userHandler.RegisterUser) + api.GET("/winners", competitionHandler.GetWinners) // Nova rota para vencedores + } +} From 5538ddef838fbe6a549c668cd7c89a740062b342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 17:19:21 -0300 Subject: [PATCH 34/60] feat: define router with new routes in main --- main.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index 2400caa..89cb30e 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,6 @@ package main import ( - "github.com/gin-gonic/gin" "github.com/jpeccia/go-backend-test/config" "github.com/jpeccia/go-backend-test/internal/database/migrations" @@ -15,14 +14,18 @@ func main() { config.LoadEnv() config.ConnectDatabase() migrations.Migrate() - + r := gin.Default() userRepo := repositories.NewUserRepository(config.DB) + userService := services.NewUserService(userRepo) + competitionService := services.NewCompetitionService(userRepo) + userHandler := handlers.NewUserHandler(userService) + competitionHandler := handlers.NewCompetitionHandler(competitionService) - routes.SetupRoutes(r, userHandler) + routes.SetupRoutes(r, userHandler, competitionHandler) r.Run(":8080") -} \ No newline at end of file +} From 070ab2acc8e8035f15b0396747e8efe615cbf7b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 17:20:29 -0300 Subject: [PATCH 35/60] feat: add EndCompetition function to call winners in Handler --- internal/handlers/competition_handler.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/internal/handlers/competition_handler.go b/internal/handlers/competition_handler.go index dfc3883..f192910 100644 --- a/internal/handlers/competition_handler.go +++ b/internal/handlers/competition_handler.go @@ -23,4 +23,19 @@ func (h *CompetitionHandler) GetWinners(c *gin.Context) { } c.JSON(http.StatusOK, winners) +} + +func (h *CompetitionHandler) EndCompetition(c *gin.Context) { + winners, err := h.competitionService.GetTopWinners(10) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve winners"}) + return + } + + err = h.competitionService.NotifyWinners(winners) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send emails to winners"}) + } + + c.JSON(http.StatusOK, gin.H{"message": "Competition ended, winners have been notified!"}) } \ No newline at end of file From bb30595a6a8c02abb91bc0283e51cf18aa116d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 17:20:58 -0300 Subject: [PATCH 36/60] feat: add NotifyWinners function to send email to winners in service --- internal/services/competition_service.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/internal/services/competition_service.go b/internal/services/competition_service.go index 6bbd5b2..e91da67 100644 --- a/internal/services/competition_service.go +++ b/internal/services/competition_service.go @@ -1,12 +1,16 @@ package services import ( + "fmt" + "log" + "github.com/jpeccia/go-backend-test/internal/models" "github.com/jpeccia/go-backend-test/internal/repositories" ) type CompetitionService interface { GetTopWinners(limit int) ([]models.User, error) + NotifyWinners(winners []models.User) error } type competitionService struct { @@ -19,4 +23,20 @@ func NewCompetitionService(userRepo repositories.UserRepository) CompetitionServ func (s *competitionService) GetTopWinners(limit int) ([]models.User, error) { return s.userRepo.FindTopUsersByPoints(limit) +} + +func (s *competitionService) NotifyWinners(winners []models.User) error { + emailService := NewEmailService() + + for _, winner := range winners { + subject := "Congratulations! You are a winner!" + body := fmt.Sprintf("Dear %s,\n\nYou are one of the top 10 winners of the competition! Congratulations!\n\nBest regards,\nCompetition Team", winner.Name) + + err := emailService.SendEmail(winner.Email, subject, body) + if err != nil { + log.Printf("Failed to send email to %s: %v", winner.Email, err) + } + } + + return nil } \ No newline at end of file From 6f49bb5eda96731378b48c01766f128d5e89c1b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 17:21:44 -0300 Subject: [PATCH 37/60] feat: add route post /end-competition to end and send email in routes.go --- internal/routes/routes.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/routes/routes.go b/internal/routes/routes.go index 9ada713..9cf30c0 100644 --- a/internal/routes/routes.go +++ b/internal/routes/routes.go @@ -9,6 +9,7 @@ func SetupRoutes(r *gin.Engine, userHandler *handlers.UserHandler, competitionHa api := r.Group("/api") { api.POST("/signup", userHandler.RegisterUser) + api.POST("/end-competition", competitionHandler.EndCompetition) api.GET("/winners", competitionHandler.GetWinners) // Nova rota para vencedores } } From 0edd2236a40fc3828bf6bfd5141eb5ac39b78272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 18:01:44 -0300 Subject: [PATCH 38/60] fix: referral points and referred by now can works normally --- internal/handlers/user_handler.go | 6 ++++-- internal/repositories/user_repository.go | 1 + internal/services/user_service.go | 2 +- tmp/build-errors.log | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 tmp/build-errors.log diff --git a/internal/handlers/user_handler.go b/internal/handlers/user_handler.go index 2b91318..731ec4d 100644 --- a/internal/handlers/user_handler.go +++ b/internal/handlers/user_handler.go @@ -24,6 +24,8 @@ func (u *UserHandler) RegisterUser(c *gin.Context) { return } + fmt.Println("Received referred_by:", input.ReferredBy) // Verifica se o campo foi enviado corretamente + user, err := u.userService.RegisterUser(input) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to register user"}) @@ -31,8 +33,8 @@ func (u *UserHandler) RegisterUser(c *gin.Context) { } c.JSON(http.StatusCreated, gin.H{ - "message": "User registered successfully", + "message": "User registered successfully", "referral_code": user.ReferralCode, "share_link": fmt.Sprintf("https://test.com/signup?ref=%s", user.ReferralCode), }) -} \ No newline at end of file +} diff --git a/internal/repositories/user_repository.go b/internal/repositories/user_repository.go index d511c42..5773c56 100644 --- a/internal/repositories/user_repository.go +++ b/internal/repositories/user_repository.go @@ -10,6 +10,7 @@ type UserRepository interface { FindUserByEmail(email string) (*models.User, error) FindUserByReferralCode(code string) (*models.User, error) FindTopUsersByPoints(limit int) ([]models.User, error) + UpdateUser(user *models.User) error } type userRepository struct { diff --git a/internal/services/user_service.go b/internal/services/user_service.go index 34e8850..32e1851 100644 --- a/internal/services/user_service.go +++ b/internal/services/user_service.go @@ -38,7 +38,7 @@ func (u *userService) RegisterUser(dto dto.RegisterUserDTO) (*models.User, error referredUser, err := u.userRepo.FindUserByReferralCode(dto.ReferredBy) if err == nil { referredUser.Points++ - u.userRepo.CreateUser(referredUser) + u.userRepo.UpdateUser(referredUser) emailService.SendEmail( referredUser.Email, diff --git a/tmp/build-errors.log b/tmp/build-errors.log new file mode 100644 index 0000000..4660a1c --- /dev/null +++ b/tmp/build-errors.log @@ -0,0 +1 @@ +exit status 1exit status 1 \ No newline at end of file From 028fb24c3f36fe02d0d49c16d0514297fe283403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 18:44:40 -0300 Subject: [PATCH 39/60] chore: add smtp vars to send mail with mailtrap example in env.example --- .env.example | 8 +++++++- internal/database/migrations/migrate.go | 2 +- internal/services/email_service.go | 14 +++++++++++--- tmp/build-errors.log | 2 +- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index 9695fda..dab2182 100644 --- a/.env.example +++ b/.env.example @@ -2,4 +2,10 @@ DB_HOST= DB_USER= DB_PASS= DB_NAME= -DB_PORT= \ No newline at end of file +DB_PORT= + + +SMTP_HOST=sandbox.smtp.mailtrap.io +SMTP_PORT=2525 +SMTP_EMAIL= +SMTP_PASSWORD= \ No newline at end of file diff --git a/internal/database/migrations/migrate.go b/internal/database/migrations/migrate.go index 40ed003..243ddc1 100644 --- a/internal/database/migrations/migrate.go +++ b/internal/database/migrations/migrate.go @@ -18,4 +18,4 @@ func Migrate() { } log.Println("Database migrated successfully!") -} \ No newline at end of file +} diff --git a/internal/services/email_service.go b/internal/services/email_service.go index 5c1f2c0..88ae332 100644 --- a/internal/services/email_service.go +++ b/internal/services/email_service.go @@ -29,9 +29,17 @@ func NewEmailService() EmailService { func (e *emailService) SendEmail(to string, subject string, body string) error { auth := smtp.PlainAuth("", e.sender, e.password, e.smtpHost) - msg := []byte(fmt.Sprintf("Subject: %s\n\n%s", subject, body)) + // Adicionando cabeçalhos obrigatórios para evitar problemas de entrega + msg := []byte(fmt.Sprintf( + "From: %s\r\nTo: %s\r\nSubject: %s\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n%s", + e.sender, to, subject, body, + )) err := smtp.SendMail(e.smtpHost+":"+e.smtpPort, auth, e.sender, []string{to}, msg) - return err -} + if err != nil { + fmt.Printf("Error to send mail: %v", err) + return err + } + return nil +} diff --git a/tmp/build-errors.log b/tmp/build-errors.log index 4660a1c..c38c619 100644 --- a/tmp/build-errors.log +++ b/tmp/build-errors.log @@ -1 +1 @@ -exit status 1exit status 1 \ No newline at end of file +exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file From e0925c6844e014e336d7cbbc23600337800188fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 18:55:21 -0300 Subject: [PATCH 40/60] fix: before referred by in db is empty and now i acrescented and fix and user referred by got email of referred user --- internal/services/user_service.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/services/user_service.go b/internal/services/user_service.go index 32e1851..8748b69 100644 --- a/internal/services/user_service.go +++ b/internal/services/user_service.go @@ -39,7 +39,8 @@ func (u *userService) RegisterUser(dto dto.RegisterUserDTO) (*models.User, error if err == nil { referredUser.Points++ u.userRepo.UpdateUser(referredUser) - + user.ReferredBy = referredUser.Email + emailService.SendEmail( referredUser.Email, "Congratulations! You earned an extra point!", From 174808e502284c86f9e6e5e69e300b3938285cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 19:01:44 -0300 Subject: [PATCH 41/60] feat: add verify if referred code dont exist --- internal/services/user_service.go | 28 +++++++++++++++++----------- tmp/build-errors.log | 2 +- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/internal/services/user_service.go b/internal/services/user_service.go index 8748b69..a08c276 100644 --- a/internal/services/user_service.go +++ b/internal/services/user_service.go @@ -1,6 +1,7 @@ package services import ( + "errors" "fmt" "github.com/google/uuid" @@ -36,17 +37,23 @@ func (u *userService) RegisterUser(dto dto.RegisterUserDTO) (*models.User, error if dto.ReferredBy != "" { referredUser, err := u.userRepo.FindUserByReferralCode(dto.ReferredBy) - if err == nil { - referredUser.Points++ - u.userRepo.UpdateUser(referredUser) - user.ReferredBy = referredUser.Email - - emailService.SendEmail( - referredUser.Email, - "Congratulations! You earned an extra point!", - fmt.Sprintf("A new person signed up using your referral link! You now have %d points.", referredUser.Points), - ) + if err != nil { + return nil, errors.New("invalid referral code") } + + referredUser.Points++ + err = u.userRepo.UpdateUser(referredUser) + if err != nil { + return nil, err + } + + user.ReferredBy = referredUser.Email + + emailService.SendEmail( + referredUser.Email, + "Congratulations! You earned an extra point!", + fmt.Sprintf("A new person signed up using your referral link! You now have %d points.", referredUser.Points), + ) } err := u.userRepo.CreateUser(&user) @@ -62,4 +69,3 @@ func (u *userService) RegisterUser(dto dto.RegisterUserDTO) (*models.User, error return &user, nil } - diff --git a/tmp/build-errors.log b/tmp/build-errors.log index c38c619..6c6d080 100644 --- a/tmp/build-errors.log +++ b/tmp/build-errors.log @@ -1 +1 @@ -exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file +exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file From 0112dd4749eb05ab3c77fe1b3e7ac688bb08e9b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 19:14:24 -0300 Subject: [PATCH 42/60] feat: add get ref code in url and add --- internal/handlers/user_handler.go | 5 ++++- tmp/build-errors.log | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/handlers/user_handler.go b/internal/handlers/user_handler.go index 731ec4d..4d87d1a 100644 --- a/internal/handlers/user_handler.go +++ b/internal/handlers/user_handler.go @@ -24,7 +24,10 @@ func (u *UserHandler) RegisterUser(c *gin.Context) { return } - fmt.Println("Received referred_by:", input.ReferredBy) // Verifica se o campo foi enviado corretamente + referralCode := c.Query("ref") + if referralCode != "" { + input.ReferredBy = referralCode + } user, err := u.userService.RegisterUser(input) if err != nil { diff --git a/tmp/build-errors.log b/tmp/build-errors.log index 6c6d080..1bc3278 100644 --- a/tmp/build-errors.log +++ b/tmp/build-errors.log @@ -1 +1 @@ -exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file +exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file From 8fd2687b9ca74ad2136382c992e7c742fba9f130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 19:20:36 -0300 Subject: [PATCH 43/60] build: install swagger --- go.mod | 23 +++++++++++++++++++- go.sum | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 5c8113e..3c64d97 100644 --- a/go.mod +++ b/go.mod @@ -2,19 +2,28 @@ module github.com/jpeccia/go-backend-test go 1.23.4 +require github.com/google/uuid v1.6.0 + require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.2.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/bytedance/sonic v1.13.2 // indirect github.com/bytedance/sonic/loader v0.2.4 // indirect github.com/cloudwego/base64x v0.1.5 // indirect github.com/cloudwego/iasm v0.2.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gin-contrib/sse v1.0.0 // indirect github.com/gin-gonic/gin v1.10.0 // indirect + github.com/go-openapi/jsonpointer v0.21.1 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/swag v0.23.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/goccy/go-json v0.10.5 // indirect - github.com/google/uuid v1.6.0 github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgx/v5 v5.7.4 // indirect @@ -22,23 +31,35 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/joho/godotenv v1.5.1 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/swaggo/files v1.0.1 // indirect + github.com/swaggo/gin-swagger v1.6.0 // indirect + github.com/swaggo/swag v1.16.4 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect + github.com/urfave/cli/v2 v2.27.6 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect golang.org/x/arch v0.15.0 // indirect golang.org/x/crypto v0.36.0 // indirect golang.org/x/net v0.38.0 // indirect golang.org/x/sync v0.12.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/text v0.23.0 // indirect + golang.org/x/tools v0.31.0 // indirect google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/postgres v1.5.11 // indirect gorm.io/gorm v1.25.12 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 320f73d..dafaef4 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,9 @@ +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28= +github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= @@ -7,6 +13,8 @@ github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCy github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= @@ -15,6 +23,14 @@ github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= +github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= +github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= @@ -23,6 +39,7 @@ github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -40,14 +57,19 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -58,6 +80,10 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -69,26 +95,67 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= +github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g= +github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= +golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -98,3 +165,5 @@ gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= From 165544792eda0234e8e5269494f9dd47bf762eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 19:25:35 -0300 Subject: [PATCH 44/60] feat: create initial structure swagger --- docs/docs.go | 36 ++++++++++++++++++++++++++++++++++++ docs/swagger.json | 7 +++++++ docs/swagger.yaml | 4 ++++ main.go | 4 ++++ 4 files changed, 51 insertions(+) create mode 100644 docs/docs.go create mode 100644 docs/swagger.json create mode 100644 docs/swagger.yaml diff --git a/docs/docs.go b/docs/docs.go new file mode 100644 index 0000000..6676994 --- /dev/null +++ b/docs/docs.go @@ -0,0 +1,36 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": {} +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/docs/swagger.json b/docs/swagger.json new file mode 100644 index 0000000..ec416cd --- /dev/null +++ b/docs/swagger.json @@ -0,0 +1,7 @@ +{ + "swagger": "2.0", + "info": { + "contact": {} + }, + "paths": {} +} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml new file mode 100644 index 0000000..b64379c --- /dev/null +++ b/docs/swagger.yaml @@ -0,0 +1,4 @@ +info: + contact: {} +paths: {} +swagger: "2.0" diff --git a/main.go b/main.go index 89cb30e..4ebe3cf 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,8 @@ import ( "github.com/jpeccia/go-backend-test/internal/repositories" "github.com/jpeccia/go-backend-test/internal/routes" "github.com/jpeccia/go-backend-test/internal/services" + swaggerFiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" ) func main() { @@ -27,5 +29,7 @@ func main() { routes.SetupRoutes(r, userHandler, competitionHandler) + r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + r.Run(":8080") } From 566fed32a750b1064a5f31da070159d97e91b152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 19:40:08 -0300 Subject: [PATCH 45/60] build: remove swaggo --- docs/docs.go | 36 ------------------------ docs/swagger.json | 7 ----- docs/swagger.yaml | 4 --- go.mod | 3 -- internal/handlers/competition_handler.go | 2 +- main.go | 4 --- tmp/build-errors.log | 2 +- 7 files changed, 2 insertions(+), 56 deletions(-) delete mode 100644 docs/docs.go delete mode 100644 docs/swagger.json delete mode 100644 docs/swagger.yaml diff --git a/docs/docs.go b/docs/docs.go deleted file mode 100644 index 6676994..0000000 --- a/docs/docs.go +++ /dev/null @@ -1,36 +0,0 @@ -// Package docs Code generated by swaggo/swag. DO NOT EDIT -package docs - -import "github.com/swaggo/swag" - -const docTemplate = `{ - "schemes": {{ marshal .Schemes }}, - "swagger": "2.0", - "info": { - "description": "{{escape .Description}}", - "title": "{{.Title}}", - "contact": {}, - "version": "{{.Version}}" - }, - "host": "{{.Host}}", - "basePath": "{{.BasePath}}", - "paths": {} -}` - -// SwaggerInfo holds exported Swagger Info so clients can modify it -var SwaggerInfo = &swag.Spec{ - Version: "", - Host: "", - BasePath: "", - Schemes: []string{}, - Title: "", - Description: "", - InfoInstanceName: "swagger", - SwaggerTemplate: docTemplate, - LeftDelim: "{{", - RightDelim: "}}", -} - -func init() { - swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) -} diff --git a/docs/swagger.json b/docs/swagger.json deleted file mode 100644 index ec416cd..0000000 --- a/docs/swagger.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "contact": {} - }, - "paths": {} -} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml deleted file mode 100644 index b64379c..0000000 --- a/docs/swagger.yaml +++ /dev/null @@ -1,4 +0,0 @@ -info: - contact: {} -paths: {} -swagger: "2.0" diff --git a/go.mod b/go.mod index 3c64d97..b197205 100644 --- a/go.mod +++ b/go.mod @@ -42,9 +42,6 @@ require ( github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - github.com/swaggo/files v1.0.1 // indirect - github.com/swaggo/gin-swagger v1.6.0 // indirect - github.com/swaggo/swag v1.16.4 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/urfave/cli/v2 v2.27.6 // indirect diff --git a/internal/handlers/competition_handler.go b/internal/handlers/competition_handler.go index f192910..6412c2c 100644 --- a/internal/handlers/competition_handler.go +++ b/internal/handlers/competition_handler.go @@ -38,4 +38,4 @@ func (h *CompetitionHandler) EndCompetition(c *gin.Context) { } c.JSON(http.StatusOK, gin.H{"message": "Competition ended, winners have been notified!"}) -} \ No newline at end of file +} diff --git a/main.go b/main.go index 4ebe3cf..89cb30e 100644 --- a/main.go +++ b/main.go @@ -8,8 +8,6 @@ import ( "github.com/jpeccia/go-backend-test/internal/repositories" "github.com/jpeccia/go-backend-test/internal/routes" "github.com/jpeccia/go-backend-test/internal/services" - swaggerFiles "github.com/swaggo/files" - ginSwagger "github.com/swaggo/gin-swagger" ) func main() { @@ -29,7 +27,5 @@ func main() { routes.SetupRoutes(r, userHandler, competitionHandler) - r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - r.Run(":8080") } diff --git a/tmp/build-errors.log b/tmp/build-errors.log index 1bc3278..3690824 100644 --- a/tmp/build-errors.log +++ b/tmp/build-errors.log @@ -1 +1 @@ -exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file +exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file From ba9062c3fb98ecd83ae74c918abad52705d10e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 19:42:09 -0300 Subject: [PATCH 46/60] docs: add insomnia test routes --- Insomnia_2025-04-02.har | 201 +++++++++++++++++++++++++++++++++++++++ Insomnia_2025-04-02.yaml | 91 ++++++++++++++++++ 2 files changed, 292 insertions(+) create mode 100644 Insomnia_2025-04-02.har create mode 100644 Insomnia_2025-04-02.yaml diff --git a/Insomnia_2025-04-02.har b/Insomnia_2025-04-02.har new file mode 100644 index 0000000..bb79b52 --- /dev/null +++ b/Insomnia_2025-04-02.har @@ -0,0 +1,201 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Insomnia REST Client", + "version": "insomnia.desktop.app:v11.0.1" + }, + "entries": [ + { + "startedDateTime": "2025-04-02T22:10:32.798Z", + "time": 2.291, + "request": { + "method": "GET", + "url": "http://localhost:8080/api/winners", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { + "name": "User-Agent", + "value": "insomnia/11.0.1" + } + ], + "queryString": [], + "postData": { + "mimeType": "", + "text": "" + }, + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 200, + "statusText": "OK", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { + "name": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "name": "Date", + "value": "Wed, 02 Apr 2025 22:09:45 GMT" + }, + { + "name": "Content-Length", + "value": "2" + } + ], + "content": { + "size": 2, + "mimeType": "application/json; charset=utf-8", + "text": "[]" + }, + "redirectURL": "", + "headersSize": -1, + "bodySize": -1 + }, + "cache": {}, + "timings": { + "blocked": -1, + "dns": -1, + "connect": -1, + "send": 0, + "wait": 2.291, + "receive": 0, + "ssl": -1 + }, + "comment": "Listar os vencedores da competição" + }, + { + "startedDateTime": "2025-04-02T22:10:32.798Z", + "time": 2.706, + "request": { + "method": "POST", + "url": "http://localhost:8080/api/end-competition", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { + "name": "User-Agent", + "value": "insomnia/11.0.1" + } + ], + "queryString": [], + "postData": { + "mimeType": "", + "text": "" + }, + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 200, + "statusText": "OK", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { + "name": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "name": "Date", + "value": "Wed, 02 Apr 2025 22:09:50 GMT" + }, + { + "name": "Content-Length", + "value": "60" + } + ], + "content": { + "size": 60, + "mimeType": "application/json; charset=utf-8", + "text": "{\"message\":\"Competition ended, winners have been notified!\"}" + }, + "redirectURL": "", + "headersSize": -1, + "bodySize": -1 + }, + "cache": {}, + "timings": { + "blocked": -1, + "dns": -1, + "connect": -1, + "send": 0, + "wait": 2.706, + "receive": 0, + "ssl": -1 + }, + "comment": "Finalizar Competição" + }, + { + "startedDateTime": "2025-04-02T22:10:32.798Z", + "time": 4140.493, + "request": { + "method": "POST", + "url": "http://localhost:8080/api/signup", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + }, + { + "name": "User-Agent", + "value": "insomnia/11.0.1" + } + ], + "queryString": [], + "postData": { + "mimeType": "application/json", + "text": "{\n\t\t\"name\": \"t harumi\",\n \"email\": \"test@email.com\",\n\t \"phone_number\": \"12342256789\",\n\t\t\"referred_by\": \"33ba65a2-7ea8-4118-880b-7f560e42d4ce\"\n}" + }, + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 201, + "statusText": "Created", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { + "name": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "name": "Date", + "value": "Wed, 02 Apr 2025 22:07:07 GMT" + }, + { + "name": "Content-Length", + "value": "177" + } + ], + "content": { + "size": 177, + "mimeType": "application/json; charset=utf-8", + "text": "{\"message\":\"User registered successfully\",\"referral_code\":\"b284f7f9-d062-43aa-b20e-f7a34dc0a949\",\"share_link\":\"https://test.com/signup?ref=b284f7f9-d062-43aa-b20e-f7a34dc0a949\"}" + }, + "redirectURL": "", + "headersSize": -1, + "bodySize": -1 + }, + "cache": {}, + "timings": { + "blocked": -1, + "dns": -1, + "connect": -1, + "send": 0, + "wait": 4140.493, + "receive": 0, + "ssl": -1 + }, + "comment": "Cadastrar Usuário" + } + ] + } +} \ No newline at end of file diff --git a/Insomnia_2025-04-02.yaml b/Insomnia_2025-04-02.yaml new file mode 100644 index 0000000..1073076 --- /dev/null +++ b/Insomnia_2025-04-02.yaml @@ -0,0 +1,91 @@ +type: collection.insomnia.rest/5.0 +name: BACK-END-TEST-COMPETITION +meta: + id: wrk_b13d67c651604252b1d7f224c975c901 + created: 1743630557310 + modified: 1743630557310 +collection: + - url: http://localhost:8080/api/signup + name: Cadastrar Usuário + meta: + id: req_5acf0c81419d4b12ae35bd5a1c7fbcfb + created: 1743630565594 + modified: 1743631623100 + isPrivate: false + sortKey: -1743630565594 + method: POST + body: + mimeType: application/json + text: |- + { + "name": "t harumi", + "email": "test@email.com", + "phone_number": "12342256789", + "referred_by": "33ba65a2-7ea8-4118-880b-7f560e42d4ce" + } + headers: + - name: Content-Type + value: application/json + - name: User-Agent + value: insomnia/11.0.1 + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8080/api/end-competition + name: Finalizar Competição + meta: + id: req_01fbead0b8034164a6bbcbb56118b836 + created: 1743630612973 + modified: 1743631681617 + isPrivate: false + sortKey: -1743630612973 + method: POST + headers: + - name: User-Agent + value: insomnia/11.0.1 + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8080/api/winners + name: Listar os vencedores da competição + meta: + id: req_8c0627869b614988aa79b4d007fe32e3 + created: 1743630630346 + modified: 1743631785681 + isPrivate: false + sortKey: -1743630630346 + method: GET + headers: + - name: User-Agent + value: insomnia/11.0.1 + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true +cookieJar: + name: Default Jar + meta: + id: jar_130abd7a0ddc52cf3e136adf08dbcf2dbdca2d00 + created: 1743630557314 + modified: 1743630557314 +environments: + name: Base Environment + meta: + id: env_130abd7a0ddc52cf3e136adf08dbcf2dbdca2d00 + created: 1743630557312 + modified: 1743630557312 + isPrivate: false From 5da78bba75c1de7a7cfe50b0ad9b1772538f2573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 19:43:37 -0300 Subject: [PATCH 47/60] chore: defining name input with name --- Insomnia_2025-04-02.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Insomnia_2025-04-02.yaml b/Insomnia_2025-04-02.yaml index 1073076..43be2c7 100644 --- a/Insomnia_2025-04-02.yaml +++ b/Insomnia_2025-04-02.yaml @@ -18,10 +18,10 @@ collection: mimeType: application/json text: |- { - "name": "t harumi", + "name": "name", "email": "test@email.com", "phone_number": "12342256789", - "referred_by": "33ba65a2-7ea8-4118-880b-7f560e42d4ce" + "referred_by": "" } headers: - name: Content-Type From 09c8cea5a3dc42b735a3f9ffd958626c4fdded40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 20:10:42 -0300 Subject: [PATCH 48/60] ops: create Dockerfile to deploy enviroment --- Dockerfile | 20 ++++++++++++++++++++ docker-compose.yml | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d70ecca --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +# Usa a imagem oficial do Go como base +FROM golang:1.23-alpine AS builder +RUN apk add --no-cache git + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN go build -o main . + +FROM alpine:latest +WORKDIR /root/ +COPY --from=builder /app/main . +COPY .env .env +EXPOSE 8080 + +CMD ["./main"] diff --git a/docker-compose.yml b/docker-compose.yml index 325c7d5..ec78339 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,4 +15,4 @@ services: - postgres_data:/var/lib/postgresql/data volumes: - postgres_data: \ No newline at end of file + postgres_data: From 7e22d0f376d3e05cb43b6fd147d3c0061b02420a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 20:16:43 -0300 Subject: [PATCH 49/60] docs: create Makefile --- Makefile | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..aa1a0a6 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +.PHONY: build run air stop logs db-up db-down clean + +# Nome do container do banco de dados +DB_CONTAINER = postgres_competition + +# 🔹 Subir apenas o banco de dados com docker-compose +db-up: + docker-compose up -d db + +# 🔹 Parar e remover o banco de dados +db-down: + docker-compose down + +# 🔹 Rodar a aplicação Go normalmente +run: + go run main.go + +# 🔹 Rodar a aplicação com live reload (precisa do Air instalado) +air: + air + +# 🔹 Parar o banco de dados e limpar containers +stop: + docker stop $(DB_CONTAINER) || true + docker rm $(DB_CONTAINER) || true + +# 🔹 Ver logs do banco de dados +logs: + docker logs -f $(DB_CONTAINER) + +# 🔹 Limpar volumes e imagens não usadas +clean: stop db-down + docker volume rm $(shell docker volume ls -q) || true From e8cf0d3ac0ac043d5ce94364f5405a66632a9567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 20:23:48 -0300 Subject: [PATCH 50/60] build: install cors --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index b197205..62f1df0 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/cloudwego/iasm v0.2.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/gin-contrib/cors v1.7.4 github.com/gin-contrib/sse v1.0.0 // indirect github.com/gin-gonic/gin v1.10.0 // indirect github.com/go-openapi/jsonpointer v0.21.1 // indirect diff --git a/go.sum b/go.sum index dafaef4..2440ea8 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gin-contrib/cors v1.7.4 h1:/fC6/wk7rCRtqKqki8lLr2Xq+hnV49aXDLIuSek9g4k= +github.com/gin-contrib/cors v1.7.4/go.mod h1:vGc/APSgLMlQfEJV5NAzkrAHb0C8DetL3K6QZuvGii0= github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= From f88895637ae8e9108bfae987bed4502f0a25eaf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 20:24:06 -0300 Subject: [PATCH 51/60] feat: create Cors config --- config/cors.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 config/cors.go diff --git a/config/cors.go b/config/cors.go new file mode 100644 index 0000000..50613e3 --- /dev/null +++ b/config/cors.go @@ -0,0 +1,21 @@ +package config + +import ( + "os" + + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" +) + +func CORSMiddleware() gin.HandlerFunc { + frontendURL := os.Getenv("FRONTEND_URL") + + config := cors.Config{ + AllowOrigins: []string{frontendURL}, + AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"}, + AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "X-Requested-With"}, + AllowCredentials: true, + } + + return cors.New(config) +} \ No newline at end of file From 25b9b6e5893a3c8bdf4d9743d2f3dcb245de0232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 20:24:23 -0300 Subject: [PATCH 52/60] chore: add front end url var in .env.example --- .env.example | 1 + 1 file changed, 1 insertion(+) diff --git a/.env.example b/.env.example index dab2182..0cf0326 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,7 @@ DB_PASS= DB_NAME= DB_PORT= +FRONTEND_URL= SMTP_HOST=sandbox.smtp.mailtrap.io SMTP_PORT=2525 From dedaf50b4286522ce5ec093cab7b773d2f943cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 20:27:05 -0300 Subject: [PATCH 53/60] feat: add env vars in link front end --- internal/handlers/user_handler.go | 3 ++- internal/services/user_service.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/handlers/user_handler.go b/internal/handlers/user_handler.go index 4d87d1a..3f6831f 100644 --- a/internal/handlers/user_handler.go +++ b/internal/handlers/user_handler.go @@ -3,6 +3,7 @@ package handlers import ( "fmt" "net/http" + "os" "github.com/gin-gonic/gin" "github.com/jpeccia/go-backend-test/internal/dto" @@ -38,6 +39,6 @@ func (u *UserHandler) RegisterUser(c *gin.Context) { c.JSON(http.StatusCreated, gin.H{ "message": "User registered successfully", "referral_code": user.ReferralCode, - "share_link": fmt.Sprintf("https://test.com/signup?ref=%s", user.ReferralCode), + "share_link": fmt.Sprintf("%s/signup?ref=%s", os.Getenv("FRONTEND_URL"), user.ReferralCode), }) } diff --git a/internal/services/user_service.go b/internal/services/user_service.go index a08c276..e6f8ffc 100644 --- a/internal/services/user_service.go +++ b/internal/services/user_service.go @@ -3,6 +3,7 @@ package services import ( "errors" "fmt" + "os" "github.com/google/uuid" "github.com/jpeccia/go-backend-test/internal/dto" @@ -64,7 +65,7 @@ func (u *userService) RegisterUser(dto dto.RegisterUserDTO) (*models.User, error emailService.SendEmail( user.Email, "Welcome to the competition!", - fmt.Sprintf("Hi %s :), you have successfully registered! Share your link to earn points: https://test.com/signup?ref=%s", user.Name, user.ReferralCode), + fmt.Sprintf("Hi %s :), you have successfully registered! Share your link to earn points: %s/signup?ref=%s", os.Getenv("FRONTEND_URL"), user.Name, user.ReferralCode), ) return &user, nil From 5093c22d2ceddbc680f07651fc9374c2699708fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 22:36:38 -0300 Subject: [PATCH 54/60] fix: error caused by a / in env var front end url cors error --- config/cors.go | 5 ++++- main.go | 1 + tmp/build-errors.log | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/config/cors.go b/config/cors.go index 50613e3..08939ab 100644 --- a/config/cors.go +++ b/config/cors.go @@ -1,6 +1,7 @@ package config import ( + "log" "os" "github.com/gin-contrib/cors" @@ -10,6 +11,8 @@ import ( func CORSMiddleware() gin.HandlerFunc { frontendURL := os.Getenv("FRONTEND_URL") + log.Println("CORS AllowOrigins:", frontendURL) + config := cors.Config{ AllowOrigins: []string{frontendURL}, AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"}, @@ -18,4 +21,4 @@ func CORSMiddleware() gin.HandlerFunc { } return cors.New(config) -} \ No newline at end of file +} diff --git a/main.go b/main.go index 89cb30e..d607d3f 100644 --- a/main.go +++ b/main.go @@ -16,6 +16,7 @@ func main() { migrations.Migrate() r := gin.Default() + r.Use(config.CORSMiddleware()) userRepo := repositories.NewUserRepository(config.DB) diff --git a/tmp/build-errors.log b/tmp/build-errors.log index 3690824..9bb8b56 100644 --- a/tmp/build-errors.log +++ b/tmp/build-errors.log @@ -1 +1 @@ -exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file +exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file From f2c733d9a6e2306fcd57ba9f7cd3de52c158c412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Wed, 2 Apr 2025 23:01:03 -0300 Subject: [PATCH 55/60] perf: add go routines to send email assync and add more performance in register --- internal/services/user_service.go | 31 +++++++++++++++++++++---------- tmp/build-errors.log | 2 +- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/internal/services/user_service.go b/internal/services/user_service.go index e6f8ffc..c39f813 100644 --- a/internal/services/user_service.go +++ b/internal/services/user_service.go @@ -50,11 +50,16 @@ func (u *userService) RegisterUser(dto dto.RegisterUserDTO) (*models.User, error user.ReferredBy = referredUser.Email - emailService.SendEmail( - referredUser.Email, - "Congratulations! You earned an extra point!", - fmt.Sprintf("A new person signed up using your referral link! You now have %d points.", referredUser.Points), - ) + go func() { + err := emailService.SendEmail( + referredUser.Email, + "Congratulations! You earned an extra point!", + fmt.Sprintf("A new person signed up using your referral link! You now have %d points.", referredUser.Points), + ) + if err != nil { + fmt.Println("Erro ao enviar e-mail para o referenciador:", err) + } + }() } err := u.userRepo.CreateUser(&user) @@ -62,11 +67,17 @@ func (u *userService) RegisterUser(dto dto.RegisterUserDTO) (*models.User, error return nil, err } - emailService.SendEmail( - user.Email, - "Welcome to the competition!", - fmt.Sprintf("Hi %s :), you have successfully registered! Share your link to earn points: %s/signup?ref=%s", os.Getenv("FRONTEND_URL"), user.Name, user.ReferralCode), - ) + go func() { + err := emailService.SendEmail( + user.Email, + "Welcome to the competition!", + fmt.Sprintf("Hi %s :), you have successfully registered! Share your link to earn points: %s/signup?ref=%s", + user.Name, os.Getenv("FRONTEND_URL"), user.ReferralCode), + ) + if err != nil { + fmt.Println("Erro ao enviar e-mail de boas-vindas:", err) + } + }() return &user, nil } diff --git a/tmp/build-errors.log b/tmp/build-errors.log index 9bb8b56..0be2c41 100644 --- a/tmp/build-errors.log +++ b/tmp/build-errors.log @@ -1 +1 @@ -exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file +exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file From 90df499001e43722f338b0a13975af58d5c353cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Thu, 3 Apr 2025 10:31:35 -0300 Subject: [PATCH 56/60] ops: remove copy .env in dockerfile for deploy --- Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d70ecca..f1b78eb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,6 @@ RUN go build -o main . FROM alpine:latest WORKDIR /root/ COPY --from=builder /app/main . -COPY .env .env EXPOSE 8080 CMD ["./main"] From 6dae1ce45f82ae53c5c10c131f06601bab1f7de4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Thu, 3 Apr 2025 10:35:09 -0300 Subject: [PATCH 57/60] ops: add copy .env in dockerfile again to deploy with security --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index f1b78eb..9674d7b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,7 @@ RUN go build -o main . FROM alpine:latest WORKDIR /root/ COPY --from=builder /app/main . +COPY .env . EXPOSE 8080 CMD ["./main"] From 6802c01f20e196fdbcf8f41204f853e4a1e03fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Thu, 3 Apr 2025 10:37:54 -0300 Subject: [PATCH 58/60] chore: remove .env --- Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9674d7b..f1b78eb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,6 @@ RUN go build -o main . FROM alpine:latest WORKDIR /root/ COPY --from=builder /app/main . -COPY .env . EXPOSE 8080 CMD ["./main"] From 0fb1a7913e0d261faf7c28658115fb909c834b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Thu, 3 Apr 2025 12:12:42 -0300 Subject: [PATCH 59/60] ops: add env_file in docker-compose --- Dockerfile | 1 - docker-compose.yml | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index f1b78eb..9561468 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,3 @@ -# Usa a imagem oficial do Go como base FROM golang:1.23-alpine AS builder RUN apk add --no-cache git diff --git a/docker-compose.yml b/docker-compose.yml index ec78339..7f9d070 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,8 @@ services: image: postgres:latest container_name: postgres_competition restart: always + env_file: + - .env environment: POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASS} From df5616ae89f32a95ab7a24e493480f2c17f6c133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ot=C3=A1vio=20Peccia?= Date: Thu, 3 Apr 2025 12:22:56 -0300 Subject: [PATCH 60/60] fix: load env error in deploy --- config/config.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index 1035fab..495cffa 100644 --- a/config/config.go +++ b/config/config.go @@ -2,13 +2,16 @@ package config import ( "log" + "os" "github.com/joho/godotenv" ) func LoadEnv() { - err := godotenv.Load() - if err != nil { - log.Fatal("Error loading .env file") + if os.Getenv("RENDER") == "" { + err := godotenv.Load() + if err != nil { + log.Println("Aviso: Nenhum arquivo .env encontrado. Usando variáveis de ambiente do sistema.") + } } } \ No newline at end of file