Help us shape the future of Go! Take the 2026 Go Developer Survey

usecase

package
v0.0.13 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package usecase implements the sealed Result pattern used by the FlowCatalyst SDK and the platform itself, plus the DomainEvent / ExecutionContext / typed Error primitives the use-case envelope builds on.

The Result[E] type is a sealed sum: only success[E] and failure[E] implement it, both unexported. Failure can be constructed by anyone; Success requires a sealed.Token, which only packages under pkg/fcsdk/ can mint. Therefore the only path to a Success-valued Result outside the SDK is through one of the Commit* free functions in usecasepgx.

This is what guarantees, at compile time, that every domain event is committed atomically with its aggregate state — no code path produces a Success without going through a UnitOfWork.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildEventType

func BuildEventType(app, domain, aggregate, action string) string

BuildEventType is the convention for forming an event type.

func BuildMessageGroup

func BuildMessageGroup(domain, aggregate, id string) string

BuildMessageGroup is the convention for forming a message group.

func BuildSubject

func BuildSubject(domain, aggregate, id string) string

BuildSubject is the convention for forming a subject from domain/aggregate/id. Mirrors the TS SDK helper.

func ExtractAggregateType

func ExtractAggregateType(subject string) string

ExtractAggregateType maps "platform.eventtype.123" → "Eventtype". Used by EventSink implementations to populate the aggregate_type column on outbox / audit rows.

func ExtractEntityID

func ExtractEntityID(subject string) string

ExtractEntityID maps "platform.eventtype.123" → "123".

func Into

func Into[E any](r Result[E]) (E, error)

Into converts a Result into the stdlib (T, error) shape. Handlers call this to turn a use case outcome into an HTTP response.

func IsFailure

func IsFailure[E any](r Result[E]) bool

IsFailure reports whether the result is a failure.

func IsSuccess

func IsSuccess[E any](r Result[E]) bool

IsSuccess reports whether the result is a success.

func RedactAuditJSON

func RedactAuditJSON(raw []byte, masked []string) ([]byte, error)

