modular

package module
v1.4.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2025 License: MIT Imports: 23 Imported by: 17

README ΒΆ

modular

Modular Go

GitHub License Go Reference CodeQL Dependabot Updates CI Modules CI Examples CI Go Report Card codecov

Testing

Run all tests:

go test ./... -v
Parallel Module BDD Suites

To speed up BDD feedback locally you can execute module BDD suites in parallel:

chmod +x scripts/run-module-bdd-parallel.sh
scripts/run-module-bdd-parallel.sh 6   # 6 workers; omit number to auto-detect CPUs

The script prefers GNU parallel and falls back to xargs -P.

Overview

Modular is a package that provides a structured way to create modular applications in Go. It allows you to build applications as collections of modules that can be easily added, removed, or replaced. Key features include:

  • Module lifecycle management: Initialize, start, and gracefully stop modules
  • Dependency management: Automatically resolve and order module dependencies
  • Service registry: Register and retrieve application services
  • Configuration management: Handle configuration for modules and services
  • Configuration validation: Validate configurations with defaults, required fields, and custom logic
  • Sample config generation: Generate sample configuration files in various formats
  • Dependency injection: Inject required services into modules
  • Multi-tenancy support: Build applications that serve multiple tenants with isolated configurations
  • Observer pattern: Event-driven communication with CloudEvents support for standardized event handling

🧩 Available Modules

Modular comes with a rich ecosystem of pre-built modules that you can easily integrate into your applications:

Module Description Configuration Documentation
auth Authentication and authorization with JWT, sessions, password hashing, and OAuth2/OIDC support Yes Documentation
cache Multi-backend caching with Redis and in-memory support Yes Documentation
chimux Chi router integration with middleware support Yes Documentation
database Database connectivity and SQL operations with multiple driver support Yes Documentation
eventbus Asynchronous event handling and pub/sub messaging Yes Documentation
eventlogger Structured logging for Observer pattern events with CloudEvents support Yes Documentation
httpclient Configurable HTTP client with connection pooling, timeouts, and verbose logging Yes Documentation
httpserver HTTP/HTTPS server with TLS support, graceful shutdown, and configurable timeouts Yes Documentation
jsonschema JSON Schema validation services No Documentation
letsencrypt SSL/TLS certificate automation with Let's Encrypt Yes Documentation
reverseproxy Reverse proxy with load balancing, circuit breaker, and health monitoring Yes Documentation
scheduler Job scheduling with cron expressions and worker pools Yes Documentation

Each module is designed to be:

  • Plug-and-play: Easy integration with minimal configuration
  • Configurable: Extensive configuration options via YAML, environment variables, or code
  • Production-ready: Built with best practices, proper error handling, and comprehensive testing
  • Well-documented: Complete documentation with examples and API references

πŸ“– For detailed information about each module, see the modules directory or click on the individual module links above.

Governance & Engineering Standards

Core, non-negotiable project principles (TDD, lifecycle determinism, API stability, performance baselines, multi-tenancy isolation) are codified in the versioned Project Constitution. Day-to-day implementation checklists (interfaces, reflection usage, error style, logging fields, concurrency annotations, export review) live in Go Best Practices. Concurrency rules and race avoidance patterns are documented in Concurrency & Race Guidelines.

Always update docs & examples in the same PR as feature code; stale documentation is considered a failing gate.

🌩️ Observer Pattern with CloudEvents Support

Modular includes a powerful Observer pattern implementation with CloudEvents specification support, enabling event-driven communication between components while maintaining full backward compatibility.

Key Features
  • Traditional Observer Pattern: Subject/Observer interfaces for event emission and handling
  • CloudEvents Integration: Industry-standard event format with built-in validation and serialization
  • Dual Event Support: Emit and handle both traditional ObserverEvents and CloudEvents
  • ObservableApplication: Enhanced application with automatic lifecycle event emission
  • EventLogger Module: Structured logging for all events with multiple output targets
  • Transport Independence: Events ready for HTTP, gRPC, AMQP, and other transports
Quick Example
// Create observable application with CloudEvents support
app := modular.NewObservableApplication(configProvider, logger)

// Register event logger for structured logging
app.RegisterModule(eventlogger.NewModule())

// Emit CloudEvents using standardized format
event := modular.NewCloudEvent(
    "com.myapp.user.created",   // Type
    "user-service",             // Source  
    userData,                   // Data
    metadata,                   // Extensions
)
err := app.NotifyCloudEventObservers(context.Background(), event)
Documentation

Examples

The examples/ directory contains complete, working examples that demonstrate how to use Modular with different patterns and module combinations:

Example Description Features
basic-app Simple modular application HTTP server, routing, configuration
reverse-proxy HTTP reverse proxy server Load balancing, backend routing, CORS
http-client HTTP client with proxy backend HTTP client integration, request routing
advanced-logging Advanced HTTP client logging Verbose logging, file output, request/response inspection
observer-pattern Event-driven architecture demo Observer pattern, CloudEvents, event logging, real-time events
Quick Start with Examples

Each example is a complete, standalone application that you can run immediately:

cd examples/basic-app
GOWORK=off go build
./basic-app

Visit the examples directory for detailed documentation, configuration guides, and step-by-step instructions for each example.

Learning Path

Installation

go get github.com/GoCodeAlone/modular

Usage

Basic Application
package main

import (
    "github.com/GoCodeAlone/modular"
    "log/slog"
    "os"
)

func main() {
    // Create a logger
    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
    
    // Create config provider with application configuration
    config := &AppConfig{
        Name: "MyApp",
        Version: "1.0.0",
    }
    configProvider := modular.NewStdConfigProvider(config)
    
    // Create the application
    app := modular.NewStdApplication(configProvider, logger)
    
    // Register modules
    app.RegisterModule(NewDatabaseModule())
    app.RegisterModule(NewAPIModule())
    
    // Run the application (this will block until the application is terminated)
    if err := app.Run(); err != nil {
        logger.Error("Application error", "error", err)
        os.Exit(1)
    }
}
Creating a Module
type DatabaseModule struct {
    db     *sql.DB
    config *DatabaseConfig
}

func NewDatabaseModule() modular.Module {
    return &DatabaseModule{}
}

// RegisterConfig registers the module's configuration
func (m *DatabaseModule) RegisterConfig(app modular.Application) error {
    m.config = &DatabaseConfig{
        DSN: "postgres://user:password@localhost:5432/dbname",
    }
    app.RegisterConfigSection("database", modular.NewStdConfigProvider(m.config))
    return nil
}

// Name returns the module's unique name
func (m *DatabaseModule) Name() string {
    return "database"
}

// Dependencies returns other modules this module depends on
func (m *DatabaseModule) Dependencies() []string {
    return []string{} // No dependencies
}

// Init initializes the module
func (m *DatabaseModule) Init(app modular.Application) error {
    // Initialize database connection
    db, err := sql.Open("postgres", m.config.DSN)
    if (err != nil) {
        return err
    }
    m.db = db
    return nil
}

// ProvidesServices returns services provided by this module
func (m *DatabaseModule) ProvidesServices() []modular.ServiceProvider {
    return []modular.ServiceProvider{
        {
            Name:        "database",
            Description: "Database connection",
            Instance:    m.db,
        },
    }
}

// RequiresServices returns services required by this module
func (m *DatabaseModule) RequiresServices() []modular.ServiceDependency {
    return []modular.ServiceDependency{} // No required services
}

// Start starts the module
func (m *DatabaseModule) Start(ctx context.Context) error {
    return nil // Database is already connected
}

// Stop stops the module
func (m *DatabaseModule) Stop(ctx context.Context) error {
    return m.db.Close()
}
Service Dependencies
// A module that depends on another service
func (m *APIModule) RequiresServices() []modular.ServiceDependency {
    return []modular.ServiceDependency{
        {
            Name:     "database",
            Required: true,  // Application won't start if this service is missing
        },
        {
            Name:     "cache",
            Required: false, // Optional dependency
        },
    }
}

// Using constructor injection
func (m *APIModule) Constructor() modular.ModuleConstructor {
    return func(app modular.Application, services map[string]any) (modular.Module, error) {
        // Services that were requested in RequiresServices() are available here
        db := services["database"].(*sql.DB)
        
        // Create a new module instance with injected services
        return &APIModule{
            db: db,
        }, nil
    }
}
Interface-Based Service Matching

Modular supports finding and injecting services based on interface compatibility, regardless of the service name:

// Define an interface that services should implement
type LoggerService interface {
    Log(level string, message string)
}

// Require a service that implements a specific interface
func (m *MyModule) RequiresServices() []modular.ServiceDependency {
    return []modular.ServiceDependency{
        {
            Name:               "logger", // The name you'll use to access it in the Constructor
            Required:           true,
            MatchByInterface:   true, // Enable interface-based matching
            SatisfiesInterface: reflect.TypeOf((*LoggerService)(nil)).Elem(),
        },
    }
}

// Constructor will receive any service implementing LoggerService
func (m *MyModule) Constructor() modular.ModuleConstructor {
    return func(app modular.Application, services map[string]any) (modular.Module, error) {
        // This will work even if the actual registered service name is different
        logger := services["logger"].(LoggerService)
        return &MyModule{logger: logger}, nil
    }
}

See DOCUMENTATION.md for more advanced details about service dependencies and interface matching.

Logger Management

The framework provides methods to get and set the application logger, allowing for dynamic logger configuration at runtime:

// Get the current logger
currentLogger := app.Logger()

// Switch to a different logger (e.g., for different log levels or output destinations)
newLogger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelDebug,
}))
app.SetLogger(newLogger)

// The new logger is now used by the application and all modules
app.Logger().Info("Logger has been switched to JSON format with debug level")

This is useful for scenarios such as:

  • Dynamic log level changes: Switch between debug and production logging based on runtime conditions
  • Configuration-driven logging: Update logger configuration based on config file changes
  • Environment-specific loggers: Use different loggers for development vs production
  • Log rotation: Switch to new log files without restarting the application

Example: Dynamic log level switching

// Switch to debug logging when needed
debugLogger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelDebug,
}))
app.SetLogger(debugLogger)

// Later, switch back to info level
infoLogger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelInfo,
}))
app.SetLogger(infoLogger)
Configuration Management
// Define your configuration struct
type AppConfig struct {
    Name    string `json:"name" yaml:"name" default:"DefaultApp" desc:"Application name"`
    Version string `json:"version" yaml:"version" required:"true" desc:"Application version"`
    Debug   bool   `json:"debug" yaml:"debug" default:"false" desc:"Enable debug mode"`
}

// Implement ConfigValidator interface for custom validation
func (c *AppConfig) Validate() error {
    // Custom validation logic
    if c.Version == "0.0.0" {
        return fmt.Errorf("invalid version: %s", c.Version)
    }
    return nil
}
Configuration Validation and Default Values

Modular now includes powerful configuration validation features:

Default Values with Struct Tags
// Define struct with default values
type ServerConfig struct {
    Host        string `yaml:"host" default:"localhost" desc:"Server host"`
    Port        int    `yaml:"port" default:"8080" desc:"Server port"`
    ReadTimeout int    `yaml:"readTimeout" default:"30" desc:"Read timeout in seconds"`
    Debug       bool   `yaml:"debug" default:"false" desc:"Enable debug mode"`
}

Default values are automatically applied to fields that have zero/empty values when configurations are loaded.

Required Field Validation
type DatabaseConfig struct {
    Host     string `yaml:"host" default:"localhost" desc:"Database host"`
    Port     int    `yaml:"port" default:"5432" desc:"Database port"`
    Name     string `yaml:"name" required:"true" desc:"Database name"` // Must be provided
    User     string `yaml:"user" default:"postgres" desc:"Database user"`
    Password string `yaml:"password" required:"true" desc:"Database password"` // Must be provided
}

Required fields are validated during configuration loading, and appropriate errors are returned if they're missing.

Custom Validation Logic
// Implement the ConfigValidator interface
func (c *AppConfig) Validate() error {
    // Validate environment is one of the expected values
    validEnvs := map[string]bool{"dev": true, "test": true, "prod": true}
    if !validEnvs[c.Environment] {
        return fmt.Errorf("%w: environment must be one of [dev, test, prod]", modular.ErrConfigValidationFailed)
    }
    
    // Additional custom validation
    if c.Server.Port < 1024 || c.Server.Port > 65535 {
        return fmt.Errorf("%w: server port must be between 1024 and 65535", modular.ErrConfigValidationFailed)
    }
    
    return nil
}
Generating Sample Configuration Files
// Generate a sample configuration file
cfg := &AppConfig{}
err := modular.SaveSampleConfig(cfg, "yaml", "config-sample.yaml")
if err != nil {
    log.Fatalf("Error generating sample config: %v", err)
}

Sample configurations can be generated in YAML, JSON, or TOML formats, with all default values pre-populated.

Command-Line Integration
func main() {
    // Generate sample config file if requested
    if len(os.Args) > 1 && os.Args[1] == "--generate-config" {
        format := "yaml"
        if len(os.Args) > 2 {
            format = os.Args[2]
        }
        outputFile := "config-sample." + format
        if len(os.Args) > 3 {
            outputFile = os.Args[3]
        }
        
        cfg := &AppConfig{}
        if err := modular.SaveSampleConfig(cfg, format, outputFile); err != nil {
            fmt.Printf("Error generating sample config: %v\n", err)
            os.Exit(1)  // Error condition should exit with non-zero code
        }
        fmt.Printf("Sample config generated at %s\n", outputFile)
        os.Exit(0)
    }
    
    // Continue with normal application startup...
}

Multi-Tenant Support

Modular provides built-in support for multi-tenant applications through:

Tenant Contexts
// Creating a tenant context
tenantID := modular.TenantID("tenant1")
ctx := modular.NewTenantContext(context.Background(), tenantID)

// Using tenant context with the application
tenantCtx, err := app.WithTenant(tenantID)
if err != nil {
    log.Fatal("Failed to create tenant context:", err)
}

// Extract tenant ID from a context
if id, ok := modular.GetTenantIDFromContext(ctx); ok {
    fmt.Println("Current tenant:", id)
}
Tenant-Aware Configuration
// Register a tenant service in your module
func (m *MultiTenantModule) ProvidesServices() []modular.ServiceProvider {
    return []modular.ServiceProvider{
        {
            Name:        "tenantService",
            Description: "Tenant management service",
            Instance:    modular.NewStandardTenantService(m.logger),
        },
        {
            Name:        "tenantConfigLoader",
            Description: "Tenant configuration loader",
            Instance:    modular.DefaultTenantConfigLoader("./configs/tenants"),
        },
    }
}

// Create tenant-aware configuration
func (m *MultiTenantModule) RegisterConfig(app *modular.Application) {
    // Default config
    defaultConfig := &MyConfig{
        Setting: "default",
    }
    
    // Get tenant service (must be provided by another module)
    var tenantService modular.TenantService
    app.GetService("tenantService", &tenantService)
    
    // Create tenant-aware config provider
    tenantAwareConfig := modular.NewTenantAwareConfig(
        modular.NewStdConfigProvider(defaultConfig),
        tenantService,
        "mymodule",
    )
    
    app.RegisterConfigSection("mymodule", tenantAwareConfig)
}

// Using tenant-aware configs in your code
func (m *MultiTenantModule) ProcessRequestWithTenant(ctx context.Context) {
    // Get config specific to the tenant in the context
    config, ok := m.config.(*modular.TenantAwareConfig)
    if !ok {
        // Handle non-tenant-aware config
        return
    }
    
    // Get tenant-specific configuration
    myConfig := config.GetConfigWithContext(ctx).(*MyConfig)
    
    // Use tenant-specific settings
    fmt.Println("Tenant setting:", myConfig.Setting)
}
Tenant-Aware Modules
// Implement the TenantAwareModule interface
type MultiTenantModule struct {
    modular.Module
    tenantData map[modular.TenantID]*TenantData
}

func (m *MultiTenantModule) OnTenantRegistered(tenantID modular.TenantID) {
    // Initialize resources for this tenant
    m.tenantData[tenantID] = &TenantData{
        initialized: true,
    }
}

func (m *MultiTenantModule) OnTenantRemoved(tenantID modular.TenantID) {
    // Clean up tenant resources
    delete(m.tenantData, tenantID)
}
Loading Tenant Configurations
// Set up a file-based tenant config loader
configLoader := modular.NewFileBasedTenantConfigLoader(modular.TenantConfigParams{
    ConfigNameRegex: regexp.MustCompile("^tenant-[\\w-]+\\.(json|yaml)$"),
    ConfigDir:       "./configs/tenants",
    // Prefer per-app feeders (via app.SetConfigFeeders) over global when testing; examples use explicit slice for clarity
    ConfigFeeders:   []modular.Feeder{},
})

// Register the loader as a service
app.RegisterService("tenantConfigLoader", configLoader)

Key Interfaces

Module

The core interface that all modules must implement:

type Module interface {
    RegisterConfig(app *Application)
    Init(app *Application) error
    Start(ctx context.Context) error
    Stop(ctx context.Context) error
    Name() string
    Dependencies() []string
    ProvidesServices() []ServiceProvider
    RequiresServices() []ServiceDependency
}
TenantAwareModule

Interface for modules that need to respond to tenant lifecycle events:

type TenantAwareModule interface {
    Module
    OnTenantRegistered(tenantID TenantID)
    OnTenantRemoved(tenantID TenantID)
}
TenantService

Interface for managing tenants:

type TenantService interface {
    GetTenantConfig(tenantID TenantID, section string) (ConfigProvider, error)
    GetTenants() []TenantID
    RegisterTenant(tenantID TenantID, configs map[string]ConfigProvider) error
}
ConfigProvider

Interface for configuration providers:

type ConfigProvider interface {
    GetConfig() any
}
ConfigValidator

Interface for implementing custom configuration validation logic:

type ConfigValidator interface {
    Validate() error
}

CLI Tool

Modular comes with a command-line tool (modcli) to help you create new modules and configurations.

Test Isolation and Configuration Feeders

Historically tests mutated the package-level modular.ConfigFeeders slice directly to control configuration sources. This created hidden coupling and prevented safe use of t.Parallel(). The framework now supports per-application feeders via:

app.(*modular.StdApplication).SetConfigFeeders([]modular.Feeder{feeders.NewYamlFeeder("config.yaml"), feeders.NewEnvFeeder()})

Guidelines:

  1. In tests, prefer app.SetConfigFeeders(...) immediately after creating the application (before Init()).
  2. Pass nil to revert an app back to using global feeders (rare in tests now).
  3. Avoid mutating modular.ConfigFeeders in tests; example applications may still set the global slice once at startup for simplicity.
  4. The legacy isolation helper no longer snapshots feeders; only environment variables are isolated.

Benefit: tests become self-contained and can run in parallel without feeder race conditions.

Parallel Testing Guidelines

Short rules for adding t.Parallel() safely:

DO:

  • Pre-create apps and call app.SetConfigFeeders(...) instead of mutating global ConfigFeeders.
  • Set all required environment variables up-front in the parent test (one t.Setenv per variable) and then parallelize independent subtests that do NOT call t.Setenv themselves.
  • Keep tests idempotent: no shared global mutation, no time-dependent ordering.
  • Use isolated temp dirs (t.TempDir()) and unique filenames.

DO NOT:

  • Call t.Parallel() on a test that itself calls t.Setenv or t.Chdir (Go 1.25 restriction: mixing causes a panic: "test using t.Setenv or t.Chdir can not use t.Parallel").
  • Rely on mutation of package-level singletons (e.g. modifying global slices) across parallel tests.
  • Write to the same file or network port from multiple parallel tests.

Patterns:

  • Serial parent + parallel children: parent sets env vars; each child t.Parallel() if it doesn't modify env/working dir.
  • Fully serial tests: keep serial when per-case env mutation is unavoidable.

