Imported from AhmedNabilko/GoOrder-Backend (
AGENTS.md). Install upstream withnpx skills add AhmedNabilko/GoOrder-Backend. Copyright stays with the author.
Agent Guidelines for GoOrder Backend
This document provides essential information for AI coding agents working on the GoOrder Backend project.
Project Overview
- Name: GoOrder Backend
- Tech Stack: Go 1.21+, Fiber v2, PostgreSQL 15+, GORM, Redis
- Architecture: Modular Monolith
- Module Name:
github.com/robaa12/goorder-backend - Primary Language: Go with multi-language support (English, Arabic)
Build, Test, and Lint Commands
Basic Commands
make build # Build the application binary
make run # Run the application locally
make dev # Run with hot reload (requires air)
make clean # Clean build artifacts
Testing
make test # Run all tests with race detector
make test-coverage # Run tests and show HTML coverage report
go test -v ./... # Run all tests verbosely
go test -v -run TestName ./path/to/package # Run a single test
go test -v ./internal/modules/auth/... # Run tests in specific module
Code Quality
make fmt # Format code with go fmt
make lint # Run golangci-lint
make deps # Download and tidy dependencies
Docker Operations
make docker-build # Build Docker image
make docker-up # Start all containers
make docker-down # Stop all containers
make docker-restart # Rebuild and restart containers
make docker-logs # View application logs
Database Migrations
# Using goose (preferred - supports +goose Up/Down format)
goose -dir migrations postgres "connection_string" up
goose -dir migrations postgres "connection_string" down
# Create new migration
# Format: YYYYMMDDHHMMSS_description.sql
# Use +goose StatementBegin/End for complex SQL like functions
Code Style Guidelines
Project Structure
internal/
├── common/ # Shared utilities (errors, models, validators, responses)
├── config/ # Configuration management
├── database/ # Database connection
├── middleware/ # HTTP middleware (auth, RBAC, etc.)
├── modules/ # Feature modules (auth, user, store, product, etc.)
│ └── [module]/
│ ├── dto/ # Data Transfer Objects
│ ├── models/ # Database models
│ ├── repository/ # Data access layer
│ ├── service/ # Business logic
│ └── handlers/ # HTTP handlers
└── pkg/ # Internal packages (jwt, hash, logger, etc.)
Import Organization
Imports must be grouped in this order (separated by blank lines):
- Standard library
- External dependencies
- Internal packages (github.com/robaa12/goorder-backend/...)
package service
import (
"time"
"github.com/google/uuid"
"github.com/gofiber/fiber/v2"
"github.com/robaa12/goorder-backend/internal/common/errors"
"github.com/robaa12/goorder-backend/internal/modules/user/repository"
)
Naming Conventions
Files: Use snake_case (e.g., auth_service.go, user_repository.go)
Packages: Use short, lowercase names without underscores
- Use package alias for disambiguation:
usermodels "github.com/.../user/models"
Types: Use PascalCase
type AuthService struct { }
type UserRepository struct { }
type RegisterRequest struct { }
Constants: Use PascalCase with descriptive prefixes
const (
RoleCustomer UserRole = "customer"
StatusActive UserStatus = "active"
ProviderGoogle AuthProvider = "google"
)
Functions/Methods: Use PascalCase for exported, camelCase for unexported
func NewAuthService() *AuthService { } // Exported
func getUserIDFromContext() uuid.UUID { } // Unexported
Error Handling
Use custom AppError types from internal/common/errors:
// Predefined errors
return errors.ErrInvalidCredentials
return errors.ErrUserNotFound
// Custom errors with context
return errors.Unauthorized("Invalid token", err)
return errors.InternalServerError("Failed to create user", err)
return errors.BadRequest("Invalid input", nil)
Error Constants: Always use Err prefix for exported error variables:
var (
ErrInvalidCredentials = Unauthorized("Invalid credentials", nil)
ErrEmailAlreadyExists = Conflict("Email already exists", nil)
)
Models and DTOs
Database Models: Embed models.BaseModel for UUID, timestamps, soft deletes
type User struct {
models.BaseModel
Email string `gorm:"uniqueIndex;not null" json:"email"`
Password string `gorm:"not null" json:"-"`
}
DTOs: Use validation tags with go-playground/validator
type RegisterRequest struct {
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8"`
FirstName string `json:"first_name" validate:"required,min=2,max=100"`
Phone string `json:"phone,omitempty" validate:"omitempty,e164"`
}
HTTP Handlers
Use standard response helpers from internal/common/responses:
func (h *Handler) Method(c *fiber.Ctx) error {
// Validate request
var req dto.Request
if err := validators.ValidateRequest(c, &req); err != nil {
return err // Returns validation error automatically
}
// Business logic
result, err := h.service.DoSomething(&req)
if err != nil {
if appErr, ok := err.(*errors.AppError); ok {
return responses.Error(c, appErr)
}
return responses.Error(c, errors.InternalServerError("Operation failed", err))
}
return responses.OK(c, "Success message", result)
}
Middleware Context Values
Auth middleware stores these values in c.Locals():
userID(uuid.UUID)email(string)role(usermodels.UserRole)
Extract with type assertions that handle both UUID and string:
func getUserIDFromContext(c *fiber.Ctx) (uuid.UUID, error) {
userIDValue := c.Locals("userID")
if userID, ok := userIDValue.(uuid.UUID); ok {
return userID, nil
}
if userIDStr, ok := userIDValue.(string); ok {
return uuid.Parse(userIDStr)
}
return uuid.Nil, errors.Unauthorized("Invalid user ID", nil)
}
Testing Guidelines
- Place tests next to the code they test (e.g.,
auth_service_test.go) - Use table-driven tests for multiple scenarios
- Mock external dependencies (database, external APIs)
- Test file naming:
*_test.go - Test function naming:
TestFunctionNameorTestType_Method
Git Commit Conventions
Follow Conventional Commits format:
feat(module): short description
- Detailed point 1
- Detailed point 2
Types: feat, fix, docs, refactor, test, chore
Modules: auth, user, store, product, order, payment, etc.
Important Notes
- Never commit sensitive data:
.envfiles, credentials, API keys - Always use UUIDs: Primary keys are UUIDs via
models.BaseModel - Soft deletes: Use GORM's soft delete (check
deleted_at IS NULL) - Migrations: Use goose format with
+goose StatementBegin/Endfor functions - API versioning: All routes prefixed with
/api/v1 - CORS: Configured in main.go, requires FRONTEND_URL env var
- JWT tokens: Access tokens (15m), Refresh tokens (168h/7d)
- Roles: customer, store_owner, driver, admin
- Status: active, inactive, suspended, pending
Environment Setup
Copy .env.example to .env and configure:
- Database credentials (PostgreSQL)
- JWT secret (change in production!)
- Redis connection
- OAuth credentials (Google, Facebook)
- PayMob payment gateway
- AWS S3 for file storage
Development Workflow
- Start dependencies:
make docker-up - Run migrations:
goose -dir migrations postgres "..." up - Start dev server:
make dev(ormake run) - Run tests:
make test - Format code:
make fmt - Lint code:
make lint - Commit with conventional format
Active Technologies
- Go 1.21+ (module:
github.com/robaa12/goorder-backend) + Fiber v2, GORM, go-playground/validator v10, zerolog, Viper, redis/go-redis/v9 (001-add-translations) - PostgreSQL 15+ (primary), Redis (language preference cache — optional, not required for MVP) (001-add-translations)
- Go 1.21+ (module:
github.com/robaa12/goorder-backend) + Fiber v2 (HTTP), GORM (ORM), go-playground/validator v10 (validation), zerolog (logging), Viper (config), redis/go-redis/v9 (caching), AWS SDK for Go v2 (S3 storage) (001-store-module) - PostgreSQL 15+ (primary data store with geospatial extensions), Redis (language preference caching - optional) (001-store-module)
- Go 1.21+ + Fiber v2, GORM, go-playground/validator v10, zerolog, Viper, redis/go-redis/v9 (001-offers-bundles-vouchers)
- PostgreSQL 15+ (primary), Redis (rate limiting and optional evaluation caching) (001-offers-bundles-vouchers)
- Go 1.21+ + Fiber v2, GORM, go-playground/validator v10, zerolog (001-multi-app-updates)
- PostgreSQL 15+ (primary), optional Redis untouched by this feature (001-multi-app-updates)
- Go 1.25.0 + GORM (ORM), Fiber v2 (HTTP), go-playground/validator v10, zerolog (logging), Viper (config), go-redis v9 (001-db-seeding)
- PostgreSQL 15+ (primary database with geospatial support), Redis (language preference caching - optional for seeding) (001-db-seeding)
- Go 1.21+ + Fiber v2, GORM, go-playground/validator v10, project i18n package, Bunny storage service (001-admin-city-banners)
- PostgreSQL 15+ (banner records), Bunny object storage (banner images) (001-admin-city-banners)
- Go 1.21+ + Fiber v2, GORM, PostgreSQL 15+, go-playground/validator v10, i18n helpers, JWT/RBAC middleware (001-admin-owner-analytics)
Recent Changes
- 001-add-translations: Added Go 1.21+ (module:
github.com/robaa12/goorder-backend) + Fiber v2, GORM, go-playground/validator v10, zerolog, Viper, redis/go-redis/v9
For additional context about technologies to be used, project structure, shell commands, and other important information, read the current plan