A Go REST server that manages modules and releases with filesystem-backed artifacts and a GORM-backed database. This repository provides a lightweight release-management backend with simple authentication, role/permission checks, and file storage for releases.
Quick highlights:
- HTTP API: Built with Gin.
- DB: GORM for data persistence.
- File storage: Releases and module artifacts stored on disk (configurable folders).
- Auth & Permissions: JWT-based middleware and permission checks.
Table of contents
- Overview
- Features
- Architecture
- API Quickstart & Reference
- Getting started
- Configuration
- Development conventions
- Testing
- Useful files
- Contributing
EvaModuleRepositoryServer exposes REST endpoints to manage modules and releases. It supports creating modules, uploading releases (files), listing/searching, and basic user/permission management. The codebase is organized by handlers, services, repositories, and models to keep handlers thin and business logic in services.
- Module management: create, update, list, and view modules.
- Release management: upload/download release artifacts, release metadata, and status tracking.
- File-based storage: release files persist to disk; paths are configurable.
- Authentication & authorization: JWT middleware and role/permission checks for endpoints.
- Transactional server-side operations: services provide transactional variants for DB + filesystem workflows.
- Test resources: example test resources and utilities under the
testsfolder.
The project is layered for clarity and testability:
cmd/server: application bootstrap and wiring.internal/backend: constructs services, repositories, and other dependencies.internal/routes: route definitions and middleware registration.internal/handlers: HTTP controllers (parse requests, validate input, return DTOs).internal/services: business logic, transactions, filesystem coordination.internal/repositories: GORM-based DB access; exposeGetDB()for transactional work.internal/models: domain objects and enums.internal/dto: response/request DTOs used by handlers.pkg/*: utilities, logger factory, and helpers (filesystem, utils, SQL helpers).
Design notes:
- Handlers should remain thin — most logic belongs in services.
- Multi-step operations that touch DB and filesystem should use the service
Txpattern (useutils.WithGormTransactionand repositoryGetDB()to obtain atx).
From the repository root (this is important because the config loader uses os.Getwd()):
Development (direct):
go run main.goBuild (direct):
go build ./...Makefile targets (convenience targets provided in the project Makefile):
make run: run the application (go run main.go)make build: build the binary (go build main.go)make goClean: rungo mod tidymake clean: remove generated*.exefilesmake testCoverage: run tests with coverage for core packages and writecoverage.outmake showCoverage: display the HTML coverage report fromcoverage.out
You can run a make target like:
make runRun tests (direct):
go test ./...
# or run specific tests
go test ./tests -run TestNameConfiguration is loaded from internal/config/application.properties by default. Key properties used by the application include:
module_folder: base path for module metadata files.release_folder: base path where release artifacts are saved.dev_folder: developer-specific storage (for local/dev flows).server_port: HTTP server listen port.- JWT and logging settings: secret, expiry, log level.
Test and helper functions support initializing config with an explicit properties map or path (see cmd/server test helpers).
- Keep handlers minimal — delegate business logic to
internal/services. - For DB changes that must be atomic with filesystem changes, implement a
*Txmethod in services and useutils.WithGormTransaction. - Use DTOs in
internal/dtofor handler responses rather than exposing GORM models directly. - Use
pkg/utilsresponse helpers (OkWithMessage,Err) for consistent JSON output.
- Test resources are under
tests/test_resources. - Use
InitializeWithPropertiesMaputilities when you need to alter folders/ports for isolated tests. - Run
go test ./...to execute all tests.
- Server entrypoint: cmd/server/server.go
- Config loader: internal/config/configreader.go
- Route map: internal/routes/router.go
- Example handler: internal/handlers/modulehandler.go
- Core service: internal/services/moduleservice.go
- Repositories: internal/repositories
- Models and DTOs: internal/models and internal/dto
- Utils and helpers: pkg/utils/utils.go, pkg/runtime/loggerfactory.go
This section summarizes the HTTP API grouped by route and provides quick curl examples for common flows.
POST /api/auth/login—AuthHandler.Login— obtain JWTPOST /api/auth/refresh—AuthHandler.Refresh— refresh tokenPOST /api/auth/register—AuthHandler.Register— create account
Example: login
curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"alice","password":"s3cret"}'
# Response contains access token (JWT)GET /api/modules/:id—ModuleHandler.FindByIDGET /api/modules/search—ModuleHandler.SearchModulesByTagsPOST /api/modules/delete—ModuleHandler.Delete(Auth + permissions)POST /api/modules/upload—ModuleHandler.Upload(Auth + multipart + permissions)POST /api/modules/update—ModuleHandler.Update(Auth + permissions)POST /api/modules/suggest—ModuleHandler.SuggestRelease(Auth + permissions)
Example: create/upload module (multipart)
# First obtain JWT from /api/auth/login, then use it in Authorization header
curl -X POST http://localhost:8080/api/modules/upload \
-H "Authorization: Bearer $JWT" \
-F "metadata=@module.json;type=application/json" \
-F "file=@artifact.zip;type=application/zip"Example: search modules by tags
curl "http://localhost:8080/api/modules/search?tag=parser&tag=example"GET /api/releases/:id—ReleaseHandler.GetModuleReleases(list by module id)GET /api/releases/:id/release/:releaseId—ReleaseHandler.GetModuleRelease(single release)GET /api/releases/:id/search—ReleaseHandler.SearchByKeywordsPOST /api/releases/:id/delete/:releaseId—ReleaseHandler.DeleteModuleRelease(Auth + permissions)POST /api/releases/:id/cancel/:releaseId—ReleaseHandler.CancelSuggestedRelease(Auth + permissions)
Example: list releases for module
curl http://localhost:8080/api/releases/123GET /api/download/release/:releaseId—DownloadHandler.DownloadRelease(download accepted release)
Example: download release
curl -L -o myrelease.zip http://localhost:8080/api/download/release/456All supervise endpoints require Auth + appropriate permission checks.
GET /api/supervise/download/release/:releaseId—DownloadHandler.DownloadAnyRelease(permission:UpdateReleases)POST /api/supervise/reject/release/:releaseId—ReleaseHandler.RejectRelease(permission:RejectReleases)POST /api/supervise/accept/release/:releaseId—ReleaseHandler.AcceptRelease(permission:AcceptReleases)POST /api/supervise/cancel/release/:releaseId—ReleaseHandler.CancelRelease(permission:CancelReleases)POST /api/supervise/pending/release/:releaseId—ReleaseHandler.ChangeToPendingRelease(permission:CancelReleases)POST /api/supervise/ban/:userId—SuperviseHandler.BanUser(permissions:BanUsers,UnbanUsers)POST /api/supervise/unban/:userId—SuperviseHandler.UnbanUser(permissions:BanUsers,UnbanUsers)
Example: accept a pending release (supervisor)
curl -X POST http://localhost:8080/api/supervise/accept/release/456 \
-H "Authorization: Bearer $SUPERVISOR_JWT"- The API base path is
/api. - Default upload limit is 8 MB (adjustable in router code via
EvaModuleRepositoryRouter.SetUploadFileLimit). - All protected endpoints require
Authorization: Bearer <JWT>header. - Permission names are defined in
internal/models(for exampleAcceptReleases,DeleteMyModule). - For handler implementation details, see
internal/handlers/*and service logic ininternal/services/*.
- Follow the existing project structure: handlers -> services -> repositories.
- Add tests for new behavior and update
tests/test_resourcesas needed. - Keep configuration usage consistent; prefer using provided helpers for tests.
See the repository LICENSE file.