Canonical, stable Protobuf contracts for SupplyChainGuard (SCG) notifications. These contracts are shared across services and clients to ensure consistent, evolvable event and notification schemas.
- Single source of truth for notification messages and enums used across SCG domains
- Stability first: linting and breaking-change checks enforced via Buf and CI
- Generated Go packages for easy consumption in Go microservices
- Install tooling: buf, protoc-gen-go, protoc-gen-go-grpc
- Generate: buf generate
- Import from gen/go/... packages
- Never break existing fields/messages in minor/patch releases
- Keep PII out of domain events; allow limited PII only in notification messages
SCG emits domain events (e.g., compliance, logistics, custody). This repository defines notification-oriented contracts that describe how those events are communicated to users and systems across channels (email, SMS, push, webhooks, in-app, digests, escalations). Contracts live under proto/scg/** and are versioned to maintain compatibility.
Key areas covered include:
- Common envelope for notifications
- Domain-specific notification messages (merchant, identity, event_log, etc.)
- Enums for channels, severity, categories, audiences, and statuses
- Models for preferences, deliveries, digests, and core notifications
- Install tools
- go install github.com/bufbuild/buf/cmd/buf@latest
- go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
- go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
- Generate Go code
- buf generate
- Use in your Go service
- go get github.com/next-trace/scg-notification-contracts@vX.Y.Z
- Configuration files:
- buf.yaml: module name, lint, breaking rules
- buf.gen.yaml: codegen plugins and output paths
- Generated Go code is under gen/go/proto/scg/... and importable via the module path.
- Regenerate after any .proto change: buf generate
Important: JSON naming
- All message fields explicitly set json_name to snake_case across the schemas.
- The Go structs generated by protoc include json tags that match the snake_case names.
- Merchant welcome notification (publisher or tests)
import ( merchantnotifs "github.com/next-trace/scg-notification-contracts/gen/go/proto/scg/merchant/v1" commonv1 "github.com/next-trace/scg-notification-contracts/gen/go/proto/scg/common/v1" "time" )
evt := &merchantnotifs.MerchantWelcomeRequested{ Meta: &commonv1.NotificationEnvelope{ NotificationUuid: "018f3c6d-7aa0-7b0b-b728-58d6a3b68400", // v7 preferred SourceService: "merchant-service", CorrelationId: "corr-123", CausationId: "evt-abc", Priority: "normal", Locale: "en-US", OccurredAt: timestamppb.New(time.Now()), Attributes: map[string]string{"region": "us-east-1"}, }, MerchantUuid: "m-123", MerchantKey: "acme", RecipientEmails: []string{"owner@acme.test"}, TemplateHint: "merchant_welcome_v1", }
- Identity invitation (publisher or tests)
import ( identitynotifs "github.com/next-trace/scg-notification-contracts/gen/go/proto/scg/identity/v1" commonv1 "github.com/next-trace/scg-notification-contracts/gen/go/proto/scg/common/v1" "time" )
inv := &identitynotifs.UserInvitedRequested{ Meta: &commonv1.NotificationEnvelope{ /* ... as above ... */ }, MerchantUuid: "m-123", UserUuid: "u-456", UserSub: "auth0|abcdef", InviteUrl: "https://console.scg.test/invite?token=...", ExpiresAt: timestamppb.New(time.Now().Add(48 * time.Hour)), TemplateHint: "user_invited_v1", }
Routing reminder:
- Merchant → topic: scg.notifications.merchant.v1, key: merchant_uuid
- Identity → topic: scg.notifications.identity.v1, key: user_uuid or merchant_uuid
- Merchant notifications: scg.notifications.merchant.v1 (key = merchant_uuid)
- Identity notifications: scg.notifications.identity.v1 (key = user_uuid or merchant_uuid)
Event → Notification mapping (aligned with scg-contracts):
- MerchantCreated → MerchantWelcomeRequested
- MerchantSoftDeleted | MerchantHardDeleted → MerchantGoodbyeRequested
- MerchantRestored | MerchantActivated → MerchantReactivatedRequested (optional)
- UserCreated (invite flow) → UserInvitedRequested
- UserDeleted → UserRemovedRequested
PII Policy
- Domain events MUST NOT contain PII.
- Notification messages MAY carry presentation-friendly fields where policy allows.
- Emails appear ONLY in notifications and are optional (e.g., recipient_emails in MerchantWelcomeRequested).
We follow Semantic Versioning (SemVer):
- MAJOR: backward-incompatible changes to protobuf contracts
- MINOR: backward-compatible additions (additive fields/messages, defaults)
- PATCH: non-breaking fixes and docs
Rules of thumb:
- Do NOT renumber fields; only append new field numbers
- Do NOT change field types or semantics in place
- Prefer new messages over mutating existing ones for behavior changes
- Mark deprecated fields with the deprecated option; keep them until next MAJOR
Consumer guidance:
- Pin to a tag in go.mod (e.g., v1.2.3) and avoid main
- Before upgrading major versions, assess with:
- buf breaking --against '.git#tag=v1.2.3'
- Create feature branch
- Make additive changes only unless preparing a MAJOR release
- Run locally:
- buf lint
- buf breaking --against '.git#branch=main'
- buf generate
- go build ./...
- Open PR with clear description and impact
- After merge, tag release (MAJOR/MINOR/PATCH) and publish
- Choose appropriate package under proto/scg//v1
- Import scg.common.v1.NotificationEnvelope and include
meta
field - Use json_name on every field (snake_case)
- Do NOT include PII unless policy allows (and only within notifications)
- Document topic and key routing in README (or message comments)
- Run buf lint, buf breaking, buf generate and verify go build
- CI runs build, tests, linting, security scans, and protobuf generation
- Buf linting and breaking checks are executed in CI to protect stability
Quick checks locally:
- buf lint
- buf breaking --against '.git#branch=main'
- buf generate
- go build ./...
- protoc-gen-go not found: ensure GOPATH/bin (or Go install dir) is on PATH
- Mismatched JSON names: rerun buf generate and verify json_name in .proto
- Import path issues: use generated paths under gen/go/proto/scg/... in imports
MIT License. See LICENSE.
If you discover a security issue, please do not open a public issue. Instead, follow SECURITY.md or contact the maintainers privately.
Changes are tracked via Git tags and Git history. See CHANGELOG.md when present.
Contract-first, stability-focused. Run Buf checks and avoid breaking changes unless performing a planned MAJOR release.