Runtime
Overview
The Runtime domain in comby serves as a meta-domain that provides introspection, control, and runtime-specific operations within the application framework. It enables the discovery and management of system capabilities such as permissions, commands, queries, events, aggregates, and event handlers. Additionally, the domain facilitates administrative tasks and monitoring through permissions and server-side events (SSE).
Concept
What is the Runtime Domain?
The Runtime domain is the meta-layer of Comby that allows applications to introspect themselves, manage permissions, and monitor system health. It provides APIs to discover what commands, queries, and events are available, control event handlers, and stream real-time system events.
Key Characteristics:
- System Introspection: Discover available commands, queries, events, and handlers
- Permission Management: Central permission registry and validation
- Real-Time Monitoring: Metrics, event streaming (SSE), and system info
- Store Access Control: Permissions for EventStore, CommandStore, DataStore, etc.
- Schema Discovery: JSON schemas for all domain types
- Event Handler Control: Start, stop, and restore event handler states
Runtime Domain (Meta-Layer)
├── Permission System (Registry & Validation)
├── Introspection (Commands, Queries, Events, Handlers)
├── Monitoring (Metrics, SSE, System Info)
├── Store Management (Access Control)
└── Schema Discovery (JSON Schemas)Architecture
Hierarchy
Runtime Domain (System-Level)
├── Permissions
│ ├── Permission Registry
│ ├── Custom Permission Functions
│ └── Permission Validation
├── Runtime Information
│ ├── Commands (All registered commands)
│ ├── Queries (All registered queries)
│ ├── Events (All domain events)
│ ├── Command Handlers
│ ├── Query Handlers
│ └── Event Handlers (with metrics)
├── Monitoring
│ ├── Metrics (Event handler statistics)
│ ├── SSE (Real-time event streaming)
│ └── System Info (Tenant, version, etc.)
└── Store Access
├── EventStore Permissions
├── CommandStore Permissions
├── DataStore Permissions
├── CacheStore Permissions
└── LogStore PermissionsRelated Entities
Runtime domain interacts with:
- All Domains: Registers their permissions, commands, queries, and events
- Auth Domain: Provides permission validation functions
- Facade: Central access point for runtime information
- Event Handlers: Controls and monitors their execution
- Stores: Manages access permissions
Permission System
Permission Hierarchy
The Runtime domain defines a 3-level permission hierarchy:
1. Anonymous
No authentication required, completely public access.
// Permission function
AnonymousCmdFn = func(ctx context.Context, cmd comby.Command) error {
return nil // Always allow
}Use cases: Public endpoints, health checks, documentation
2. Authenticated
User is logged in (has account + session) but no active identity.
// Permission function
AuthenticatedCmdFn = func(ctx context.Context, cmd comby.Command) error {
// Requires: SenderAccountUuid + SenderSessionUuid
if hasValidAccountAndSession {
return nil
}
return ErrPermissionDenied
}Use cases: Profile management, account settings, identity selection
3. Authorized
User is logged in AND has selected an active identity with tenant context.
// Permission function
AuthorizedCmdFn = func(ctx context.Context, cmd comby.Command) error {
// Requires: SenderAccountUuid + SenderSessionUuid + SenderIdentityUuid + SenderTenantUuid
if hasCompleteContext {
return nil
}
return ErrPermissionDenied
}Use cases: Most domain operations, tenant-specific actions
Store Permissions
The Runtime domain defines permissions for all storage backends:
EventStore Permissions
StoreEvent.Info - Retrieve EventStore information
StoreEvent.Read - Read EventStore entries
StoreEvent.Update - Update EventStore entries
StoreEvent.Delete - Delete EventStore entriesCommandStore Permissions
StoreCommand.Info - Retrieve CommandStore information
StoreCommand.Read - Read CommandStore entries
StoreCommand.Update - Update CommandStore entries
StoreCommand.Delete - Delete CommandStore entriesDataStore Permissions
StoreData.Info - Retrieve DataStore information
StoreData.Read - Read DataStore entries
StoreData.Update - Update DataStore entries
StoreData.Delete - Delete DataStore entriesCacheStore Permissions
StoreCache.Info - Retrieve CacheStore information
StoreCache.Read - Read CacheStore entries
StoreCache.Update - Update CacheStore entries
StoreCache.Delete - Delete CacheStore entriesLogStore Permissions
StoreLog.Info - Retrieve LogStore information
StoreLog.Read - Read LogStore entries
StoreLog.Update - Update LogStore entries
StoreLog.Delete - Delete LogStore entries// Debug: Show all available commands for a domain
func ShowDomainCommands(domain string, facade *comby.Facade) {
handlers := runtime.CommandHandlerList(ctx, facade)
for _, handler := range handlers {
if handler.CommandHandlerDomain == domain {
for _, cmd := range handler.DomainCommandHandlers {
fmt.Printf("%s\n", cmd.DomainCmdName)
}
}
}
}Features
- Complete system introspection
- Permission management and validation
- Custom permission functions
- Real-time event streaming (SSE)
- Event handler metrics and monitoring
- Event handler state control
- Store access permissions
- JSON schema discovery
- System information API
- Three-level permission hierarchy (Anonymous, Authenticated, Authorized)
Best Practices
Permission Registration
- Register permissions during domain initialization
- Use descriptive permission names
- Provide clear permission descriptions
- Use custom functions only when RBAC is insufficient
Monitoring
- Monitor event handler metrics regularly
- Alert on failed events
- Track event processing latency
- Use SSE for real-time monitoring
Store Access
- Restrict store access to admin users only
- Use separate permissions for read vs write
- Audit all store modifications
- Never expose store endpoints publicly
Security Considerations
Permission Validation
- Always validate permissions before execution
- Use the three-level hierarchy appropriately
- Custom functions should fail securely (deny by default)
- Never skip permission checks in production
Store Access
- Store permissions are highly privileged
- Only system administrators should have store access
- Audit all store operations
- Implement rate limiting for store endpoints
SSE Streaming
- Require authentication for SSE connections
- Limit data exposed in SSE streams
- Implement connection limits
- Monitor for abuse
Runtime Information
- Runtime endpoints can reveal system architecture
- Restrict access to authorized users only
- Don't expose sensitive configuration
- Use HTTPS for all runtime endpoints
Troubleshooting
Permission denied for custom function
Cause: Custom permission function returned error.
Debug:
perm := findPermission(domain, permissionType)
if perm.FuncSet && perm.CmdFunc != nil {
err := perm.CmdFunc(ctx, cmd)
if err != nil {
fmt.Printf("Custom function denied: %v\n", err)
}
}Event handler metrics not updating
Check:
- Is the event handler a
StateRestorer? - Does it implement
EventHandlerMetricProvider? - Are events being processed?
Solution: Ensure event handler implements required interfaces:
type MyReadmodel struct {
*comby.BaseReadmodel // Provides metrics
}SSE connection failing
Check:
- Is authentication valid?
- Are required permissions granted?
- Is the SSE producer running?
Debug: Check SSE producer status in logs.
Store permissions not working
Cause: Store permissions not registered.
Solution:
runtime.RegisterStore(ctx, facade)Integration with Other Domains
All Domains
Every domain automatically:
- Registers commands and queries
- Creates runtime permissions
- Exposes schemas
Auth Domain
- Consumes permission definitions
- Validates permissions during authorization
- Uses permission functions for custom logic
Custom Domains
// Custom domain registers its permissions
func Register(ctx context.Context, fc *comby.Facade) {
// Commands and queries are auto-registered
// Optional: Register custom permission functions
runtime.RegisterPermission(
runtime.NewPermissionCmdFunc(
"MyDomain",
"MyCommand",
myCustomPermissionFn,
),
)
}Advanced Features
Event Handler Control
Restore event handler state:
// Via API
POST /api/tenants/{tenantUuid}/runtime/event-handler-list
{
"action": "restore",
"eventHandlerName": "CustomerReadmodel",
"restoreFromZero": true
}Schema Introspection
Get JSON schema for any command:
POST /api/tenants/{tenantUuid}/runtime/schema
{
"domain": "Customer",
"type": "CustomerCommandCreate"
}
Response:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"customerUuid": {"type": "string"},
"name": {"type": "string"},
"email": {"type": "string", "format": "email"}
}
}