Files
member-console/internal/migrate/sources.go
T
cgalo5758 8d05934e93 Add domains registry with claims and placements
Domain names become an allocatable resource with one authority. A new
core module (schema `domains`, own migration stream between core and the
integrations) owns claims — a DNS node plus its whole subtree, mutually
disjoint: operator shared-domain roots, member claims carved from them,
and bring-your-own names proven by TXT verification — and placements,
which bind a name inside a claim to a provider slug and resource ref.

Verification moves to the claim and decouples from creation. A member
proves control of a domain once; afterwards every name inside it places
instantly, wildcard-CNAME friendly, with no further DNS work. The claim
workflow activates the claim and stops — it no longer creates a site —
so the sites list offers a one-click create once a domain verifies.

/domains/ask answers from placements and is registered by core rather
than the FedWiki adapter; its HTTP contract is unchanged. A configured
`domains-ask-fallback-url` forwards names the registry does not know to
a legacy answerer, the strangler seam wiki.cafe's migration needs; a
name the registry knows but has archived is refused locally.

FedWiki's create saga reserves the name before the farm call, carrying a
workflow-minted site id so retries are idempotent, and compensates on
failure. Sync places only names it owns, never stealing a member's;
lifecycle transitions and the retention purge maintain servability. An
unconditional boot pass seeds operator roots, releases orphaned
placements, and adopts pre-existing sites — grandfathering member-owned
external domains shortest-name-first, and skipping name policy, so a
live single-letter site cannot lose its certificate.

Members manage domains at /domains: claims with verification status, DNS
records including an optional wildcard row, check-now, cancel, release.
Name policy (reserved, blocked, premium, plus a single-letter guard) is
operator data; refusals collapse to a plain "unavailable" so the console
never becomes an oracle for who holds what.

BREAKING (pre-release): `fedwiki.custom_domain_verifications` and
`sites.is_custom_domain` are dropped, the flag now derived from the
placement's claim kind; resource key `fedwiki_custom_domains` migrates
to the platform-owned `external_domain_claims`; running
verify-custom-domain workflows must be terminated before deploy.
2026-07-24 21:25:40 -05:00

39 lines
2.0 KiB
Go

// Package migrate exposes the canonical, ordered migration source list for
// the application. Each source runs against its own goose ledger table
// (goose_db_version_<name>) with its native file numbering, so a source's
// version numbers no longer depend on its position in this slice. Ordering
// is still meaningful, in three tiers: core first, because every other
// schema's FKs point at core (never the reverse); then core-module streams
// (currently just `domains`), which FK into core and whose objects
// integrations grant on and write; then the integration streams. Within
// the integration tier order is insignificant — there are no
// integration-to-integration FK edges, so fedwiki and stripe (and any
// future integration) may appear in any order relative to each other.
// Every caller — app boot, the migrate CLI, and DB-backed tests — must
// assemble sources through this package rather than hand-building a subset.
package migrate
import (
"git.coopcloud.tech/wiki-cafe/member-console/internal/db"
"git.coopcloud.tech/wiki-cafe/member-console/internal/domains"
"git.coopcloud.tech/wiki-cafe/member-console/internal/integrations"
)
// Sources returns every migration source in dependency order: core first,
// then the core-module streams, then one source per registered integration
// (see internal/integrations.All). The tiers are load-bearing — core owns
// the FK targets and core_reader; domains owns registry tables that
// integration migrations grant on (fedwiki grants domains_writer to
// fedwiki_writer) and that integration runtime code writes — but the
// relative order of integrations is insignificant; each runs against its
// own version ledger. The core source (internal/db's own baseline) is
// prefixed via db.BaseSources().
func Sources() []db.MigrationSource {
sources := db.BaseSources()
sources = append(sources, domains.MigrationSource())
for _, integ := range integrations.All() {
sources = append(sources, integ.MigrationSource())
}
return sources
}