foundation

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jun 17, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package foundation (Citadel) serves as the core booting and structural bedrock of the GoStack framework, managing low-level application lifecycles and diagnostics.

Purpose: This file implements environment configuration access helper functions for the GoStack framework.

Philosophy: We believe application configuration should be decoupled from logic. By storing configs in environment variables, we ensure portability across local dev, staging, and production runtimes.

Architecture: Part of the foundation package, providing environment lookup utilities to bootstrapper files (like main.go).

Choice: We consolidated the framework/config package directly into the foundation package, removing package import cycles and folder fragmentation.

Implementation: - Get: retrieves environment variables with support for default fallbacks.

Package foundation (Citadel) serves as the core booting and structural bedrock of the GoStack framework, managing low-level application lifecycles and diagnostics.

Purpose: This file implements the Citadel pluggable database driver registry.

Philosophy: GoStack follows the principle of "modular self-containment" — the core framework binary should not carry compile-time dependencies on any specific database driver (MySQL, PostgreSQL, SQLite, etc.) unless that driver is explicitly imported by the application developer's own code.

This registry achieves that by reversing the dependency direction: Instead of GoStack importing drivers, drivers register themselves into GoStack via their own init() functions, following the same pattern as Go's standard "database/sql" package driver registration model.

LIFECYCLE:

  1. The developer imports their chosen driver package (e.g. a GoStack MySQL adapter).
  2. That package's init() calls foundation.Register("mysql", constructorFunc).
  3. During application boot, GoStack calls foundation.GetDriver("mysql") to retrieve the constructor and build the live database connection.

This guarantees that only actively-imported drivers are compiled into the binary, keeping the executable lean and free of unused transitive dependencies.

Package foundation (Citadel) provides the core orchestration layer for the Gostack framework. It is responsible for booting the application, managing lifecycle events, and coordinating between the HTTP and database layers.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Get

func Get(key, fallback string) string

Get retrieves an environment variable or returns a default value.

Parameters:

  • key: The name of the environment variable.
  • fallback: The value to return if the variable is not set.

func Register

func Register(name string, f DriverFunc)

Register adds a named driver constructor to the central registry.

PANIC BEHAVIOR (INTENTIONAL): This function panics rather than returning an error for two specific invalid states:

  • Registering a nil constructor: A nil DriverFunc would cause a silent crash at connection time. Panicking at registration time makes the error immediately visible.
  • Registering the same driver name twice: Double-registration indicates a package import conflict or accidental duplicate init() calls. Panicking here prevents silent overwrite of a valid driver with an incorrect one.

This mirrors the design of Go's standard "database/sql".Register() for the same reasons.

Parameters:

  • name: The unique driver identifier string (e.g. "mysql", "postgres").
  • f: The DriverFunc constructor to associate with this driver name.

Types

type Application

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

Application serves as the absolute master core runtime manager for the GoStack framework. It encapsulates the root Service Container and coordinates the execution loop of providers.

func NewApplication

func NewApplication() *Application

NewApplication instantiates a fresh framework coordinator bound to a new Service Container.

func (*Application) Boot

func (a *Application) Boot()

Boot executes the master two-step lifecycle processing loop across all registered providers. Once executed, the framework layer is fully initialized and open to accept incoming traffic.

func (*Application) Container

func (a *Application) Container() *Container

Container returns the underlying Inversion of Control (IoC) instance managed by the application.

func (*Application) RegisterProvider

func (a *Application) RegisterProvider(provider ServiceProvider)

RegisterProvider appends a modular service provider to the framework's internal lifecycle stack. If the application has already entered its runtime phase (isBooted == true), the provider's structural phases are instantly executed on the fly to support dynamic runtime hot-swaps.

type Container

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

Container implements a high-performance, thread-safe Inversion of Control (IoC) Service Container based on the Explicit Factory Design Pattern.

