{"id":13400435,"url":"https://github.com/evrone/go-clean-template","last_synced_at":"2026-04-05T23:08:59.134Z","repository":{"id":37094342,"uuid":"330616364","full_name":"evrone/go-clean-template","owner":"evrone","description":"Clean Architecture template for Golang services","archived":false,"fork":false,"pushed_at":"2026-03-28T12:52:59.000Z","size":1750,"stargazers_count":7524,"open_issues_count":4,"forks_count":651,"subscribers_count":46,"default_branch":"master","last_synced_at":"2026-03-28T16:05:18.808Z","etag":null,"topics":["clean-architecture","dependency-injection","example","go","golang","microservices","template"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evrone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-01-18T09:29:43.000Z","updated_at":"2026-03-28T12:53:01.000Z","dependencies_parsed_at":"2025-04-01T20:11:13.847Z","dependency_job_id":"1f859ac3-54b3-48b7-b112-3afabd10c7bd","html_url":"https://github.com/evrone/go-clean-template","commit_stats":{"total_commits":146,"total_committers":14,"mean_commits":"10.428571428571429","dds":"0.48630136986301364","last_synced_commit":"34844d644b3cd20696b7bebbec32b0a65678ba7a"},"previous_names":["evrone/go-service-template"],"tags_count":51,"template":true,"template_full_name":null,"purl":"pkg:github/evrone/go-clean-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evrone%2Fgo-clean-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evrone%2Fgo-clean-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evrone%2Fgo-clean-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evrone%2Fgo-clean-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evrone","download_url":"https://codeload.github.com/evrone/go-clean-template/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evrone%2Fgo-clean-template/sbom","scorecard":{"id":213406,"data":{"date":"2025-08-11","repo":{"name":"github.com/evrone/go-clean-template","commit":"d082d079c9e0f35799b367abfd67e6e0baedcaad"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.4,"checks":[{"name":"Maintained","score":10,"reason":"30 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":2,"reason":"Found 1/5 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:54: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:55: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:59: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:66: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:67: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:79: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:35: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:36: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:45: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:46: update your workflow using https://app.stepsecurity.io/secureworkflow/evrone/go-clean-template/ci.yml/master?enable=pin","Warn: containerImage not pinned by hash: Dockerfile:2","Warn: containerImage not pinned by hash: Dockerfile:11","Warn: containerImage not pinned by hash: integration-test/Dockerfile:2","Warn: containerImage not pinned by hash: integration-test/Dockerfile:11: pin your Docker image by updating golang:1.24.6-alpine3.21 to golang:1.24.6-alpine3.21@sha256:50f8a10a46c0c26b5b816a80314f1999196c44c3e3571f41026b061339c29db6","Warn: downloadThenRun not pinned by hash: .github/workflows/ci.yml:74","Info:   0 out of  10 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   5 third-party GitHubAction dependencies pinned","Info:   0 out of   4 containerImage dependencies pinned","Info:   0 out of   1 downloadThenRun dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2022-0635","Warn: Project is vulnerable to: GO-2022-0646"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-17T01:10:17.293Z","repository_id":37094342,"created_at":"2025-08-17T01:10:17.293Z","updated_at":"2025-08-17T01:10:17.293Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31452902,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T21:22:52.476Z","status":"ssl_error","status_checked_at":"2026-04-05T21:22:51.943Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clean-architecture","dependency-injection","example","go","golang","microservices","template"],"created_at":"2024-07-30T19:00:51.999Z","updated_at":"2026-04-05T23:08:59.129Z","avatar_url":"https://github.com/evrone.png","language":"Go","readme":"![Go Clean Template](docs/img/logo.svg)\n\n# Go Clean template\n\n[🇨🇳 中文](README_CN.md)\n[🇷🇺 RU](README_RU.md)\n\nClean Architecture template for Golang services\n\n[![Release](https://img.shields.io/github/v/release/evrone/go-clean-template.svg)](https://github.com/evrone/go-clean-template/releases/)\n[![License](https://img.shields.io/badge/License-MIT-success)](https://github.com/evrone/go-clean-template/blob/master/LICENSE)\n[![Go Report Card](https://goreportcard.com/badge/github.com/evrone/go-clean-template)](https://goreportcard.com/report/github.com/evrone/go-clean-template)\n[![codecov](https://codecov.io/gh/evrone/go-clean-template/branch/master/graph/badge.svg?token=XE3E0X3EVQ)](https://codecov.io/gh/evrone/go-clean-template)\n\n[![Web Framework](https://img.shields.io/badge/Fiber-Web%20Framework-blue)](https://github.com/gofiber/fiber)\n[![API Documentation](https://img.shields.io/badge/Swagger-API%20Documentation-blue)](https://github.com/swaggo/swag)\n[![Validation](https://img.shields.io/badge/Validator-Data%20Integrity-blue)](https://github.com/go-playground/validator)\n[![JSON Handling](https://img.shields.io/badge/Go--JSON-Fast%20Serialization-blue)](https://github.com/goccy/go-json)\n[![Query Builder](https://img.shields.io/badge/Squirrel-SQL%20Query%20Builder-blue)](https://github.com/Masterminds/squirrel)\n[![Database Migrations](https://img.shields.io/badge/Migrations-Seamless%20Schema%20Updates-blue)](https://github.com/golang-migrate/migrate)\n[![Logging](https://img.shields.io/badge/ZeroLog-Structured%20Logging-blue)](https://github.com/rs/zerolog)\n[![Metrics](https://img.shields.io/badge/Prometheus-Metrics%20Integration-blue)](https://github.com/ansrivas/fiberprometheus)\n[![Testing](https://img.shields.io/badge/Testify-Testing%20Framework-blue)](https://github.com/stretchr/testify)\n[![Mocking](https://img.shields.io/badge/Mock-Mocking%20Library-blue)](https://go.uber.org/mock)\n\n## Overview\n\nThe purpose of the template is to show:\n\n- how to organize a project and prevent it from turning into spaghetti code\n- where to store business logic so that it remains independent, clean, and extensible\n- how not to lose control when a microservice grows\n\nUsing the principles of Robert Martin (aka Uncle Bob).\n\n[Go-clean-template](https://evrone.com/go-clean-template?utm_source=github\u0026utm_campaign=go-clean-template) is created \u0026\nsupported by [Evrone](https://evrone.com/?utm_source=github\u0026utm_campaign=go-clean-template).\n\nThis template implements four types of servers:\n\n- AMQP RPC (based on RabbitMQ as [transport](https://github.com/rabbitmq/amqp091-go)\n  and [Request-Reply pattern](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html))\n- MQ RPC (based on NATS as [transport](https://github.com/nats-io/nats.go)\n  and [Request-Reply pattern](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html))\n- gRPC ([gRPC](https://grpc.io/) framework based on protobuf)\n- REST API ([Fiber](https://github.com/gofiber/fiber) framework)\n\nThe template includes three domains to demonstrate multi-service architecture:\n\n- **User Authentication** — registration, login, JWT-based authorization\n- **Task Management** — CRUD operations with status transitions (todo, in_progress, done)\n- **Translation** — text translation with history tracking\n\nAll domains are available across all four transports (REST, gRPC, AMQP RPC, NATS RPC).\n\n## Content\n\n- [Domains](#domains)\n- [Quick start](#quick-start)\n- [Project structure](#project-structure)\n- [Dependency Injection](#dependency-injection)\n- [Clean Architecture](#clean-architecture)\n\n## Domains\n\nThe template includes three fully implemented domains, each available across all four transports (REST, gRPC, AMQP RPC, NATS RPC).\n\n### User Authentication\n\nRegistration, login, and JWT-based authorization.\n\n| Operation   | REST                     | gRPC                     |\n|-------------|--------------------------|--------------------------|\n| Register    | `POST /v1/auth/register` | `AuthService/Register`   |\n| Login       | `POST /v1/auth/login`    | `AuthService/Login`      |\n| Get profile | `GET /v1/user/profile`   | `AuthService/GetProfile` |\n\n- Passwords hashed with bcrypt\n- JWT tokens with configurable expiry\n- Auth middleware on all transports\n\n### Task Management\n\nCRUD operations with a status state machine.\n\n| Operation  | REST                         | gRPC                         |\n|------------|------------------------------|------------------------------|\n| Create     | `POST /v1/tasks`             | `TaskService/CreateTask`     |\n| List       | `GET /v1/tasks`              | `TaskService/ListTasks`      |\n| Get        | `GET /v1/tasks/:id`          | `TaskService/GetTask`        |\n| Update     | `PUT /v1/tasks/:id`          | `TaskService/UpdateTask`     |\n| Transition | `PATCH /v1/tasks/:id/status` | `TaskService/TransitionTask` |\n| Delete     | `DELETE /v1/tasks/:id`       | `TaskService/DeleteTask`     |\n\n- Status transitions: `todo` → `in_progress` → `done` (and `in_progress` → `todo`)\n- Pagination with `limit`/`offset` and optional status filter\n- Tasks scoped to the authenticated user\n\n### Translation\n\nText translation via external API with history tracking.\n\n| Operation | REST                                | gRPC                                    |\n|-----------|-------------------------------------|-----------------------------------------|\n| Translate | `POST /v1/translation/do-translate` | `TranslationHistoryService/DoTranslate` |\n| History   | `GET /v1/translation/history`       | `TranslationHistoryService/ShowHistory` |\n\n## Quick start\n\n### Local development\n\n```sh\n# Postgres, RabbitMQ, NATS\nmake compose-up\n# Run app with migrations\nmake run\n```\n\n### Integration tests (can be run in CI)\n\n```sh\n# DB, app + migrations, integration tests\nmake compose-up-integration-test\n```\n\n### Full docker stack with reverse proxy\n\n```sh\nmake compose-up-all \n```\n\nCheck services:\n\n- AMQP RPC:\n  - URL: `amqp://guest:guest@127.0.0.1:5672/`\n  - Client Exchange: `rpc_client`\n  - Server Exchange: `rpc_server`\n- NATS RPC:\n  - URL: `nats://guest:guest@127.0.0.1:4222/`\n  - Server Exchange: `rpc_server`\n- REST API:\n  - http://app.lvh.me/healthz | http://127.0.0.1:8080/healthz\n  - http://app.lvh.me/metrics | http://127.0.0.1:8080/metrics\n  - http://app.lvh.me/swagger | http://127.0.0.1:8080/swagger\n- gRPC:\n  - URL: `tcp://grpc.lvh.me:8081` | `tcp://127.0.0.1:8081`\n  - [v1/auth.proto](docs/proto/v1/auth.proto)\n  - [v1/task.proto](docs/proto/v1/task.proto)\n  - [v1/translation.history.proto](docs/proto/v1/translation.history.proto)\n- PostgreSQL:\n  - `postgres://user:myAwEsOm3pa55@w0rd@127.0.0.1:5432/db`\n- RabbitMQ:\n  - http://rabbitmq.lvh.me | http://127.0.0.1:15672\n  - Credentials: `guest` / `guest`\n- NATS monitoring:\n  - http://nats.lvh.me | http://127.0.0.1:8222/\n  - Credentials: `guest` / `guest`\n\n## Project structure\n\n### `cmd/app/main.go`\n\nConfiguration and logger initialization. Then the main function \"continues\" in\n`internal/app/app.go`.\n\n### `config`\n\nThe twelve-factor app stores config in environment variables (often shortened to `env vars` or `env`). Env vars are easy\nto change between deploys without changing any code; unlike config files, there is little chance of them being checked\ninto the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System\nProperties, they are a language- and OS-agnostic standard.\n\nConfig: [config.go](config/config.go)\n\nExample: [.env.example](.env.example)\n\n[docker-compose.yml](docker-compose.yml) uses `env` variables to configure services.\n\n### `docs`\n\nSwagger documentation. Auto-generated by [swag](https://github.com/swaggo/swag) library.\nYou don't need to correct anything by yourself.\n\n#### `docs/proto`\n\nProtobuf files. They are used to generate Go code for gRPC services.\nThe proto files are also used to generate documentation for gRPC services.\nYou don't need to correct anything by yourself.\n\n### `integration-test`\n\nIntegration tests.\nThey are launched as a separate container, next to the application container.\n\n### `internal/app`\n\nThere is always one _Run_ function in the `app.go` file, which \"continues\" the _main_ function.\n\nThis is where all the main objects are created.\nDependency injection occurs through the \"New ...\" constructors (see Dependency Injection).\nThis technique allows us to layer the application using the [Dependency Injection](#dependency-injection) principle.\nThis makes the business logic independent from other layers.\n\nNext, we start the server and wait for signals in _select_ for graceful completion.\nIf `app.go` starts to grow, you can split it into multiple files.\n\nFor a large number of injections, [wire](https://github.com/google/wire) can be used.\n\nThe `migrate.go` file is used for database auto migrations.\nIt is included if an argument with the _migrate_ tag is specified.\nFor example:\n\n```sh\ngo run -tags migrate ./cmd/app\n```\n\n### `internal/controller`\n\nServer handler layer (MVC controllers). The template shows 4 servers:\n\n- AMQP RPC (based on RabbitMQ as transport)\n- NATS RPC (based on NATS as transport)\n- gRPC ([gRPC](https://grpc.io/) framework based on protobuf)\n- REST API ([Fiber](https://github.com/gofiber/fiber) framework)\n\nServer routers are written in the same style:\n\n- Handlers are grouped by area of application (by a common basis)\n- For each group, its own router structure is created, the methods of which process paths\n- The structure of the business logic is injected into the router structure, which will be called by the handlers\n\n#### `internal/controller/amqp_rpc`\n\nSimple RPC versioning.\nFor v2, we will need to add the `amqp_rpc/v2` folder with the same content.\nAnd in the file `internal/controller/amqp_rpc/router.go` add the line:\n\n```go\nroutes := make(map[string]server.CallHandler)\n\n{\n    v1.NewRoutes(routes, t, u, tk, j, l)\n}\n\n{\n    v2.NewTranslationRoutes(routes, t, l)\n}\n```\n\n#### `internal/controller/grpc`\n\nSimple gRPC versioning.\nFor v2, we will need to add the `grpc/v2` folder with the same content.\nAlso add the `v2` folder to the proto files in `docs/proto`.\nAnd in the file `internal/controller/grpc/router.go` add the line:\n\n```go\n{\n    v1.NewAuthRoutes(app, u, l)\n    v1.NewTaskRoutes(app, tk, l)\n    v1.NewTranslationRoutes(app, t, l)\n}\n\n{\n    v2.NewAuthRoutes(app, u, l)\n    v2.NewTaskRoutes(app, tk, l)\n    v2.NewTranslationRoutes(app, t, l)\n}\n\nreflection.Register(app)\n```\n\n#### `internal/controller/nats_rpc`\n\nSimple RPC versioning.\nFor v2, we will need to add the `nats_rpc/v2` folder with the same content.\nAnd in the file `internal/controller/nats_rpc/router.go` add the line:\n\n```go\nroutes := make(map[string]server.CallHandler)\n\n{\n    v1.NewRoutes(routes, t, u, tk, j, l)\n}\n\n{\n    v2.NewTranslationRoutes(routes, t, l)\n}\n```\n\n#### `internal/controller/restapi`\n\nSimple REST versioning.\nFor v2, we will need to add the `restapi/v2` folder with the same content.\nAnd in the file `internal/controller/restapi/router.go` add the line:\n\n```go\napiV1Group := app.Group(\"/v1\")\n{\n\tv1.NewRoutes(apiV1Group, t, u, tk, jwtManager, l)\n}\napiV2Group := app.Group(\"/v2\")\n{\n\tv2.NewRoutes(apiV2Group, t, u, tk, jwtManager, l)\n}\n```\n\nInstead of [Fiber](https://github.com/gofiber/fiber), you can use any other http framework.\n\nIn `router.go` and above the handler methods, there are comments for generating swagger documentation\nusing [swag](https://github.com/swaggo/swag).\n\n### `internal/entity`\n\nEntities of business logic (models) can be used in any layer.\nThere can also be methods, for example, for validation.\n\n### `internal/usecase`\n\nBusiness logic.\n\n- Methods are grouped by area of application (on a common basis)\n- Each group has its own structure\n- One file - one structure\n\nRepositories, webapi, rpc, and other business logic structures are injected into business logic structures\n(see [Dependency Injection](#dependency-injection)).\n\n#### `internal/repo/persistent`\n\nA repository is an abstract storage (database) that business logic works with.\n\n#### `internal/repo/webapi`\n\nIt is an abstract web API that business logic works with.\nFor example, it could be another microservice that business logic accesses via the REST API.\nThe package name changes depending on the purpose.\n\n### `pkg/rabbitmq`\n\nRabbitMQ RPC pattern:\n\n- There is no routing inside RabbitMQ\n- Exchange fanout is used, to which 1 exclusive queue is bound, this is the most productive config\n- Reconnect on the loss of connection\n\n## Dependency Injection\n\nIn order to remove the dependence of business logic on external packages, dependency injection is used.\n\nFor example, through the New constructor, we inject the dependency into the structure of the business logic.\nThis makes the business logic independent (and portable).\nWe can override the implementation of the interface without making changes to the `usecase` package.\n\n```go\npackage usecase\n\nimport (\n// Nothing!\n)\n\ntype Repository interface {\n\tGet()\n}\n\ntype UseCase struct {\n\trepo Repository\n}\n\nfunc New(r Repository) *UseCase {\n\treturn \u0026UseCase{\n\t\trepo: r,\n\t}\n}\n\nfunc (uc *UseCase) Do() {\n\tuc.repo.Get()\n}\n```\n\nIt will also allow us to do auto-generation of mocks (for example with [go.uber.org/mock](https://go.uber.org/mock)) and\neasily write unit tests.\n\n\u003e We are not tied to specific implementations in order to always be able to change one component to another.\n\u003e If the new component implements the interface, nothing needs to be changed in the business logic.\n\n## Clean Architecture\n\n### Key idea\n\nProgrammers realize the optimal architecture for an application after most of the code has been written.\n\n\u003e A good architecture allows decisions to be delayed to as late as possible.\n\n### The main principle\n\nDependency Inversion (the same one from SOLID) is the principle of dependency injection.\nThe direction of dependencies goes from the outer layer to the inner layer.\nDue to this, business logic and entities remain independent from other parts of the system.\n\nSo, the application is divided into 2 layers, internal and external:\n\n1. **Business logic** (Go standard library).\n2. **Tools** (databases, servers, message brokers, any other packages and frameworks).\n\n![Clean Architecture](docs/img/layers-1.png)\n\n**The inner layer** with business logic should be clean. It should:\n\n- Not have package imports from the outer layer.\n- Use only the capabilities of the standard library.\n- Make calls to the outer layer through the interface (!).\n\nThe business logic doesn't know anything about Postgres or a specific web API.\nBusiness logic has an interface for working with an _abstract_ database or _abstract_ web API.\n\n**The outer layer** has other limitations:\n\n- All components of this layer are unaware of each other's existence. How to call another from one tool? Not directly,\n  only through the inner layer of business logic.\n- All calls to the inner layer are made through the interface (!).\n- Data is transferred in a format that is convenient for business logic (`internal/entity`).\n\nFor example, you need to access the database from HTTP (controller).\nBoth HTTP and database are in the outer layer, which means they know nothing about each other.\nThe communication between them is carried out through `usecase` (business logic):\n\n```\n    HTTP \u003e usecase\n           usecase \u003e repository (Postgres)\n           usecase \u003c repository (Postgres)\n    HTTP \u003c usecase\n```\n\nThe symbols \u003e and \u003c show the intersection of layer boundaries through Interfaces.\nThe same is shown in the picture:\n\n![Example](docs/img/example-http-db.png)\n\nOr more complex business logic:\n\n```\n    HTTP \u003e usecase\n           usecase \u003e repository\n           usecase \u003c repository\n           usecase \u003e webapi\n           usecase \u003c webapi\n           usecase \u003e RPC\n           usecase \u003c RPC\n           usecase \u003e repository\n           usecase \u003c repository\n    HTTP \u003c usecase\n```\n\n### Layers\n\n![Example](docs/img/layers-2.png)\n\n### Clean Architecture Terminology\n\n- **Entities** are structures that business logic operates on.\n  They are located in the `internal/entity` folder.\n  In MVC terms, entities are models.\n- **Use Cases** is business logic located in `internal/usecase`.\n\nThe layer with which business logic directly interacts is usually called the _infrastructure_ layer.\nThese can be repositories `internal/repo/persistent`, external webapi `internal/repo/webapi`, any pkg, and other\nmicroservices.\nIn the template, the _infrastructure_ packages are located inside `internal/repo`.\n\nYou can choose how to call the entry points as you wish. The options are:\n\n- controller (in our case)\n- delivery\n- transport\n- gateways\n- entrypoints\n- primary\n- input\n\n### Additional layers\n\nThe classic version\nof [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) was designed for\nbuilding large monolithic applications and has 4 layers.\n\nIn the original version, the outer layer is divided into two more, which also have an inversion of dependencies\nto each other (directed inward) and communicate through interfaces.\n\nThe inner layer is also divided into two (with separation of interfaces), in the case of complex logic.\n\n---\n\nComplex tools can be divided into additional layers.\nHowever, you should add layers only if really necessary.\n\n### Alternative approaches\n\nIn addition to Clean architecture, _Onion architecture_ and _Hexagonal_ (_Ports and adapters_) are similar to it.\nBoth are based on the principle of Dependency Inversion.\n_Ports and adapters_ are very close to _Clean Architecture_, the differences are mainly in terminology.\n\n## Similar projects\n\n- [https://github.com/bxcodec/go-clean-arch](https://github.com/bxcodec/go-clean-arch)\n- [https://github.com/zhashkevych/courses-backend](https://github.com/zhashkevych/courses-backend)\n\n## Useful links\n\n- [The Clean Architecture article](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)\n- [Twelve factors](https://12factor.net/ru/)\n","funding_links":[],"categories":["Go","Popular","Websites","Repositories","资源","clean-architecture","网站","Tutorials"],"sub_categories":["Tutorials","教程"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevrone%2Fgo-clean-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevrone%2Fgo-clean-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevrone%2Fgo-clean-template/lists"}