RedactAuditJSON applies the audit redaction rule (the Java platform's docs/spec/audit-redaction.md; the shared cases are testdata/audit-redaction-vectors.json) to a serialised command: a key is secret when, lower-cased with '_' and '-' removed, it ends with password, passwordhash, secret, secretref, passphrase or token, or equals apikey, privatekey, authorization or cookie; a secret key's value becomes "***" whatever its type, except null and booleans, which are kept. Objects and arrays are walked; masked names top-level fields masked the same way. Input that is not a JSON object or array is returned unchanged.

func RedactedAuditCommand

func RedactedAuditCommand(command any) ([]byte, error)

RedactedAuditCommand marshals a command for an audit row with the rule applied, including the command's own AuditMaskedFields when it has them.

Types

type AuditMasked

type AuditMasked interface {
	AuditMaskedFields() []string
}

AuditMasked is implemented by a command whose audit document must hide a field the name rule would keep (a SECRET platform-config value, say). The fields are top-level JSON keys of the serialised command.

type DomainEvent

type DomainEvent interface {
	EventID() string
	EventType() string   // e.g. "platform:admin:eventtype:created"
	SpecVersion() string // CloudEvents spec version
	Source() string      // e.g. "platform:admin"
	Subject() string     // e.g. "platform.eventtype.evt_01H..."
	Time() time.Time
	PrincipalID() string
	CorrelationID() string
	CausationID() string
	ExecutionID() string
	MessageGroup() string

	// ToDataJSON returns the event-specific data payload as JSON.
	// Implementations typically json.Marshal a struct of their fields.
	ToDataJSON() ([]byte, error)
}

DomainEvent is the contract every emitted event must satisfy — methods rather than fields so events can embed metadata however suits their JSON shape.

type Error

type Error struct {
	Kind    Kind
	Code    string
	Message string
	Details map[string]any
	// Cause is the wrapped error, if any.
	Cause error
}

Error is the canonical use case error. Implements the standard error interface; inspect with errors.As(err, &usecase.Error{}).

func AsError

func AsError(err error) *Error

AsError extracts a *Error from any error in the chain. Returns nil if absent.

func Authorization

func Authorization(code, message string) *Error

Authorization builds an authorization error.

func BusinessRule

func BusinessRule(code, message string) *Error

BusinessRule builds a business rule violation error.

func Conflict

func Conflict(code, message string) *Error

Conflict builds a conflict error (e.g., uniqueness violation).

func Internal

func Internal(code, message string, cause error) *Error

Internal builds an internal error wrapping a lower-level cause.

func NotFound

func NotFound(code, message string) *Error

NotFound builds a not-found error.

func Validation

func Validation(code, message string) *Error

Validation builds a validation error. Use for field-level checks.

func (*Error) Error

func (e *Error) Error() string

func (*Error) HTTPStatus

func (e *Error) HTTPStatus() int

HTTPStatus maps the Kind to an HTTP status code.

func (*Error) Unwrap

func (e *Error) Unwrap() error

func (*Error) WithDetails

func (e *Error) WithDetails(details map[string]any) *Error

WithDetails attaches structured details (e.g., field name → constraint).

type EventMetadata

type EventMetadata struct {
	EventID       string    `json:"eventId"`
	SpecVersion   string    `json:"specVersion"`
	Source        string    `json:"source"`
	Type          string    `json:"type"`
	Subject       string    `json:"subject"`
	OccurredAt    time.Time `json:"time"`
	CorrelationID string    `json:"correlationId,omitempty"`
	CausationID   string    `json:"causationId,omitempty"`
	PrincipalID   string    `json:"principalId,omitempty"`
	ExecutionID   string    `json:"executionId,omitempty"`
	MessageGroup  string    `json:"messageGroup,omitempty"`
}

EventMetadata is the CloudEvents-shaped envelope embedded into every domain event. Implementations typically embed this struct and provide a custom MarshalJSON that flattens it alongside the event-specific data fields.

Concrete events still implement the DomainEvent interface explicitly (Go's field/method namespace overlap means you can't have both `EventID string` and `EventID() string` on the same struct). The methods typically delegate to the embedded EventMetadata fields:

func (e EventFoo) EventID() string       { return e.Metadata.EventID }
func (e EventFoo) Time() time.Time       { return e.Metadata.OccurredAt }
func (e EventFoo) CorrelationID() string { return e.Metadata.CorrelationID }
... etc

func NewEventMetadata

func NewEventMetadata(ec ExecutionContext, eventType, source, subject string) EventMetadata

NewEventMetadata builds an EventMetadata from an ExecutionContext plus the per-event fields. Convenience constructor — events can also construct EventMetadata field-by-field for full control.

type ExecutionContext

type ExecutionContext struct {
	// PrincipalID is the acting user or service account.
	PrincipalID string
	// CorrelationID is propagated from inbound requests; new requests
	// generate a fresh ID.
	CorrelationID string
	// CausationID points to the event that caused this one (for chains).
	// Empty for top-level / user-initiated actions.
	CausationID string
	// ExecutionID is unique per use case invocation.
	ExecutionID string
	// InitiatedAt is when this context was created.
	InitiatedAt time.Time
}

ExecutionContext threads trace identifiers and the acting principal through the use case pipeline.

func FromParentEvent

func FromParentEvent(parent DomainEvent, principalID string) ExecutionContext

FromParentEvent derives a context from a parent event, preserving the correlation chain and recording the parent as the causation.

func NewExecutionContext

func NewExecutionContext(principalID string) ExecutionContext

NewExecutionContext creates a fresh context with the given principal and freshly-generated correlation + execution IDs.

CorrelationID is seeded from ExecutionID for top-level requests. Use WithCorrelation when an inbound request already carries one.

func WithCorrelation

func WithCorrelation(principalID, correlationID string) ExecutionContext

WithCorrelation creates a context using an inbound correlation ID. Use this when handling a request that originated upstream and already carries trace identifiers.

func (ExecutionContext) WithCausation

func (ec ExecutionContext) WithCausation(causationID string) ExecutionContext

WithCausation returns a copy with the causation ID set, for events emitted as a consequence of another event.

type HasID

type HasID interface {
	IDStr() string
}

HasID is implemented by every aggregate so the UnitOfWork can identify the row being committed without reflection.

The method is named IDStr (not ID) so it doesn't collide with the typical exported `ID string` field on entity structs. Every entity provides:

type Foo struct { ID string `json:"id"` ... }
func (f *Foo) IDStr() string { return f.ID }

type Kind

type Kind string

Kind classifies a use case error. The Kind drives the HTTP status code mapping in API handlers.

const (
	KindValidation    Kind = "validation"
	KindBusinessRule  Kind = "business_rule"
	KindAuthorization Kind = "authorization"
	KindNotFound      Kind = "not_found"
	KindConflict      Kind = "conflict"
	KindInternal      Kind = "internal"
)

type Result

type Result[E any] interface {
	// contains filtered or unexported methods
}

Result is the outcome of a use case execution. It's a sealed sum with exactly two implementors: success[E] (constructible only via Success) and failure[E] (constructible by anyone via Failure).

func Failure

func Failure[E any](err error) Result[E]

Failure constructs a Result wrapping an error. Public — anyone can return a Failure for validation errors, business rule violations, authorization failures, etc.

func Success

func Success[E any](_ sealed.Token, value E) Result[E]

Success constructs a Result wrapping a value. The sealed.Token is the compile-time witness that the caller is internal to the SDK; external code cannot import internal/sealed and therefore cannot call this.

SDK-internal callers: pass sealed.New() as the token argument.

Jump to

Keyboard shortcuts

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