package store import ( "context" "encoding/json" "time" ) // ClusterNode represents a registered node in the cluster registry. type ClusterNode struct { NodeID string `json:"node_id"` Endpoint string `json:"endpoint"` Seq int `json:"seq"` RegisteredAt time.Time `json:"registered_at"` Heartbeat time.Time `json:"heartbeat"` Stats json.RawMessage `json:"stats"` } // ClusterStore manages the node_registry table for cluster self-assembly. // Postgres-only — SQLite deployments set this to nil. type ClusterStore interface { // Register inserts or re-registers a node (idempotent). Register(ctx context.Context, nodeID, endpoint string) error // Heartbeat updates the node's heartbeat timestamp and stats. // Returns rows affected — 0 means the node was swept (self-eviction). Heartbeat(ctx context.Context, nodeID string, stats json.RawMessage) (int64, error) // SweepStale deletes nodes whose heartbeat is older than threshold. SweepStale(ctx context.Context, threshold time.Duration) (int64, error) // ListNodes returns all registered nodes ordered by sequence. ListNodes(ctx context.Context) ([]ClusterNode, error) // Deregister removes a node (best-effort cleanup on shutdown). Deregister(ctx context.Context, nodeID string) error }