If in doubt, leave the test serial and add a brief comment explaining why (// NOTE: cannot parallelize because ...).

Installation

You can install the CLI tool using one of the following methods:

go install github.com/GoCodeAlone/modular/cmd/modcli@latest

This will download, build, and install the latest version of the CLI tool directly to your GOPATH's bin directory, which should be in your PATH.

Download pre-built binaries

Download the latest release from the GitHub Releases page and add it to your PATH.

Build from source
# Clone the repository
git clone https://github.com/GoCodeAlone/modular.git
cd modular/cmd/modcli

# Build the CLI tool
go build -o modcli

# Move to a directory in your PATH
mv modcli /usr/local/bin/  # Linux/macOS
# or add the current directory to your PATH
Usage

Generate a new module:

modcli generate module --name MyFeature

Generate a configuration:

modcli generate config --name Server

For more details on available commands:

modcli --help

Each command includes interactive prompts to guide you through the process of creating modules or configurations with the features you need.

πŸ“š Additional Resources

Having Issues?

If you're experiencing problems with module interfaces (e.g., "Module does not implement Startable"), check out the debugging section which includes diagnostic tools like:

// Debug module interface implementations
modular.DebugModuleInterfaces(app, "your-module-name")

// Check all modules at once
modular.DebugAllModuleInterfaces(app)

License

MIT License

Documentation ΒΆ

Overview ΒΆ

Package modular provides a flexible, modular application framework for Go. It supports configuration management, dependency injection, service registration, and multi-tenant functionality.

The modular framework allows you to build applications composed of independent modules that can declare dependencies, provide services, and be configured individually. Each module implements the Module interface and can optionally implement additional interfaces like Configurable, ServiceAware, Startable, etc.

Basic usage:

app := modular.NewStdApplication(configProvider, logger)
app.RegisterModule(&MyModule{})
if err := app.Run(); err != nil {
	log.Fatal(err)
}

Package modular provides Observer pattern interfaces for event-driven communication. These interfaces use CloudEvents specification for standardized event format and better interoperability with external systems.

Package modular provides CloudEvents integration for the Observer pattern. This file provides CloudEvents utility functions and validation for standardized event format and better interoperability.

Package modular provides SecretValue for basic secret protection.

SECURITY NOTICE: The SecretValue type in this package provides protection against accidental exposure but has significant security limitations due to Go's memory model. It cannot guarantee secure memory handling and should NOT be used for highly sensitive secrets like private keys or critical passwords.

For maximum security, use dedicated secure memory libraries or OS-level secret storage mechanisms.

Package modular provides tenant functionality for multi-tenant applications. This file contains tenant-related types and interfaces.

The tenant functionality enables a single application instance to serve multiple isolated tenants, each with their own configuration, data, and potentially customized behavior.

Key concepts:

  • TenantID: unique identifier for each tenant
  • TenantContext: context that carries tenant information through the call chain
  • TenantService: manages tenant registration and configuration
  • TenantAwareModule: modules that can adapt their behavior per tenant

Example multi-tenant application setup:

// Create tenant service
tenantSvc := modular.NewStandardTenantService(logger)

// Register tenant service
app.RegisterService("tenantService", tenantSvc)

// Register tenant-aware modules
app.RegisterModule(&MyTenantAwareModule{})

// Register tenants with specific configurations
tenantSvc.RegisterTenant("tenant-1", map[string]ConfigProvider{
    "database": modular.NewStdConfigProvider(&DatabaseConfig{Host: "tenant1-db"}),
})

Package modular provides tenant-aware functionality for multi-tenant applications. This file contains the core tenant service implementation.

Index ΒΆ

Constants ΒΆ

View Source
const (
	// Module lifecycle events
	EventTypeModuleRegistered  = "com.modular.module.registered"
	EventTypeModuleInitialized = "com.modular.module.initialized"
	EventTypeModuleStarted     = "com.modular.module.started"
	EventTypeModuleStopped     = "com.modular.module.stopped"
	EventTypeModuleFailed      = "com.modular.module.failed"

	// Service lifecycle events
	EventTypeServiceRegistered   = "com.modular.service.registered"
	EventTypeServiceUnregistered = "com.modular.service.unregistered"
	EventTypeServiceRequested    = "com.modular.service.requested"

	// Configuration events
	EventTypeConfigLoaded    = "com.modular.config.loaded"
	EventTypeConfigValidated = "com.modular.config.validated"
	EventTypeConfigChanged   = "com.modular.config.changed"

	// Dynamic reload events (FR-045 specification)
	EventTypeConfigReloadStart   = "config.reload.start"
	EventTypeConfigReloadSuccess = "config.reload.success"
	EventTypeConfigReloadFailed  = "config.reload.failed"
	EventTypeConfigReloadNoop    = "config.reload.noop"

	// Health aggregation events (FR-048 specification)
	EventTypeHealthAggregateUpdated = "health.aggregate.updated"

	// Application lifecycle events
	EventTypeApplicationStarted = "com.modular.application.started"
	EventTypeApplicationStopped = "com.modular.application.stopped"
	EventTypeApplicationFailed  = "com.modular.application.failed"
)

EventType constants for common application events. These provide a standardized vocabulary for CloudEvent types emitted by the core framework. Following CloudEvents specification, these use reverse domain notation.

View Source
const ModuleLifecycleSchema = "modular.module.lifecycle.v1"

ModuleLifecycleSchema is the schema identifier for module lifecycle payloads.

Variables ΒΆ

View Source
var (
	ErrModuleNameEmpty       = errors.New("module name cannot be empty")
	ErrProviderNil           = errors.New("provider cannot be nil")
	ErrProviderAlreadyExists = errors.New("provider already registered")
	ErrProviderNotRegistered = errors.New("no provider registered")
)

Static errors for health aggregation

View Source
var (
	ErrDynamicReloadNotAvailable    = errors.New("dynamic reload not available - use WithDynamicReload() option when creating application")
	ErrInvalidHealthAggregator      = errors.New("invalid health aggregator service")
	ErrHealthAggregatorNotAvailable = errors.New("health aggregator not available - use WithHealthAggregator() option when creating application")
)

Static errors for application

View Source
var (
	// Configuration errors - issues with loading and managing configuration
	ErrConfigSectionNotFound = errors.New("config section not found")
	ErrApplicationNil        = errors.New("application is nil")
	ErrConfigProviderNil     = errors.New("failed to load app config: config provider is nil")
	ErrConfigSectionError    = errors.New("failed to load app config: error triggered by section")
	ErrLoggerNotSet          = errors.New("logger not set in application builder")

	// Config validation errors - problems with configuration structure and values
	ErrConfigNil                  = errors.New("config is nil")
	ErrConfigNotPointer           = errors.New("config must be a pointer")
	ErrConfigNotStruct            = errors.New("config must be a struct")
	ErrConfigRequiredFieldMissing = errors.New("required field is missing")
	ErrConfigValidationFailed     = errors.New("config validation failed")
	ErrUnsupportedTypeForDefault  = errors.New("unsupported type for default value")
	ErrDefaultValueParseError     = errors.New("failed to parse default value")
	ErrDefaultValueOverflowsInt   = errors.New("default value overflows int")
	ErrDefaultValueOverflowsUint  = errors.New("default value overflows uint")
	ErrDefaultValueOverflowsFloat = errors.New("default value overflows float")
	ErrInvalidFieldKind           = errors.New("invalid field kind")
	ErrIncompatibleFieldKind      = errors.New("incompatible field kind")
	ErrUnexpectedFieldKind        = errors.New("unexpected field kind")
	ErrUnsupportedFormatType      = errors.New("unsupported format type")
	ErrConfigFeederError          = errors.New("config feeder error")
	ErrConfigSetupError           = errors.New("config setup error")
	ErrConfigNilPointer           = errors.New("config is nil pointer")
	ErrFieldCannotBeSet           = errors.New("field cannot be set")

	// Service registry errors
	ErrServiceAlreadyRegistered = errors.New("service already registered")
	ErrServiceNotFound          = errors.New("service not found")

	// Service injection errors
	ErrTargetNotPointer      = errors.New("target must be a non-nil pointer")
	ErrTargetValueInvalid    = errors.New("target value is invalid")
	ErrServiceIncompatible   = errors.New("service cannot be assigned to target")
	ErrServiceNil            = errors.New("service is nil")
	ErrServiceWrongType      = errors.New("service doesn't satisfy required type")
	ErrServiceWrongInterface = errors.New("service doesn't satisfy required interface")

	// Dependency resolution errors
	ErrCircularDependency      = errors.New("circular dependency detected")
	ErrModuleDependencyMissing = errors.New("module depends on non-existent module")
	ErrRequiredServiceNotFound = errors.New("required service not found for module")

	// Constructor errors
	ErrConstructorNotFunction              = errors.New("constructor must be a function")
	ErrConstructorInvalidReturnCount       = errors.New("constructor must return exactly two values (Module, error)")
	ErrConstructorInvalidReturnType        = errors.New("constructor must return a Module as first value")
	ErrConstructorParameterServiceNotFound = errors.New("no service found for constructor parameter")
	ErrInvalidInterfaceConfiguration       = errors.New("invalid interface configuration for required service")
	ErrInterfaceConfigurationNil           = errors.New("SatisfiesInterface is nil")
	ErrInterfaceConfigurationNotInterface  = errors.New("SatisfiesInterface is not an interface type")
	ErrServiceInterfaceIncompatible        = errors.New("service does not implement required interface")

	// Tenant errors
	ErrAppContextNotInitialized        = errors.New("application context not initialized")
	ErrTenantNotFound                  = errors.New("tenant not found")
	ErrTenantConfigNotFound            = errors.New("tenant config section not found")
	ErrTenantConfigProviderNil         = errors.New("tenant config provider is nil")
	ErrTenantConfigValueNil            = errors.New("tenant config value is nil")
	ErrTenantRegisterNilConfig         = errors.New("cannot register nil config for tenant")
	ErrMockTenantConfigsNotInitialized = errors.New("mock tenant configs not initialized")
	ErrConfigSectionNotFoundForTenant  = errors.New("config section not found for tenant")

	// Observer/Event emission errors
	ErrNoSubjectForEventEmission = errors.New("no subject available for event emission")

	// Test-specific errors
	ErrSetupFailed   = errors.New("setup error")
	ErrFeedFailed    = errors.New("feed error")
	ErrFeedKeyFailed = errors.New("feedKey error")

	// Tenant config errors
	ErrConfigCastFailed      = errors.New("failed to cast config to expected type")
	ErrOriginalOrLoadedNil   = errors.New("original or loaded config is nil")
	ErrDestinationNotPointer = errors.New("destination must be a pointer")
	ErrCannotCopyMapToStruct = errors.New("cannot copy from map to non-struct")
	ErrUnsupportedSourceType = errors.New("unsupported source type")

	// Additional tenant config errors
	ErrTenantSectionConfigNil     = errors.New("tenant section config is nil after feeding")
	ErrCreatedNilProvider         = errors.New("created nil provider for tenant section")
	ErrIncompatibleFieldTypes     = errors.New("incompatible types for field assignment")
	ErrIncompatibleInterfaceValue = errors.New("incompatible interface value for field")

	// Dynamic reload errors
	ErrReloadNotSupported = errors.New("dynamic reload not supported")

	// Health system errors
	ErrInvalidHealthTrigger = errors.New("invalid health trigger")

	// Reload orchestrator errors
	ErrReloadModuleNameEmpty     = errors.New("reload orchestrator: module name cannot be empty")
	ErrReloadModuleNil           = errors.New("reload orchestrator: module cannot be nil")
	ErrReloadModuleAlreadyExists = errors.New("reload orchestrator: module already registered")
	ErrReloadModuleNotFound      = errors.New("reload orchestrator: no module registered")
	ErrReloadQueueFull           = errors.New("reload orchestrator: request queue is full")
	ErrReloadBackoffActive       = errors.New("reload orchestrator: backing off after recent failures")
	ErrReloadStopTimeout         = errors.New("reload orchestrator: timeout waiting for stop")

	// Secret provider errors
	ErrUnknownSecretProvider        = errors.New("unknown secret provider")
	ErrSecretProviderNotSecure      = errors.New("provider is not secure, but secure memory is required")
	ErrUnknownProvider              = errors.New("unknown provider")
	ErrSecretLimitReached           = errors.New("maximum number of secrets reached")
	ErrInvalidSecretHandle          = errors.New("invalid secret handle")
	ErrSecretStoreNotInitialized    = errors.New("secret store not initialized")
	ErrSecretNotFound               = errors.New("secret not found")
	ErrInvalidSecretKeyLength       = errors.New("invalid secret key length")
	ErrSecretTypeMismatch           = errors.New("secret type mismatch")
	ErrCannotClearSecretValue       = errors.New("cannot clear secret value")
	ErrSecretHandleInvalid          = errors.New("secret handle is invalid")
	ErrSecretValueOverflow          = errors.New("secret value overflow")
	ErrSecretProviderUnavailable    = errors.New("secret provider unavailable")
	ErrSecretConfigInvalid          = errors.New("secret configuration invalid")
	ErrMemguardNotAvailable         = errors.New("memguard library is not available - ensure 'github.com/awnumar/memguard' is imported and CGO is enabled")
	ErrMemguardProviderNotAvailable = errors.New("memguard provider not available")
	ErrInvalidSecureBuffer          = errors.New("invalid secure buffer")

	// Tenant isolation errors
	ErrTenantNotIsolated               = errors.New("tenant is not properly isolated")
	ErrInvalidTenantGuardMode          = errors.New("invalid tenant guard mode")
	ErrInvalidTenantGuardConfiguration = errors.New("invalid tenant guard configuration")
	ErrUnknownTenantGuardMode          = errors.New("unknown tenant guard mode")

	// HTTP/Server errors
	ErrServerClosed = errors.New("server closed")
)

Application errors

View Source
var (
	// ErrReloadInProgress indicates that a reload operation is already in progress
	ErrReloadInProgress = errors.New("reload operation already in progress")

	// ErrReloadTimeout indicates that the reload operation exceeded its timeout
	ErrReloadTimeout = errors.New("reload operation timed out")
)

Additional errors for reload operations

View Source
var ConfigFeeders = []Feeder{
	feeders.NewEnvFeeder(),
}

ConfigFeeders provides a default set of configuration feeders for common use cases

View Source
var (
	ErrConfigsNil = errors.New("configs cannot be nil")
)

Static errors for config validation

View Source
var (
	ErrInvalidReloadTrigger = errors.New("invalid reload trigger")
)

Static errors for config diff

View Source
var (
	// ErrInvalidServiceScope indicates that an invalid service scope was provided
	ErrInvalidServiceScope = errors.New("invalid service scope")
)

Errors related to service scope validation

View Source
var (
	ErrUnsupportedExtension = errors.New("unsupported file extension")
)

Static errors for better error handling

View Source
var MustImplementHealthProvider = func(HealthProvider) {}

MustImplementHealthProvider is a compile-time check to ensure a type implements HealthProvider. This can be used in tests or during development to verify interface compliance.

Usage:

var _ HealthProvider = (*YourType)(nil) // Add this line to verify YourType implements HealthProvider
View Source
var MustImplementHealthReporter = func(HealthReporter) {}

MustImplementHealthReporter is a compile-time check for HealthReporter (legacy interface). This helps during migration to identify which types implement the legacy interface.

Usage:

var _ HealthReporter = (*YourLegacyType)(nil) // Add this line to verify YourLegacyType implements HealthReporter

Functions ΒΆ

func CompareModuleInstances ΒΆ added in v1.2.9

func CompareModuleInstances(original, current Module, moduleName string)

CompareModuleInstances compares two module instances to see if they're the same

func DebugAllModuleInterfaces ΒΆ added in v1.2.9

func DebugAllModuleInterfaces(app Application)

DebugAllModuleInterfaces debugs all registered modules

func DebugModuleInterfaces ΒΆ added in v1.2.9

func DebugModuleInterfaces(app Application, moduleName string)

DebugModuleInterfaces helps debug interface implementation issues during module lifecycle

func DetectBaseConfigStructure ΒΆ added in v1.4.3

func DetectBaseConfigStructure() bool

DetectBaseConfigStructure automatically detects if base configuration structure exists and enables it if found. This is called automatically during application initialization.

func EnableMemguardForTesting ΒΆ added in v1.4.3

func EnableMemguardForTesting(provider SecretProvider)

EnableMemguardForTesting enables the memguard provider for testing purposes This should only be used in test code

func GenerateSampleConfig ΒΆ added in v1.2.2

func GenerateSampleConfig(cfg interface{}, format string) ([]byte, error)

GenerateSampleConfig generates a sample configuration for a config struct The format parameter can be "yaml", "json", or "toml"

func GetBaseConfigFeeder ΒΆ added in v1.4.3

func GetBaseConfigFeeder() feeders.Feeder

GetBaseConfigFeeder returns a BaseConfigFeeder if base config is enabled

func GetInsecureProviderStats ΒΆ added in v1.4.3

func GetInsecureProviderStats(provider SecretProvider) map[string]interface{}

GetInsecureProviderStats returns statistics about the insecure provider (for testing/monitoring)

func GetMemguardProviderStats ΒΆ added in v1.4.3

func GetMemguardProviderStats(provider SecretProvider) map[string]interface{}

GetMemguardProviderStats returns statistics about the memguard provider (for testing/monitoring)

func HandleEventEmissionError ΒΆ added in v1.4.3

func HandleEventEmissionError(err error, logger Logger, moduleName, eventType string) bool

HandleEventEmissionError provides consistent error handling for event emission failures. This helper function standardizes how modules should handle the "no subject available" error and other emission failures to reduce noisy output during tests and in non-observable applications.

It returns true if the error was handled (i.e., it was ErrNoSubjectForEventEmission or similar), false if the error should be handled by the caller.

Example usage:

if err := module.EmitEvent(ctx, event); err != nil {
	if !modular.HandleEventEmissionError(err, logger, "my-module", eventType) {
		// Handle other types of errors here
	}
}

func InitializeSecretProvider ΒΆ added in v1.4.3

func InitializeSecretProvider(config SecretProviderConfig, logger Logger) error

InitializeSecretProvider initializes the global secret provider

func IsBaseConfigEnabled ΒΆ added in v1.4.3

func IsBaseConfigEnabled() bool

IsBaseConfigEnabled returns true if base configuration support is enabled

func IsErrCircularDependency ΒΆ added in v1.4.3

func IsErrCircularDependency(err error) bool

IsErrCircularDependency checks if an error is a circular dependency error

func IsSynchronousNotification ΒΆ added in v1.4.3

func IsSynchronousNotification(ctx context.Context) bool

IsSynchronousNotification returns true if the context requests synchronous delivery.

func LoadTenantConfigs ΒΆ added in v1.1.0

func LoadTenantConfigs(app Application, tenantService TenantService, params TenantConfigParams) error

LoadTenantConfigs scans the given directory for config files. Each file should be named with the tenant ID (e.g. "tenant123.json"). For each file, it unmarshals the configuration and registers it with the provided TenantService for the given section. The configNameRegex is a regex pattern for the config file names (e.g. "^tenant[0-9]+\\.json$").

func NewCloudEvent ΒΆ added in v1.4.3

func NewCloudEvent(eventType, source string, data interface{}, metadata map[string]interface{}) cloudevents.Event

NewCloudEvent creates a new CloudEvent with the specified parameters. This is a convenience function for creating properly formatted CloudEvents.

func NewModuleLifecycleEvent ΒΆ added in v1.4.3

func NewModuleLifecycleEvent(source, subject, name, version, action string, metadata map[string]interface{}) cloudevents.Event

NewModuleLifecycleEvent builds a CloudEvent for a module/application lifecycle using the structured payload. It sets payload_schema and module_action extensions for lightweight routing without full payload decode.

func ProcessConfigDefaults ΒΆ added in v1.2.2

func ProcessConfigDefaults(cfg interface{}) error

ProcessConfigDefaults applies default values to a config struct based on struct tags. It looks for `default:"value"` tags on struct fields and sets the field value if currently zero/empty.

Supported field types:

  • Basic types: string, int, float, bool
  • Slices: []string, []int, etc.
  • Pointers to basic types

Example struct tags:

type Config struct {
    Host     string `default:"localhost"`
    Port     int    `default:"8080"`
    Debug    bool   `default:"false"`
    Features []string `default:"feature1,feature2"`
}

This function is automatically called by the configuration loading system before validation, but can also be called manually if needed.

func RedactGlobally ΒΆ added in v1.4.3

func RedactGlobally(text string) string

RedactGlobally redacts secrets using the global redactor

func RedactGloballyStructured ΒΆ added in v1.4.3

func RedactGloballyStructured(fields map[string]interface{}) map[string]interface{}

RedactGloballyStructured redacts secrets from structured log fields using the global redactor

func RegisterGlobalPattern ΒΆ added in v1.4.3

func RegisterGlobalPattern(pattern string)

RegisterGlobalPattern registers a pattern with the global redactor

func RegisterGlobalSecret ΒΆ added in v1.4.3

func RegisterGlobalSecret(secret *SecretValue)

RegisterGlobalSecret registers a secret with the global redactor

func RegisterSecretProvider ΒΆ added in v1.4.3

func RegisterSecretProvider(name string, creator func(config SecretProviderConfig) (SecretProvider, error))

RegisterSecretProvider registers a custom provider globally

func SaveSampleConfig ΒΆ added in v1.2.2

func SaveSampleConfig(cfg interface{}, format, filePath string) error

SaveSampleConfig generates and saves a sample configuration file

func SetBaseConfig ΒΆ added in v1.4.3

func SetBaseConfig(configDir, environment string)

SetBaseConfig configures the framework to use base configuration with environment overrides This should be called before building the application if you want to use base config support

func ValidateCloudEvent ΒΆ added in v1.4.3

func ValidateCloudEvent(event cloudevents.Event) error

ValidateCloudEvent validates that a CloudEvent conforms to the specification. This provides validation beyond the basic CloudEvent SDK validation.

func ValidateConfig ΒΆ added in v1.2.2

func ValidateConfig(cfg interface{}) error

ValidateConfig validates a configuration using the following steps: 1. Processes default values 2. Validates required fields 3. If the config implements ConfigValidator, calls its Validate method

func ValidateConfigRequired ΒΆ added in v1.2.2

func ValidateConfigRequired(cfg interface{}) error

ValidateConfigRequired checks all struct fields with `required:"true"` tag and verifies they are not zero/empty values

func WithScopeContext ΒΆ added in v1.4.3

func WithScopeContext(ctx context.Context, scopeKey, scopeValue string) context.Context

WithScopeContext creates a new context with scope information for scoped services.

func WithSynchronousNotification ΒΆ added in v1.4.3

func WithSynchronousNotification(ctx context.Context) context.Context

WithSynchronousNotification marks the context to request synchronous observer delivery. Subjects may honor this hint to deliver events inline instead of spawning goroutines.

func WithTenantContext ΒΆ added in v1.4.3

func WithTenantContext(ctx context.Context, tenantID string) context.Context

WithTenantContext creates a new context with tenant information attached.

Types ΒΆ

type AggregateHealthService ΒΆ added in v1.4.3

type AggregateHealthService struct {
	// contains filtered or unexported fields
}

AggregateHealthService implements the HealthAggregator interface to collect health reports from registered providers and aggregate them according to the design brief specifications for FR-048 Health Aggregation.

The service provides:

  • Thread-safe provider registration and management
  • Concurrent health collection with timeouts
  • Status aggregation following readiness/health rules
  • Caching with configurable TTL
  • Event emission on status changes
  • Panic recovery for provider failures

func NewAggregateHealthService ΒΆ added in v1.4.3

func NewAggregateHealthService() *AggregateHealthService

NewAggregateHealthService creates a new aggregate health service with default configuration

func NewAggregateHealthServiceWithConfig ΒΆ added in v1.4.3

func NewAggregateHealthServiceWithConfig(config AggregateHealthServiceConfig) *AggregateHealthService

NewAggregateHealthServiceWithConfig creates a new aggregate health service with custom configuration

func (*AggregateHealthService) Collect ΒΆ added in v1.4.3

Collect gathers health reports from all registered providers and aggregates them according to the design brief specifications.

Aggregation Rules:

  • Readiness: Start healthy, degrade only for non-optional failures (Optional=false)
  • Health: Worst status across ALL providers (including optional)
  • Status hierarchy: healthy < degraded < unhealthy

func (*AggregateHealthService) GetProviders ΒΆ added in v1.4.3

func (s *AggregateHealthService) GetProviders() map[string]ProviderInfo

GetProviders returns information about all registered providers (for testing/debugging)

func (*AggregateHealthService) RegisterProvider ΒΆ added in v1.4.3

func (s *AggregateHealthService) RegisterProvider(moduleName string, provider HealthProvider, optional bool) error

RegisterProvider registers a health provider for the specified module

func (*AggregateHealthService) SetEventSubject ΒΆ added in v1.4.3

func (s *AggregateHealthService) SetEventSubject(subject Subject)

SetEventSubject sets the event subject for publishing health events

func (*AggregateHealthService) UnregisterProvider ΒΆ added in v1.4.3

func (s *AggregateHealthService) UnregisterProvider(moduleName string) error

UnregisterProvider removes a health provider for the specified module

type AggregateHealthServiceConfig ΒΆ added in v1.4.3

type AggregateHealthServiceConfig struct {
	// CacheTTL is the time-to-live for cached health results
	// Default: 250ms as specified in design brief
	CacheTTL time.Duration

	// DefaultTimeout is the default timeout for individual provider calls
	// Default: 200ms as specified in design brief
	DefaultTimeout time.Duration

	// CacheEnabled controls whether result caching is active
	// Default: true
	CacheEnabled bool
}

AggregateHealthServiceConfig provides configuration for the health aggregation service

type AggregateHealthSnapshot deprecated added in v1.4.3

type AggregateHealthSnapshot struct {
	// OverallStatus is the aggregated health status across all components
	OverallStatus HealthStatus

	// ReadinessStatus indicates whether the system is ready to serve requests
	// This may differ from OverallStatus in cases where a system is degraded
	// but still ready to serve traffic
	ReadinessStatus HealthStatus

	// Components contains the individual health status for each monitored component
	// Using HealthResult for compatibility with existing tests
	Components map[string]HealthResult

	// Summary provides a summary of the health check results
	Summary HealthSummary

	// GeneratedAt indicates when this snapshot was created
	GeneratedAt time.Time

	// Timestamp is an alias for GeneratedAt for compatibility
	Timestamp time.Time

	// SnapshotID is a unique identifier for this health snapshot,
	// useful for tracking and correlation in logs and monitoring systems
	SnapshotID string

	// Metadata contains additional system-wide health information
	Metadata map[string]interface{}
}

AggregateHealthSnapshot represents the combined health status of multiple components at a specific point in time. This is used for system-wide health monitoring.

Deprecated: Use AggregatedHealth instead for new implementations. This type is maintained for backward compatibility.

func (*AggregateHealthSnapshot) GetUnhealthyComponents ΒΆ added in v1.4.3

func (s *AggregateHealthSnapshot) GetUnhealthyComponents() []string

GetUnhealthyComponents returns a slice of component names that are not healthy

func (*AggregateHealthSnapshot) IsHealthy ΒΆ added in v1.4.3

func (s *AggregateHealthSnapshot) IsHealthy() bool

IsHealthy returns true if the overall status is healthy

func (*AggregateHealthSnapshot) IsReady ΒΆ added in v1.4.3

func (s *AggregateHealthSnapshot) IsReady() bool

IsReady returns true if the system is ready to serve requests

type AggregatedHealth ΒΆ added in v1.4.3

type AggregatedHealth struct {
	// Readiness indicates whether the system is ready to accept traffic
	// This only considers non-optional (required) components
	Readiness HealthStatus `json:"readiness"`

	// Health indicates the overall health status across all components
	// This includes both required and optional components
	Health HealthStatus `json:"health"`

	// Reports contains the individual health reports from all providers
	Reports []HealthReport `json:"reports"`

	// GeneratedAt indicates when this aggregated health was collected
	GeneratedAt time.Time `json:"generatedAt"`
}

AggregatedHealth represents the combined health status of multiple components as defined in the design brief for FR-048. This structure provides distinct readiness and health status along with individual component reports.

type AppRegistry ΒΆ

type AppRegistry interface {
	// SvcRegistry retrieves the service registry.
	// The service registry contains all services registered by modules
	// and the application, providing a central location for service lookup.
	SvcRegistry() ServiceRegistry
}

AppRegistry provides registry functionality for applications. This interface provides access to the application's service registry, allowing modules and components to access registered services.

type Application ΒΆ

type Application interface {
	// ConfigProvider retrieves the application's main configuration provider.
	// This provides access to application-level configuration that isn't
	// specific to any particular module.
	ConfigProvider() ConfigProvider

	// SvcRegistry retrieves the service registry.
	// Modules use this to register services they provide and lookup
	// services they need from other modules.
	SvcRegistry() ServiceRegistry

	// RegisterModule adds a module to the application.
	// Modules must be registered before calling Init(). The framework
	// will handle initialization order based on declared dependencies.
	//
	// Example:
	//   app.RegisterModule(&DatabaseModule{})
	//   app.RegisterModule(&WebServerModule{})
	RegisterModule(module Module)

	// RegisterConfigSection registers a configuration section with the application.
	// This allows modules to register their configuration requirements,
	// making them available for loading from configuration sources.
	//
	// Example:
	//   cfg := &MyModuleConfig{}
	//   provider := modular.NewStdConfigProvider(cfg)
	//   app.RegisterConfigSection("mymodule", provider)
	RegisterConfigSection(section string, cp ConfigProvider)

	// ConfigSections retrieves all registered configuration sections.
	// Returns a map of section names to their configuration providers.
	// Useful for debugging and introspection.
	ConfigSections() map[string]ConfigProvider

	// GetConfigSection retrieves a specific configuration section.
	// Returns an error if the section doesn't exist.
	//
	// Example:
	//   provider, err := app.GetConfigSection("database")
	//   if err != nil {
	//       return err
	//   }
	//   cfg := provider.GetConfig().(*DatabaseConfig)
	GetConfigSection(section string) (ConfigProvider, error)

	// RegisterService adds a service to the service registry with type checking.
	// Services registered here become available to all modules that declare
	// them as dependencies.
	//
	// Returns an error if a service with the same name is already registered.
	//
	// Example:
	//   db := &DatabaseConnection{}
	//   err := app.RegisterService("database", db)
	RegisterService(name string, service any) error

	// GetService retrieves a service from the registry with type assertion.
	// The target parameter must be a pointer to the expected type.
	// The framework will perform type checking and assignment.
	//
	// Example:
	//   var db *DatabaseConnection
	//   err := app.GetService("database", &db)
	GetService(name string, target any) error

	// Init initializes the application and all registered modules.
	// This method:
	//   - Calls RegisterConfig on all configurable modules
	//   - Loads configuration from all registered sources
	//   - Resolves module dependencies
	//   - Initializes modules in dependency order
	//   - Registers services provided by modules
	//
	// Must be called before Start() or Run().
	Init() error

	// Start starts the application and all startable modules.
	// Modules implementing the Startable interface will have their
	// Start method called in dependency order.
	//
	// This is typically used when you want to start the application
	// but handle the shutdown logic yourself (rather than using Run()).
	Start() error

	// Stop stops the application and all stoppable modules.
	// Modules implementing the Stoppable interface will have their
	// Stop method called in reverse dependency order.
	//
	// Provides a timeout context for graceful shutdown.
	Stop() error

	// Run starts the application and blocks until termination.
	// This is equivalent to calling Init(), Start(), and then waiting
	// for a termination signal (SIGINT, SIGTERM) before calling Stop().
	//
	// This is the most common way to run a modular application:
	//   if err := app.Run(); err != nil {
	//       log.Fatal(err)
	//   }
	Run() error

	// Logger retrieves the application's logger.
	// This logger is used by the framework and can be used by modules
	// for consistent logging throughout the application.
	Logger() Logger

	// SetLogger sets the application's logger.
	// Should be called before module registration to ensure
	// all framework operations use the new logger.
	SetLogger(logger Logger)

	// SetVerboseConfig enables or disables verbose configuration debugging.
	// When enabled, DEBUG level logging will be performed during configuration
	// processing to show which config is being processed, which key is being
	// evaluated, and which attribute or key is being searched for.
	SetVerboseConfig(enabled bool)

	// IsVerboseConfig returns whether verbose configuration debugging is enabled.
	IsVerboseConfig() bool

	// ServiceIntrospector groups advanced service registry introspection helpers.
	// Use this instead of adding new methods directly to Application.
	ServiceIntrospector() ServiceIntrospector

	// RequestReload triggers a dynamic configuration reload for the specified sections.
	// If no sections are specified, all dynamic configuration will be reloaded.
	// This method follows the design brief specification for FR-045 Dynamic Reload.
	//
	// The reload process will:
	//   - Detect changes in configuration since last load
	//   - Filter to only fields tagged with `dynamic:"true"`
	//   - Validate all changes atomically before applying
	//   - Call Reload() on all affected modules with the changes
	//   - Emit appropriate events (config.reload.start/success/failed/noop)
	//
	// Returns an error if the reload fails for any reason.
	RequestReload(sections ...string) error

	// RegisterHealthProvider registers a health provider for the specified module.
	// This method follows the design brief specification for FR-048 Health Aggregation.
	//
	// Parameters:
	//   - moduleName: The name of the module providing health information
	//   - provider: The HealthProvider implementation
	//   - optional: Whether this provider is optional for readiness calculations
	//
	// Optional providers don't affect readiness status but are included in health reporting.
	// Required providers affect both readiness and overall health status.
	RegisterHealthProvider(moduleName string, provider HealthProvider, optional bool) error

	// Health returns the health aggregator service if available.
	// This method follows the design brief specification for FR-048 Health Aggregation.
	//
	// The health aggregator provides system-wide health monitoring by collecting
	// health reports from all registered providers and aggregating them according
	// to readiness and health rules.
	//
	// Returns an error if the health aggregator service is not available.
	// Use WithHealthAggregator() option when creating the application to register
	// the health aggregation service.
	//
	// Example:
	//   healthAgg, err := app.Health()
	//   if err != nil {
	//       return fmt.Errorf("health aggregation not available: %w", err)
	//   }
	//   status, err := healthAgg.Collect(ctx)
	Health() (HealthAggregator, error)

	// GetTenantGuard returns the tenant guard service if configured.
	// This provides access to tenant isolation enforcement features.
	// Returns nil when no tenant guard is configured (e.g., disabled mode or not set).
	GetTenantGuard() TenantGuard
}

func NewApplication ΒΆ

func NewApplication(opts ...Option) (Application, error)

NewApplication creates a new application with the provided options. This is the main entry point for the new builder API.

func NewStdApplication ΒΆ added in v1.1.0

func NewStdApplication(cp ConfigProvider, logger Logger) Application

NewStdApplication creates a new application instance with the provided configuration and logger. This is the standard way to create a modular application.

Parameters:

  • cp: ConfigProvider for application-level configuration
  • logger: Logger implementation for framework and module logging

The created application will have empty registries that can be populated by registering modules and services. The application must be initialized with Init() before it can be started.

Example:

// Create configuration
appConfig := &MyAppConfig{}
configProvider := modular.NewStdConfigProvider(appConfig)

// Create logger (implement modular.Logger interface)
logger := &MyLogger{}

// Create application
app := modular.NewStdApplication(configProvider, logger)

// Register modules
app.RegisterModule(&DatabaseModule{})
app.RegisterModule(&WebServerModule{})

// Run application
if err := app.Run(); err != nil {
    log.Fatal(err)
}

func NewStdApplicationWithOptions ΒΆ added in v1.4.3

func NewStdApplicationWithOptions(cp ConfigProvider, logger Logger, options ...ApplicationOption) Application

NewStdApplicationWithOptions creates a new application with options

type ApplicationBuilder ΒΆ added in v1.4.3

type ApplicationBuilder struct {
	// contains filtered or unexported fields
}

ApplicationBuilder helps construct applications with various decorators and options

func NewApplicationBuilder ΒΆ added in v1.4.3

func NewApplicationBuilder() *ApplicationBuilder

NewApplicationBuilder creates a new application builder that can be used to configure and construct applications step by step.

func (*ApplicationBuilder) Build ΒΆ added in v1.4.3

func (b *ApplicationBuilder) Build() (Application, error)

Build constructs the final application with all decorators applied. NOTE: The signature intentionally matches the stable API on main (no context parameters) to avoid a breaking contract change. Context should be supplied to individual operations/services rather than the builder itself.

func (*ApplicationBuilder) WithOption ΒΆ added in v1.4.3

func (b *ApplicationBuilder) WithOption(opt Option) *ApplicationBuilder

WithOption applies an option to the application builder

type ApplicationBuilderExtension ΒΆ added in v1.4.3

type ApplicationBuilderExtension struct {
	*ApplicationBuilder
	// contains filtered or unexported fields
}

Extend ApplicationBuilder to support tenant guard

type ApplicationDecorator ΒΆ added in v1.4.3

type ApplicationDecorator interface {
	Application

	// GetInnerApplication returns the wrapped application
	GetInnerApplication() Application
}

ApplicationDecorator defines the interface for decorating applications. Decorators wrap applications to add additional functionality without modifying the core application implementation.

type ApplicationOption ΒΆ added in v1.4.3

type ApplicationOption func(*StdApplication) error

ApplicationOption represents a configuration option for the application

func WithDynamicReload ΒΆ added in v1.4.3

func WithDynamicReload(config DynamicReloadConfig) ApplicationOption

WithDynamicReload configures dynamic reload functionality

func WithHealthAggregator ΒΆ added in v1.4.3

func WithHealthAggregator(config HealthAggregatorConfig) ApplicationOption

WithHealthAggregator configures health aggregation functionality

type BaseApplicationDecorator ΒΆ added in v1.4.3

type BaseApplicationDecorator struct {
	// contains filtered or unexported fields
}

BaseApplicationDecorator provides a foundation for application decorators. It implements ApplicationDecorator by forwarding all calls to the wrapped application.

func NewBaseApplicationDecorator ΒΆ added in v1.4.3

func NewBaseApplicationDecorator(inner Application) *BaseApplicationDecorator

NewBaseApplicationDecorator creates a new base decorator wrapping the given application.

func (*BaseApplicationDecorator) ConfigProvider ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) ConfigProvider() ConfigProvider

