Go
Backend Template

> Clean architecture based backend template in Go. ## Makefile Makefile requires installed dependecies: * [go](https://go.dev/doc/install) * [docker-compose](https://docs.docker.com/compose/reference) * [migrate](https://github.com/golang-migrate/migrate) ```shell $ make Usage: make [command] [ENV=staging|production] Commands: run Run server (default: staging) run ENV=production Run server with production config rename-project name={name} Rename project build-http Build http server migration-create name={name} Create migration migration-up Up migrations migration-up ENV=production Up migrations (production DB) migration-down Down last migration docker-up Up docker services docker-down Down docker services fmt Format source code test Run unit tests ``` ## HTTP Server The server takes no CLI flags. It reads `ENV_MODE` and loads the matching YAML file from [infra/](infra/) — see [Running the Application](#running-the-application) for details. ```shell # Build, then start with the staging config (default) $ go build -o ./bin/http-server ./cmd/server/main.go $ ENV_MODE=staging ./bin/http-server # Start with the production config $ ENV_MODE=production ./bin/http-server ``` ## API Docs * [apskel-pos Backend](https://apskel-pos-be.app-dev.altru.id/docs/index.html#/) ## License This project is licensed under the [MIT License](https://github.com/pvarentsov/apskel-pos-be/blob/main/LICENSE). # Apskel POS Backend A SaaS Point of Sale (POS) Restaurant System backend built with clean architecture principles in Go. ## Architecture Overview This application follows a clean architecture pattern with clear separation of concerns: ``` Handler → Service → Processor → Repository ``` ### Layers 1. **Contract Package** (`internal/contract/`) - Request/Response DTOs for API communication - Contains JSON tags for serialization - Input validation tags 2. **Handler Layer** (`internal/handler/`) - HTTP request/response handling - Request validation using go-playground/validator - Route definitions and middleware - Transforms contracts to/from services 3. **Service Layer** (`internal/service/`) - Business logic orchestration - Calls processors and transformers - Coordinates between different business operations 4. **Processor Layer** (`internal/processor/`) - Complex business operations - Cross-repository transactions - Business rule enforcement - Handles operations like order creation with inventory updates 5. **Repository Layer** (`internal/repository/`) - Data access layer - Individual repository per entity - Database-specific operations - Uses entities for database models 6. **Supporting Packages**: - **Models** (`internal/models/`) - Pure business logic models (no database dependencies) - **Entities** (`internal/entities/`) - Database models with GORM tags - **Constants** (`internal/constants/`) - Type-safe enums and business constants - **Transformer** (`internal/transformer/`) - Contract ↔ Model conversions - **Mappers** (`internal/mappers/`) - Model ↔ Entity conversions ## Key Features - **Clean Architecture**: Strict separation between business logic and infrastructure - **Type Safety**: Constants package with validation helpers - **Validation**: Comprehensive request validation using go-playground/validator - **Error Handling**: Structured error responses with proper HTTP status codes - **Database Independence**: Business logic never depends on database implementation - **Testability**: Each layer can be tested independently ## API Endpoints ### Health Check - `GET /health` - Health check endpoint (registered at the root, not under `/api/v1`) ### Organizations - `POST /api/v1/organizations` - Create organization - `GET /api/v1/organizations` - List organizations - `GET /api/v1/organizations/{id}` - Get organization by ID - `PUT /api/v1/organizations/{id}` - Update organization - `DELETE /api/v1/organizations/{id}` - Delete organization ### Users - `POST /api/v1/users` - Create user - `GET /api/v1/users` - List users - `GET /api/v1/users/{id}` - Get user by ID - `PUT /api/v1/users/{id}` - Update user - `DELETE /api/v1/users/{id}` - Delete user - `PUT /api/v1/users/{id}/password` - Change password - `PUT /api/v1/users/{id}/activate` - Activate user - `PUT /api/v1/users/{id}/deactivate` - Deactivate user ### Orders - `POST /api/v1/orders` - Create order with items - `GET /api/v1/orders` - List orders - `GET /api/v1/orders/{id}` - Get order by ID - `GET /api/v1/orders/{id}?include_items=true` - Get order with items - `PUT /api/v1/orders/{id}` - Update order - `PUT /api/v1/orders/{id}/cancel` - Cancel order - `PUT /api/v1/orders/{id}/complete` - Complete order - `POST /api/v1/orders/{id}/items` - Add item to order ### Order Items - `PUT /api/v1/order-items/{id}` - Update order item - `DELETE /api/v1/order-items/{id}` - Remove order item ## Running the Application ### Prerequisites | Tool | Version | Needed for | |------|---------|------------| | [Go](https://go.dev/doc/install) | 1.24+ | building & running the server | | [golang-migrate](https://github.com/golang-migrate/migrate) | latest | `make migration-*` targets | | [make](https://www.gnu.org/software/make/) | any | shortcut commands (Windows: use Git Bash / WSL, see note below) | | [docker & docker-compose](https://docs.docker.com/compose/) | optional | running Postgres/Redis locally | | [air](https://github.com/air-verse/air) | optional | hot reload during development (`.air.toml` is already configured) | ### 1. Clone & install dependencies ```bash git clone cd apskel-pos-backend go mod download ``` ### 2. Configuration Configuration is **not** read from `.env` files — it is loaded from YAML files in [infra/](infra/) by [config/configs.go](config/configs.go) using viper. The file is selected by the `ENV_MODE` environment variable: | `ENV_MODE` | Config file loaded | |------------|--------------------| | `local` | `infra/local.yaml` | | `development` | `infra/development.yaml` | | `staging` *(default)* | `infra/staging.yaml` | | `production` | `infra/production.yaml` | Any other/unset value falls back to `staging`. Only `staging.yaml` and `production.yaml` are committed — for `local`/`development` copy one of them first: ```bash cp infra/staging.yaml infra/local.yaml ``` Two important notes: * The config path is **relative to the working directory**, so always run the server from the repository root, otherwise viper panics with `failed to read config file`. * Push notifications need `infra/firebase-service-account.json` (git-ignored). Without it, obtain the file from the team before enabling FCM features. ### 3. Run migrations The migration targets build the DB URL from the credentials at the top of the [Makefile](Makefile): ```bash make migration-up # staging DB (default) make migration-up ENV=production # production DB make migration-create name=create_cash_advances_table make migration-down # roll back the last migration make migration-force version=87 # clear a dirty migration state ``` ### 4. Start the server ```bash make run # ENV_MODE=staging make run ENV=production # ENV_MODE=production ``` `make run` is just a wrapper around: ```bash ENV_MODE=staging go run cmd/server/main.go ``` The server listens on the `server.port` value from the loaded YAML (**4000** for both staging and production). Verify it is up: ```bash curl http://localhost:4000/health ``` All application routes live under `/api/v1` (see [internal/router/router.go](internal/router/router.go)). #### Windows note The `run`/`start` targets use POSIX inline env-var syntax, which `cmd.exe` and PowerShell do not understand. Either run `make` from Git Bash / WSL, or start the server directly: ```powershell # PowerShell $env:ENV_MODE = "staging"; go run cmd/server/main.go ``` ```cmd :: cmd.exe set ENV_MODE=staging && go run cmd/server/main.go ``` #### Hot reload ```bash ENV_MODE=local air # rebuilds ./tmp/main on every .go change ``` ### 5. Other commands ```bash make # show all available targets make fmt # go fmt ./... make test # go test ./... -v # Build a binary (make build-http still points at the old ./cmd/http path) go build -o ./bin/http-server ./cmd/server/main.go ``` ### Running with Docker `docker-compose.yaml` provides Postgres (`5432`), Redis (`6379`), and the API image. See [DOCKER.md](DOCKER.md) for the full workflow. ```bash make docker-up # docker-compose up -d make docker-down # docker-compose down ``` If you use the containerised Postgres/Redis, point `infra/local.yaml` at `localhost:5432` / `localhost:6379` instead of the remote hosts baked into `staging.yaml`. ## Example API Usage ### Create Organization ```bash curl -X POST http://localhost:4000/api/v1/organizations \ -H "Content-Type: application/json" \ -d '{ "name": "My Restaurant", "plan_type": "premium" }' ``` ### Create User ```bash curl -X POST http://localhost:4000/api/v1/users \ -H "Content-Type: application/json" \ -d '{ "organization_id": "uuid-here", "username": "john_doe", "email": "john@example.com", "password": "password123", "full_name": "John Doe", "role": "manager" }' ``` ### Create Order with Items ```bash curl -X POST http://localhost:4000/api/v1/orders \ -H "Content-Type: application/json" \ -d '{ "outlet_id": "uuid-here", "user_id": "uuid-here", "table_number": "A1", "order_type": "dine_in", "notes": "No onions", "order_items": [ { "product_id": "uuid-here", "quantity": 2, "unit_price": 15.99 } ] }' ``` ## Project Structure ``` apskel-pos-backend/ ├── cmd/ │ └── server/ # Application entry point ├── internal/ │ ├── app/ # Application wiring and dependency injection │ ├── contract/ # API contracts (request/response DTOs) │ ├── handler/ # HTTP handlers and routes │ ├── service/ # Business logic orchestration │ ├── processor/ # Complex business operations │ ├── repository/ # Data access layer │ ├── models/ # Pure business models │ ├── entities/ # Database entities (GORM models) │ ├── constants/ # Business constants and enums │ ├── transformer/ # Contract ↔ Model transformations │ └── mappers/ # Model ↔ Entity transformations ├── migrations/ # Database migrations ├── Makefile # Build and development commands ├── go.mod # Go module definition └── README.md # This file ``` ## Dependencies - **[Gorilla Mux](https://github.com/gorilla/mux)** - HTTP router and URL matcher - **[GORM](https://gorm.io/)** - ORM for database operations - **[PostgreSQL Driver](https://github.com/lib/pq)** - PostgreSQL database driver - **[Validator](https://github.com/go-playground/validator)** - Struct validation - **[UUID](https://github.com/google/uuid)** - UUID generation and parsing ## Contributing 1. Fork the repository 2. Create a feature branch 3. Commit your changes 4. Push to the branch 5. Create a Pull Request ## License This project is licensed under the MIT License - see the LICENSE file for details.