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.
109 lines
5.6 KiB
Go
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
|
|
}
|