func (*BaseApplicationDecorator) ConfigSections ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) ConfigSections() map[string]ConfigProvider

func (*BaseApplicationDecorator) GetConfigSection ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) GetConfigSection(section string) (ConfigProvider, error)

func (*BaseApplicationDecorator) GetInnerApplication ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) GetInnerApplication() Application

GetInnerApplication returns the wrapped application

func (*BaseApplicationDecorator) GetObservers ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) GetObservers() []ObserverInfo

func (*BaseApplicationDecorator) GetService ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) GetService(name string, target any) error

func (*BaseApplicationDecorator) GetTenantConfig ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) GetTenantConfig(tenantID TenantID, section string) (ConfigProvider, error)

func (*BaseApplicationDecorator) GetTenantGuard ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) GetTenantGuard() TenantGuard

GetTenantGuard forwards to the inner application's GetTenantGuard method if implemented

func (*BaseApplicationDecorator) GetTenantService ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) GetTenantService() (TenantService, error)

TenantAware methods - if inner supports TenantApplication interface

func (*BaseApplicationDecorator) Health ΒΆ added in v1.4.3

Health forwards to the inner application's Health method

func (*BaseApplicationDecorator) Init ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) Init() error

func (*BaseApplicationDecorator) IsVerboseConfig ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) IsVerboseConfig() bool

func (*BaseApplicationDecorator) Logger ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) Logger() Logger

func (*BaseApplicationDecorator) NotifyObservers ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) NotifyObservers(ctx context.Context, event cloudevents.Event) error

func (*BaseApplicationDecorator) RegisterConfigSection ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) RegisterConfigSection(section string, cp ConfigProvider)

func (*BaseApplicationDecorator) RegisterHealthProvider ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) RegisterHealthProvider(moduleName string, provider HealthProvider, optional bool) error

RegisterHealthProvider forwards to the inner application's RegisterHealthProvider method

func (*BaseApplicationDecorator) RegisterModule ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) RegisterModule(module Module)

func (*BaseApplicationDecorator) RegisterObserver ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) RegisterObserver(observer Observer, eventTypes ...string) error

Observer methods - if inner supports Subject interface

func (*BaseApplicationDecorator) RegisterService ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) RegisterService(name string, service any) error

func (*BaseApplicationDecorator) RequestReload ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) RequestReload(sections ...string) error

RequestReload forwards to the inner application's RequestReload method

func (*BaseApplicationDecorator) Run ΒΆ added in v1.4.3

func (*BaseApplicationDecorator) ServiceIntrospector ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) ServiceIntrospector() ServiceIntrospector

ServiceIntrospector forwards to the inner application's ServiceIntrospector implementation.

func (*BaseApplicationDecorator) SetLogger ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) SetLogger(logger Logger)

func (*BaseApplicationDecorator) SetVerboseConfig ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) SetVerboseConfig(enabled bool)

func (*BaseApplicationDecorator) Start ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) Start() error

func (*BaseApplicationDecorator) Stop ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) Stop() error

func (*BaseApplicationDecorator) SvcRegistry ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) SvcRegistry() ServiceRegistry

func (*BaseApplicationDecorator) UnregisterObserver ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) UnregisterObserver(observer Observer) error

func (*BaseApplicationDecorator) WithTenant ΒΆ added in v1.4.3

func (d *BaseApplicationDecorator) WithTenant(tenantID TenantID) (*TenantContext, error)

type BaseConfigOptions ΒΆ added in v1.4.3

type BaseConfigOptions struct {
	// ConfigDir is the root directory containing base/ and environments/ subdirectories
	ConfigDir string
	// Environment specifies which environment overrides to apply (e.g., "prod", "staging", "dev")
	Environment string
	// Enabled determines whether base config support is active
	Enabled bool
}

BaseConfigOptions holds configuration for base config support

var BaseConfigSettings BaseConfigOptions

BaseConfigSettings holds the global base config settings

type BaseLoggerDecorator ΒΆ added in v1.4.3

type BaseLoggerDecorator struct {
	// contains filtered or unexported fields
}

BaseLoggerDecorator provides a foundation for logger decorators. It implements LoggerDecorator by forwarding all calls to the wrapped logger.

func NewBaseLoggerDecorator ΒΆ added in v1.4.3

func NewBaseLoggerDecorator(inner Logger) *BaseLoggerDecorator

NewBaseLoggerDecorator creates a new base decorator wrapping the given logger.

func (*BaseLoggerDecorator) Debug ΒΆ added in v1.4.3

func (d *BaseLoggerDecorator) Debug(msg string, args ...any)

func (*BaseLoggerDecorator) Error ΒΆ added in v1.4.3

func (d *BaseLoggerDecorator) Error(msg string, args ...any)

func (*BaseLoggerDecorator) GetInnerLogger ΒΆ added in v1.4.3

func (d *BaseLoggerDecorator) GetInnerLogger() Logger

GetInnerLogger returns the wrapped logger

func (*BaseLoggerDecorator) Info ΒΆ added in v1.4.3

func (d *BaseLoggerDecorator) Info(msg string, args ...any)

func (*BaseLoggerDecorator) Warn ΒΆ added in v1.4.3

func (d *BaseLoggerDecorator) Warn(msg string, args ...any)

type BasicHealthAggregator ΒΆ added in v1.4.3

type BasicHealthAggregator struct {
	// contains filtered or unexported fields
}

BasicHealthAggregator provides a simple health aggregation implementation

func (*BasicHealthAggregator) Collect ΒΆ added in v1.4.3

Collect gathers health reports from all registered providers

func (*BasicHealthAggregator) RegisterProvider ΒΆ added in v1.4.3

func (a *BasicHealthAggregator) RegisterProvider(provider HealthProvider)

RegisterProvider registers a health provider (basic implementation)

type ChangeSummary ΒΆ added in v1.4.3

type ChangeSummary struct {
	// TotalChanges is the total number of changes (added + modified + removed)
	TotalChanges int

	// AddedCount is the number of fields that were added
	AddedCount int

	// ModifiedCount is the number of fields that were modified
	ModifiedCount int

	// RemovedCount is the number of fields that were removed
	RemovedCount int

	// SensitiveChanges is the number of sensitive fields that were changed
	SensitiveChanges int
}

ChangeSummary provides a high-level summary of the configuration changes

type ChangeType ΒΆ added in v1.4.3

type ChangeType string

ChangeType represents the type of change that occurred to a configuration field

const (
	// ChangeTypeAdded indicates a field was added to the configuration
	ChangeTypeAdded ChangeType = "added"

	// ChangeTypeModified indicates a field value was changed
	ChangeTypeModified ChangeType = "modified"

	// ChangeTypeRemoved indicates a field was removed from the configuration
	ChangeTypeRemoved ChangeType = "removed"
)

func (ChangeType) String ΒΆ added in v1.4.3

func (c ChangeType) String() string

String returns the string representation of the change type

type CloudEvent ΒΆ added in v1.4.3

type CloudEvent = cloudevents.Event

CloudEvent is an alias for the CloudEvents Event type for convenience

type ComplexFeeder ΒΆ

type ComplexFeeder interface {
	Feeder
	FeedKey(string, interface{}) error
}

ComplexFeeder extends the basic Feeder interface with additional functionality for complex configuration scenarios

func GetBaseConfigComplexFeeder ΒΆ added in v1.4.3

func GetBaseConfigComplexFeeder() ComplexFeeder

GetBaseConfigComplexFeeder returns a BaseConfigFeeder as ComplexFeeder if base config is enabled

type Config ΒΆ

type Config struct {
	// Feeders contains all the registered configuration feeders
	Feeders []Feeder
	// StructKeys maps struct identifiers to their configuration objects.
	// Used internally to track which configuration structures have been processed.
	StructKeys map[string]interface{}
	// VerboseDebug enables detailed logging during configuration processing
	VerboseDebug bool
	// Logger is used for verbose debug logging
	Logger Logger
	// FieldTracker tracks which fields are populated by which feeders
	FieldTracker FieldTracker
}

Config represents a configuration builder that can combine multiple feeders and structures. It provides functionality for the modular framework to coordinate configuration loading.

The Config builder allows you to:

  • Add multiple configuration sources (files, environment, etc.)
  • Combine configuration from different feeders
  • Apply configuration to multiple struct targets
  • Track which structs have been configured
  • Enable verbose debugging for configuration processing
  • Track field-level population details

func NewConfig ΒΆ

func NewConfig() *Config

NewConfig creates a new configuration builder. The returned Config can be used to set up complex configuration scenarios involving multiple sources and target structures.

Example:

cfg := modular.NewConfig()
cfg.AddFeeder(modular.ConfigFeeders[0]) // Add file feeder
cfg.AddStruct(&myConfig)                // Add target struct
err := cfg.Feed()                       // Load configuration

func (*Config) AddFeeder ΒΆ added in v1.3.3

func (c *Config) AddFeeder(feeder Feeder) *Config

AddFeeder adds a configuration feeder to support verbose debugging and field tracking

func (*Config) AddStructKey ΒΆ

func (c *Config) AddStructKey(key string, target interface{}) *Config

AddStructKey adds a structure with a key to the configuration

func (*Config) Feed ΒΆ

func (c *Config) Feed() error

Feed with validation applies defaults and validates configs after feeding

func (*Config) FeedWithModuleContext ΒΆ added in v1.4.3

func (c *Config) FeedWithModuleContext(target interface{}, moduleName string) error

FeedWithModuleContext feeds a single configuration structure with module context information This allows module-aware feeders to customize their behavior based on the module name

func (*Config) SetFieldTracker ΒΆ added in v1.3.4

func (c *Config) SetFieldTracker(tracker FieldTracker) *Config

SetFieldTracker sets the field tracker for capturing field population details

func (*Config) SetVerboseDebug ΒΆ added in v1.3.3

func (c *Config) SetVerboseDebug(enabled bool, logger Logger) *Config

SetVerboseDebug enables or disables verbose debug logging

type ConfigChange ΒΆ added in v1.4.3

type ConfigChange struct {
	// Section is the configuration section name (e.g., "database", "cache")
	Section string

	// FieldPath is the full dotted path to this field in the configuration
	// (e.g., "database.connection.host", "logging.level")
	FieldPath string

	// OldValue is the previous value of the field
	OldValue any

	// NewValue is the new value of the field
	NewValue any

	// Source is the feeder/source identifier that provided this change
	// (e.g., "env", "file:/config/app.yaml", "programmatic")
	Source string
}

ConfigChange represents a change in a specific configuration field. This is the structure used by the dynamic reload system to inform modules about configuration changes, following the design brief specifications.

type ConfigDecorator ΒΆ added in v1.4.3

type ConfigDecorator interface {
	// DecorateConfig takes a base config provider and returns a decorated one
	DecorateConfig(base ConfigProvider) ConfigProvider

	// Name returns the decorator name for debugging
	Name() string
}

ConfigDecorator defines the interface for decorating configuration providers. Config decorators can modify, enhance, or validate configuration during loading.

func InstanceAwareConfig ΒΆ added in v1.4.3

func InstanceAwareConfig() ConfigDecorator

InstanceAwareConfig creates an instance-aware configuration decorator

func TenantAwareConfigDecorator ΒΆ added in v1.4.3

func TenantAwareConfigDecorator(loader TenantLoader) ConfigDecorator

TenantAwareConfigDecorator creates a tenant-aware configuration decorator

type ConfigDiff ΒΆ added in v1.4.3

type ConfigDiff struct {
	// Changed maps field paths to their change information.
	// The key is the field path (e.g., "database.host", "api.timeout")
	// and the value contains the old and new values.
	Changed map[string]FieldChange

	// Added maps field paths to their new values.
	// These are fields that didn't exist in the previous configuration
	// but are present in the new configuration.
	Added map[string]interface{}

	// Removed maps field paths to their previous values.
	// These are fields that existed in the previous configuration
	// but are not present in the new configuration.
	Removed map[string]interface{}

	// Timestamp indicates when this diff was generated
	Timestamp time.Time

	// DiffID is a unique identifier for this configuration diff,
	// useful for tracking and correlation in logs and audit trails
	DiffID string
}

ConfigDiff represents the differences between two configuration states. It tracks what fields have been added, changed, or removed, along with metadata about when the diff was generated and how to identify it.

This type is used by the dynamic reload system to inform modules about exactly what has changed in their configuration, allowing them to make targeted updates rather than full reinitialization.

func GenerateConfigDiff ΒΆ added in v1.4.3

func GenerateConfigDiff(oldConfig, newConfig interface{}) (*ConfigDiff, error)

GenerateConfigDiff generates a diff between two configuration objects

func GenerateConfigDiffWithOptions ΒΆ added in v1.4.3

func GenerateConfigDiffWithOptions(oldConfig, newConfig interface{}, options ConfigDiffOptions) (*ConfigDiff, error)

GenerateConfigDiffWithOptions generates a diff with the specified options

func (*ConfigDiff) ChangeSummary ΒΆ added in v1.4.3

func (d *ConfigDiff) ChangeSummary() ChangeSummary

ChangeSummary returns a summary of all changes in this diff

func (*ConfigDiff) FilterByPrefix ΒΆ added in v1.4.3

func (d *ConfigDiff) FilterByPrefix(prefix string) *ConfigDiff

FilterByPrefix returns a new ConfigDiff containing only changes to fields with the given prefix

func (*ConfigDiff) GetAddedFields ΒΆ added in v1.4.3

func (d *ConfigDiff) GetAddedFields() []string

GetAddedFields returns a slice of field paths that have been added

func (*ConfigDiff) GetAllAffectedFields ΒΆ added in v1.4.3

func (d *ConfigDiff) GetAllAffectedFields() []string

GetAllAffectedFields returns a slice of all field paths that are affected by this diff

func (*ConfigDiff) GetChangedFields ΒΆ added in v1.4.3

func (d *ConfigDiff) GetChangedFields() []string

GetChangedFields returns a slice of field paths that have changed values

func (*ConfigDiff) GetRemovedFields ΒΆ added in v1.4.3

func (d *ConfigDiff) GetRemovedFields() []string

GetRemovedFields returns a slice of field paths that have been removed

func (*ConfigDiff) HasChanges ΒΆ added in v1.4.3

func (d *ConfigDiff) HasChanges() bool

HasChanges returns true if the diff contains any changes

func (*ConfigDiff) IsEmpty ΒΆ added in v1.4.3

func (d *ConfigDiff) IsEmpty() bool

IsEmpty returns true if the diff contains no changes

func (*ConfigDiff) RedactSensitiveFields ΒΆ added in v1.4.3

func (d *ConfigDiff) RedactSensitiveFields() *ConfigDiff

RedactSensitiveFields returns a copy of the diff with sensitive field values redacted

type ConfigDiffOptions ΒΆ added in v1.4.3

type ConfigDiffOptions struct {
	// IgnoreFields is a list of field paths to ignore when generating the diff
	IgnoreFields []string

	// SensitiveFields is a list of field paths that should be marked as sensitive
	SensitiveFields []string

	// ValidateChanges indicates whether to validate changes during diff generation
	ValidateChanges bool

	// IncludeValidation indicates whether to include validation results in the diff
	IncludeValidation bool

	// MaxDepth limits how deep to recurse into nested structures
	MaxDepth int
}

ConfigDiffOptions provides options for generating configuration diffs

type ConfigFieldChange ΒΆ added in v1.4.3

type ConfigFieldChange = FieldChange

ConfigFieldChange is an alias for FieldChange to maintain compatibility with existing test code while using the more descriptive FieldChange name

type ConfigProvider ΒΆ

type ConfigProvider interface {
	// GetConfig returns the configuration object.
	// The returned value should be a pointer to a struct that represents
	// the configuration schema. Modules typically type-assert this to
	// their expected configuration type.
	//
	// Example:
	//   cfg := provider.GetConfig().(*MyModuleConfig)
	GetConfig() any
}

ConfigProvider defines the interface for providing configuration objects. Configuration providers encapsulate configuration data and make it available to modules and the application framework.

The framework supports multiple configuration sources (files, environment variables, command-line flags) and formats (JSON, YAML, TOML) through different providers.

type ConfigReloadCompletedEvent ΒΆ added in v1.4.3

type ConfigReloadCompletedEvent struct {
	// ReloadID is a unique identifier for this reload operation
	ReloadID string

	// Timestamp indicates when the reload completed
	Timestamp time.Time

	// Success indicates whether the reload was successful
	Success bool

	// Duration indicates how long the reload took
	Duration time.Duration

	// AffectedModules lists the modules that were affected by this reload
	AffectedModules []string

	// Error contains error details if Success is false
	Error string

	// ChangesApplied contains the number of configuration changes that were applied
	ChangesApplied int
}

ConfigReloadCompletedEvent represents an event emitted when a config reload completes

func (*ConfigReloadCompletedEvent) EventSource ΒΆ added in v1.4.3

func (e *ConfigReloadCompletedEvent) EventSource() string

EventSource returns the standardized event source for reload completed events

func (*ConfigReloadCompletedEvent) EventType ΒΆ added in v1.4.3

func (e *ConfigReloadCompletedEvent) EventType() string

EventType returns the standardized event type for reload completed events

func (*ConfigReloadCompletedEvent) GetEventSource ΒΆ added in v1.4.3

func (e *ConfigReloadCompletedEvent) GetEventSource() string

GetEventSource returns the source that generated this event (implements ObserverEvent)

func (*ConfigReloadCompletedEvent) GetEventType ΒΆ added in v1.4.3

func (e *ConfigReloadCompletedEvent) GetEventType() string

GetEventType returns the type identifier for this event (implements ObserverEvent)

func (*ConfigReloadCompletedEvent) GetTimestamp ΒΆ added in v1.4.3

func (e *ConfigReloadCompletedEvent) GetTimestamp() time.Time

GetTimestamp returns when this event occurred (implements ObserverEvent)

func (*ConfigReloadCompletedEvent) StructuredFields ΒΆ added in v1.4.3

func (e *ConfigReloadCompletedEvent) StructuredFields() map[string]interface{}

StructuredFields returns the structured field data for this event

type ConfigReloadFailedEvent ΒΆ added in v1.4.3

type ConfigReloadFailedEvent struct {
	// ReloadID is a unique identifier for this reload operation
	ReloadID string

	// Timestamp indicates when the reload failed
	Timestamp time.Time

	// Error contains the error that caused the failure
	Error string

	// FailedModule contains the name of the module that caused the failure (if applicable)
	FailedModule string

	// Duration indicates how long the reload attempt took before failing
	Duration time.Duration
}

ConfigReloadFailedEvent represents an event emitted when a config reload fails

func (*ConfigReloadFailedEvent) EventSource ΒΆ added in v1.4.3

func (e *ConfigReloadFailedEvent) EventSource() string

EventSource returns the standardized event source for reload failed events

func (*ConfigReloadFailedEvent) EventType ΒΆ added in v1.4.3

func (e *ConfigReloadFailedEvent) EventType() string

EventType returns the standardized event type for reload failed events

func (*ConfigReloadFailedEvent) GetEventSource ΒΆ added in v1.4.3

func (e *ConfigReloadFailedEvent) GetEventSource() string

GetEventSource returns the source that generated this event (implements ObserverEvent)

func (*ConfigReloadFailedEvent) GetEventType ΒΆ added in v1.4.3

func (e *ConfigReloadFailedEvent) GetEventType() string

GetEventType returns the type identifier for this event (implements ObserverEvent)

func (*ConfigReloadFailedEvent) GetTimestamp ΒΆ added in v1.4.3

func (e *ConfigReloadFailedEvent) GetTimestamp() time.Time

