Files
member-console/internal/integrations/integration.go
T
cgalo5758 dd3962990b Adopt entity keys and add invoice numbers
Replace the entity slugs on organizations, workspaces, resource pools,
and
plan ladders with nullable `key` columns and add keys to products,
prices,
and entitlement sets. Rename `providers.slug` to `provider` and add
partial
unique indexes for system and org role names.

Assign invoice numbers per billing account from a gapless transactional
counter; Stripe's number moves to the invoice mapping as an external
reference.

Seeds, fixtures, and the operator lookup address rows by key, and the
returning-login resync no longer blanks a display name when the IdP
sends
no `name` claim.
2026-08-29 20:12:04 -05:00

109 lines
5.6 KiB
Go

// Package integrations is the composition root's view of the installed
// integration set. Each integration lives in its own subtree
// (internal/integrations/<key>) and is listed once in registry.go's
// All(). Adding an integration is one tree + one registry line — no
// init()-time self-registration.
//
// Import-direction rule (mirrors the FK rule for schemas): integration
// trees MAY import core packages (internal/db, internal/integration,
// internal/server's exported deps, ...); core packages MUST NOT import
// integration trees. Only composition roots — cmd/start.go and
// internal/migrate/sources.go — consume this package.
//
// Cycle note: integration subpackages (e.g. internal/integrations/fedwiki)
// deliberately do NOT import this package. Their New() constructors return
// a concrete type that structurally satisfies Integration; registry.go
// (in this package) is the only place the concrete types are named as the
// interface. This keeps the dependency edge one-directional — this
// package imports the subpackages, never the reverse — which a two-way
// import would turn into a compile-time cycle.
//
// This package deliberately does NOT define a routes capability interface
// (see internal/server.RouteProvider instead): internal/migrate imports
// this package (Sources loops All()), and internal/server's own DB-backed
// tests (internal test files, package server) import internal/migrate —
// so if this package imported internal/server to reference its Deps type,
// internal/server's test binary would cycle (server -> migrate ->
// integrations -> server). Defining RouteProvider at the point of use
// (internal/server, which cmd/start.go already imports to build Config)
// avoids that without weakening the capability-discovery pattern: the
// composition root still type-asserts each Integration from All() against
// server.RouteProvider exactly as it would against a hook declared here.
//
// A workflows capability interface is excluded for the same reason:
// internal/workflows.WorkflowProvider is declared in internal/workflows
// instead of here, so that internal/workflows (which this package's
// registered integrations import, e.g. internal/integrations/stripe ->
// internal/workflows/stripe) never has to import this package to
// reference its own capability type — keeping the design's import-
// direction rule (internal/server and internal/workflows end this change
// with zero integration imports; see design.md Decision 3) true by
// construction rather than by incidental non-cycling. cmd/start.go, which
// already imports both packages to build Config and WorkerConfig,
// type-asserts against workflows.WorkflowProvider exactly as it does
// against server.RouteProvider.
package integrations
import (
"io/fs"
"git.coopcloud.tech/wiki-cafe/member-console/internal/db"
"git.coopcloud.tech/wiki-cafe/member-console/internal/integration"
)
// Integration is the mandatory capability every registered integration
// implements. Optional capabilities (routes, workflows, config, UI
// assets) are discovered by type-asserting an Integration against the
// interfaces below; an integration lacking a capability simply doesn't
// implement the corresponding interface.
type Integration interface {
// Key is the integration's short identifier (e.g. "fedwiki",
// "stripe"). It must match the Key in Provider()'s manifest.
Key() string
// Provider returns the provider-registry manifest source, consumed by
// internal/integration.RegisterProviders at boot.
Provider() integration.ProviderSource
// MigrationSource returns the integration's migration source,
// consumed by internal/migrate.Sources.
MigrationSource() db.MigrationSource
}
// Routes capability: see internal/server.RouteProvider. An integration
// implements it by defining RegisterRoutes(mux *http.ServeMux, deps
// server.Deps) error and CSRFExemptPaths() []string — the same shape this
// package's other capability interfaces follow — but the interface itself
// is declared in internal/server to avoid the import cycle documented in
// this file's package comment.
// Workflows capability: see internal/workflows.WorkflowProvider. An
// integration implements it by defining RegisterWorkflows(w worker.Worker,
// database *sql.DB, logger *slog.Logger) and Startup(ctx, c client.Client,
// taskQueue string, database *sql.DB, logger *slog.Logger) error — again
// the same shape this package's other capability interfaces follow, but
// declared in internal/workflows for the same import-cycle reason as
// RouteProvider above (see internal/workflows.WorkflowProvider's doc
// comment for the concrete cycle it avoids).
// ConfigProvider capability: see internal/config.ConfigProvider. An
// integration implements it by defining ConfigSpec() []config.ConfigKey —
// the same shape this package's other capability interfaces follow, but
// declared in internal/config rather than here: that package is the one
// that actually consumes ConfigKey values (its ValidateStart), and
// cmd/start.go already imports it for that call, so declaring the type
// there means internal/config never has to import this package (and,
// transitively, every concrete adapter's own dependencies — internal/
// server, internal/workflows/*, the Temporal client) merely to reference a
// plain declaration struct. Same reasoning as the Routes/Workflows
// capability pointers above.
// UIProvider is implemented by integrations that ship templates and/or
// static assets. Both filesystems are key-namespaced: template files,
// defined template names, and static asset paths must be prefixed with
// the integration's key.
type UIProvider interface {
Templates() fs.FS
Static() fs.FS
}