// Package integrations is the composition root's view of the installed // integration set. Each integration lives in its own subtree // (internal/integrations/) 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 }