GetTimestamp returns when this event occurred (implements ObserverEvent)

type ConfigReloadNoopEvent ΒΆ added in v1.4.3

type ConfigReloadNoopEvent struct {
	// ReloadID is a unique identifier for this reload operation
	ReloadID string

	// Timestamp indicates when the no-op was determined
	Timestamp time.Time

	// Reason indicates why this was a no-op (e.g., "no changes detected")
	Reason string
}

ConfigReloadNoopEvent represents an event emitted when a config reload is a no-op

func (*ConfigReloadNoopEvent) EventSource ΒΆ added in v1.4.3

func (e *ConfigReloadNoopEvent) EventSource() string

EventSource returns the standardized event source for reload noop events

func (*ConfigReloadNoopEvent) EventType ΒΆ added in v1.4.3

func (e *ConfigReloadNoopEvent) EventType() string

EventType returns the standardized event type for reload noop events

func (*ConfigReloadNoopEvent) GetEventSource ΒΆ added in v1.4.3

func (e *ConfigReloadNoopEvent) GetEventSource() string

GetEventSource returns the source that generated this event (implements ObserverEvent)

func (*ConfigReloadNoopEvent) GetEventType ΒΆ added in v1.4.3

func (e *ConfigReloadNoopEvent) GetEventType() string

GetEventType returns the type identifier for this event (implements ObserverEvent)

func (*ConfigReloadNoopEvent) GetTimestamp ΒΆ added in v1.4.3

func (e *ConfigReloadNoopEvent) GetTimestamp() time.Time

GetTimestamp returns when this event occurred (implements ObserverEvent)

type ConfigReloadStartedEvent ΒΆ added in v1.4.3

type ConfigReloadStartedEvent struct {
	// ReloadID is a unique identifier for this reload operation
	ReloadID string

	// Timestamp indicates when the reload started
	Timestamp time.Time

	// TriggerType indicates what triggered this reload
	TriggerType ReloadTrigger

	// ConfigDiff contains the configuration changes that triggered this reload
	ConfigDiff *ConfigDiff
}

ConfigReloadStartedEvent represents an event emitted when a config reload starts

func (*ConfigReloadStartedEvent) EventSource ΒΆ added in v1.4.3

func (e *ConfigReloadStartedEvent) EventSource() string

EventSource returns the standardized event source for reload started events

func (*ConfigReloadStartedEvent) EventType ΒΆ added in v1.4.3

func (e *ConfigReloadStartedEvent) EventType() string

EventType returns the standardized event type for reload started events

func (*ConfigReloadStartedEvent) GetEventSource ΒΆ added in v1.4.3

func (e *ConfigReloadStartedEvent) GetEventSource() string

GetEventSource returns the source that generated this event (implements ObserverEvent)

func (*ConfigReloadStartedEvent) GetEventType ΒΆ added in v1.4.3

func (e *ConfigReloadStartedEvent) GetEventType() string

GetEventType returns the type identifier for this event (implements ObserverEvent)

func (*ConfigReloadStartedEvent) GetTimestamp ΒΆ added in v1.4.3

func (e *ConfigReloadStartedEvent) GetTimestamp() time.Time

GetTimestamp returns when this event occurred (implements ObserverEvent)

func (*ConfigReloadStartedEvent) StructuredFields ΒΆ added in v1.4.3

func (e *ConfigReloadStartedEvent) StructuredFields() map[string]interface{}

StructuredFields returns the structured field data for this event

type ConfigSetup ΒΆ added in v1.0.0

type ConfigSetup interface {
	Setup() error
}

ConfigSetup is an interface that configs can implement to perform additional setup after being populated by feeders

type ConfigValidator ΒΆ added in v1.2.2

type ConfigValidator interface {
	// Validate validates the configuration and returns an error if invalid.
	// This method is called automatically by the framework after configuration
	// loading and default value processing. It should return a descriptive
	// error if the configuration is invalid.
	Validate() error
}

ConfigValidator is an interface for configuration validation. Configuration structs can implement this interface to provide custom validation logic beyond the standard required field checking.

The framework automatically calls Validate() on configuration objects that implement this interface during module initialization.

Example implementation:

type MyConfig struct {
    Host string `json:"host" required:"true"`
    Port int    `json:"port" default:"8080" validate:"range:1024-65535"`
}

func (c *MyConfig) Validate() error {
    if c.Port < 1024 || c.Port > 65535 {
        return fmt.Errorf("port must be between 1024 and 65535")
    }
    return nil
}

type Configurable ΒΆ added in v1.2.0

type Configurable interface {
	// RegisterConfig registers configuration requirements with the application.
	// This method is called during application initialization before Init().
	//
	// Implementation should:
	//   - Define the configuration structure
	//   - Register the configuration section with app.RegisterConfigSection()
	//   - Set up any configuration validation rules
	//
	// Example:
	//   func (m *MyModule) RegisterConfig(app Application) error {
	//       cfg := &MyModuleConfig{}
	//       provider := modular.NewStdConfigProvider(cfg)
	//       app.RegisterConfigSection(m.Name(), provider)
	//       return nil
	//   }
	RegisterConfig(app Application) error
}

Configurable is an interface for modules that can have configuration. Modules implementing this interface can register configuration sections with the application, allowing them to receive typed configuration data.

The configuration system supports multiple formats (JSON, YAML, TOML) and multiple sources (files, environment variables, etc.).

type Constructable ΒΆ added in v1.2.0

type Constructable interface {
	// Constructor returns a function to construct this module with dependency injection.
	// The returned function should have the signature:
	//   func(app Application, services map[string]any) (Module, error)
	//
	// The services map contains all services that this module declared as requirements.
	// The constructor can also accept individual service types as parameters, and
	// the framework will automatically provide them based on type matching.
	//
	// Example:
	//   func (m *WebModule) Constructor() ModuleConstructor {
	//       return func(app Application, services map[string]any) (Module, error) {
	//           db := services["database"].(Database)
	//           return NewWebModule(db), nil
	//       }
	//   }
	Constructor() ModuleConstructor
}

Constructable is an interface for modules that support constructor-based dependency injection. This is an advanced feature that allows modules to be reconstructed with their dependencies automatically injected as constructor parameters.

This is useful when a module needs its dependencies available during construction rather than after initialization, or when using dependency injection frameworks.

type DefaultFieldTracker ΒΆ added in v1.3.4

type DefaultFieldTracker struct {
	FieldPopulations []FieldPopulation
	// contains filtered or unexported fields
}

DefaultFieldTracker is a basic implementation of FieldTracker

func NewDefaultFieldTracker ΒΆ added in v1.3.4

func NewDefaultFieldTracker() *DefaultFieldTracker

NewDefaultFieldTracker creates a new default field tracker

func (*DefaultFieldTracker) GetFieldPopulation ΒΆ added in v1.3.4

func (t *DefaultFieldTracker) GetFieldPopulation(fieldPath string) *FieldPopulation

GetFieldPopulation returns the population info for a specific field path It returns the first population found for the given field path

func (*DefaultFieldTracker) GetMostRelevantFieldPopulation ΒΆ added in v1.4.3

func (t *DefaultFieldTracker) GetMostRelevantFieldPopulation(fieldPath string) *FieldPopulation

GetMostRelevantFieldPopulation returns the population info for a specific field path It returns the last population that actually set a non-nil value

func (*DefaultFieldTracker) GetPopulationsByFeeder ΒΆ added in v1.3.4

func (t *DefaultFieldTracker) GetPopulationsByFeeder(feederType string) []FieldPopulation

GetPopulationsByFeeder returns all field populations by a specific feeder type

func (*DefaultFieldTracker) GetPopulationsBySource ΒΆ added in v1.3.4

func (t *DefaultFieldTracker) GetPopulationsBySource(sourceType string) []FieldPopulation

GetPopulationsBySource returns all field populations by a specific source type

func (*DefaultFieldTracker) RecordFieldPopulation ΒΆ added in v1.3.4

func (t *DefaultFieldTracker) RecordFieldPopulation(fp FieldPopulation)

RecordFieldPopulation records a field population event

func (*DefaultFieldTracker) SetLogger ΒΆ added in v1.3.4

func (t *DefaultFieldTracker) SetLogger(logger Logger)

SetLogger sets the logger for the tracker

type DependencyAware ΒΆ added in v1.2.0

type DependencyAware interface {
	// Dependencies returns names of other modules this module depends on.
	// The returned slice should contain the exact names returned by
	// the Name() method of the dependency modules.
	//
	// Dependencies are initialized before this module during application startup.
	// If any dependency is missing, application initialization will fail.
	//
	// Example:
	//   func (m *WebModule) Dependencies() []string {
	//       return []string{"database", "auth", "cache"}
	//   }
	Dependencies() []string
}

DependencyAware is an interface for modules that depend on other modules. The framework uses this information to determine initialization order, ensuring dependencies are initialized before dependent modules.

Dependencies are resolved by module name and must be exact matches. Circular dependencies will cause initialization to fail.

type DependencyEdge ΒΆ added in v1.4.3

type DependencyEdge struct {
	From string
	To   string
	Type EdgeType
	// For interface-based dependencies, show which interface is involved
	InterfaceType reflect.Type
	ServiceName   string
}

DependencyEdge represents a dependency edge with its source type

type DualWriterLoggerDecorator ΒΆ added in v1.4.3

type DualWriterLoggerDecorator struct {
	*BaseLoggerDecorator
	// contains filtered or unexported fields
}

DualWriterLoggerDecorator logs to two destinations simultaneously. This decorator forwards all log calls to both the primary logger and a secondary logger.

func NewDualWriterLoggerDecorator ΒΆ added in v1.4.3

func NewDualWriterLoggerDecorator(primary, secondary Logger) *DualWriterLoggerDecorator

NewDualWriterLoggerDecorator creates a decorator that logs to both primary and secondary loggers.

func (*DualWriterLoggerDecorator) Debug ΒΆ added in v1.4.3

func (d *DualWriterLoggerDecorator) Debug(msg string, args ...any)

func (*DualWriterLoggerDecorator) Error ΒΆ added in v1.4.3

func (d *DualWriterLoggerDecorator) Error(msg string, args ...any)

func (*DualWriterLoggerDecorator) Info ΒΆ added in v1.4.3

func (d *DualWriterLoggerDecorator) Info(msg string, args ...any)

func (*DualWriterLoggerDecorator) Warn ΒΆ added in v1.4.3

func (d *DualWriterLoggerDecorator) Warn(msg string, args ...any)

type DynamicFieldParser ΒΆ added in v1.4.3

type DynamicFieldParser interface {
	// GetDynamicFields analyzes a configuration struct and returns a slice
	// of field names that are tagged with `dynamic:"true"`
	GetDynamicFields(config interface{}) ([]string, error)

	// ValidateDynamicReload compares two configurations and generates a ConfigDiff
	// that only includes changes to fields marked as dynamic
	ValidateDynamicReload(oldConfig, newConfig interface{}) (*ConfigDiff, error)
}

DynamicFieldParser interface defines how dynamic field detection works for configuration reload functionality according to T044 requirements

func NewDynamicFieldParser ΒΆ added in v1.4.3

func NewDynamicFieldParser() DynamicFieldParser

NewDynamicFieldParser creates a new standard dynamic field parser

type DynamicReloadConfig ΒΆ added in v1.4.3

type DynamicReloadConfig struct {
	Enabled       bool          `json:"enabled"`
	ReloadTimeout time.Duration `json:"reload_timeout"`
}

DynamicReloadConfig configures dynamic reload behavior

type EdgeType ΒΆ added in v1.4.3

type EdgeType int

EdgeType represents the type of dependency edge

const (
	EdgeTypeModule EdgeType = iota
	EdgeTypeNamedService
	EdgeTypeInterfaceService
)

func (EdgeType) String ΒΆ added in v1.4.3

func (e EdgeType) String() string

type EnhancedServiceRegistry ΒΆ added in v1.4.3

type EnhancedServiceRegistry struct {
	// contains filtered or unexported fields
}

EnhancedServiceRegistry provides enhanced service registry functionality that tracks module associations and handles automatic conflict resolution.

func NewEnhancedServiceRegistry ΒΆ added in v1.4.3

func NewEnhancedServiceRegistry() *EnhancedServiceRegistry

NewEnhancedServiceRegistry creates a new enhanced service registry.

func (*EnhancedServiceRegistry) AsServiceRegistry ΒΆ added in v1.4.3

func (r *EnhancedServiceRegistry) AsServiceRegistry() ServiceRegistry

AsServiceRegistry returns a backwards-compatible ServiceRegistry view.

func (*EnhancedServiceRegistry) ClearCurrentModule ΒΆ added in v1.4.3

func (r *EnhancedServiceRegistry) ClearCurrentModule()

ClearCurrentModule clears the current module context.

func (*EnhancedServiceRegistry) GetService ΒΆ added in v1.4.3

func (r *EnhancedServiceRegistry) GetService(name string) (any, bool)

GetService retrieves a service by name.

func (*EnhancedServiceRegistry) GetServiceEntry ΒΆ added in v1.4.3

func (r *EnhancedServiceRegistry) GetServiceEntry(name string) (*ServiceRegistryEntry, bool)

GetServiceEntry retrieves the full service registry entry.

func (*EnhancedServiceRegistry) GetServicesByInterface ΒΆ added in v1.4.3

func (r *EnhancedServiceRegistry) GetServicesByInterface(interfaceType reflect.Type) []*ServiceRegistryEntry

GetServicesByInterface returns all services that implement the given interface.

func (*EnhancedServiceRegistry) GetServicesByModule ΒΆ added in v1.4.3

func (r *EnhancedServiceRegistry) GetServicesByModule(moduleName string) []string

GetServicesByModule returns all services provided by a specific module.

func (*EnhancedServiceRegistry) RegisterService ΒΆ added in v1.4.3

func (r *EnhancedServiceRegistry) RegisterService(name string, service any) (string, error)

RegisterService registers a service with automatic conflict resolution. If a service name conflicts, it will automatically append module information.

func (*EnhancedServiceRegistry) SetCurrentModule ΒΆ added in v1.4.3

func (r *EnhancedServiceRegistry) SetCurrentModule(module Module)

SetCurrentModule sets the module that is currently being initialized. This is used to track which module is registering services.

type EventObserver ΒΆ added in v1.4.3

type EventObserver interface {
	OnStatusChange(ctx context.Context, event *HealthStatusChangedEvent)
}

EventObserver interface for health status change notifications

type EventValidationObserver ΒΆ added in v1.4.3

type EventValidationObserver struct {
	// contains filtered or unexported fields
}

EventValidationObserver is a special observer that tracks which events have been emitted and can validate against a whitelist of expected events. This is primarily used in testing to ensure all module events are emitted.

func NewEventValidationObserver ΒΆ added in v1.4.3

func NewEventValidationObserver(id string, expectedEvents []string) *EventValidationObserver

NewEventValidationObserver creates a new observer that validates events against an expected list. This is useful for testing event completeness.

func (*EventValidationObserver) GetAllEvents ΒΆ added in v1.4.3

func (v *EventValidationObserver) GetAllEvents() []cloudevents.Event

GetAllEvents returns all events that were captured by this observer.

func (*EventValidationObserver) GetMissingEvents ΒΆ added in v1.4.3

func (v *EventValidationObserver) GetMissingEvents() []string

GetMissingEvents returns a list of expected events that were not emitted.

func (*EventValidationObserver) GetUnexpectedEvents ΒΆ added in v1.4.3

func (v *EventValidationObserver) GetUnexpectedEvents() []string

GetUnexpectedEvents returns a list of emitted events that were not expected.

func (*EventValidationObserver) ObserverID ΒΆ added in v1.4.3

func (v *EventValidationObserver) ObserverID() string

ObserverID implements the Observer interface.

func (*EventValidationObserver) OnEvent ΒΆ added in v1.4.3

OnEvent implements the Observer interface and tracks emitted events.

func (*EventValidationObserver) Reset ΒΆ added in v1.4.3

func (v *EventValidationObserver) Reset()

Reset clears all captured events for reuse in new test scenarios.

type Feeder ΒΆ

type Feeder interface {
	// Feed gets a struct and feeds it using configuration data.
	Feed(structure interface{}) error
}

Feeder defines the interface for configuration feeders that provide configuration data.

type FieldChange deprecated added in v1.4.3

type FieldChange struct {
	// OldValue is the previous value of the field
	OldValue interface{}

	// NewValue is the new value of the field
	NewValue interface{}

	// FieldPath is the full dotted path to this field in the configuration
	// (e.g., "database.connection.host", "logging.level")
	FieldPath string

	// ChangeType indicates what kind of change this represents
	ChangeType ChangeType

	// IsSensitive indicates whether this field contains sensitive information
	// that should be redacted from logs or audit trails
	IsSensitive bool

	// ValidationResult contains the result of validating this field change
	ValidationResult *ValidationResult
}

FieldChange represents a change in a specific configuration field. It captures both the previous and new values, along with metadata about the field and whether it contains sensitive information.

Deprecated: Use ConfigChange instead for new reload implementations. This type is maintained for backward compatibility.

type FieldPopulation ΒΆ added in v1.3.4

type FieldPopulation struct {
	FieldPath   string      // Full path to the field (e.g., "Connections.primary.DSN")
	FieldName   string      // Name of the field
	FieldType   string      // Type of the field
	FeederType  string      // Type of feeder that populated it
	SourceType  string      // Type of source (env, yaml, etc.)
	SourceKey   string      // Source key that was used (e.g., "DB_PRIMARY_DSN")
	Value       interface{} // Value that was set
	InstanceKey string      // Instance key for instance-aware fields
	SearchKeys  []string    // All keys that were searched for this field
	FoundKey    string      // The key that was actually found
}

FieldPopulation represents a single field population event

type FieldTracker ΒΆ added in v1.3.4

type FieldTracker interface {
	// RecordFieldPopulation records that a field was populated by a feeder
	RecordFieldPopulation(fp FieldPopulation)

	// SetLogger sets the logger for the tracker
	SetLogger(logger Logger)
}

FieldTracker interface allows feeders to report which fields they populate

type FieldTrackerBridge ΒΆ added in v1.3.4

type FieldTrackerBridge struct {
	// contains filtered or unexported fields
}

FieldTrackerBridge adapts between the main package's FieldTracker interface and the feeders package's FieldTracker interface

func NewFieldTrackerBridge ΒΆ added in v1.3.4

func NewFieldTrackerBridge(mainTracker FieldTracker) *FieldTrackerBridge

NewFieldTrackerBridge creates a new bridge adapter

func (*FieldTrackerBridge) RecordFieldPopulation ΒΆ added in v1.3.4

func (b *FieldTrackerBridge) RecordFieldPopulation(fp feeders.FieldPopulation)

RecordFieldPopulation implements the feeders.FieldTracker interface by converting feeders.FieldPopulation to the main package's FieldPopulation

type FieldTrackingFeeder ΒΆ added in v1.3.4

type FieldTrackingFeeder interface {
	// SetFieldTracker sets the field tracker for this feeder
	SetFieldTracker(tracker FieldTracker)
}

FieldTrackingFeeder interface allows feeders to support field tracking

type FileBasedTenantConfigLoader ΒΆ added in v1.1.0

type FileBasedTenantConfigLoader struct {
	// contains filtered or unexported fields
}

FileBasedTenantConfigLoader implements TenantConfigLoader for file-based tenant configurations

func DefaultTenantConfigLoader ΒΆ added in v1.1.0

func DefaultTenantConfigLoader(configDir string) *FileBasedTenantConfigLoader

DefaultTenantConfigLoader creates a loader with default configuration

func NewFileBasedTenantConfigLoader ΒΆ added in v1.1.0

func NewFileBasedTenantConfigLoader(params TenantConfigParams) *FileBasedTenantConfigLoader

NewFileBasedTenantConfigLoader creates a new file-based tenant config loader

func (*FileBasedTenantConfigLoader) LoadTenantConfigurations ΒΆ added in v1.1.0

func (l *FileBasedTenantConfigLoader) LoadTenantConfigurations(app Application, tenantService TenantService) error

LoadTenantConfigurations loads tenant configurations from files

type FilterLoggerDecorator ΒΆ added in v1.4.3

type FilterLoggerDecorator struct {
	*BaseLoggerDecorator
	// contains filtered or unexported fields
}

FilterLoggerDecorator filters log events based on configurable criteria. This decorator can filter by log level, message content, or key-value pairs.

func NewFilterLoggerDecorator ΒΆ added in v1.4.3

func NewFilterLoggerDecorator(inner Logger, messageFilters []string, keyFilters map[string]string, levelFilters map[string]bool) *FilterLoggerDecorator

NewFilterLoggerDecorator creates a decorator that filters log events. If levelFilters is nil, all levels (info, error, warn, debug) are allowed by default.

func (*FilterLoggerDecorator) Debug ΒΆ added in v1.4.3

func (d *FilterLoggerDecorator) Debug(msg string, args ...any)

func (*FilterLoggerDecorator) Error ΒΆ added in v1.4.3

func (d *FilterLoggerDecorator) Error(msg string, args ...any)

func (*FilterLoggerDecorator) Info ΒΆ added in v1.4.3

func (d *FilterLoggerDecorator) Info(msg string, args ...any)

func (*FilterLoggerDecorator) Warn ΒΆ added in v1.4.3

func (d *FilterLoggerDecorator) Warn(msg string, args ...any)

type FunctionalObserver ΒΆ added in v1.4.3

type FunctionalObserver struct {
	// contains filtered or unexported fields
}

FunctionalObserver provides a simple way to create observers using functions. This is useful for quick observer creation without defining full structs.

func (*FunctionalObserver) ObserverID ΒΆ added in v1.4.3

func (f *FunctionalObserver) ObserverID() string

ObserverID implements the Observer interface by returning the observer ID.

func (*FunctionalObserver) OnEvent ΒΆ added in v1.4.3

func (f *FunctionalObserver) OnEvent(ctx context.Context, event cloudevents.Event) error

OnEvent implements the Observer interface by calling the handler function.

type HealthAggregator ΒΆ added in v1.4.3

type HealthAggregator interface {
	// Collect gathers health reports from all registered providers and
	// returns an aggregated view of the system's health status.
	// The context can be used to timeout the collection process.
	Collect(ctx context.Context) (AggregatedHealth, error)
}

HealthAggregator interface defines how health reports are collected and aggregated as specified in the design brief for FR-048.

type HealthAggregatorConfig ΒΆ added in v1.4.3

type HealthAggregatorConfig struct {
	Enabled       bool          `json:"enabled"`
	CheckInterval time.Duration `json:"check_interval"`
	CheckTimeout  time.Duration `json:"check_timeout"`
}

HealthAggregatorConfig configures health aggregation

type HealthComponent ΒΆ added in v1.4.3

type HealthComponent struct {
	// Name is the identifier for this component
	Name string

	// Status is the health status of this component
	Status HealthStatus

	// Message provides details about the component's health
	Message string

	// CheckDuration is how long the health check took
	CheckDuration time.Duration

	// LastChecked indicates when this component was last evaluated
	LastChecked time.Time

	// Metadata contains additional component-specific health information
	Metadata map[string]interface{}
}

HealthComponent represents the health information for a single component within an aggregate health snapshot.

type HealthEvaluatedEvent ΒΆ added in v1.4.3

type HealthEvaluatedEvent struct {
	// EvaluationID is a unique identifier for this health evaluation
	EvaluationID string

	// Timestamp indicates when the evaluation was performed
	Timestamp time.Time

	// Snapshot contains the health snapshot result
	Snapshot AggregateHealthSnapshot

	// Duration indicates how long the evaluation took
	Duration time.Duration

	// TriggerType indicates what triggered this health evaluation
	TriggerType HealthTrigger

	// StatusChanged indicates whether the health status changed from the previous evaluation
	StatusChanged bool

	// PreviousStatus contains the previous health status if it changed
	PreviousStatus HealthStatus

	// Metrics contains additional metrics about the health evaluation
	Metrics *HealthEvaluationMetrics
}

HealthEvaluatedEvent represents an event emitted when health evaluation completes

func (*HealthEvaluatedEvent) EventSource ΒΆ added in v1.4.3

func (e *HealthEvaluatedEvent) EventSource() string

EventSource returns the standardized event source for health evaluations

func (*HealthEvaluatedEvent) EventType ΒΆ added in v1.4.3

func (e *HealthEvaluatedEvent) EventType() string

EventType returns the standardized event type for health evaluations

func (*HealthEvaluatedEvent) GetEventSource ΒΆ added in v1.4.3

func (e *HealthEvaluatedEvent) GetEventSource() string

GetEventSource returns the source that generated this event (implements ObserverEvent)

func (*HealthEvaluatedEvent) GetEventType ΒΆ added in v1.4.3

func (e *HealthEvaluatedEvent) GetEventType() string

GetEventType returns the type identifier for this event (implements ObserverEvent)

func (*HealthEvaluatedEvent) GetTimestamp ΒΆ added in v1.4.3

func (e *HealthEvaluatedEvent) GetTimestamp() time.Time

GetTimestamp returns when this event occurred (implements ObserverEvent)

func (*HealthEvaluatedEvent) StructuredFields ΒΆ added in v1.4.3

func (e *HealthEvaluatedEvent) StructuredFields() map[string]interface{}

StructuredFields returns the structured field data for this event

type HealthEvaluationMetrics ΒΆ added in v1.4.3

type HealthEvaluationMetrics struct {
	ComponentsEvaluated   int
	FailedEvaluations     int
	AverageResponseTimeMs float64
	ComponentsSkipped     int
	ComponentsTimedOut    int
	TotalEvaluationTime   time.Duration
	SlowestComponentName  string
	SlowestComponentTime  time.Duration
}

Additional types and functions needed for tests to compile

func (*HealthEvaluationMetrics) BottleneckPercentage ΒΆ added in v1.4.3

func (h *HealthEvaluationMetrics) BottleneckPercentage() float64

BottleneckPercentage returns the percentage of total time consumed by the slowest component