DESIGN PHILOSOPHY & ARCHITECTURAL CHOICES:

  1. Explicit Factory Functions vs Reflection: GoStack explicitly avoids dynamic, runtime reflection-based containers (e.g., Laravel's automatic injection). Reflection degrades execution speed and converts compile-time security into unstable runtime panics. Instead, we map explicit string keys to highly efficient factory function pointers.
  1. Explicit Factory Functions vs Compile-Time Code Generation: While tools like Google Wire provide zero runtime overhead by generating static initializations, they introduce friction into the developer workflow by requiring constant CLI compilation passes. GoStack balances maximum speed with architectural flexibility by managing bindings dynamically in local RAM.
  1. Thread Safety & Concurrent Map Mutations: Go's native maps are structurally unsafe for concurrent read/write mutations. Because GoStack is engineered for high-concurrency HTTP architectures, our internal registries are fully shielded by a sync.RWMutex. We use granular RLock() transitions for lightning-fast concurrent reads, and strict Lock() barriers for single-instance structural state initialization mutations.

func NewContainer

func NewContainer() *Container

NewContainer initializes an empty, production-ready framework IoC storage instance.

func (*Container) BindSingleton

func (c *Container) BindSingleton(key string, factory func(c *Container) any)

BindSingleton registers a shared structural dependency blueprint into the container.

LIFECYCLE BEHAVIOR: A Singleton is a deferred single-instance object. Passing a factory recipe into this method does NOT allocate memory for the service immediately. The service remains dormant until the application explicitly requests it via Resolve(). Once built, it is stored in the cache, and the same shared instance is returned across all subsequent lifecycle calls.

PARAMETERS:

  • key: A unique string identifier representing the service binding (e.g., "db", "config").
  • factory: A custom callback function housing the exact instantiation mechanics for the service.

func (*Container) BindTransient

func (c *Container) BindTransient(key string, factory func(c *Container) any)

BindTransient registers a volatile dependency blueprint into the container.

LIFECYCLE BEHAVIOR: Transients represent short-lived, state-free, or request-scoped helpers. Unlike Singletons, the container does not cache transient records. Every single time Resolve() is executed against a transient key, the factory function fires freshly, resulting in a unique object allocation.

PARAMETERS:

  • key: A unique string identifier representing the service binding (e.g., "validator", "formatter").
  • factory: A custom callback function executing the instantiation mechanics on every call.

func (*Container) Has

func (c *Container) Has(key string) bool

Has executes a non-blocking, concurrent inspection to verify if a service key is bound.

func (*Container) Resolve

func (c *Container) Resolve(key string) (any, error)

Resolve fetches, builds, or extracts a registered service out of the container warehouse.

RESOLUTION RESOLVING PIPELINE STEP-BY-STEP:

  1. High-Performance Cache Lookups: Checks if the target key is already an active, warmed Singleton.
  2. On-The-Fly Singleton Materialization: If a blueprint factory exists, we acquire a write lock, execute the factory to materialize the service, store it inside the cache, and clean up the factory reference.
  3. Volatile Transient Processing: If a transient registry matches, we execute the factory directly.
  4. Safe Error Routing: If the key cannot be found, we return a structured error instead of panicking.

NESTED DEPENDENCY INJECTION (CHAINING): Because the container passes its own instance pointer `c` straight into the executing factories, dependencies can dynamically resolve other dependencies out of the container during their own construction loop.

type DriverFunc

type DriverFunc func(dsn string) (any, error)

DriverFunc defines the universal constructor signature for all database driver adapters.

DESIGN RATIONALE: By standardizing on a single function signature (DSN string in, interface + error out), the registry can invoke any driver's constructor without knowing its concrete type. The returned interface{} is subsequently type-asserted to contract.Database by the framework bootstrap layer.

Parameters:

  • dsn: The Data Source Name string containing all connection credentials and parameters.

Returns:

  • An initialized database connection object satisfying contract.Database, or an error.

func GetDriver

func GetDriver(name string) (DriverFunc, error)

GetDriver retrieves a registered driver constructor by its name identifier.

Parameters:

  • name: The driver name string to look up (e.g. "mysql", "postgres").

Returns:

  • The registered DriverFunc constructor, or an error if no driver with that name exists.
  • An error if the driver has not been registered (most likely the driver's package was not imported).

type Kernel

type Kernel struct {
	// DB provides access to the database layer throughout the application lifecycle.
	DB contract.Database

	// Router manages incoming HTTP requests and directs them to the correct logic.
	Router *http.Router
}

Kernel acts as the heart of the framework. It holds the application's configuration and coordinates the startup process. It bridges the gap between the database infrastructure and the routing engine.

func NewKernel

func NewKernel(db contract.Database, router *http.Router) *Kernel

NewKernel creates a new instance of the application kernel. By injecting the database and router here, we ensure that the kernel remains decoupled from specific implementations.

Parameters:

  • db: A concrete database adapter implementation that satisfies the contract.Database interface.
  • router: The configured HTTP router instance.

func (*Kernel) Run

func (k *Kernel) Run(addr string) error

Run starts the HTTP server. It binds the configured router and runtime engine dependencies together, spins up the internal view compiler pipeline, and begins listening for incoming requests on the specified address.

Architectural Note: Because our Path A refactor migrated route processing to use a custom, decoupled http.Context, the raw http.Router cannot be passed directly to the standard network engine anymore. Instead, this method instantiates GoStack's unified HTTP Engine core container, binds the global template renderer runtime, and streams execution payloads through it.

Parameters:

  • addr: The network address socket (e.g., ":8080") to listen and serve traffic on.

Returns:

  • An error if the network socket cannot be claimed, bound, or handled safely.

type ServiceProvider

type ServiceProvider interface {
	// Register binds service factory recipes into the central Service Container.
	//
	// EXCLUSIVITY ARCHITECTURAL CRITERIA:
	// Providers are ONLY allowed to execute Container.BindSingleton() or Container.BindTransient()
	// within this method block. They are strictly forbidden from executing Resolve() or querying
	// other services, because those companion dependencies might not have been registered yet.
	Register(c *Container)

	// Boot executes initialization, bootstrap, or configuration routines.
	//
	// EXCLUSIVITY ARCHITECTURAL CRITERIA:
	// This method fires ONLY after every single Service Provider in the application has completed
	// its Register() step. Therefore, you are guaranteed that all service blueprints coexist
	// inside the container warehouse. Here, a provider can safely run Resolve(), spawn background
	// queue workers, or read active configuration variables.
	Boot(c *Container)
}

ServiceProvider establishes the unified structural lifecycle contract for all modular packages, sub-systems, and feature drivers within the GoStack ecosystem.

DESIGN PHILOSOPHY: In compliance with battle-tested architectural paradigms (like Laravel and Django), a Service Provider decouples module initialization from the global startup script. Instead of cluttering main.go with database client initializations, router wiring, and config parsing, each package provides an implementation of this contract.

DECOUPLED LIFECYCLE PARADIGM: To completely eliminate dependency-ordering deadlock bugs (e.g., a router module attempting to resolve an uninitialized database connector during startup), the framework enforces a strict, two-step boot pipeline managed via Register() and Boot().

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL