diff --git a/backend/shared/errors/errors.go b/backend/shared/errors/errors.go new file mode 100644 index 0000000..1382cb8 --- /dev/null +++ b/backend/shared/errors/errors.go @@ -0,0 +1,46 @@ +package errors + +import ( + "fmt" +) + +type AppError struct { + Code string + Message string + Err error +} + +func (e *AppError) Error() string { + if e.Err != nil { + return fmt.Sprintf("%s: %s (code: %s)", e.Message, e.Err.Error(), e.Code) + } + return fmt.Sprintf("%s (code: %s)", e.Message, e.Code) +} + +func (e *AppError) Unwrap() error { + return e.Err +} + +func NewAppError(code, message string, err error) *AppError { + return &AppError{ + Code: code, + Message: message, + Err: err, + } +} + +func NewBadRequestError(message string, err error) *AppError { + return NewAppError("BAD_REQUEST", message, err) +} + +func NewInternalError(message string, err error) *AppError { + return NewAppError("INTERNAL_ERROR", message, err) +} + +func NewNotFoundError(message string, err error) *AppError { + return NewAppError("NOT_FOUND", message, err) +} + +func NewUnauthorizedError(message string, err error) *AppError { + return NewAppError("UNAUTHORIZED", message, err) +} diff --git a/backend/shared/go.mod b/backend/shared/go.mod new file mode 100644 index 0000000..c87a8c2 --- /dev/null +++ b/backend/shared/go.mod @@ -0,0 +1,44 @@ +module shared + +go 1.26 + +require ( + github.com/go-redis/redis/v8 v8.11.5 + github.com/rs/zerolog v1.30.0 + gorm.io/driver/postgres v1.5.4 + gorm.io/gorm v1.25.5 + google.golang.org/protobuf v1.31.0 +) + +require ( + github.com/bytedance/sonic v1.9.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.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.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.4.3 // 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.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-isatty v0.0.19 // 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.0.8 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + yaml.v3 v3.0.1 // indirect +) \ No newline at end of file diff --git a/backend/shared/logger/logger.go b/backend/shared/logger/logger.go new file mode 100644 index 0000000..9c67bfb --- /dev/null +++ b/backend/shared/logger/logger.go @@ -0,0 +1,33 @@ +package logger + +import ( + "os" + + "github.com/rs/zerolog" +) + +var log zerolog.Logger + +func init() { + log = zerolog.New(os.Stdout).With().Timestamp().Logger() +} + +func Info() *zerolog.Event { + return log.Info() +} + +func Error() *zerolog.Event { + return log.Error() +} + +func Debug() *zerolog.Event { + return log.Debug() +} + +func Warn() *zerolog.Event { + return log.Warn() +} + +func Fatal() *zerolog.Event { + return log.Fatal() +} diff --git a/backend/shared/postgres/postgres.go b/backend/shared/postgres/postgres.go new file mode 100644 index 0000000..1d37cc2 --- /dev/null +++ b/backend/shared/postgres/postgres.go @@ -0,0 +1,32 @@ +package postgres + +import ( + "fmt" + "shared/logger" + + "gorm.io/driver/postgres" + "gorm.io/gorm" +) + +type Config struct { + Host string + Port string + User string + Password string + DBName string + SSLMode string +} + +func NewPostgresDB(cfg Config) (*gorm.DB, error) { + dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s", + cfg.Host, cfg.Port, cfg.User, cfg.Password, cfg.DBName, cfg.SSLMode) + + db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + logger.Error().Err(err).Msg("Failed to connect to PostgreSQL database") + return nil, err + } + + logger.Info().Msg("Connected to PostgreSQL database successfully") + return db, nil +} diff --git a/backend/shared/proto/common.proto b/backend/shared/proto/common.proto new file mode 100644 index 0000000..6f246bb --- /dev/null +++ b/backend/shared/proto/common.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package common; + +option go_package = "./common"; + +message Empty { +} + +message Status { + bool success = 1; + string message = 2; + string code = 3; +} + +message Pagination { + int32 page = 1; + int32 page_size = 2; + int32 total = 3; +} + +message IdRequest { + string id = 1; +} diff --git a/backend/shared/redis/redis.go b/backend/shared/redis/redis.go new file mode 100644 index 0000000..fc5beef --- /dev/null +++ b/backend/shared/redis/redis.go @@ -0,0 +1,32 @@ +package redis + +import ( + "context" + "shared/logger" + + "github.com/go-redis/redis/v8" +) + +type Config struct { + Addr string + Password string + DB int +} + +func NewRedisClient(cfg Config) *redis.Client { + client := redis.NewClient(&redis.Options{ + Addr: cfg.Addr, + Password: cfg.Password, + DB: cfg.DB, + }) + + ctx := context.Background() + _, err := client.Ping(ctx).Result() + if err != nil { + logger.Error().Err(err).Msg("Failed to connect to Redis") + return nil + } + + logger.Info().Msg("Connected to Redis successfully") + return client +}