package collaboration import ( "crypto/rand" "crypto/sha256" "encoding/hex" "strings" "time" ) func randomID(prefix string) string { buf := make([]byte, 12) if _, err := rand.Read(buf); err != nil { panic(err) } return prefix + ":" + hex.EncodeToString(buf) } func hashAnchor(text string) string { normalized := strings.TrimSpace(text) sum := sha256.Sum256([]byte(normalized)) return hex.EncodeToString(sum[:8]) } func parseTime(raw string) (time.Time, error) { if raw == "" { return time.Time{}, nil } return time.Parse(time.RFC3339, raw) } func formatTime(t time.Time) string { return t.UTC().Format(time.RFC3339) } func ptr[T any](v T) *T { return &v } func nullString(s string) *string { if s == "" { return nil } return &s } func scanNullString(ns *string) string { if ns == nil { return "" } return *ns } func coalesceString(values ...string) string { for _, v := range values { if v != "" { return v } } return "" } func formatDocumentID(path string) string { clean := strings.TrimPrefix(path, "/") clean = strings.TrimSuffix(clean, ".md") return "doc:" + clean } func documentPathFromID(id string) string { return strings.TrimPrefix(id, "doc:") }