Files
member-console/cmd/bootstate.go
T
cgalo5758 88db730fcc Add dual licensing and SPDX headers
Introduce a commercial license option alongside AGPL-3.0-only, require a
CLA for contributors, and document the terms in COMMERCIAL.md and
NOTICE. Add a script to stamp SPDX headers on Go files and apply it
across the tree.
2026-09-06 02:29:42 -05:00

87 lines
3.6 KiB
Go

// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial
// SPDX-FileCopyrightText: 2025-2026 Christian Galo
package cmd
import (
"context"
"database/sql"
"fmt"
"log/slog"
"time"
"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/integration"
"git.coopcloud.tech/wiki-cafe/member-console/internal/integrations"
"git.coopcloud.tech/wiki-cafe/member-console/internal/systemtenant"
)
// ensureBootDataState performs the data-state work `start` does after
// migrations and before serving, and `seed-demo` does before seeding, so a
// database that was reset, migrated, and reseeded (test/reset-app-db.sh,
// the screen-capture utility's first step) holds exactly what a booted
// deployment holds:
//
// - every installed integration's provider record, after its key is
// checked against its manifest (integration-registration);
// - the System tenant (system-tenant);
// - expired pending domain claims swept (claim-expiry-and-carve-guards
// D1/D3): core registry work with no integration in it, run BEFORE the
// reconciliation below because a stranded pending external claim at a
// configured farm domain is exactly what makes EnsureOperatorRoot fail;
// logged, not fatal, since an unswept claim holds one name where an
// unensurable root leaves every hosted name unallocatable;
// - monthly RANGE partitions for core.webhook_events for the months ahead
// (webhook-partition-maintenance); logged, not fatal;
// - each integration's domains reconciliation (design D8): operator roots
// ensured from deployment configuration and placements backfilled for
// resources that predate the registry. Unconditional, not an
// integration's Startup hook, which runs only when Temporal is
// configured. Fatal: a registry that does not fit the deployment's own
// namespace configuration is a misconfiguration.
func ensureBootDataState(ctx context.Context, database *sql.DB, logger *slog.Logger, integs []integrations.Integration) error {
providerSources := make([]integration.ProviderSource, 0, len(integs))
for _, integ := range integs {
ps := integ.Provider()
if err := integration.AssertKeyMatch(integ.Key(), ps.ProviderManifest()); err != nil {
return fmt.Errorf("integration key mismatch: %w", err)
}
providerSources = append(providerSources, ps)
}
if err := integration.RegisterProviders(ctx, database, providerSources); err != nil {
return fmt.Errorf("register providers: %w", err)
}
if _, err := systemtenant.Ensure(ctx, database); err != nil {
return fmt.Errorf("ensure system tenant: %w", err)
}
if result, err := domains.NewRegistry(database).SweepExpiredClaims(ctx); err != nil {
logger.Error("domain claim expiry sweep failed",
slog.Int("candidates", result.Candidates),
slog.Int("expired", result.Expired),
slog.Int("failed", result.Failed),
slog.Any("error", err))
} else if result.Candidates > 0 {
logger.Info("domain claim expiry sweep completed",
slog.Int("candidates", result.Candidates),
slog.Int("expired", result.Expired))
}
if err := db.EnsureWebhookEventPartitions(ctx, database, time.Now(), db.DefaultWebhookPartitionMonthsAhead); err != nil {
logger.Warn("webhook_events partition ensure failed", slog.Any("error", err))
}
for _, integ := range integs {
dr, ok := integ.(domainsReconciler)
if !ok {
continue
}
if err := dr.ReconcileDomains(ctx, database, logger); err != nil {
return fmt.Errorf("reconcile domains registry for %s: %w", integ.Key(), err)
}
}
return nil
}