What problem does it solve?
It standardizes how to structure business logic in a forge codebase so domain operations stay independent from wire (API) and storage (DB) concerns, and so errors map consistently to client-facing responses.
Core Features & Use Cases
- Defines the service boundary: places a
Service interface in internal/<svc>/contract.go using domain-shaped inputs and outputs.
- Encourages dependency injection: uses a
Deps struct and a New(deps Deps) Service constructor to inject DB handles and deterministic helpers like time.Now and ID generators.
- Implements a typed error domain: routes storage/driver failures into shared
forge/pkg/svcerr sentinels and uses typed errors that Unwrap() to the corresponding sentinel for correct handler mapping.
- Keeps observability at the handler edge: applies logging, tracing, metrics, recovery, and request-id uniformly via
forge/pkg/observe interceptors rather than sprinkling middleware wrappers through the service.
- Supports testable design: enables unit testing at the service boundary with injected deps, and generates mocks from the service interface for consumers (handlers and other services).
Quick Start
Write an internal/<svc>/contract.go that declares Service methods with domain inputs/outputs, then implement them in internal/<svc>/service.go using an injected Deps struct and return svcerr-backed errors for not-found, invalid-argument, and already-exists cases.