func (*HealthEvaluationMetrics) CalculateEfficiency ΒΆ added in v1.4.3

func (h *HealthEvaluationMetrics) CalculateEfficiency() float64

CalculateEfficiency returns the efficiency percentage of the health evaluation

func (*HealthEvaluationMetrics) HasPerformanceBottleneck ΒΆ added in v1.4.3

func (h *HealthEvaluationMetrics) HasPerformanceBottleneck() bool

HasPerformanceBottleneck returns true if there are performance bottlenecks

type HealthProvider ΒΆ added in v1.4.3

type HealthProvider interface {
	// HealthCheck performs a health check and returns health reports.
	// The context can be used to timeout long-running health checks.
	//
	// Implementations should:
	//   - Respect context cancellation and timeouts
	//   - Return meaningful status and messages
	//   - Include relevant metadata for debugging
	//   - Be idempotent and safe to call repeatedly
	//
	// Returns a slice of HealthReport objects, allowing a single provider
	// to report on multiple components or aspects of the service.
	HealthCheck(ctx context.Context) ([]HealthReport, error)
}

HealthProvider defines the interface for components that can report their health status. This interface follows the design brief specification for FR-048 Health Aggregation, providing structured health reports with module and component information.

Components implementing this interface can participate in system-wide health monitoring and provide detailed information about their operational state.

Health checks should be:

  • Fast: typically complete within a few seconds
  • Reliable: not prone to false positives/negatives
  • Meaningful: accurately reflect the component's ability to serve requests
  • Non-disruptive: not impact normal operations when executed

func HealthReporterToProvider deprecated added in v1.4.3

func HealthReporterToProvider(reporter HealthReporter, moduleName string) HealthProvider

HealthReporterToProvider converts a HealthReporter to a HealthProvider using the adapter. This is a convenience function for the common case of adapting a single reporter.

Deprecated: Use NewHealthReporterAdapter directly for better clarity.

func NewCompositeHealthProvider ΒΆ added in v1.4.3

func NewCompositeHealthProvider(providers ...HealthProvider) HealthProvider

NewCompositeHealthProvider creates a HealthProvider that combines multiple providers. This allows you to aggregate health reports from multiple sources into a single provider.

All provided HealthProviders will be called and their reports combined. If any provider returns an error, the composite will return that error.

func NewHealthReporterAdapter ΒΆ added in v1.4.3

func NewHealthReporterAdapter(reporter HealthReporter, moduleName string) HealthProvider

NewHealthReporterAdapter creates a HealthProvider adapter for legacy HealthReporter implementations. This allows existing HealthReporter implementations to work with the new standardized interface.

Parameters:

  • reporter: The legacy HealthReporter implementation
  • moduleName: The module name to use in the generated HealthReport

The adapter will:

  • Convert HealthResult to HealthReport format
  • Use HealthCheckName() as the component name
  • Respect HealthCheckTimeout() for context timeout
  • Handle context cancellation appropriately

func NewSimpleHealthProvider ΒΆ added in v1.4.3

func NewSimpleHealthProvider(moduleName, componentName string, checkFunc func(context.Context) (HealthStatus, string, error)) HealthProvider

NewSimpleHealthProvider creates a HealthProvider for simple health checks. This is useful for creating lightweight health providers without implementing the full interface.

Parameters:

  • moduleName: The module name for the health report
  • componentName: The component name for the health report
  • checkFunc: A function that performs the actual health check

The checkFunc receives a context and should return:

  • HealthStatus: The health status
  • string: A message describing the health status
  • error: Any error that occurred during the check

func NewStaticHealthProvider ΒΆ added in v1.4.3

func NewStaticHealthProvider(moduleName, componentName string, status HealthStatus, message string) HealthProvider

NewStaticHealthProvider creates a HealthProvider that always returns the same status. This is useful for testing or for components that have a fixed health status.

Parameters:

  • moduleName: The module name for the health report
  • componentName: The component name for the health report
  • status: The health status to always return
  • message: The message to always return

type HealthReport ΒΆ added in v1.4.3

type HealthReport struct {
	// Module is the identifier for the module that provides this health check
	Module string `json:"module"`

	// Component is an optional identifier for the specific component within the module
	// (e.g., "database-connection", "cache-client", "worker-pool")
	Component string `json:"component,omitempty"`

	// Status is the health status determined by the check
	Status HealthStatus `json:"status"`

	// Message provides human-readable details about the health status.
	// This should be concise but informative for debugging and monitoring.
	Message string `json:"message,omitempty"`

	// CheckedAt indicates when the health check was performed
	CheckedAt time.Time `json:"checkedAt"`

	// ObservedSince indicates when this status was first observed
	// This helps track how long a component has been in its current state
	ObservedSince time.Time `json:"observedSince"`

	// Optional indicates whether this component is optional for overall readiness
	// Optional components don't affect the readiness status but are included in health
	Optional bool `json:"optional"`

	// Details contains additional structured information about the health check
	// This can include metrics, diagnostic information, or other contextual data
	Details map[string]any `json:"details,omitempty"`
}

HealthReport represents a health report as defined in the design brief for FR-048. This structure provides detailed information about the health of a specific module or component, including timing and observability information.

type HealthReporter deprecated added in v1.4.3

type HealthReporter interface {
	// CheckHealth performs a health check and returns the current status.
	// The context can be used to timeout long-running health checks.
	//
	// Implementations should:
	//   - Respect context cancellation and timeouts
	//   - Return meaningful status and messages
	//   - Include relevant metadata for debugging
	//   - Be idempotent and safe to call repeatedly
	//
	// The returned HealthResult should always be valid, even if the check fails.
	CheckHealth(ctx context.Context) HealthResult

	// HealthCheckName returns a human-readable name for this health check.
	// This name is used in logs, metrics, and health dashboards.
	// It should be unique within the application and descriptive of what is being checked.
	HealthCheckName() string

	// HealthCheckTimeout returns the maximum time this health check needs to complete.
	// This is used by health aggregators to set appropriate context timeouts.
	//
	// Typical values:
	//   - Simple checks (memory, CPU): 1-5 seconds
	//   - Database connectivity: 5-15 seconds
	//   - External service calls: 10-30 seconds
	//
	// A zero duration indicates the health check should use a reasonable default timeout.
	HealthCheckTimeout() time.Duration
}

HealthReporter defines the legacy interface for backward compatibility. New implementations should use HealthProvider instead.

MIGRATION GUIDE:

To migrate from HealthReporter to HealthProvider:

  1. For existing implementations, use the adapter: ```go oldReporter := &MyHealthReporter{} newProvider := NewHealthReporterAdapter(oldReporter, "my-module") ```

  2. For new implementations, implement HealthProvider directly: ```go func (m *MyModule) HealthCheck(ctx context.Context) ([]HealthReport, error) { return []HealthReport{{ Module: "my-module", Component: "my-component", Status: HealthStatusHealthy, Message: "All good", CheckedAt: time.Now(), }}, nil } ```

  3. For simple cases, use utility functions: ```go provider := NewSimpleHealthProvider("module", "component", func(ctx context.Context) (HealthStatus, string, error) { return HealthStatusHealthy, "OK", nil }) ```

DEPRECATION TIMELINE: - v1.x: Interface available with deprecation warnings - v2.0: Interface removed (breaking change)

Deprecated: Use HealthProvider interface instead. This interface will be removed in v2.0.0. See migration guide above for transition strategies.

type HealthResult deprecated added in v1.4.3

type HealthResult struct {
	// Status is the overall health status determined by the check
	Status HealthStatus

	// Message provides human-readable details about the health status.
	// This should be concise but informative for debugging and monitoring.
	Message string

	// Timestamp indicates when the health check was performed
	Timestamp time.Time

	// CheckDuration is the time it took to complete the health check
	CheckDuration time.Duration

	// Details provides detailed information about the health check
	// This can include additional diagnostic information, nested results, etc.
	Details map[string]interface{}

	// Metadata contains additional key-value pairs with health check details.
	// This can include metrics, error details, or other contextual information.
	Metadata map[string]interface{}
}

HealthResult contains the result of a health check operation. It includes the status, timing information, and optional metadata about the health check execution.

Deprecated: Use HealthReport instead for new implementations. This type is maintained for backward compatibility.

type HealthStatus ΒΆ added in v1.4.3

type HealthStatus int

HealthStatus represents the overall health state of a component or service. It follows a standard set of states that can be used for monitoring and alerting.

const (
	// HealthStatusUnknown indicates that the health status cannot be determined.
	// This is typically used when health checks are not yet complete or have failed
	// to execute due to timeouts or other issues.
	HealthStatusUnknown HealthStatus = iota

	// HealthStatusHealthy indicates that the component is operating normally.
	// All health checks are passing and the component is ready to serve requests.
	HealthStatusHealthy

	// HealthStatusDegraded indicates that the component is operational but
	// not performing optimally. Some non-critical functionality may be impaired.
	HealthStatusDegraded

	// HealthStatusUnhealthy indicates that the component is not functioning
	// properly and may not be able to serve requests reliably.
	HealthStatusUnhealthy
)

func (HealthStatus) IsHealthy ΒΆ added in v1.4.3

func (s HealthStatus) IsHealthy() bool

IsHealthy returns true if the status represents a healthy state

func (HealthStatus) String ΒΆ added in v1.4.3

func (s HealthStatus) String() string

String returns the string representation of the health status.

type HealthStatusChangedEvent ΒΆ added in v1.4.3

type HealthStatusChangedEvent struct {
	Timestamp      time.Time
	NewStatus      HealthStatus
	PreviousStatus HealthStatus
	Duration       time.Duration
	ReportCount    int
}

HealthStatusChangedEvent represents an event emitted when the overall health status changes

func (*HealthStatusChangedEvent) GetEventSource ΒΆ added in v1.4.3

func (e *HealthStatusChangedEvent) GetEventSource() string

GetEventSource returns the event source for status change events

func (*HealthStatusChangedEvent) GetEventType ΒΆ added in v1.4.3

func (e *HealthStatusChangedEvent) GetEventType() string

GetEventType returns the event type for status change events

func (*HealthStatusChangedEvent) GetTimestamp ΒΆ added in v1.4.3

func (e *HealthStatusChangedEvent) GetTimestamp() time.Time

GetTimestamp returns when this event occurred

type HealthSummary ΒΆ added in v1.4.3

type HealthSummary struct {
	// HealthyCount is the number of healthy components
	HealthyCount int

	// TotalCount is the total number of components checked
	TotalCount int

	// DegradedCount is the number of degraded components
	DegradedCount int

	// UnhealthyCount is the number of unhealthy components
	UnhealthyCount int
}

HealthSummary provides a summary of health check results

type HealthTrigger ΒΆ added in v1.4.3

type HealthTrigger int

HealthTrigger represents what triggered a health evaluation

const (
	// HealthTriggerThreshold indicates the health check was triggered by a threshold
	HealthTriggerThreshold HealthTrigger = iota

	// HealthTriggerScheduled indicates the health check was triggered by a schedule
	HealthTriggerScheduled

	// HealthTriggerOnDemand indicates the health check was triggered manually/on-demand
	HealthTriggerOnDemand

	// HealthTriggerStartup indicates the health check was triggered at startup
	HealthTriggerStartup

	// HealthTriggerPostReload indicates the health check was triggered after a config reload
	HealthTriggerPostReload
)

func ParseHealthTrigger ΒΆ added in v1.4.3

func ParseHealthTrigger(s string) (HealthTrigger, error)

ParseHealthTrigger parses a string into a HealthTrigger

func (HealthTrigger) String ΒΆ added in v1.4.3

func (h HealthTrigger) String() string

String returns the string representation of the health trigger

type InsecureSecretProvider ΒΆ added in v1.4.3

type InsecureSecretProvider struct {
	// contains filtered or unexported fields
}

InsecureSecretProvider implements SecretProvider using the original XOR-based approach. This provider offers basic obfuscation but NO cryptographic security guarantees.

SECURITY WARNING: This provider: - Uses simple XOR encryption for obfuscation only - Cannot prevent memory dumps from revealing secrets - Cannot guarantee secure memory clearing in Go - Should NOT be used for highly sensitive secrets in production

Use this provider for: - Development and testing environments - Non-critical secrets where convenience outweighs security - Situations where secure memory libraries are unavailable

func (*InsecureSecretProvider) Cleanup ΒΆ added in v1.4.3

func (p *InsecureSecretProvider) Cleanup() error

func (*InsecureSecretProvider) Clone ΒΆ added in v1.4.3

func (*InsecureSecretProvider) Compare ΒΆ added in v1.4.3

func (p *InsecureSecretProvider) Compare(handle SecretHandle, value string) (bool, error)

func (*InsecureSecretProvider) Destroy ΒΆ added in v1.4.3

func (p *InsecureSecretProvider) Destroy(handle SecretHandle) error

func (*InsecureSecretProvider) GetMetadata ΒΆ added in v1.4.3

func (p *InsecureSecretProvider) GetMetadata(handle SecretHandle) (SecretMetadata, error)

func (*InsecureSecretProvider) IsEmpty ΒΆ added in v1.4.3

func (p *InsecureSecretProvider) IsEmpty(handle SecretHandle) bool

func (*InsecureSecretProvider) IsSecure ΒΆ added in v1.4.3

func (p *InsecureSecretProvider) IsSecure() bool

func (*InsecureSecretProvider) Name ΒΆ added in v1.4.3

func (p *InsecureSecretProvider) Name() string

func (*InsecureSecretProvider) Retrieve ΒΆ added in v1.4.3

func (p *InsecureSecretProvider) Retrieve(handle SecretHandle) (string, error)

func (*InsecureSecretProvider) Store ΒΆ added in v1.4.3

func (p *InsecureSecretProvider) Store(value string, secretType SecretType) (SecretHandle, error)

type InstanceAwareConfigProvider ΒΆ added in v1.3.1

type InstanceAwareConfigProvider struct {
	// contains filtered or unexported fields
}

InstanceAwareConfigProvider handles configuration for multiple instances of the same type

func NewInstanceAwareConfigProvider ΒΆ added in v1.3.1

func NewInstanceAwareConfigProvider(cfg any, prefixFunc InstancePrefixFunc) *InstanceAwareConfigProvider

NewInstanceAwareConfigProvider creates a new instance-aware configuration provider

func (*InstanceAwareConfigProvider) GetConfig ΒΆ added in v1.3.1

func (p *InstanceAwareConfigProvider) GetConfig() any

GetConfig returns the configuration object

func (*InstanceAwareConfigProvider) GetInstancePrefixFunc ΒΆ added in v1.3.1

func (p *InstanceAwareConfigProvider) GetInstancePrefixFunc() InstancePrefixFunc

GetInstancePrefixFunc returns the instance prefix function

type InstanceAwareConfigSupport ΒΆ added in v1.3.1

type InstanceAwareConfigSupport interface {
	// GetInstanceConfigs returns a map of instance configurations that should be fed with instance-aware feeders
	GetInstanceConfigs() map[string]interface{}
}

InstanceAwareConfigSupport indicates that a configuration supports instance-aware feeding

type InstanceAwareFeeder ΒΆ added in v1.3.1

type InstanceAwareFeeder interface {
	ComplexFeeder
	// FeedInstances feeds multiple instances from a map[string]ConfigType
	FeedInstances(instances interface{}) error
}

InstanceAwareFeeder provides functionality for feeding multiple instances of the same configuration type

func NewInstanceAwareEnvFeeder ΒΆ added in v1.3.1

func NewInstanceAwareEnvFeeder(prefixFunc InstancePrefixFunc) InstanceAwareFeeder

NewInstanceAwareEnvFeeder creates a new instance-aware environment variable feeder

type InstancePrefixFunc ΒΆ added in v1.3.1

type InstancePrefixFunc = feeders.InstancePrefixFunc

InstancePrefixFunc is a function that generates a prefix for an instance key

type InterfaceMatch ΒΆ added in v1.4.3

type InterfaceMatch struct {
	Consumer      string
	Provider      string
	InterfaceType reflect.Type
	ServiceName   string
	Required      bool
}

InterfaceMatch represents a consumer-provider match for an interface-based dependency

type LevelModifierLoggerDecorator ΒΆ added in v1.4.3

type LevelModifierLoggerDecorator struct {
	*BaseLoggerDecorator
	// contains filtered or unexported fields
}

LevelModifierLoggerDecorator modifies the log level of events. This decorator can promote or demote log levels based on configured rules.

func NewLevelModifierLoggerDecorator ΒΆ added in v1.4.3

func NewLevelModifierLoggerDecorator(inner Logger, levelMappings map[string]string) *LevelModifierLoggerDecorator

NewLevelModifierLoggerDecorator creates a decorator that modifies log levels.

func (*LevelModifierLoggerDecorator) Debug ΒΆ added in v1.4.3

func (d *LevelModifierLoggerDecorator) Debug(msg string, args ...any)

func (*LevelModifierLoggerDecorator) Error ΒΆ added in v1.4.3

func (d *LevelModifierLoggerDecorator) Error(msg string, args ...any)

func (*LevelModifierLoggerDecorator) Info ΒΆ added in v1.4.3

func (d *LevelModifierLoggerDecorator) Info(msg string, args ...any)

func (*LevelModifierLoggerDecorator) Warn ΒΆ added in v1.4.3

func (d *LevelModifierLoggerDecorator) Warn(msg string, args ...any)

type LoadAppConfigFunc ΒΆ added in v1.0.0

type LoadAppConfigFunc func(*StdApplication) error

LoadAppConfigFunc is the function type for loading application configuration. This function is responsible for loading configuration data into the application using the registered config feeders and config sections.

The default implementation can be replaced for testing or custom configuration scenarios.

var AppConfigLoader LoadAppConfigFunc = loadAppConfig

AppConfigLoader is the default implementation that can be replaced in tests. This variable allows the configuration loading strategy to be customized, which is particularly useful for testing scenarios where you want to control how configuration is loaded.

Example of replacing for tests:

oldLoader := modular.AppConfigLoader
defer func() { modular.AppConfigLoader = oldLoader }()
modular.AppConfigLoader = func(app *StdApplication) error {
    // Custom test configuration loading
    return nil
}

type Logger ΒΆ

type Logger interface {
	// Info logs an informational message with optional key-value pairs.
	// Used for normal application events like module startup, service registration, etc.
	//
	// Example:
	//   logger.Info("Module initialized", "module", "database", "version", "1.2.3")
	Info(msg string, args ...any)

	// Error logs an error message with optional key-value pairs.
	// Used for errors that don't prevent application startup but should be noted.
	//
	// Example:
	//   logger.Error("Failed to connect to service", "service", "cache", "error", err)
	Error(msg string, args ...any)

	// Warn logs a warning message with optional key-value pairs.
	// Used for conditions that are unusual but don't prevent normal operation.
	//
	// Example:
	//   logger.Warn("Service unavailable, using fallback", "service", "external-api")
	Warn(msg string, args ...any)

	// Debug logs a debug message with optional key-value pairs.
	// Used for detailed diagnostic information, typically disabled in production.
	//
	// Example:
	//   logger.Debug("Dependency resolved", "from", "module1", "to", "module2")
	Debug(msg string, args ...any)
}

Logger defines the interface for application logging. The modular framework uses structured logging with key-value pairs to provide consistent, parseable log output across all modules.

All framework operations (module initialization, service registration, dependency resolution, etc.) are logged using this interface, so implementing applications can control how framework logs appear.

The Logger interface uses variadic arguments in key-value pairs:

logger.Info("message", "key1", "value1", "key2", "value2")

This approach is compatible with popular structured logging libraries like slog, logrus, zap, and others.

Example implementation using Go's standard log/slog:

type SlogLogger struct {
    logger *slog.Logger
}

func (l *SlogLogger) Info(msg string, args ...any) {
    l.logger.Info(msg, args...)
}

func (l *SlogLogger) Error(msg string, args ...any) {
    l.logger.Error(msg, args...)
}

func (l *SlogLogger) Warn(msg string, args ...any) {
    l.logger.Warn(msg, args...)
}

func (l *SlogLogger) Debug(msg string, args ...any) {
    l.logger.Debug(msg, args...)
}

type LoggerDecorator ΒΆ added in v1.4.3

type LoggerDecorator interface {
	Logger

	// GetInnerLogger returns the wrapped logger
	GetInnerLogger() Logger
}

LoggerDecorator defines the interface for decorating loggers. Decorators wrap loggers to add additional functionality without modifying the core logger implementation.

type MemguardSecretProvider ΒΆ added in v1.4.3

type MemguardSecretProvider struct {
	// contains filtered or unexported fields
}

MemguardSecretProvider implements SecretProvider using github.com/awnumar/memguard for cryptographically secure memory handling.

This provider offers: - Secure memory allocation that is not swapped to disk - Memory encryption to protect against memory dumps - Secure memory wiping when secrets are destroyed - Protection against Heartbleed-style attacks - Memory canaries to detect buffer overflows

IMPORTANT NOTES: - Requires CGO and may not work on all platforms - Has performance overhead compared to insecure provider - May be unstable on some systems or Go versions - Requires the memguard dependency to be available

This provider should be used for: - Production systems with sensitive secrets - Compliance requirements for secure memory handling - High-security environments where memory protection is critical

func (*MemguardSecretProvider) Cleanup ΒΆ added in v1.4.3

func (p *MemguardSecretProvider) Cleanup() error

func (*MemguardSecretProvider) Clone ΒΆ added in v1.4.3

func (*MemguardSecretProvider) Compare ΒΆ added in v1.4.3

func (p *MemguardSecretProvider) Compare(handle SecretHandle, value string) (bool, error)

func (*MemguardSecretProvider) Destroy ΒΆ added in v1.4.3

func (p *MemguardSecretProvider) Destroy(handle SecretHandle) error

func (*MemguardSecretProvider) GetMetadata ΒΆ added in v1.4.3

func (p *MemguardSecretProvider) GetMetadata(handle SecretHandle) (SecretMetadata, error)

func (*MemguardSecretProvider) IsEmpty ΒΆ added in v1.4.3

func (p *MemguardSecretProvider) IsEmpty(handle SecretHandle) bool

func (*MemguardSecretProvider) IsSecure ΒΆ added in v1.4.3

func (p *MemguardSecretProvider) IsSecure() bool

func (*MemguardSecretProvider) Name ΒΆ added in v1.4.3

func (p *MemguardSecretProvider) Name() string

func (*MemguardSecretProvider) Retrieve ΒΆ added in v1.4.3

func (p *MemguardSecretProvider) Retrieve(handle SecretHandle) (string, error)

func (*MemguardSecretProvider) Store ΒΆ added in v1.4.3

func (p *MemguardSecretProvider) Store(value string, secretType SecretType) (SecretHandle, error)

type Module ΒΆ

type Module interface {
	// Name returns the unique identifier for this module.
	// The name is used for dependency resolution and service registration.
	// It must be unique within the application and should be descriptive
	// of the module's purpose.
	//
	// Example: "database", "auth", "httpserver", "cache"
	Name() string

	// Init initializes the module with the application context.
	// This method is called during application initialization after
	// all modules have been registered and their configurations loaded.
	//
	// The Init method should:
	//   - Validate any required configuration
	//   - Initialize internal state
	//   - Register any services this module provides
	//   - Prepare for Start() to be called
	//
	// Init is called in dependency order - modules that depend on others
	// are initialized after their dependencies.
	Init(app Application) error
}

Module represents a registrable component in the application. All modules must implement this interface to be managed by the application.

A module is the basic building block of a modular application. It encapsulates a specific piece of functionality and can interact with other modules through the application's service registry and configuration system.

type ModuleAwareFeeder ΒΆ added in v1.4.3

type ModuleAwareFeeder interface {
	Feeder
	// FeedWithModuleContext feeds configuration with module context information.
	// The moduleName parameter provides the name of the module whose configuration
	// is being processed, allowing the feeder to customize its behavior accordingly.
	FeedWithModuleContext(structure interface{}, moduleName string) error
}

ModuleAwareFeeder provides functionality for feeders that can receive module context during configuration feeding. This allows feeders to customize behavior based on which module's configuration is being processed.

type ModuleConstructor ΒΆ

type ModuleConstructor func(app Application, services map[string]any) (Module, error)

ModuleConstructor is a function type that creates module instances with dependency injection. Constructor functions receive the application instance and a map of resolved services that the module declared as requirements.

The constructor should:

  • Extract required services from the services map
  • Perform any type assertions needed
  • Create and return a new module instance
  • Return an error if construction fails

Constructor functions enable advanced dependency injection patterns and can also accept typed parameters that the framework will resolve automatically.

type ModuleLifecyclePayload ΒΆ added in v1.4.3

type ModuleLifecyclePayload struct {
	// Subject indicates whether this is a module or application lifecycle event (e.g., "module", "application").
	Subject string `json:"subject"`
	// Name is the module/application name.
	Name string `json:"name"`
	// Action is the lifecycle action (e.g., start|stop|init|register|fail|initialize|initialized).
	Action string `json:"action"`
	// Version optionally records the module version if available.
	Version string `json:"version,omitempty"`
	// Timestamp is when the lifecycle action occurred (RFC3339 in JSON output).
	Timestamp time.Time `json:"timestamp"`
	// Additional arbitrary metadata (kept minimal; prefer evolving the struct if fields become first-class).
	Metadata map[string]interface{} `json:"metadata,omitempty"`
}

ModuleLifecyclePayload represents a structured lifecycle event for a module or the application. This provides a strongly-typed alternative to scattering lifecycle details across CloudEvent extensions. Additional routing-friendly metadata (like action) is still duplicated into a small extension for fast filtering.

type ModuleRegistry ΒΆ

type ModuleRegistry map[string]Module

ModuleRegistry represents a registry of modules keyed by their names. This is used internally by the application to manage registered modules and resolve dependencies between them.

The registry ensures each module name is unique and provides efficient lookup during dependency resolution and lifecycle management.

type ModuleWithConstructor ΒΆ

