sgrbot is a Discord bot written in Go, designed with a modular architecture that follows Domain-Driven Design (DDD) principles and Test-Driven Development (TDD) practices.
sgrbot employs a modular architecture. The core functionality of the bot is
implemented in internal/bot, while additional features are implemented as
modules under internal/modules.
Modules register themselves via init() functions, allowing the main package
to include them with blank imports:
import (
_ "github.com/sglre6355/sgrbot/internal/modules/example"
)Each module follows a layered architecture:
- Domain Layer: Pure business logic, entities, value objects, and repository interfaces. No external dependencies.
- Application Layer: Application logic (interactors). Depends only on domain and defines port interfaces for infrastructure.
- Infrastructure Layer: Implements interfaces defined by domain/application (adapters). Handles external systems (e.g. databases).
- Presentation Layer: Discord-facing code (commands, handlers). Translates between Discord API and application/usecase logic.
- Domain and application/usecase layers have comprehensive unit tests
- Tests use mock implementations of interfaces
- Test files are co-located with implementation (
*_test.go) - Adheres to t_wada's TDD principles
| Component | Technology |
|---|---|
| Language | Go |
| Discord Library | github.com/bwmarrin/discordgo |
| Config | github.com/caarlos0/env/v11 (environment variables) |
| Logging | log/slog (structured JSON logging) |
sgrbot/
├── cmd/
│ └── sgrbot/
│ └── main.go # Entry point, signal handling
├── internal/
│ ├── bot/
│ │ ├── bot.go # Bot lifecycle, session management
│ │ ├── config.go # Environment config loading
│ │ ├── module.go # Module interface definition
│ │ ├── registry.go # Global module registry
│ │ └── responder.go # Discord response helpers
│ └── modules/
└── go.mod
type Module interface {
Name() string
Commands() []*discordgo.ApplicationCommand
CommandHandlers() map[string]InteractionHandler
EventHandlers() []EventHandler
Init(deps ModuleDependencies) error
Shutdown() error
}Modules can optionally implement ConfigurableModule to load and validate
module-specific configuration before Init() and before the Discord connection
is established.
type ConfigurableModule interface {
LoadConfig() error
}main()loads config and createsBotBot.LoadModules()retrieves modules from global registryBot.Start():- Loads module configuration (optional
ConfigurableModule.LoadConfig()) - Creates Discord session
- Registers interaction handler
- Opens Discord connection
- Calls
module.Init()for each module (after Open so session state is available) - Builds handler map
- Registers event handlers
- Registers slash commands
- Loads module configuration (optional
- Wait for SIGINT/SIGTERM
Bot.Stop()callsmodule.Shutdown()and closes session
Environment variables:
DISCORD_TOKEN: (required)LOG_LEVEL: Log level (debug,info,warn,error). Defaults toinfo.
# Development
DISCORD_TOKEN=your_token go run ./cmd/sgrbot
# Build with version
go build -ldflags "-X main.version=1.0.0" ./cmd/sgrbot# Run all tests
go test -race ./...
# Run with coverage
go test -race -cover ./...
# Run specific module tests
go test -race ./internal/modules/example/...