Skip to content

paper-board/sdk

github.com/paper-board/sdk is the shared Go library that all seven paper-board backend services import. It provides common infrastructure primitives so each service can stay thin and consistent.

PackageWhat it does
migratorgolang-migrate wrapper + cobra CLI; per-service schema migrations
logslog-based structured logging; context-aware helpers
obsOpenTelemetry SDK setup (OTLP/HTTP exporter; no Prometheus endpoint)
authJWT + API-key HTTP middleware backed by identity gRPC
errorsSentinel errors + gRPC/HTTP status mapping
configEnv-only config loader (MustBind[T])
healthcheckComposable readiness probe registry; built-in DB + gRPC checkers
idempotencyHTTP middleware for Idempotency-Key replay (Stripe-style, 24h TTL)
httpmwShared HTTP middleware: request-id, logger, recover, body-limit, OTLP
httpclientPre-configured *http.Client with OTLP transport and timeouts
storeGeneric WithTx helper for pgx transaction management
clockClock interface + Real / Fake implementations for testing
testfixtureTestcontainers-based Postgres helpers for integration tests

Every backend service pins a released SDK version:

ServicePhasePrimary packages used
agents1.1migrator, log, obs, auth, errors, config, healthcheck
identity2migrator, log, obs, errors, config, healthcheck
runtime3migrator, log, obs, auth, errors, config, healthcheck
compute3log, obs, errors, config, healthcheck
billing5migrator, log, obs, auth, errors, config, healthcheck
platform4migrator, log, obs, auth, errors, config, healthcheck
gateway7log, obs, auth, errors, config, healthcheck, httpmw
github.com/paper-board/sdk
├── migrator/ ← schema migration CLI (ADR-0004)
├── log/ ← structured logging
│ └── redact.go ← secret-scrubbing slog handler
├── obs/ ← OpenTelemetry setup
├── auth/ ← JWT + API-key HTTP middleware
│ └── mock/ ← test double for identity AuthServiceClient
├── errors/ ← sentinels + gRPC/HTTP status mapping
├── config/ ← env-only loader
├── healthcheck/ ← readiness probe registry
├── idempotency/ ← Idempotency-Key middleware
├── httpmw/ ← shared HTTP middleware chain
├── httpclient/ ← pre-configured *http.Client
├── store/ ← pgx transaction helper
├── clock/ ← Clock interface
└── testfixture/ ← integration test helpers
Terminal window
go get github.com/paper-board/sdk@latest

The module is private. Ensure your environment has GOPRIVATE=github.com/paper-board/* and a GitHub PAT configured (see CI setup in paper-board/.github/go-ci.yml).

// cmd/migrator/main.go — ~30 lines, same in every service
package main
import (
"context"
"log"
"os"
"github.com/paper-board/sdk/migrator"
"github.com/paper-board/myservice/migrations" // embed.FS lives here
)
func main() {
cfg := migrator.Config{
DBURL: os.Getenv("MIGRATION_DB_URL"),
Schema: "myservice",
EmbedFS: migrations.SchemaFS,
EmbedRoot: "schema",
}
if err := migrator.Run(context.Background(), cfg, os.Args[1:]); err != nil {
log.Fatal(err)
}
}

MIGRATION_DB_URL must point to direct Postgres (port 5432), never PgBouncer. Advisory locking requires a session-mode connection.

import "github.com/paper-board/sdk/log"
logger := log.New(os.Stdout, "myservice", log.LevelFromEnv())
log.SetDefault(logger)
// In handlers, enrich ctx and log:
ctx = log.WithRequestID(ctx, requestID)
log.Pkg(ctx).Info("request started", "path", r.URL.Path)
import "github.com/paper-board/sdk/obs"
shutdown, err := obs.SetupOTel("myservice", version)
if err != nil {
log.Fatal(err)
}
defer shutdown(context.Background())

Set OTEL_EXPORTER_OTLP_ENDPOINT to your collector; unset = OTLP disabled.

Terminal window
go test -race -count=1 ./...

Integration tests (packages migrator, testfixture) spin up a testcontainers-managed Postgres instance. Docker must be running. CI runs the same command via the reusable workflow in paper-board/.github.