type ModuleWithConstructor interface {
	Module
	Constructable
}

ModuleWithConstructor defines modules that support constructor-based dependency injection. This is a convenience interface that combines Module and Constructable.

Modules implementing this interface will be reconstructed using their constructor after dependencies are resolved, allowing for cleaner dependency injection patterns.

type ObservableApplication ΒΆ added in v1.4.3

type ObservableApplication struct {
	*StdApplication
	// contains filtered or unexported fields
}

ObservableApplication extends StdApplication with observer pattern capabilities. This struct embeds StdApplication and adds observer management functionality. It uses CloudEvents specification for standardized event handling and interoperability.

func NewObservableApplication ΒΆ added in v1.4.3

func NewObservableApplication(cp ConfigProvider, logger Logger) *ObservableApplication

NewObservableApplication creates a new application instance with observer pattern support. This wraps the standard application with observer capabilities while maintaining all existing functionality.

func (*ObservableApplication) GetObservers ΒΆ added in v1.4.3

func (app *ObservableApplication) GetObservers() []ObserverInfo

GetObservers returns information about currently registered observers. This is useful for debugging and monitoring.

func (*ObservableApplication) Init ΒΆ added in v1.4.3

func (app *ObservableApplication) Init() error

Init initializes the application and emits lifecycle events

func (*ObservableApplication) NotifyObservers ΒΆ added in v1.4.3

func (app *ObservableApplication) NotifyObservers(ctx context.Context, event cloudevents.Event) error

NotifyObservers sends a CloudEvent to all registered observers. The notification process is non-blocking for the caller and handles observer errors gracefully.

func (*ObservableApplication) RegisterModule ΒΆ added in v1.4.3

func (app *ObservableApplication) RegisterModule(module Module)

RegisterModule registers a module and emits CloudEvent

func (*ObservableApplication) RegisterObserver ΒΆ added in v1.4.3

func (app *ObservableApplication) RegisterObserver(observer Observer, eventTypes ...string) error

RegisterObserver adds an observer to receive notifications from the application. Observers can optionally filter events by type using the eventTypes parameter. If eventTypes is empty, the observer receives all events.

func (*ObservableApplication) RegisterService ΒΆ added in v1.4.3

func (app *ObservableApplication) RegisterService(name string, service any) error

RegisterService registers a service and emits CloudEvent

func (*ObservableApplication) Start ΒΆ added in v1.4.3

func (app *ObservableApplication) Start() error

Start starts the application and emits lifecycle events

func (*ObservableApplication) Stop ΒΆ added in v1.4.3

func (app *ObservableApplication) Stop() error

Stop stops the application and emits lifecycle events

func (*ObservableApplication) UnregisterObserver ΒΆ added in v1.4.3

func (app *ObservableApplication) UnregisterObserver(observer Observer) error

UnregisterObserver removes an observer from receiving notifications. This method is idempotent and won't error if the observer wasn't registered.

type ObservableDecorator ΒΆ added in v1.4.3

type ObservableDecorator struct {
	*BaseApplicationDecorator
	// contains filtered or unexported fields
}

ObservableDecorator wraps an application to add observer pattern capabilities. It emits CloudEvents for application lifecycle events and manages observers.

func NewObservableDecorator ΒΆ added in v1.4.3

func NewObservableDecorator(inner Application, observers ...ObserverFunc) *ObservableDecorator

NewObservableDecorator creates a new observable decorator with the provided observers

func (*ObservableDecorator) AddObserver ΒΆ added in v1.4.3

func (d *ObservableDecorator) AddObserver(observer ObserverFunc)

AddObserver adds a new observer function

func (*ObservableDecorator) Init ΒΆ added in v1.4.3

func (d *ObservableDecorator) Init() error

Init overrides the base Init method to emit lifecycle events

func (*ObservableDecorator) RemoveObserver ΒΆ added in v1.4.3

func (d *ObservableDecorator) RemoveObserver(observer ObserverFunc)

RemoveObserver removes an observer function (not commonly used with functional observers)

func (*ObservableDecorator) Start ΒΆ added in v1.4.3

func (d *ObservableDecorator) Start() error

Start overrides the base Start method to emit lifecycle events

func (*ObservableDecorator) Stop ΒΆ added in v1.4.3

func (d *ObservableDecorator) Stop() error

Stop overrides the base Stop method to emit lifecycle events

type ObservableModule ΒΆ added in v1.4.3

type ObservableModule interface {
	Module

	// RegisterObservers is called during module initialization to allow
	// the module to register as an observer for events it's interested in.
	// The subject parameter is typically the application itself.
	RegisterObservers(subject Subject) error

	// EmitEvent allows modules to emit their own CloudEvents.
	// This should typically delegate to the application's NotifyObservers method.
	EmitEvent(ctx context.Context, event cloudevents.Event) error

	// GetRegisteredEventTypes returns a list of all event types this module
	// can emit. This is used for validation in testing to ensure all events
	// are properly tested and emitted during execution.
	GetRegisteredEventTypes() []string
}

ObservableModule is an optional interface that modules can implement to participate in the observer pattern. Modules implementing this interface can emit their own events and register observers for events they're interested in. All events use the CloudEvents specification for standardization.

type Observer ΒΆ added in v1.4.3

type Observer interface {
	// OnEvent is called when an event occurs that the observer is interested in.
	// The context can be used for cancellation and timeouts.
	// Observers should handle events quickly to avoid blocking other observers.
	OnEvent(ctx context.Context, event cloudevents.Event) error

	// ObserverID returns a unique identifier for this observer.
	// This ID is used for registration tracking and debugging.
	ObserverID() string
}

Observer defines the interface for objects that want to be notified of events. Observers register with Subjects to receive notifications when events occur. This follows the traditional Observer pattern where observers are notified of state changes or events in subjects they're watching. Events use the CloudEvents specification for standardization.

func NewFunctionalObserver ΒΆ added in v1.4.3

func NewFunctionalObserver(id string, handler func(ctx context.Context, event cloudevents.Event) error) Observer

NewFunctionalObserver creates a new observer that uses the provided function to handle events. This is a convenience constructor for simple use cases.

type ObserverEvent ΒΆ added in v1.4.3

type ObserverEvent interface {
	// GetEventType returns the type identifier for this event
	GetEventType() string

	// GetEventSource returns the source that generated this event
	GetEventSource() string

	// GetTimestamp returns when this event occurred
	GetTimestamp() time.Time
}

ObserverEvent represents an event that can be observed in the system. This is a generic interface that allows different event types to be handled uniformly.

func FilterEventsByReloadID ΒΆ added in v1.4.3

func FilterEventsByReloadID(events []ObserverEvent, reloadID string) []ObserverEvent

FilterEventsByReloadID filters a slice of observer events to include only reload events with the specified reload ID

func FilterHealthEventsByStatus ΒΆ added in v1.4.3

func FilterHealthEventsByStatus(events []ObserverEvent, status HealthStatus) []ObserverEvent

func FilterHealthEventsByStatusChange ΒΆ added in v1.4.3

func FilterHealthEventsByStatusChange(events []ObserverEvent, statusChanged bool) []ObserverEvent

Filter functions for health events

func FilterHealthEventsByTrigger ΒΆ added in v1.4.3

func FilterHealthEventsByTrigger(events []ObserverEvent, trigger HealthTrigger) []ObserverEvent

type ObserverFunc ΒΆ added in v1.4.3

type ObserverFunc func(ctx context.Context, event cloudevents.Event) error

ObserverFunc is a functional observer that can be registered with the application

type ObserverInfo ΒΆ added in v1.4.3

type ObserverInfo struct {
	// ID is the unique identifier of the observer
	ID string `json:"id"`

	// EventTypes are the event types this observer is subscribed to.
	// Empty slice means all events.
	EventTypes []string `json:"eventTypes"`

	// RegisteredAt indicates when the observer was registered
	RegisteredAt time.Time `json:"registeredAt"`
}

ObserverInfo provides information about a registered observer. This is used for debugging, monitoring, and administrative interfaces.

type Option ΒΆ added in v1.4.3

type Option func(*ApplicationBuilder) error

Option represents a functional option for configuring applications

func WithBaseApplication ΒΆ added in v1.4.3

func WithBaseApplication(base Application) Option

WithBaseApplication sets the base application to decorate

func WithConfigDecorators ΒΆ added in v1.4.3

func WithConfigDecorators(decorators ...ConfigDecorator) Option

WithConfigDecorators adds configuration decorators

func WithConfigProvider ΒΆ added in v1.4.3

func WithConfigProvider(provider ConfigProvider) Option

WithConfigProvider sets the configuration provider

func WithLogger ΒΆ added in v1.4.3

func WithLogger(logger Logger) Option

WithLogger sets the logger for the application

func WithModules ΒΆ added in v1.4.3

func WithModules(modules ...Module) Option

WithModules adds modules to the application

func WithObserver ΒΆ added in v1.4.3

func WithObserver(observers ...ObserverFunc) Option

WithObserver enables observer pattern and adds observer functions

func WithTenantAware ΒΆ added in v1.4.3

func WithTenantAware(loader TenantLoader) Option

WithTenantAware enables tenant-aware functionality with the provided loader

func WithTenantGuardMode ΒΆ added in v1.4.3

func WithTenantGuardMode(mode TenantGuardMode) Option

WithTenantGuardMode configures tenant isolation strictness for multi-tenant applications. This option configures tenant access validation throughout the framework.

Supported modes:

  • TenantGuardModeStrict: Fail on cross-tenant access attempts with error
  • TenantGuardModeLenient: Log warnings but allow access (backward compatibility)
  • TenantGuardModeDisabled: No tenant checking (single-tenant mode)

Parameters:

  • mode: The tenant guard mode to use

Example:

app := NewApplication(
    WithTenantGuardMode(TenantGuardModeStrict),
)

func WithTenantGuardModeConfig ΒΆ added in v1.4.3

func WithTenantGuardModeConfig(config TenantGuardConfig) Option

WithTenantGuardModeConfig configures tenant isolation with detailed configuration. This allows fine-tuned control over tenant isolation behavior.

Parameters:

  • config: Detailed tenant guard configuration

Example:

config := TenantGuardConfig{
    Mode: TenantGuardModeStrict,
    EnforceIsolation: true,
    ValidationTimeout: 5 * time.Second,
}
app := NewApplication(
    WithTenantGuardModeConfig(config),
)

type PrefixLoggerDecorator ΒΆ added in v1.4.3

type PrefixLoggerDecorator struct {
	*BaseLoggerDecorator
	// contains filtered or unexported fields
}

PrefixLoggerDecorator adds a prefix to all log messages. This decorator automatically prepends a configured prefix to every log message.

func NewPrefixLoggerDecorator ΒΆ added in v1.4.3

func NewPrefixLoggerDecorator(inner Logger, prefix string) *PrefixLoggerDecorator

NewPrefixLoggerDecorator creates a decorator that adds a prefix to log messages.

func (*PrefixLoggerDecorator) Debug ΒΆ added in v1.4.3

func (d *PrefixLoggerDecorator) Debug(msg string, args ...any)

func (*PrefixLoggerDecorator) Error ΒΆ added in v1.4.3

func (d *PrefixLoggerDecorator) Error(msg string, args ...any)

func (*PrefixLoggerDecorator) Info ΒΆ added in v1.4.3

func (d *PrefixLoggerDecorator) Info(msg string, args ...any)

func (*PrefixLoggerDecorator) Warn ΒΆ added in v1.4.3

func (d *PrefixLoggerDecorator) Warn(msg string, args ...any)

type ProviderInfo ΒΆ added in v1.4.3

type ProviderInfo struct {
	Module   string
	Optional bool
}

ProviderInfo provides information about a registered provider

type ReloadOrchestrator ΒΆ added in v1.4.3

type ReloadOrchestrator struct {
	// contains filtered or unexported fields
}

ReloadOrchestrator manages configuration reload lifecycle according to the design brief specifications for FR-045 Dynamic Reload.

The orchestrator provides:

  • Atomic validation of all changes before applying
  • Dynamic field parsing with reflection and struct tags
  • Sequential module updates in registration order
  • Rollback on failure with no partial state
  • Event emission for all lifecycle phases
  • Exponential backoff for repeated failures
  • Concurrent request queueing

func NewReloadOrchestrator ΒΆ added in v1.4.3

func NewReloadOrchestrator() *ReloadOrchestrator

NewReloadOrchestrator creates a new reload orchestrator with default configuration

func NewReloadOrchestratorWithConfig ΒΆ added in v1.4.3

func NewReloadOrchestratorWithConfig(config ReloadOrchestratorConfig) *ReloadOrchestrator

NewReloadOrchestratorWithConfig creates a new reload orchestrator with custom configuration

func (*ReloadOrchestrator) RegisterModule ΒΆ added in v1.4.3

func (o *ReloadOrchestrator) RegisterModule(name string, module Reloadable) error

RegisterModule registers a reloadable module with the orchestrator

func (*ReloadOrchestrator) RequestReload ΒΆ added in v1.4.3

func (o *ReloadOrchestrator) RequestReload(ctx context.Context, sections ...string) error

RequestReload triggers a dynamic configuration reload for the specified sections. If no sections are specified, all dynamic configuration will be reloaded.

func (*ReloadOrchestrator) SetEventSubject ΒΆ added in v1.4.3

func (o *ReloadOrchestrator) SetEventSubject(subject Subject)

SetEventSubject sets the event subject for publishing reload events

func (*ReloadOrchestrator) Stop ΒΆ added in v1.4.3

func (o *ReloadOrchestrator) Stop(ctx context.Context) error

Stop gracefully stops the orchestrator

func (*ReloadOrchestrator) UnregisterModule ΒΆ added in v1.4.3

func (o *ReloadOrchestrator) UnregisterModule(name string) error

UnregisterModule removes a module from the orchestrator

type ReloadOrchestratorConfig ΒΆ added in v1.4.3

type ReloadOrchestratorConfig struct {
	// BackoffBase is the base duration for exponential backoff
	// Default: 2 seconds
	BackoffBase time.Duration

	// BackoffCap is the maximum duration for exponential backoff
	// Default: 2 minutes as specified in design brief
	BackoffCap time.Duration

	// QueueSize is the size of the request queue
	// Default: 100
	QueueSize int
}

ReloadOrchestratorConfig provides configuration for the reload orchestrator

type ReloadTrigger ΒΆ added in v1.4.3

type ReloadTrigger int

ReloadTrigger represents what triggered a configuration reload

const (
	// ReloadTriggerManual indicates the reload was triggered manually
	ReloadTriggerManual ReloadTrigger = iota

	// ReloadTriggerFileChange indicates the reload was triggered by file changes
	ReloadTriggerFileChange

	// ReloadTriggerAPIRequest indicates the reload was triggered by API request
	ReloadTriggerAPIRequest

	// ReloadTriggerScheduled indicates the reload was triggered by schedule
	ReloadTriggerScheduled
)

Reload trigger constants

func ParseReloadTrigger ΒΆ added in v1.4.3

func ParseReloadTrigger(s string) (ReloadTrigger, error)

ParseReloadTrigger parses a string into a ReloadTrigger

func (ReloadTrigger) String ΒΆ added in v1.4.3

func (r ReloadTrigger) String() string

String returns the string representation of the reload trigger

type Reloadable ΒΆ added in v1.4.3

type Reloadable interface {
	// Reload applies configuration changes to the module.
	// The changes parameter contains a slice of ConfigChange objects that
	// describe exactly what configuration fields have changed, along with
	// their old and new values.
	//
	// Implementations should:
	//   - Check context cancellation/timeout regularly
	//   - Validate all configuration changes before applying any
	//   - Apply changes atomically (all or nothing)
	//   - Preserve existing configuration on failure
	//   - Return meaningful errors for debugging
	//
	// Only fields tagged with `dynamic:"true"` will be included in the changes.
	// The context may have a timeout set based on ReloadTimeout().
	Reload(ctx context.Context, changes []ConfigChange) error

	// CanReload returns true if this module supports dynamic reloading.
	// This allows for compile-time or runtime determination of reload capability.
	//
	// Modules may return false if:
	//   - They require restart for configuration changes
	//   - They are in a state where reloading is temporarily unsafe
	//   - The current configuration doesn't support dynamic changes
	CanReload() bool

	// ReloadTimeout returns the maximum time the module needs to complete a reload.
	// This is used by the application to set appropriate context timeouts.
	//
	// Typical values:
	//   - Simple config changes: 1-5 seconds
	//   - Database reconnections: 10-30 seconds
	//   - Complex reconfigurations: 30-60 seconds
	//
	// A zero duration indicates the module will use a reasonable default.
	ReloadTimeout() time.Duration
}

Reloadable defines the interface for modules that support dynamic configuration reloading. Modules implementing this interface can have their configuration updated at runtime without requiring a full application restart.

This interface follows the design brief specification for FR-045 Dynamic Reload, using the ConfigChange structure to provide detailed information about what configuration fields have changed, including their previous and new values.

Reload operations must be:

  • Idempotent: calling Reload multiple times with the same changes should be safe
  • Fast: operations should typically complete in <50ms to avoid blocking
  • Atomic: either fully apply all changes or leave existing config unchanged on failure

type ReloadableLegacy deprecated added in v1.4.3

type ReloadableLegacy interface {
	// Reload applies configuration changes to the module using the legacy interface.
	Reload(ctx context.Context, newConfig interface{}) error

	// CanReload returns true if this module supports dynamic reloading.
	CanReload() bool

	// ReloadTimeout returns the maximum time the module needs to complete a reload.
	ReloadTimeout() time.Duration
}

ReloadableLegacy defines the legacy interface for backward compatibility. New modules should implement Reloadable instead.

Deprecated: Use Reloadable interface instead. This interface is maintained for backward compatibility but will be removed in a future version.

type ScopedServiceRegistry ΒΆ added in v1.4.3

type ScopedServiceRegistry struct {
	*EnhancedServiceRegistry
	// contains filtered or unexported fields
}

ScopedServiceRegistry provides scoped service registry functionality. This extends the basic ServiceRegistry with scope-based instance management.

func NewServiceRegistry ΒΆ added in v1.4.3

func NewServiceRegistry() *ScopedServiceRegistry

NewServiceRegistry creates a new service registry with scope support. This is the constructor expected by the service registry tests.

func (*ScopedServiceRegistry) ApplyOption ΒΆ added in v1.4.3

func (r *ScopedServiceRegistry) ApplyOption(option ServiceRegistryOption) error

ApplyOption applies a service registry option to configure service scoping behavior.

func (*ScopedServiceRegistry) Get ΒΆ added in v1.4.3

func (r *ScopedServiceRegistry) Get(name string) (any, error)

Get retrieves a service instance respecting the configured scope.

func (*ScopedServiceRegistry) GetServiceScope ΒΆ added in v1.4.3

func (r *ScopedServiceRegistry) GetServiceScope(serviceName string) ServiceScope

GetServiceScope returns the configured scope for a service.

func (*ScopedServiceRegistry) GetWithContext ΒΆ added in v1.4.3

func (r *ScopedServiceRegistry) GetWithContext(ctx context.Context, name string) (any, error)

GetWithContext retrieves a service instance with context for scoped services.

func (*ScopedServiceRegistry) Register ΒΆ added in v1.4.3

func (r *ScopedServiceRegistry) Register(name string, factory any) error

Register registers a service factory with the scoped registry.

type SecretHandle ΒΆ added in v1.4.3

type SecretHandle interface {
	// ID returns a unique identifier for this handle
	ID() string

	// Provider returns the name of the provider that created this handle
	Provider() string

	// IsValid returns true if this handle is still valid
	IsValid() bool
}

SecretHandle is an opaque reference to a stored secret. The actual implementation varies by provider.

type SecretMetadata ΒΆ added in v1.4.3

type SecretMetadata struct {
	Type          SecretType `json:"type"`
	Created       time.Time  `json:"created"`
	IsEmpty       bool       `json:"is_empty"`
	Provider      string     `json:"provider"`
	SecureStorage bool       `json:"secure_storage"`
}

SecretMetadata contains metadata about a secret

type SecretProvider ΒΆ added in v1.4.3

type SecretProvider interface {
	// Name returns the provider's identifier
	Name() string

	// IsSecure indicates if this provider offers cryptographically secure memory handling
	IsSecure() bool

	// Store securely stores a secret value and returns a handle for retrieval
	Store(value string, secretType SecretType) (SecretHandle, error)

	// Retrieve retrieves the secret value using the provided handle
	Retrieve(handle SecretHandle) (string, error)

	// Destroy securely destroys the secret associated with the handle
	Destroy(handle SecretHandle) error

	// Compare performs a secure comparison of the secret with a provided value
	// This should use constant-time comparison to prevent timing attacks
	Compare(handle SecretHandle, value string) (bool, error)

	// IsEmpty checks if the secret handle represents an empty/null secret
	IsEmpty(handle SecretHandle) bool

	// Clone creates a new handle with the same secret value
	Clone(handle SecretHandle) (SecretHandle, error)

	// GetMetadata returns metadata about the secret (type, creation time, etc.)
	GetMetadata(handle SecretHandle) (SecretMetadata, error)

	// Cleanup performs any necessary cleanup operations (called on shutdown)
	Cleanup() error
}

SecretProvider defines the interface for secure secret storage implementations. Different providers can offer varying levels of security, from basic obfuscation to hardware-backed secure memory handling.

func GetGlobalSecretProvider ΒΆ added in v1.4.3

func GetGlobalSecretProvider() SecretProvider

GetGlobalSecretProvider returns the current global secret provider

func NewInsecureSecretProvider ΒΆ added in v1.4.3

func NewInsecureSecretProvider(config SecretProviderConfig) (SecretProvider, error)

NewInsecureSecretProvider creates a new insecure secret provider

func NewMemguardSecretProvider ΒΆ added in v1.4.3

func NewMemguardSecretProvider(config SecretProviderConfig) (SecretProvider, error)

NewMemguardSecretProvider creates a new memguard-based secret provider

type SecretProviderConfig ΒΆ added in v1.4.3

type SecretProviderConfig struct {
	// Provider specifies which secret provider to use
	// Available options: "insecure", "memguard"
	Provider string `yaml:"provider" env:"SECRET_PROVIDER" default:"insecure" desc:"Secret storage provider (insecure, memguard)"`

	// EnableSecureMemory forces the use of secure memory providers only
	// If true and the configured provider is not secure, initialization will fail
	EnableSecureMemory bool `yaml:"enable_secure_memory" env:"ENABLE_SECURE_MEMORY" default:"false" desc:"Require secure memory handling"`

	// WarnOnInsecure logs warnings when using insecure providers
	WarnOnInsecure bool `yaml:"warn_on_insecure" env:"WARN_ON_INSECURE" default:"true" desc:"Warn when using insecure secret providers"`

	// MaxSecrets limits the number of secrets that can be stored (0 = unlimited)
	MaxSecrets int `yaml:"max_secrets" env:"MAX_SECRETS" default:"1000" desc:"Maximum number of secrets to store (0 = unlimited)"`

	// AutoDestroy automatically destroys secrets after the specified duration (0 = never)
	AutoDestroy time.Duration `yaml:"auto_destroy" env:"AUTO_DESTROY" default:"0s" desc:"Automatically destroy secrets after duration (0 = never)"`
}

SecretProviderConfig configures secret provider behavior

type SecretProviderFactory ΒΆ added in v1.4.3

type SecretProviderFactory struct {
	// contains filtered or unexported fields
}

SecretProviderFactory creates secret providers based on configuration

func NewSecretProviderFactory ΒΆ added in v1.4.3

func NewSecretProviderFactory(logger Logger) *SecretProviderFactory

NewSecretProviderFactory creates a new secret provider factory

func (*SecretProviderFactory) CreateProvider ΒΆ added in v1.4.3

func (f *SecretProviderFactory) CreateProvider(config SecretProviderConfig) (SecretProvider, error)

CreateProvider creates a secret provider based on configuration

func (*SecretProviderFactory) GetProviderInfo ΒΆ added in v1.4.3

func (f *SecretProviderFactory) GetProviderInfo(name string) (map[string]interface{}, error)

GetProviderInfo returns information about a provider's security level

func (*SecretProviderFactory) ListProviders ΒΆ added in v1.4.3

func (f *SecretProviderFactory) ListProviders() []string

ListProviders returns the names of all registered providers

func (*SecretProviderFactory) RegisterProvider ΒΆ added in v1.4.3

func (f *SecretProviderFactory) RegisterProvider(name string, creator func(config SecretProviderConfig) (SecretProvider, error))

RegisterProvider registers a custom secret provider

type SecretRedactor ΒΆ added in v1.4.3

type SecretRedactor struct {
	// contains filtered or unexported fields
}

SecretRedactor provides utility functions for secret redaction in logs and output

func NewSecretRedactor ΒΆ added in v1.4.3

func NewSecretRedactor() *SecretRedactor

NewSecretRedactor creates a new secret redactor

func (*SecretRedactor) AddPattern ΒΆ added in v1.4.3

func (r *SecretRedactor) AddPattern(pattern string)

AddPattern adds a pattern to be redacted

func (*SecretRedactor) AddSecret ΒΆ added in v1.4.3

func (r *SecretRedactor) AddSecret(secret *SecretValue)

AddSecret adds a secret to be redacted

func (*SecretRedactor) Redact ΒΆ added in v1.4.3

func (r *SecretRedactor) Redact(text string) string

Redact redacts secrets and patterns from the input text

func (*SecretRedactor) RedactStructuredLog ΒΆ added in v1.4.3

func (r *SecretRedactor) RedactStructuredLog(fields map[string]interface{}) map[string]interface{}

RedactStructuredLog redacts secrets from structured log fields

type SecretType ΒΆ added in v1.4.3

type SecretType int

SecretType represents different classifications of secrets

