A collection of opinionated Go packages for building hexagonal applications: a
stdlib-only kernel (sdk), reusable third-party connectors (integrations/),
pluggable pocket modules (pockets/), and worked example hosts (examples/)
that prove the design end to end — one on Turso, one with zero external
infrastructure. Gopernicus is open source under the MIT License,
very much a work in progress, and not stable. See ARCHITECTURE.md
for the full layering rules and NOTES.md for the decision log.
sdk/ stdlib-only, layered: root = kernel; pkg/ + capabilities/ (empty go.mod = structural enforcement)
integrations/cryptids/bcrypt/ password-hashing connector (x/crypto), its own module
integrations/cryptids/golang-jwt/ JWT-signing connector (golang-jwt/jwt v5), its own module
integrations/cryptids/google-uuid/ uuid ID-generation connector (google/uuid v4/v7), its own module
integrations/datastores/firestore/ reusable Google Cloud Firestore connector (Native mode; sdk + cloud.google.com/go/firestore), its own module
integrations/datastores/pgxdb/ reusable Postgres connector (sdk + pgx/v5), its own module
integrations/datastores/turso/ reusable Turso/libSQL connector (sdk + libsql), its own module
integrations/email/sendgrid/ SendGrid email connector (sendgrid-go), its own module
integrations/filestorage/gcs/ Google Cloud Storage connector (cloud.google.com/go/storage), its own module
integrations/filestorage/s3/ S3-compatible object-storage connector (aws-sdk-go-v2; MinIO/DO Spaces via endpoint + path-style), its own module
integrations/kvstores/goredis/ Redis connector — events bus, cacher, ratelimiter over one go-redis client, its own module
integrations/oauth/github/ GitHub OAuth provider (vendor API contract; zero external libs), its own module
integrations/oauth/google/ Google OIDC provider connector (coreos/go-oidc v3), its own module
integrations/scheduling/robfig-cron/ cron-expression connector (robfig/cron v3), its own module
integrations/tracing/otel/ OpenTelemetry tracing connector (stdout/OTLP-gRPC exporters or caller-supplied provider), its own module
pockets/ shared host-contract module; requires SDK only
pockets/authentication/ session-auth hexagon — public logic services and HTTP adapters; datastore-free
pockets/authentication/stores/pgx/ auth's pgx store adapter, its own module
pockets/authentication/stores/turso/ auth's Turso store adapter, its own module
pockets/authentication/stores/firestore/ auth's Firestore store adapter (Native mode; no ambient-transaction join — ruling R1), its own module
pockets/authentication/views/goth/ auth's bundled default views (ui/goth), its own module
pockets/authorization/ IAM hexagon — independently wireable kinds (relationships/ReBAC + roles); datastore-free; public memstore/
pockets/authorization/stores/pgx/ authorization's pgx store adapter, its own module
pockets/authorization/stores/turso/ authorization's Turso store adapter, its own module
pockets/authorization/stores/firestore/ authorization's Firestore store adapter (Native mode; no ambient-transaction join — ruling R1), its own module
pockets/cms/ the CMS hexagon — datastore-free; domain/ public rim, internal/ interior
pockets/cms/stores/pgx/ the CMS pocket's pgx store adapter, its own module
pockets/cms/stores/turso/ the CMS pocket's Turso store adapter, its own module
pockets/cms/views/goth/ cms's bundled default views (ui/goth) — the FS3 sibling, its own module
pockets/events/ durable outbox + SSE gateway — public logic services and HTTP adapters; datastore-free
pockets/events/stores/pgx/ events' pgx store adapter, its own module
pockets/events/stores/turso/ events' Turso store adapter, its own module
pockets/jobs/ durable queue + schedules hexagon — datastore-free; public memstore/
pockets/jobs/stores/pgx/ jobs' pgx store adapter, its own module
pockets/jobs/stores/turso/ jobs' Turso store adapter, its own module
ui/goth/ reusable templ + plain-CSS presentation system, its own module
examples/cms/ a host app: pockets/cms on Turso, with a custom theme
examples/minimal/ a host app: pockets/cms on an in-memory store — zero libsql in its module graph
examples/auth-cms/ a host app: auth + cms + events + the authorization flagship composed in-memory (rule 6, live)
examples/jobs-minimal/ a host app: pockets/jobs on its memstore — zero drivers, the §8 protocol host
examples/goth-showcase/ a zero-datastore browser and accessibility proof for ui/goth
workshop/gopernicus/ the scaffolding CLI (init / new pocket / db verbs) — stdlib-only, its own module
go.work resolves these locally for development; real consumers would pin
tagged versions, not the workspace.
-
sdkimports only the standard library. Third-party types cross intosdkonly via structural typing seams (e.g.templ.Componentsatisfyingsdk/pkg/web.Renderer). -
One external dependency ⇒ its own module. A stdlib-only implementation
of an
sdkport ships insidesdkas a default (cacher.Memory,filestorage.Disk,email.SMTP/Console); anything needing a third-party library is anintegrations/<category>/<tech>module. -
A pocket core uses SDK and the shared pocket contract, with per-concern sibling modules.
pockets/<name>'s go.mod permits onlysdkand sharedpockets, and never importsintegrations/,examples/, or its ownstores//views/; eachpockets/<name>/stores/<dialect>is its own module owning that dialect's SQL and migrations, and presentation defaults ship the same way (views/<pkg>, where a pocket has HTML). -
No init() registration, no service locator. A host wires a pocket
explicitly in its
main. Root constructors assemble named components; hosts can also construct focusedlogic/<concern>.Serviceinstances directly. Publicinbound/httpadapters supply optional routes and middleware. CMS retains its earlierRegister(mount, repos, cfg)form while its audit is deferred. -
A UI implementation is a reusable presentation system, not a pocket.
The top-level
ui/family (ui/goth, plannedui/react/ui/vue) is the seventh module kind: it owns view-library dependencies, semantic tokens, components, controllers, and assets, but owns no schema and no routes. It may require its own view/runtime libraries andsdk, and never imports a pocket, integration, example, or workshop package; a pocket reaches it only through that pocket's ownviews/<pkg>adapter module. See ARCHITECTURE.md for the dependency arrows. -
Dependencies point inward.
examples→pockets/integrations→sdk, never the reverse; aui/implementation depends only on its own view/runtime libraries andsdk.make check's twenty-three layering guards enforce this.
See ARCHITECTURE.md for the full detail, including the
pocket contract (pockets), the app-hexagon pattern (internal/logic),
and the Registry content model.
The host side of that boundary has its own charter: examples/README.md is the host contract — rules H0–H10 for a host's layout, imports, host pockets, and composition root, the sibling of pockets/README.md.
Zero external infrastructure — an in-memory store, no libsql in the build:
cd examples/minimal && go run ./cmd/server # localhost:8081 by defaultThe Turso-backed host (needs .env with TURSO_DATABASE_URL/TURSO_AUTH_TOKEN):
cp .env.example .env # fill in Turso credentials
make migrate # applies examples/cms/workshop/migrations pre-boot
make run # or: cd examples/cms && go run ./cmd/serverFrom the repo root, make check builds, vets, and tests all forty-two modules
and runs the twenty-three layering guards; make test-stores runs the live dialect
conformance suites (expects POSTGRES_TEST_DSN / TURSO_* / FIRESTORE_EMULATOR_HOST). See examples/cms/README.md
for that host's full env/make-target reference.
The documentation site lives in workshop/documentation.
It describes the current SDK, pocket and integration boundaries, worked examples,
the optional UI layers, and the Workshop CLI.
make docs-install # install the pinned pnpm dependency graph
make docs # development server at localhost:3000/gopernicus/
make docs-build # type-check and create the production siteGopernicus is currently maintained by jrazmi and contributors. It is open source, but the contribution model is still being figured out. There is no formal contributor guide, support commitment, or release process yet. If you want to propose a change, an issue or pull request is the best place to start; please include the problem, the affected package boundaries, and any compatibility concerns.