Sentinel

Forge Extension

Mount Sentinel into a Forge application as a first-class extension with automatic route registration and migrations.

Sentinel ships a ready-made Forge extension in the extension package. It wires the engine, HTTP API, and lifecycle management into Forge's extension system.

Installation

import "github.com/xraph/sentinel/extension"

Registering the extension

package main

import (
    "github.com/xraph/forge"
    pgstore "github.com/xraph/sentinel/store/postgres"
    "github.com/xraph/sentinel/extension"
)

func main() {
    app := forge.New()

    sentinelExt := extension.New(
        extension.WithStore(pgstore.New(bunDB)),
    )

    app.RegisterExtension(sentinelExt)
    app.Run()
}

What the extension does

Lifecycle eventBehaviour
RegisterCreates the engine from the provided options
StartRuns store.Migrate (unless disabled)
RegisterRoutesMounts all 32+ Sentinel HTTP endpoints under /sentinel
StopCalls engine.Stop → emits OnShutdown to all extensions

Extension options

OptionDescription
extension.WithStore(s)Sets the composite store (required)
extension.WithExtension(x)Registers a Sentinel plugin extension
extension.WithEngineOption(opt)Passes an engine option directly
extension.WithLogger(l)Sets the structured logger

Accessing the engine from other extensions

After Register is called by Forge, sentinelExt.Engine() returns the fully initialised engine:

eng := sentinelExt.Engine()
// use eng.CreateSuite, eng.ListRuns, etc. from another extension

Tenant middleware

In a Forge app, tenant scope is typically set by middleware. Implement a Forge middleware that calls sentinel.WithTenant and sentinel.WithApp:

func tenantMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        tenantID := r.Header.Get("X-Tenant-ID")
        appID := r.Header.Get("X-App-ID")
        ctx := sentinel.WithTenant(r.Context(), tenantID)
        ctx = sentinel.WithApp(ctx, appID)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

router.Use(tenantMiddleware)

Adding metrics

Register the observability extension alongside the Sentinel engine extension:

import "github.com/xraph/sentinel/observability"

metricsExt := observability.NewMetricsExtensionWithFactory(fapp.Metrics())

sentinelExt := extension.New(
    extension.WithStore(store),
    extension.WithExtension(metricsExt),
)

On this page