api-go
	|
	|-------> cmd/server
	|             |------> main.go
	|
	|
	|-------> internal 
	|             |
	|             |------> app
	|             |         |-----> app.go
	|             |    
	|             |------> auth
	|             |         |-----> jwt.go 
	|             |
	|             |
	|							|------> db
	|							|         |-----> postgres.go
	|             |         |
	|             |         |-----> seed
	|             |                   |--------> admin.go // added
	|             |                   
	|             |         
	|							|
	|							|------> domain 
	|             |         |-----> errors.go
	|             |         |
	|             |         |-----> user.go
	|             |         |
	|							|         |-----> website.go
	|							|
	|							|------> dto
	|							|					|-----> websites.go
	|             |         |
	|             |         |-----> auth.go      
	|             |
	|							|
	|							|------> handlers
	|							|					|-----> websites.go
	|             |         |
	|             |         |-----> users.go     
	|             |
	|             |
	|             |------> http
	|             |         |-----> apperror
	|							|         |          |-----------> mapper.go
	|             |         |
	|             |         |-----> context
	|             |         |          |-----------> context.go
	|             |         |
	|             |         |-----> middleware
	|             |         |          |-----------> auth.go
	|             |         |          |
	|             |         |          |-----------> rateLimit.go
	|             |         |          |
	|             |         |          |-----------> rbac.go // added
	|             |         |
	|             |         |     
	|             |         |
	|							|         |-----> response
	|							|                    |-----------> response.go 		
	|             |
	|							|
	|							|------> repository
	|							|         |-----> website_repository_pg.go
	|							|         |-----> website_repository.go
	|             |         |-----> user_repository.go     
	|             |         |-----> user_repository_pg.go  
	|							|
	|							|
	|							|------> routes
	|							|					|-----> websites.go
	|             |         |
	|             |         |-----> health.go
	|             |         |
	|             |         |-----> router.go
	|             |         |
	|             |         |-----> user.go   
	|             |         |
	|             |         |-----> admin.go    // added
	|             |            
	|             |
	|							|
	|							|------> service
	|							|					|-----> websites.go	
	|             |         |
	|             |         |-----> users.go 
	|             |         
	|             |
	|             |------> validation
	|                       |-----> password.go	
	|
	|------> migrations
	|							|------> 20251226095007_create_websites_table.down.sql		
	|							|------> 20251226095007_create_websites_table.up.sql	
	|
	|------> .env	

Seeding Admin to DB

Step 1 : Update .env file at these

APP_ENV = "dev"
ADMIN_EMAIL = "[email protected]"
ADMIN_PASSWORD = "runstate-admin-logging"

Step 2 : Create SeedAdmin function

internal/db/seed/admin.go

package seed

import (
	"errors"
	"os"

	"github.com/jmoiron/sqlx"
	"golang.org/x/crypto/bcrypt"
)

// Creates a default admin user in the database only if it doesn't already exists.

func SeedAdmin(db *sqlx.DB) error {
	adminEmail := os.Getenv("ADMIN_EMAIL")
	adminPassword := os.Getenv("ADMIN_PASSWORD")

	if adminEmail == "" || adminPassword == "" {
		return errors.New("ADMIN_EMAIL or ADMIN_PASSWORD not set")
	}

	query := `
	INSERT INTO users (email, password, role)
	VALUES ($1, $2, 'ADMIN')
	ON CONFLICT (email) DO NOTHING
	`

	hashed, err := bcrypt.GenerateFromPassword(
		[]byte(adminPassword),
		bcrypt.DefaultCost,
	)

	if err != nil {
		return err
	}

	_, err = db.Exec(
		query,
		adminEmail,
		string(hashed),
	)
	return err
}

Step 3 : Add seeding logic at app startup

internal/app/app.go

package app

import (
	"log"
	"os"
	"time"

	"github.com/RitikaxG/runState/apps/api-go/internal/auth"
	"github.com/RitikaxG/runState/apps/api-go/internal/db"
	"github.com/RitikaxG/runState/apps/api-go/internal/db/seed"
	"github.com/RitikaxG/runState/apps/api-go/internal/handlers"
	"github.com/RitikaxG/runState/apps/api-go/internal/http/middleware"
	"github.com/RitikaxG/runState/apps/api-go/internal/repository"
	"github.com/RitikaxG/runState/apps/api-go/internal/routes"
	"github.com/RitikaxG/runState/apps/api-go/internal/service"
	"github.com/RitikaxG/runState/apps/api-go/internal/validation"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
)

func BuildServer() *gin.Engine {
	r := gin.Default()

	dbConn := db.NewPostgres(os.Getenv("DATABASE_URL"))

	// Add Seeding
	if os.Getenv("APP_ENV") == "development" || os.Getenv("APP_ENV") == "local" {
		if err := seed.SeedAdmin(dbConn); err != nil {
			log.Fatal("failed to seed admin:", err)
		}
	}

	// 1. Initialise JWT Manager
	jwtManager := auth.NewJWTManager(
		os.Getenv("JWT_SECRET"),
		24*time.Hour,
	)

	// Start cleanup goroutine once
	middleware.StartRateLimiterCleanup()

	// Apply rate limiting to all requests
	r.Use(middleware.RateLimitMiddleware())

	websiteRepo := repository.NewWebsiteRepository(dbConn)
	websiteService := service.NewWebsiteService(websiteRepo)
	websiteHandler := handlers.NewWebsiteHandler(websiteService)

	userRepo := repository.NewUserRepository(dbConn)
	userService := service.NewUserService(userRepo, jwtManager)
	userHandler := handlers.NewUserHandler(userService)

	routes.RegisterRouter(r, websiteHandler, userHandler, jwtManager)

	/*
		Custom validators live in a validation package and must be registered once during app startup before routes run.

			It gets Gin’s internal validator engine,
			safely casts it to *validator.Validate, and registers your custom password rule.

			- binding.Validator : Gin's global validator instance
			- binding.Validator.Engine() : returns actual underlying validator, its return type is interface
			- .(*validator.Validate) → type assertion
				 Is this engine actually a *validator.Validate ?
				 Since it returned an interface this type check is imp)
			- ok : true if assertion succeeded otherwise false
	*/
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		validation.RegisterPasswordValidator(v)
	}

	return r
}

Step 4 : Load .env at cmd/server/main.go

 // Install godotenv package
 go get github.com/joho/godotenv

cmd/server/main.go

package main

import (
	"github.com/RitikaxG/runState/apps/api-go/internal/app"
	"github.com/joho/godotenv"
)

func main() {
// Load env
	_ = godotenv.Load()
	server := app.BuildServer()
	server.Run(":3001")
}