Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/helpers/projectHelper.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func (h *projectHelper) InitProject(project models.Project) error {
fileConfigs := []models.FileConfig{
{TemplatePath: "templates/gitignore.tmpl", Destination: "/.gitignore"},
{TemplatePath: "templates/Makefile.tmpl", Destination: "/Makefile"},
{TemplatePath: "templates/README.md", Destination: "/README.md"},
{TemplatePath: "templates/go.tmpl", Destination: "/go.mod"},
{TemplatePath: "templates/main.tmpl", Destination: "/main.go"},
{TemplatePath: "templates/editorconfig.tmpl", Destination: "/.editorconfig"},
Expand Down
126 changes: 126 additions & 0 deletions templates/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# 🧭 Project Structure Documentation

This Go project was scaffolded using [`gozen`](https://github.com/tech-thinker/gozen). It follows a clean and modular architecture suited for microservices and REST/gRPC APIs.

## 🗂️ Root-Level Files and Directories

| Path | Description |
|-----------------------------|-------------------------------------------------------------------------|
| `main.go` | Entry point that initializes and runs the application. |
| `go.mod`, `go.sum` | Go modules files for dependency management. |
| `Makefile` | Contains commands to build, run, and manage the project. |
| `gozen.json` | GoZen metadata and configuration file. |
| `docker-compose*.yml` | Docker Compose files for different environments (dev, debug, prod). |
| `Dockerfile*` | Docker configurations for building images in various contexts. |
| `modd-*.conf` | Modd configs for live reloading. |
| `.env`, `.env.example` | Environment variables configuration files. |
| `.gitignore` | Git ignore file for project-specific files and directories. |
| `.editorconfig` | Editor configuration file for consistent coding styles. |

### Environment Variables
| Environment | Description |
|-----------------------------|-------------------------------------------------------------------------|
| VERSION | Application version. |
| APP_NAME | Application name. |
| APP_ENV | Environment name (development, staging, production). |
| API_PORT | Port number for the rest api to listen on. |
| GRPC_PORT | Port number for the gRPC api to listen on. |
| DB_DRIVER | Database driver (mysql, postgres, sqlite etc.). |
| DB_HOST | Database host address. |
| DB_PORT | Database port number. |
| DB_USER | Database username. |
| DB_PASS | Database password. |
| DB_NAME | Database name. |


## 📦 Application Structure

### `app/`
Main application logic divided into REST and gRPC interfaces.

#### `app/init.go`
- Main service registry for the application.


### `app/rest/`
Handles REST API endpoints.

| Path | Description |
|-----------------------------|-------------------------------------------------|
| `controllers/health.go` | Health check handler implementation (REST). |
| `router/router.go` | REST route registration. |


### `app/grpc/`
Handles gRPC endpoints and server setup.

| Path | Description |
|---------------------------------|--------------------------------------------------|
| `handlers/health.go` | Health check handler implementation (gRPC). |
| `proto/health.proto` | Protobuf definitions for health service. |
| `proto/*.pb.go` | Generated Go code from `.proto`. |
| `router/router.go` | gRPC server and service registration. |


## ⚙️ Configuration and Constants

### `config/config.go`
- Centralized configuration handling environments.

### `constants/app.go`
- Defines constants used throughout the application.


## 🧱 Core Domain Layers

### `models/health.go`
- Domain model for the health resource.

### `repository/health.go`
- Database or external service access logic for health module.

### `service/health.go`
- Business logic layer for the health service.


## 🧰 Supporting Infrastructure

### `instance/`

| Path | Description |
|------------------------------|------------------------------------------------------------------|
| `instance.go` | Initializes shared instances (DB, cache, etc). |
| `registry/models.go` | Structures for model registry or instance metadata. |


### `logger/logger.go`
- Logger setup and utilities (e.g., wrapper for Zap or Logrus).


### `runner/`

| Path | Description |
|-----------------|------------------------------------|
| `api.go` | Initializes and runs REST server. |
| `grpc.go` | Initializes and runs gRPC server. |


### `utils/utils.go`
- General-purpose utility functions.


## 🐳 Docker Support

| Path | Description |
|------------------------|---------------------------------------------------|
| `Dockerfile*` | Various Dockerfiles for dev/debug/production. |
| `modd-*.conf` | Live-reload configs using `modd` utility. |


## ✅ Summary

This project structure promotes:

- **Separation of Concerns**: Clear division between transport, logic, and infrastructure.
- **Scalability**: Easy to add new modules or services.
- **Maintainability**: Decoupled layers and modular design.
12 changes: 10 additions & 2 deletions templates/config/config.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "github.com/spf13/viper"
type Configuration interface {
Version() string
AppName() string
AppEnv() string
APIPort() string
GrpcPort() string

Expand All @@ -18,6 +19,7 @@ type Configuration interface {
type configuration struct {
version string
appName string
appEnv string
apiPort string
grpcPort string

Expand All @@ -39,6 +41,11 @@ func (cfg *configuration) AppName() string {
return cfg.appName
}

// AppEnv returns AppEnv
func (cfg *configuration) AppEnv() string {
return cfg.appEnv
}

// APIPort returns port
func (cfg *configuration) APIPort() string {
return cfg.apiPort
Expand Down Expand Up @@ -87,10 +94,11 @@ func Init(

env.AutomaticEnv()
config.version = env.GetString("version")
config.apiPort = env.GetString("app_name")
config.appName = env.GetString("app_name")
config.appEnv = env.GetString("app_env")
config.apiPort = env.GetString("api_port")
config.grpcPort = env.GetString("grpc_port")

config.db_driver = env.GetString("db_driver")
config.db_host = env.GetString("db_host")
config.db_port = env.GetString("db_port")
Expand Down
6 changes: 6 additions & 0 deletions templates/constants/app.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package constants

const (
APP_ENV_DEVELOPMENT = "development"
APP_ENV_STAGING = "staging"
APP_ENV_PRODUCTION = "production"
)

const (
DbDriverSQLite = "sqlite"
DbDriverMySQL = "mysql"
Expand Down
1 change: 1 addition & 0 deletions templates/env.sample.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
VERSION=1.0.0
APP_NAME={{.AppName}}
APP_ENV=development
API_PORT=3000
GRPC_PORT=3001

Expand Down
8 changes: 5 additions & 3 deletions templates/instance/instance.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ func Init(cfg config.Configuration) Instance {
instance := &instance{}

var conn gorm.Dialector
if cfg.DbDriver() == constants.DbDriverSQLite {
conn = sqlite.Open(cfg.DbName())
} else if cfg.DbDriver() == constants.DbDriverMySQL {
if cfg.DbDriver() == constants.DbDriverMySQL {
url := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", cfg.DbUser(), cfg.DbPass(), cfg.DbHost(), cfg.DbPort(), cfg.DbName())
conn = mysql.Open(url)
} else if cfg.DbDriver() == constants.DbDriverPostgres {
url := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Jakarta", cfg.DbHost(), cfg.DbUser(), cfg.DbPass(), cfg.DbName(), cfg.DbPort())
conn = postgres.Open(url)
} else if cfg.DbDriver() == constants.DbDriverSQLite {
conn = sqlite.Open(cfg.DbName())
} else {
log.Fatal("unsupported database driver. use [mysql, postgres or sqlite] instead.")
}
gormDB, err := gorm.Open(conn, &gorm.Config{})
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions templates/runner/grpc.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import (
"{{.PackageName}}/app"
"{{.PackageName}}/app/grpc/router"
"{{.PackageName}}/config"
"{{.PackageName}}/constants"
"{{.PackageName}}/instance"
"{{.PackageName}}/logger"
"google.golang.org/grpc/reflection"
)

// GrpcRunner is the interface for rest grpcRunner runner
Expand All @@ -39,6 +41,9 @@ func (runner *grpcRunner) Go(ctx context.Context, wg *sync.WaitGroup) {
}

routerV1 := router.Init(svc)
if runner.cfg.AppEnv() == constants.APP_ENV_DEVELOPMENT {
reflection.Register(routerV1)
}

// Channel to listen for interrupt signals
stopChan := make(chan os.Signal, 1)
Expand Down