const (
	// SecretTypeGeneric represents a generic secret
	SecretTypeGeneric SecretType = iota

	// SecretTypePassword represents a password secret
	SecretTypePassword

	// SecretTypeToken represents a token or API key secret
	SecretTypeToken

	// SecretTypeKey represents a cryptographic key secret
	SecretTypeKey

	// SecretTypeCertificate represents a certificate secret
	SecretTypeCertificate
)

func (SecretType) String ΒΆ added in v1.4.3

func (s SecretType) String() string

String returns the string representation of the secret type

type SecretValue ΒΆ added in v1.4.3

type SecretValue struct {
	// contains filtered or unexported fields
}

SecretValue is a wrapper for sensitive configuration values that helps prevent accidental exposure in logs, JSON output, and debugging. It provides basic protection against accidental disclosure but has important security limitations.

Security features:

  • Automatic redaction in String(), fmt output, and JSON marshaling
  • Controlled access via Reveal() method
  • Classification system for different secret types
  • Basic encryption of stored values (XOR-based, not cryptographically secure)
  • Constant-time comparison methods to prevent timing attacks
  • Integration with structured logging to prevent accidental exposure

IMPORTANT SECURITY LIMITATIONS:

  • Cannot zero string memory due to Go's immutable strings
  • Garbage collector may leave copies of secrets in memory
  • XOR encryption provides obfuscation, not cryptographic security
  • Memory dumps may contain plaintext secrets
  • Not suitable for highly sensitive secrets (e.g., private keys, passwords for critical systems)

For maximum security, consider dedicated libraries like:

  • github.com/awnumar/memguard (secure memory handling)
  • Operating system secure storage (Keychain, Credential Manager, etc.)
  • Hardware Security Modules (HSMs) for critical secrets

Use this type for:

  • Preventing accidental logging of API keys, tokens
  • Basic protection against casual inspection
  • Configuration values where convenience outweighs maximum security

func NewCertificateSecret ΒΆ added in v1.4.3

func NewCertificateSecret(value string) *SecretValue

NewCertificateSecret creates a new certificate SecretValue

func NewGenericSecret ΒΆ added in v1.4.3

func NewGenericSecret(value string) *SecretValue

NewGenericSecret creates a new generic SecretValue

func NewKeySecret ΒΆ added in v1.4.3

func NewKeySecret(value string) *SecretValue

NewKeySecret creates a new key SecretValue

func NewPasswordSecret ΒΆ added in v1.4.3

func NewPasswordSecret(value string) *SecretValue

NewPasswordSecret creates a new password SecretValue

func NewSecretValue ΒΆ added in v1.4.3

func NewSecretValue(value string, secretType SecretType) *SecretValue

NewSecretValue creates a new SecretValue with the given value and type This function now uses the global secret provider by default

func NewSecretValueWithProvider ΒΆ added in v1.4.3

func NewSecretValueWithProvider(value string, secretType SecretType, provider SecretProvider) *SecretValue

NewSecretValueWithProvider creates a new SecretValue using a specific provider

func NewTokenSecret ΒΆ added in v1.4.3

func NewTokenSecret(value string) *SecretValue

NewTokenSecret creates a new token SecretValue

func (*SecretValue) Clone ΒΆ added in v1.4.3

func (s *SecretValue) Clone() *SecretValue

Clone creates a copy of the SecretValue

func (*SecretValue) Created ΒΆ added in v1.4.3

func (s *SecretValue) Created() time.Time

Created returns when the secret was created

func (*SecretValue) Destroy ΒΆ added in v1.4.3

func (s *SecretValue) Destroy()

Destroy explicitly zeros out the secret's memory

func (*SecretValue) Equals ΒΆ added in v1.4.3

func (s *SecretValue) Equals(other *SecretValue) bool

Equals performs a constant-time comparison with another SecretValue This prevents timing attacks that could leak information about the secret

func (*SecretValue) EqualsString ΒΆ added in v1.4.3

func (s *SecretValue) EqualsString(value string) bool

EqualsString performs a constant-time comparison with a string value

func (*SecretValue) GetMaskStrategy ΒΆ added in v1.4.3

func (s *SecretValue) GetMaskStrategy() string

GetMaskStrategy returns the preferred masking strategy for this secret

func (*SecretValue) GetMaskedValue ΒΆ added in v1.4.3

func (s *SecretValue) GetMaskedValue() any

GetMaskedValue returns a masked representation of this secret

func (*SecretValue) GoString ΒΆ added in v1.4.3

func (s *SecretValue) GoString() string

GoString returns a redacted representation for fmt %#v

func (*SecretValue) IsEmpty ΒΆ added in v1.4.3

func (s *SecretValue) IsEmpty() bool

IsEmpty returns true if the secret value is empty

func (*SecretValue) MarshalJSON ΒΆ added in v1.4.3

func (s *SecretValue) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler to always redact secrets in JSON

func (*SecretValue) MarshalText ΒΆ added in v1.4.3

func (s *SecretValue) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler to redact in text formats

func (*SecretValue) Reveal ΒΆ added in v1.4.3

func (s *SecretValue) Reveal() string

Reveal returns the actual secret value for controlled access This should only be used in internal paths where the secret is needed

func (*SecretValue) ShouldMask ΒΆ added in v1.4.3

func (s *SecretValue) ShouldMask() bool

ShouldMask returns true indicating this value should be masked in logs

func (*SecretValue) String ΒΆ added in v1.4.3

func (s *SecretValue) String() string

String returns a redacted representation of the secret

func (*SecretValue) Type ΒΆ added in v1.4.3

func (s *SecretValue) Type() SecretType

Type returns the secret type classification

func (*SecretValue) UnmarshalJSON ΒΆ added in v1.4.3

func (s *SecretValue) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler to handle JSON input Note: This creates a generic secret from the input

func (*SecretValue) UnmarshalText ΒΆ added in v1.4.3

func (s *SecretValue) UnmarshalText(text []byte) error

UnmarshalText implements encoding.TextUnmarshaler

type ServiceAware ΒΆ added in v1.2.0

type ServiceAware interface {
	// ProvidesServices returns a list of services provided by this module.
	// These services will be registered in the application's service registry
	// after the module is initialized, making them available to other modules.
	//
	// Each ServiceProvider should specify:
	//   - Name: unique identifier for the service
	//   - Instance: the actual service implementation
	//
	// Example:
	//   func (m *DatabaseModule) ProvidesServices() []ServiceProvider {
	//       return []ServiceProvider{
	//           {Name: "database", Instance: m.db},
	//           {Name: "migrator", Instance: m.migrator},
	//       }
	//   }
	ProvidesServices() []ServiceProvider

	// RequiresServices returns a list of services required by this module.
	// These services must be provided by other modules or the application
	// for this module to function correctly.
	//
	// Services can be matched by name or by interface. When using interface
	// matching, the framework will find any service that implements the
	// specified interface.
	//
	// Example:
	//   func (m *WebModule) RequiresServices() []ServiceDependency {
	//       return []ServiceDependency{
	//           {Name: "database", Required: true},
	//           {Name: "logger", SatisfiesInterface: reflect.TypeOf((*Logger)(nil)).Elem(), MatchByInterface: true},
	//       }
	//   }
	RequiresServices() []ServiceDependency
}

ServiceAware is an interface for modules that can provide or consume services. Services enable loose coupling between modules by providing a registry for sharing functionality without direct dependencies.

Modules can both provide services for other modules to use and require services that other modules provide. The framework handles service injection automatically based on these declarations.

type ServiceDependency ΒΆ

type ServiceDependency struct {
	// Name is the service identifier to lookup.
	// For interface-based matching, this is used as the key in the
	// injected services map but may not correspond to a registered service name.
	Name string

	// Required indicates whether the application should fail to start
	// if this service is not available. Optional services (Required: false)
	// will be silently ignored if not found.
	Required bool

	// Type specifies the concrete type expected for this service.
	// Used for additional type checking during dependency resolution.
	// Optional - if nil, no concrete type checking is performed.
	Type reflect.Type

	// SatisfiesInterface specifies an interface that the service must implement.
	// Used with MatchByInterface to find services by interface rather than name.
	// Obtain with: reflect.TypeOf((*InterfaceName)(nil)).Elem()
	SatisfiesInterface reflect.Type

	// MatchByInterface enables interface-based service lookup.
	// When true, the framework will search for any service that implements
	// SatisfiesInterface rather than looking up by exact name.
	// Useful for loose coupling where modules depend on interfaces rather than specific implementations.
	MatchByInterface bool
}

ServiceDependency defines a requirement for a service from another module. Dependencies can be matched either by exact name or by interface type. The framework handles dependency resolution and injection automatically.

There are two main patterns for service dependencies:

  1. Name-based lookup: ServiceDependency{Name: "database", Required: true}

  2. Interface-based lookup: ServiceDependency{ Name: "logger", MatchByInterface: true, SatisfiesInterface: reflect.TypeOf((*Logger)(nil)).Elem(), Required: true, }

type ServiceIntrospector ΒΆ added in v1.4.3

type ServiceIntrospector interface {
	GetServicesByModule(moduleName string) []string
	GetServiceEntry(serviceName string) (*ServiceRegistryEntry, bool)
	GetServicesByInterface(interfaceType reflect.Type) []*ServiceRegistryEntry
}

ServiceIntrospector provides advanced service registry introspection helpers. This extension interface allows future additions without expanding Application.

type ServiceIntrospectorImpl ΒΆ added in v1.4.3

type ServiceIntrospectorImpl struct {
	// contains filtered or unexported fields
}

ServiceIntrospectorImpl implements ServiceIntrospector backed by StdApplication's enhanced registry.

func (*ServiceIntrospectorImpl) GetServiceEntry ΒΆ added in v1.4.3

func (s *ServiceIntrospectorImpl) GetServiceEntry(serviceName string) (*ServiceRegistryEntry, bool)

func (*ServiceIntrospectorImpl) GetServicesByInterface ΒΆ added in v1.4.3

func (s *ServiceIntrospectorImpl) GetServicesByInterface(interfaceType reflect.Type) []*ServiceRegistryEntry

func (*ServiceIntrospectorImpl) GetServicesByModule ΒΆ added in v1.4.3

func (s *ServiceIntrospectorImpl) GetServicesByModule(moduleName string) []string

type ServiceProvider ΒΆ added in v1.0.0

type ServiceProvider struct {
	// Name is the unique identifier for this service.
	// Other modules reference this service by this exact name.
	// Should be descriptive and follow naming conventions like "database", "logger", "cache".
	Name string

	// Description provides human-readable documentation for this service.
	// Used for debugging and documentation purposes.
	// Example: "PostgreSQL database connection pool"
	Description string

	// Instance is the actual service implementation.
	// Can be any type - struct, interface implementation, function, etc.
	// Consuming modules are responsible for type assertion.
	Instance any
}

ServiceProvider defines a service offered by a module. Services are registered in the application's service registry and can be consumed by other modules that declare them as dependencies.

A service provider encapsulates:

  • Name: unique identifier for service lookup
  • Description: human-readable description for documentation
  • Instance: the actual service implementation (interface{})

type ServiceRegistry ΒΆ

type ServiceRegistry map[string]any

ServiceRegistry allows registration and retrieval of services by name. Services are stored as interface{} values and must be type-asserted when retrieved. The registry supports both concrete types and interfaces.

Services enable loose coupling between modules by providing a shared registry where modules can publish functionality for others to consume.

type ServiceRegistryEntry ΒΆ added in v1.4.3

type ServiceRegistryEntry struct {
	// Service is the actual service instance
	Service any

	// ModuleName is the name of the module that provided this service
	ModuleName string

	// ModuleType is the reflect.Type of the module that provided this service
	ModuleType reflect.Type

	// OriginalName is the original name requested when registering the service
	OriginalName string

	// ActualName is the final name used in the registry (may be modified for uniqueness)
	ActualName string
}

ServiceRegistryEntry represents an enhanced service registry entry that tracks both the service instance and its providing module.

type ServiceRegistryOption ΒΆ added in v1.4.3

type ServiceRegistryOption func(*ScopedServiceRegistry) error

ServiceRegistryOption represents an option that can be applied to a service registry.

func WithServiceScope ΒΆ added in v1.4.3

func WithServiceScope(serviceName string, scope ServiceScope) ServiceRegistryOption

WithServiceScope creates a service registry option to configure service scope.

func WithServiceScopeConfig ΒΆ added in v1.4.3

func WithServiceScopeConfig(serviceName string, config ServiceScopeConfig) ServiceRegistryOption

WithServiceScopeConfig creates a service registry option with detailed scope configuration.

type ServiceScope ΒΆ added in v1.4.3

type ServiceScope string

ServiceScope defines the lifecycle and instantiation behavior of services within the dependency injection container.

The scope determines:

  • How many instances of a service can exist
  • When instances are created and destroyed
  • How long instances are cached
  • Whether instances are shared across requests
const (
	// ServiceScopeSingleton creates a single instance that is shared across
	// the entire application lifetime. The instance is created on first access
	// and reused for all subsequent requests. This is the most memory-efficient
	// scope for stateless services.
	ServiceScopeSingleton ServiceScope = "singleton"

	// ServiceScopeTransient creates a new instance every time the service
	// is requested. No caching is performed, and each instance is independent.
	// This is useful for stateful services or when you need fresh instances.
	ServiceScopeTransient ServiceScope = "transient"

	// ServiceScopeScoped creates one instance per logical scope (e.g., per HTTP request,
	// per tenant, per transaction). The instance is cached within the scope
	// and reused for all requests within that scope. This balances memory efficiency
	// with instance isolation.
	ServiceScopeScoped ServiceScope = "scoped"

	// ServiceScopeFactory provides a factory function that creates instances
	// on demand. The factory itself is typically a singleton, but it can create
	// instances with any desired behavior. This provides maximum flexibility
	// for complex instantiation scenarios.
	ServiceScopeFactory ServiceScope = "factory"
)

func GetDefaultServiceScope ΒΆ added in v1.4.3

func GetDefaultServiceScope() ServiceScope

GetDefaultServiceScope returns the default service scope used when no explicit scope is specified.

func OrderScopesByLifetime ΒΆ added in v1.4.3

func OrderScopesByLifetime(scopes []ServiceScope) []ServiceScope

OrderScopesByLifetime orders service scopes by their lifetime, from longest to shortest. This is useful for dependency resolution and initialization ordering.

func ParseServiceScope ΒΆ added in v1.4.3

func ParseServiceScope(s string) (ServiceScope, error)

ParseServiceScope parses a string into a ServiceScope, returning an error if the string is not a valid service scope.

func (ServiceScope) AllowsMultipleInstances ΒΆ added in v1.4.3

func (s ServiceScope) AllowsMultipleInstances() bool

AllowsMultipleInstances returns true if this scope allows multiple instances to exist simultaneously.

func (ServiceScope) Description ΒΆ added in v1.4.3

func (s ServiceScope) Description() string

Description returns a brief description of the service scope behavior.

func (ServiceScope) DetailedDescription ΒΆ added in v1.4.3

func (s ServiceScope) DetailedDescription() string

DetailedDescription returns a detailed explanation of the service scope.

func (ServiceScope) Equals ΒΆ added in v1.4.3

func (s ServiceScope) Equals(other ServiceScope) bool

Equals checks if two service scopes are the same.

func (ServiceScope) IsCacheable ΒΆ added in v1.4.3

func (s ServiceScope) IsCacheable() bool

IsCacheable returns true if instances of this scope should be cached and reused rather than recreated each time.

func (ServiceScope) IsCompatibleWith ΒΆ added in v1.4.3

func (s ServiceScope) IsCompatibleWith(other ServiceScope) bool

IsCompatibleWith checks if this scope is compatible with another scope for dependency injection purposes.

func (ServiceScope) IsValid ΒΆ added in v1.4.3

func (s ServiceScope) IsValid() bool

IsValid returns true if the service scope is one of the defined constants.

func (ServiceScope) String ΒΆ added in v1.4.3

func (s ServiceScope) String() string

String returns the string representation of the service scope.

type ServiceScopeConfig ΒΆ added in v1.4.3

type ServiceScopeConfig struct {
	// Scope defines the service scope type
	Scope ServiceScope

	// ScopeKey is the key used to identify the scope boundary (for scoped services)
	ScopeKey string

	// MaxInstances limits the number of instances that can be created
	MaxInstances int

	// InstanceTimeout specifies how long instances should be cached
	InstanceTimeout string

	// EnableCaching determines if caching is enabled for cacheable scopes
	EnableCaching bool

	// EnableMetrics determines if scope-related metrics should be collected
	EnableMetrics bool
}

ServiceScopeConfig provides configuration options for service scope behavior.

func GetDefaultScopeConfig ΒΆ added in v1.4.3

func GetDefaultScopeConfig(scope ServiceScope) ServiceScopeConfig

GetDefaultScopeConfig returns the default configuration for a specific service scope.

func (ServiceScopeConfig) IsValid ΒΆ added in v1.4.3

func (c ServiceScopeConfig) IsValid() bool

IsValid returns true if the service scope configuration is valid.

type StandardTenantService ΒΆ added in v1.1.0

type StandardTenantService struct {
	// contains filtered or unexported fields
}

StandardTenantService provides a basic implementation of the TenantService interface

func NewStandardTenantService ΒΆ added in v1.1.0

func NewStandardTenantService(logger Logger) *StandardTenantService

NewStandardTenantService creates a new tenant service

func (*StandardTenantService) GetTenantConfig ΒΆ added in v1.1.0

func (ts *StandardTenantService) GetTenantConfig(tenantID TenantID, section string) (ConfigProvider, error)

GetTenantConfig retrieves tenant-specific configuration

func (*StandardTenantService) GetTenants ΒΆ added in v1.1.0

func (ts *StandardTenantService) GetTenants() []TenantID

GetTenants returns all registered tenant IDs

func (*StandardTenantService) RegisterTenant ΒΆ added in v1.1.0

func (ts *StandardTenantService) RegisterTenant(tenantID TenantID, configs map[string]ConfigProvider) error

RegisterTenant registers a new tenant with optional initial configs

func (*StandardTenantService) RegisterTenantAwareModule ΒΆ added in v1.1.0

func (ts *StandardTenantService) RegisterTenantAwareModule(module TenantAwareModule) error

RegisterTenantAwareModule registers a module to receive tenant events

func (*StandardTenantService) RegisterTenantConfigSection ΒΆ added in v1.1.0

func (ts *StandardTenantService) RegisterTenantConfigSection(
	tenantID TenantID,
	section string,
	provider ConfigProvider,
) error

RegisterTenantConfigSection registers a configuration section for a specific tenant

func (*StandardTenantService) RemoveTenant ΒΆ added in v1.1.0

func (ts *StandardTenantService) RemoveTenant(tenantID TenantID) error

RemoveTenant removes a tenant and its configurations

type Startable ΒΆ added in v1.2.0

type Startable interface {
	// Start begins the module's runtime operations.
	// This method is called after Init() and after all modules have been initialized.
	// Start is called in dependency order - dependencies start before dependents.
	//
	// The provided context is the application's lifecycle context. When this
	// context is cancelled, the module should stop its operations gracefully.
	//
	// Start should be non-blocking for short-running initialization, but may
	// spawn goroutines for long-running operations. Use the provided context
	// to handle graceful shutdown.
	//
	// Example:
	//   func (m *HTTPServerModule) Start(ctx context.Context) error {
	//       go func() {
	//           <-ctx.Done()
	//           m.server.Shutdown(context.Background())
	//       }()
	//       return m.server.ListenAndServe()
	//   }
	Start(ctx context.Context) error
}

Startable is an interface for modules that need to perform startup operations. Modules implementing this interface will have their Start method called after all modules have been initialized successfully.

Start operations typically involve:

  • Starting background goroutines
  • Opening network listeners
  • Connecting to external services
  • Beginning periodic tasks

type StdApplication ΒΆ added in v1.1.0

type StdApplication struct {
	// contains filtered or unexported fields
}

StdApplication represents the core StdApplication container

func (*StdApplication) ConfigProvider ΒΆ added in v1.1.0

func (app *StdApplication) ConfigProvider() ConfigProvider

ConfigProvider retrieves the application config provider

func (*StdApplication) ConfigSections ΒΆ added in v1.1.0

func (app *StdApplication) ConfigSections() map[string]ConfigProvider

ConfigSections retrieves all registered configuration sections

func (*StdApplication) GetConfigSection ΒΆ added in v1.1.0

func (app *StdApplication) GetConfigSection(section string) (ConfigProvider, error)

GetConfigSection retrieves a configuration section

func (*StdApplication) GetModules ΒΆ added in v1.4.3

func (app *StdApplication) GetModules() map[string]Module

GetModules returns a copy of the module registry for inspection. This is primarily used for testing and debugging purposes.

func (*StdApplication) GetService ΒΆ added in v1.1.0

func (app *StdApplication) GetService(name string, target any) error

GetService retrieves a service with type assertion

func (*StdApplication) GetTenantConfig ΒΆ added in v1.1.0

func (app *StdApplication) GetTenantConfig(tenantID TenantID, section string) (ConfigProvider, error)

GetTenantConfig retrieves configuration for a specific tenant and section

func (*StdApplication) GetTenantGuard ΒΆ added in v1.4.3

func (app *StdApplication) GetTenantGuard() TenantGuard

GetTenantGuard returns the application's tenant guard if configured. Returns nil if no tenant guard service has been registered.

func (*StdApplication) GetTenantService ΒΆ added in v1.1.0

func (app *StdApplication) GetTenantService() (TenantService, error)

GetTenantService returns the application's tenant service if available

func (*StdApplication) Health ΒΆ added in v1.4.3

func (app *StdApplication) Health() (HealthAggregator, error)

Health returns the health aggregator service if available

func (*StdApplication) Init ΒΆ added in v1.1.0

func (app *StdApplication) Init() error

Init initializes the application with the provided modules

func (*StdApplication) InitWithApp ΒΆ added in v1.4.3

func (app *StdApplication) InitWithApp(appToPass Application) error

InitWithApp initializes the application with the provided modules, using appToPass as the application instance passed to modules

func (*StdApplication) IsVerboseConfig ΒΆ added in v1.3.3

func (app *StdApplication) IsVerboseConfig() bool

IsVerboseConfig returns whether verbose configuration debugging is enabled

func (*StdApplication) Logger ΒΆ added in v1.1.0

func (app *StdApplication) Logger() Logger

Logger represents a logger

func (*StdApplication) RegisterConfigSection ΒΆ added in v1.1.0

func (app *StdApplication) RegisterConfigSection(section string, cp ConfigProvider)

RegisterConfigSection registers a configuration section with the application

func (*StdApplication) RegisterHealthProvider ΒΆ added in v1.4.3

func (app *StdApplication) RegisterHealthProvider(moduleName string, provider HealthProvider, optional bool) error

RegisterHealthProvider registers a health provider for a module

func (*StdApplication) RegisterModule ΒΆ added in v1.1.0

func (app *StdApplication) RegisterModule(module Module)

RegisterModule adds a module to the application

func (*StdApplication) RegisterService ΒΆ added in v1.1.0

func (app *StdApplication) RegisterService(name string, service any) error

RegisterService adds a service with type checking

func (*StdApplication) RequestReload ΒΆ added in v1.4.3

func (app *StdApplication) RequestReload(sections ...string) error

RequestReload triggers a dynamic configuration reload for specified sections

func (*StdApplication) Run ΒΆ added in v1.1.0

func (app *StdApplication) Run() error

Run starts the application and blocks until termination

func (*StdApplication) ServiceIntrospector ΒΆ added in v1.4.3

func (app *StdApplication) ServiceIntrospector() ServiceIntrospector

ServiceIntrospector returns an implementation of ServiceIntrospector.

func (*StdApplication) SetConfigFeeders ΒΆ added in v1.4.3

func (app *StdApplication) SetConfigFeeders(feeders []Feeder)

SetConfigFeeders sets per-application configuration feeders overriding the package-level ConfigFeeders for this app's Init lifecycle. Passing nil resets to use the global ConfigFeeders again.

func (*StdApplication) SetLogger ΒΆ added in v1.3.0

func (app *StdApplication) SetLogger(logger Logger)

SetLogger sets the application's logger

func (*StdApplication) SetVerboseConfig ΒΆ added in v1.3.3

func (app *StdApplication) SetVerboseConfig(enabled bool)

SetVerboseConfig enables or disables verbose configuration debugging

func (*StdApplication) Start ΒΆ added in v1.1.0

func (app *StdApplication) Start() error

Start starts the application

func (*StdApplication) Stop ΒΆ added in v1.1.0

func (app *StdApplication) Stop() error

Stop stops the application

func (*StdApplication) SvcRegistry ΒΆ added in v1.1.0

func (app *StdApplication) SvcRegistry() ServiceRegistry

SvcRegistry retrieves the service svcRegistry

func (*StdApplication) WithTenant ΒΆ added in v1.1.0

func (app *StdApplication) WithTenant(tenantID TenantID) (*TenantContext, error)

WithTenant creates a tenant context from the application context

type StdConfigProvider ΒΆ

type StdConfigProvider struct {
	// contains filtered or unexported fields
}

StdConfigProvider provides a standard implementation of ConfigProvider. It wraps a configuration struct and makes it available through the ConfigProvider interface.

This is the most common way to create configuration providers for modules. Simply create your configuration struct and wrap it with NewStdConfigProvider.

func NewStdConfigProvider ΒΆ

func NewStdConfigProvider(cfg any) *StdConfigProvider

NewStdConfigProvider creates a new standard configuration provider. The cfg parameter should be a pointer to a struct that defines the configuration schema for your module.

Example:

type MyConfig struct {
    Host string `json:"host" default:"localhost"`
    Port int    `json:"port" default:"8080"`
}

cfg := &MyConfig{}
provider := modular.NewStdConfigProvider(cfg)

func (*StdConfigProvider) GetConfig ΒΆ

func (s *StdConfigProvider) GetConfig() any

GetConfig returns the configuration object. The returned value is the exact object that was passed to NewStdConfigProvider.

type StdDynamicFieldParser ΒΆ added in v1.4.3

type StdDynamicFieldParser struct{}

StdDynamicFieldParser implements DynamicFieldParser using reflection

func (*StdDynamicFieldParser) GetDynamicFields ΒΆ added in v1.4.3

func (p *StdDynamicFieldParser) GetDynamicFields(config interface{}) ([]string, error)

GetDynamicFields parses a config struct and returns dynamic field names

func (*StdDynamicFieldParser) ValidateDynamicReload ΒΆ added in v1.4.3

func (p *StdDynamicFieldParser) ValidateDynamicReload(oldConfig, newConfig interface{}) (*ConfigDiff, error)

ValidateDynamicReload compares configs and creates a diff with only dynamic changes

type Stoppable ΒΆ added in v1.2.0

type Stoppable interface {
	// Stop performs graceful shutdown of the module.
	// This method is called during application shutdown, in reverse dependency
	// order (dependents stop before their dependencies).
	//
	// The provided context includes a timeout for the shutdown process.
	// Modules should respect this timeout and return promptly when it expires.
	//
	// Stop should:
	//   - Stop accepting new work
	//   - Complete or cancel existing work
	//   - Close resources and connections
	//   - Return any critical errors that occurred during shutdown
	//
	// Example:
	//   func (m *DatabaseModule) Stop(ctx context.Context) error {
	//       return m.db.Close()
	//   }
	Stop(ctx context.Context) error
}

Stoppable is an interface for modules that need to perform cleanup operations. Modules implementing this interface will have their Stop method called during application shutdown, in reverse dependency order.

Stop operations typically involve:

  • Gracefully shutting down background goroutines
  • Closing network connections
  • Flushing buffers and saving state
  • Releasing external resources

type StructStateDiffer ΒΆ added in v1.3.4

type StructStateDiffer struct {
	// contains filtered or unexported fields
}

StructStateDiffer captures before/after states to determine field changes

func NewStructStateDiffer ΒΆ added in v1.3.4

func NewStructStateDiffer(tracker FieldTracker, logger Logger) *StructStateDiffer

NewStructStateDiffer creates a new struct state differ

func (*StructStateDiffer) CaptureAfterStateAndDiff ΒΆ added in v1.3.4

func (d *StructStateDiffer) CaptureAfterStateAndDiff(structure interface{}, prefix string, feederType, sourceType string)

CaptureAfterStateAndDiff captures the state after feeder processing and computes diffs

func (*StructStateDiffer) CaptureBeforeState ΒΆ added in v1.3.4

func (d *StructStateDiffer) CaptureBeforeState(structure interface{}, prefix string)

CaptureBeforeState captures the state before feeder processing

func (*StructStateDiffer) Reset ΒΆ added in v1.3.4

func (d *StructStateDiffer) Reset()

Reset clears the captured states for reuse

type Subject ΒΆ added in v1.4.3

type Subject interface {
	// RegisterObserver adds an observer to receive notifications.
	// Observers can optionally filter events by type using the eventTypes parameter.
	// If eventTypes is empty, the observer receives all events.
	RegisterObserver(observer Observer, eventTypes ...string) error

	// UnregisterObserver removes an observer from receiving notifications.
	// This method should be idempotent and not error if the observer
	// wasn't registered.
	UnregisterObserver(observer Observer) error

	// NotifyObservers sends an event to all registered observers.
	// The notification process should be non-blocking for the caller
	// and handle observer errors gracefully.
	NotifyObservers(ctx context.Context, event cloudevents.Event) error

	// GetObservers returns information about currently registered observers.
	// This is useful for debugging and monitoring.
	GetObservers() []ObserverInfo
}

Subject defines the interface for objects that can be observed. Subjects maintain a list of observers and notify them when events occur. This is the core interface that event emitters implement. Events use the CloudEvents specification for standardization.

type Tenant ΒΆ added in v1.4.3

type Tenant struct {
	ID   TenantID `json:"id"`
	Name string   `json:"name"`
}

Tenant represents a tenant in the system with basic information

type TenantApplication ΒΆ added in v1.1.0

type TenantApplication interface {
	Application

	// GetTenantService returns the application's tenant service if available.
	// The tenant service manages tenant registration, lookup, and lifecycle.
	// Returns an error if no tenant service has been registered.
	//
	// Example:
	//   tenantSvc, err := app.GetTenantService()
	//   if err != nil {
	//       return fmt.Errorf("multi-tenancy not configured: %w", err)
	//   }
	GetTenantService() (TenantService, error)

	// WithTenant creates a tenant context from the application context.
	// Tenant contexts provide scoped access to tenant-specific configurations
	// and services, enabling isolation between different tenants.
	//
	// The returned context can be used for tenant-specific operations
	// and will carry tenant identification through the call chain.
	//
	// Example:
	//   tenantCtx, err := app.WithTenant("customer-456")
	//   if err != nil {
	//       return err
	//   }
	//   // Use tenantCtx for tenant-specific operations
	WithTenant(tenantID TenantID) (*TenantContext, error)

	// GetTenantConfig retrieves configuration for a specific tenant and section.
	// This allows modules to access tenant-specific configuration that may
	// override or extend the default application configuration.
	//
	// The section parameter specifies which configuration section to retrieve
	// (e.g., "database", "cache", etc.), and the framework will return the
	// tenant-specific version if available, falling back to defaults otherwise.
	//
	// Example:
	//   cfg, err := app.GetTenantConfig("tenant-789", "database")
	//   if err != nil {
	//       return err
	//   }
	//   dbConfig := cfg.GetConfig().(*DatabaseConfig)
	GetTenantConfig(tenantID TenantID, section string) (ConfigProvider, error)
}

TenantApplication extends Application with multi-tenant functionality. This interface adds tenant-aware capabilities to the standard Application, allowing the same application instance to serve multiple tenants with isolated configurations and contexts.

Multi-tenant applications can:

  • Maintain separate configurations per tenant
  • Provide tenant-specific service instances
  • Isolate tenant data and operations
  • Support dynamic tenant registration and management

Example usage:

app := modular.NewStdApplication(configProvider, logger)
// Register tenant service and tenant-aware modules
tenantCtx, err := app.WithTenant("tenant-123")
if err != nil {
    return err
}
// Use tenant context for tenant-specific operations

type TenantAwareConfig ΒΆ added in v1.1.0

type TenantAwareConfig struct {
	// contains filtered or unexported fields
}

TenantAwareConfig provides configuration that's aware of tenant context

func NewTenantAwareConfig ΒΆ added in v1.1.0

func NewTenantAwareConfig(
	defaultConfig ConfigProvider,
	tenantService TenantService,
	configSection string,
) *TenantAwareConfig

NewTenantAwareConfig creates a new tenant-aware configuration provider

func (*TenantAwareConfig) GetConfig ΒΆ added in v1.1.0

func (tac *TenantAwareConfig) GetConfig() any

GetConfig retrieves the default configuration when no tenant is specified

func (*TenantAwareConfig) GetConfigWithContext ΒΆ added in v1.1.0

func (tac *TenantAwareConfig) GetConfigWithContext(ctx context.Context) any

GetConfigWithContext retrieves tenant-specific configuration based on context

type TenantAwareDecorator ΒΆ added in v1.4.3

type TenantAwareDecorator struct {
	*BaseApplicationDecorator
	// contains filtered or unexported fields
}

TenantAwareDecorator wraps an application to add tenant resolution capabilities. It injects tenant resolution before Start() and provides tenant-aware functionality.

func NewTenantAwareDecorator ΒΆ added in v1.4.3

func NewTenantAwareDecorator(inner Application, loader TenantLoader) *TenantAwareDecorator

NewTenantAwareDecorator creates a new tenant-aware decorator

func (*TenantAwareDecorator) GetTenantConfig ΒΆ added in v1.4.3

func (d *TenantAwareDecorator) GetTenantConfig(tenantID TenantID, section string) (ConfigProvider, error)

GetTenantConfig implements TenantApplication interface

func (*TenantAwareDecorator) GetTenantGuard ΒΆ added in v1.4.3

func (d *TenantAwareDecorator) GetTenantGuard() TenantGuard

GetTenantGuard forwards to inner application's GetTenantGuard implementation

func (*TenantAwareDecorator) GetTenantService ΒΆ added in v1.4.3

func (d *TenantAwareDecorator) GetTenantService() (TenantService, error)

GetTenantService implements TenantApplication interface

func (*TenantAwareDecorator) Start ΒΆ added in v1.4.3

func (d *TenantAwareDecorator) Start() error

Start overrides the base Start method to inject tenant resolution

func (*TenantAwareDecorator) WithTenant ΒΆ added in v1.4.3

func (d *TenantAwareDecorator) WithTenant(tenantID TenantID) (*TenantContext, error)

WithTenant implements TenantApplication interface

type TenantAwareModule ΒΆ added in v1.1.0

type TenantAwareModule interface {
	Module

	// OnTenantRegistered is called when a new tenant is registered.
	// This method should be used to initialize any tenant-specific resources,
	// such as database connections, caches, or configuration.
	//
	// The method should be non-blocking and handle errors gracefully.
	// If initialization fails, the module should log the error but not
	// prevent the tenant registration from completing.
	OnTenantRegistered(tenantID TenantID)

	// OnTenantRemoved is called when a tenant is removed.
	// This method should be used to clean up any tenant-specific resources
	// to prevent memory leaks or resource exhaustion.
	//
	// The method should be non-blocking and handle cleanup failures gracefully.
	// Even if cleanup fails, the tenant removal should proceed.
	OnTenantRemoved(tenantID TenantID)
}

type TenantAwareRegistry ΒΆ added in v1.1.0

type TenantAwareRegistry interface {
	// GetServiceForTenant returns a service instance for a specific tenant
	GetServiceForTenant(name string, tenantID TenantID, target any) error
}

TenantAwareRegistry provides common service discovery methods that are tenant-aware

type TenantConfigLoader ΒΆ added in v1.1.0

type TenantConfigLoader interface {
	// LoadTenantConfigurations loads configurations for all tenants
	LoadTenantConfigurations(app Application, tenantService TenantService) error
}

TenantConfigLoader is an interface for loading tenant configurations

type TenantConfigParams ΒΆ added in v1.1.0

type TenantConfigParams struct {
	// ConfigNameRegex is a regex pattern for the config file names (e.g. "^tenant[0-9]+\\.json$").
	ConfigNameRegex *regexp.Regexp
	// ConfigDir is the directory where tenant config files are located.
	ConfigDir string
	// ConfigFeeders are the feeders to use for loading tenant configs.
	ConfigFeeders []Feeder
}

TenantConfigParams defines parameters for loading tenant configurations

type TenantConfigProvider ΒΆ added in v1.1.0

type TenantConfigProvider struct {
	// contains filtered or unexported fields
}

TenantConfigProvider manages configurations for multiple tenants

func NewTenantConfigProvider ΒΆ added in v1.1.0

func NewTenantConfigProvider(defaultConfig ConfigProvider) *TenantConfigProvider

NewTenantConfigProvider creates a new tenant configuration provider

func (*TenantConfigProvider) GetConfig ΒΆ added in v1.1.0

func (tcp *TenantConfigProvider) GetConfig() any

GetConfig returns the default configuration to satisfy ConfigProvider interface

func (*TenantConfigProvider) GetDefaultConfig ΒΆ added in v1.1.0

func (tcp *TenantConfigProvider) GetDefaultConfig() ConfigProvider

GetDefaultConfig returns the default configuration (non-tenant specific)

func (*TenantConfigProvider) GetTenantConfig ΒΆ added in v1.1.0

func (tcp *TenantConfigProvider) GetTenantConfig(tenantID TenantID, section string) (ConfigProvider, error)

GetTenantConfig retrieves a configuration for a specific tenant and section

func (*TenantConfigProvider) HasTenantConfig ΒΆ added in v1.1.0

func (tcp *TenantConfigProvider) HasTenantConfig(tenantID TenantID, section string) bool

HasTenantConfig checks if a configuration exists for a specific tenant and section

func (*TenantConfigProvider) SetTenantConfig ΒΆ added in v1.1.0

func (tcp *TenantConfigProvider) SetTenantConfig(tenantID TenantID, section string, provider ConfigProvider)

SetTenantConfig sets a configuration for a specific tenant and section

type TenantContext ΒΆ added in v1.1.0

type TenantContext struct {
	context.Context
	// contains filtered or unexported fields
}

TenantContext is a context for tenant-aware operations. It extends the standard Go context.Context interface to carry tenant identification through the call chain, enabling tenant-specific behavior in modules and services.

TenantContext should be used whenever performing operations that need to be tenant-specific, such as database queries, configuration lookups, or service calls.

func NewTenantContext ΒΆ added in v1.1.0

func NewTenantContext(ctx context.Context, tenantID TenantID) *TenantContext

NewTenantContext creates a new context with tenant information. The returned context carries the tenant ID and can be used throughout the application to identify which tenant an operation belongs to.

Example:

tenantCtx := modular.NewTenantContext(ctx, "customer-123")
result, err := tenantAwareService.DoSomething(tenantCtx, data)

func (*TenantContext) GetTenantID ΒΆ added in v1.1.0

func (tc *TenantContext) GetTenantID() TenantID

GetTenantID returns the tenant ID from the context. This allows modules and services to determine which tenant the current operation is for.

type TenantGuard ΒΆ added in v1.4.3

type TenantGuard interface {
	// GetMode returns the current tenant guard mode
	GetMode() TenantGuardMode

	// ValidateAccess validates whether a tenant access should be allowed
	ValidateAccess(ctx context.Context, violation *TenantViolation) (bool, error)

	// GetRecentViolations returns recent tenant violations
	GetRecentViolations() []*TenantViolation
}

TenantGuard provides tenant isolation enforcement functionality.

type TenantGuardConfig ΒΆ added in v1.4.3

type TenantGuardConfig struct {
	// Mode defines the tenant guard enforcement mode
	Mode TenantGuardMode `json:"mode"`

	// EnforceIsolation enables tenant isolation enforcement
	EnforceIsolation bool `json:"enforce_isolation"`

	// AllowCrossTenant allows cross-tenant access (when false, blocks cross-tenant)
	AllowCrossTenant bool `json:"allow_cross_tenant"`

	// ValidationTimeout specifies timeout for tenant validation operations
	ValidationTimeout time.Duration `json:"validation_timeout"`

	// MaxTenantCacheSize limits the size of the tenant cache
	MaxTenantCacheSize int `json:"max_tenant_cache_size"`

	// TenantTTL specifies how long to cache tenant information
	TenantTTL time.Duration `json:"tenant_ttl"`

	// LogViolations enables logging of tenant violations
	LogViolations bool `json:"log_violations"`

	// BlockViolations enables blocking of tenant violations
	BlockViolations bool `json:"block_violations"`

	// CrossTenantWhitelist maps tenants to allowed cross-tenant access targets
	CrossTenantWhitelist map[string][]string `json:"cross_tenant_whitelist,omitempty"`
}

TenantGuardConfig provides configuration options for tenant guard behavior.

func NewDefaultTenantGuardConfig ΒΆ added in v1.4.3

func NewDefaultTenantGuardConfig(mode TenantGuardMode) TenantGuardConfig

NewDefaultTenantGuardConfig creates a default tenant guard configuration for the given mode.

func (TenantGuardConfig) IsValid ΒΆ added in v1.4.3

func (c TenantGuardConfig) IsValid() bool

IsValid validates the tenant guard configuration.

type TenantGuardMode ΒΆ added in v1.4.3

type TenantGuardMode string

TenantGuardMode defines the strictness level for tenant isolation enforcement. Different modes provide different levels of tenant isolation checking and violation handling.

const (
	// TenantGuardModeStrict enforces strict tenant isolation.
	// Cross-tenant access attempts will be blocked and result in errors.
	// This provides the highest level of tenant isolation security.
	TenantGuardModeStrict TenantGuardMode = "strict"

	// TenantGuardModeLenient enforces tenant isolation with warnings.
	// Cross-tenant access attempts are logged but allowed to proceed.
	// This provides backward compatibility while monitoring violations.
	TenantGuardModeLenient TenantGuardMode = "lenient"

	// TenantGuardModeDisabled disables tenant isolation enforcement.
	// No tenant checking is performed, essentially single-tenant mode.
	// This is useful for testing or single-tenant deployments.
	TenantGuardModeDisabled TenantGuardMode = "disabled"
)

func ParseTenantGuardMode ΒΆ added in v1.4.3

func ParseTenantGuardMode(s string) (TenantGuardMode, error)

ParseTenantGuardMode parses a string into a TenantGuardMode.

func (TenantGuardMode) IsEnforcing ΒΆ added in v1.4.3

func (m TenantGuardMode) IsEnforcing() bool

IsEnforcing returns true if this mode performs any kind of tenant enforcement.

func (TenantGuardMode) IsStrict ΒΆ added in v1.4.3

func (m TenantGuardMode) IsStrict() bool

IsStrict returns true if this mode strictly enforces tenant isolation.

func (TenantGuardMode) String ΒΆ added in v1.4.3

func (m TenantGuardMode) String() string

String returns the string representation of the tenant guard mode.

type TenantID ΒΆ added in v1.1.0

type TenantID string

TenantID represents a unique tenant identifier. Tenant IDs should be stable, unique strings that identify tenants throughout the application lifecycle. Common patterns include:

  • Customer IDs: "customer-12345"
  • Domain names: "example.com"
  • UUIDs: "550e8400-e29b-41d4-a716-446655440000"

func GetTenantIDFromContext ΒΆ added in v1.1.0

func GetTenantIDFromContext(ctx context.Context) (TenantID, bool)

GetTenantIDFromContext attempts to extract tenant ID from a context. Returns the tenant ID and true if the context is a TenantContext, or empty string and false if it's not a tenant-aware context.

This is useful for functions that may or may not receive a tenant context:

if tenantID, ok := modular.GetTenantIDFromContext(ctx); ok {
    // Handle tenant-specific logic
} else {
    // Handle default/non-tenant logic
}

type TenantLoader ΒΆ added in v1.4.3

type TenantLoader interface {
	// LoadTenants loads and returns all available tenants
	LoadTenants() ([]Tenant, error)
}

TenantLoader is an interface for loading tenant information. Implementations can load tenants from various sources like databases, configuration files, APIs, etc.

type TenantService ΒΆ added in v1.1.0

type TenantService interface {
	// GetTenantConfig returns tenant-specific configuration for the given tenant and section.
	// This method looks up configuration that has been specifically registered for
	// the tenant, falling back to default configuration if tenant-specific config
	// is not available.
	//
	// The section parameter identifies which configuration section to retrieve
	// (e.g., "database", "cache", "api").
	//
	// Example:
	//   cfg, err := tenantSvc.GetTenantConfig("tenant-123", "database")
	//   if err != nil {
	//       return err
	//   }
	//   dbConfig := cfg.GetConfig().(*DatabaseConfig)
	GetTenantConfig(tenantID TenantID, section string) (ConfigProvider, error)

	// GetTenants returns all registered tenant IDs.
	// This is useful for operations that need to iterate over all tenants,
	// such as maintenance tasks, reporting, or health checks.
	//
	// Example:
	//   for _, tenantID := range tenantSvc.GetTenants() {
	//       // Perform operation for each tenant
	//       err := performMaintenanceForTenant(tenantID)
	//   }
	GetTenants() []TenantID

	// RegisterTenant registers a new tenant with optional initial configurations.
	// The configs map provides tenant-specific configuration for different sections.
	// If a section is not provided in the configs map, the tenant will use the
	// default application configuration for that section.
	//
	// Example:
	//   tenantConfigs := map[string]ConfigProvider{
	//       "database": modular.NewStdConfigProvider(&DatabaseConfig{
	//           Host: "tenant-specific-db.example.com",
	//       }),
	//       "cache": modular.NewStdConfigProvider(&CacheConfig{
	//           Prefix: "tenant-123:",
	//       }),
	//   }
	//   err := tenantSvc.RegisterTenant("tenant-123", tenantConfigs)
	RegisterTenant(tenantID TenantID, configs map[string]ConfigProvider) error

	// RegisterTenantAwareModule registers a module that wants to be notified about tenant lifecycle events.
	// Modules implementing the TenantAwareModule interface can register to receive
	// notifications when tenants are added or removed, allowing them to perform
	// tenant-specific initialization or cleanup.
	//
	// This is typically called automatically by the application framework during
	// module initialization, but can also be called directly if needed.
	//
	// Example:
	//   module := &MyTenantAwareModule{}
	//   err := tenantSvc.RegisterTenantAwareModule(module)
	RegisterTenantAwareModule(module TenantAwareModule) error
}

TenantService provides tenant management functionality. The tenant service is responsible for:

  • Managing tenant registration and lifecycle
  • Providing tenant-specific configuration
  • Notifying modules about tenant events
  • Coordinating tenant-aware operations

Applications that need multi-tenant functionality should register a TenantService implementation as a service named "tenantService".

type TenantViolation ΒΆ added in v1.4.3

type TenantViolation struct {
	// RequestingTenant is the tenant that initiated the request
	RequestingTenant string `json:"requesting_tenant"`

	// AccessedResource is the resource that was accessed
	AccessedResource string `json:"accessed_resource"`

	// ViolationType classifies the type of violation
	ViolationType TenantViolationType `json:"violation_type"`

	// Timestamp records when the violation occurred
	Timestamp time.Time `json:"timestamp"`

	// Severity indicates the severity level of the violation
	Severity TenantViolationSeverity `json:"severity"`

	// Context provides additional context about the violation
	Context map[string]interface{} `json:"context,omitempty"`
}

TenantViolation represents a tenant isolation violation.

type TenantViolationSeverity ΒΆ added in v1.4.3

type TenantViolationSeverity string

TenantViolationSeverity defines the severity level of tenant violations.

const (
	// TenantViolationSeverityLow indicates low-severity violations
	TenantViolationSeverityLow TenantViolationSeverity = "low"

	// TenantViolationSeverityMedium indicates medium-severity violations
	TenantViolationSeverityMedium TenantViolationSeverity = "medium"

	// TenantViolationSeverityHigh indicates high-severity violations
	TenantViolationSeverityHigh TenantViolationSeverity = "high"

	// TenantViolationSeverityCritical indicates critical-severity violations
	TenantViolationSeverityCritical TenantViolationSeverity = "critical"
)

type TenantViolationType ΒΆ added in v1.4.3

type TenantViolationType string

TenantViolationType defines the type of tenant isolation violation.

const (
	// TenantViolationCrossTenantAccess indicates access across tenant boundaries
	TenantViolationCrossTenantAccess TenantViolationType = "cross_tenant_access"

	// TenantViolationInvalidTenantContext indicates invalid tenant context
	TenantViolationInvalidTenantContext TenantViolationType = "invalid_tenant_context"

	// TenantViolationMissingTenantContext indicates missing tenant context
	TenantViolationMissingTenantContext TenantViolationType = "missing_tenant_context"

	// TenantViolationUnauthorizedOperation indicates unauthorized tenant operation
	TenantViolationUnauthorizedOperation TenantViolationType = "unauthorized_tenant_operation"
)

type ValidationResult ΒΆ added in v1.4.3

type ValidationResult struct {
	// IsValid indicates whether the configuration change is valid
	IsValid bool

	// Message provides details about the validation result
	Message string

	// Warnings contains any validation warnings (non-fatal issues)
	Warnings []string
}

ValidationResult represents the result of validating a configuration change

type ValueInjectionLoggerDecorator ΒΆ added in v1.4.3

type ValueInjectionLoggerDecorator struct {
	*BaseLoggerDecorator
	// contains filtered or unexported fields
}

ValueInjectionLoggerDecorator automatically injects key-value pairs into all log events. This decorator adds configured key-value pairs to every log call.

func NewValueInjectionLoggerDecorator ΒΆ added in v1.4.3

func NewValueInjectionLoggerDecorator(inner Logger, injectedArgs ...any) *ValueInjectionLoggerDecorator

NewValueInjectionLoggerDecorator creates a decorator that automatically injects values into log events.

func (*ValueInjectionLoggerDecorator) Debug ΒΆ added in v1.4.3

func (d *ValueInjectionLoggerDecorator) Debug(msg string, args ...any)

func (*ValueInjectionLoggerDecorator) Error ΒΆ added in v1.4.3

func (d *ValueInjectionLoggerDecorator) Error(msg string, args ...any)

func (*ValueInjectionLoggerDecorator) Info ΒΆ added in v1.4.3

func (d *ValueInjectionLoggerDecorator) Info(msg string, args ...any)

func (*ValueInjectionLoggerDecorator) Warn ΒΆ added in v1.4.3

func (d *ValueInjectionLoggerDecorator) Warn(msg string, args ...any)

type VerboseAwareFeeder ΒΆ added in v1.3.3

type VerboseAwareFeeder interface {
	// SetVerboseDebug enables or disables verbose debug logging
	SetVerboseDebug(enabled bool, logger interface{ Debug(msg string, args ...any) })
}

VerboseAwareFeeder provides functionality for verbose debug logging during configuration feeding

type VerboseLogger ΒΆ added in v1.3.3

type VerboseLogger interface {
	Debug(msg string, args ...any)
}

VerboseLogger provides a minimal logging interface to avoid circular dependencies

Directories ΒΆ

Path Synopsis
cmd
modcli module
Package feeders provides configuration feeders for reading data from various sources including environment variables, JSON, YAML, TOML files, and .env files.
Package feeders provides configuration feeders for reading data from various sources including environment variables, JSON, YAML, TOML files, and .env files.
internal
secrets
Package secrets provides secret redaction, provenance tracking and classification utilities.
Package secrets provides secret redaction, provenance tracking and classification utilities.
tenant
Package tenant provides tenant guard, isolation and enforcement logic.
Package tenant provides tenant guard, isolation and enforcement logic.
modules
auth module
cache module
chimux module
database module
eventbus module
eventlogger module
httpclient module
httpserver module
jsonschema module
letsencrypt module
logmasker module
reverseproxy module
scheduler module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL