package domain import ( "crypto/rand" "encoding/hex" "fmt" "regexp" "strings" "time" ) // NewID generates a readable prefixed ID as specified in BRAIN.md (e.g. th_4x8z19a0b1) func NewID(prefix string) string { b := make([]byte, 5) _, _ = rand.Read(b) return fmt.Sprintf("%s_%s", prefix, hex.EncodeToString(b)) } // NowISO returns the current UTC timestamp in ISO-8601 format func NowISO() string { return time.Now().UTC().Format(time.RFC3339) } var hashtagRegex = regexp.MustCompile(`#([a-zA-Z0-9äöüÄÖÜß_-]+)`) // ExtractTags extracts #hashtags from content func ExtractTags(content string) []string { matches := hashtagRegex.FindAllStringSubmatch(content, -1) seen := make(map[string]bool) tags := make([]string, 0, len(matches)) for _, m := range matches { if len(m) > 1 { tag := strings.ToLower(m[1]) if !seen[tag] { seen[tag] = true tags = append(tags, tag) } } } return tags } // FormatGermanDateTime formats an ISO-8601 string into "25. Okt. 2026 - 15:40 Uhr" func FormatGermanDateTime(isoStr string) string { if isoStr == "" { return "" } var t time.Time var err error formats := []string{ time.RFC3339Nano, time.RFC3339, "2006-01-02T15:04:05Z07:00", "2006-01-02T15:04:05", "2006-01-02 15:04:05", "2006-01-02", } for _, f := range formats { if parsed, parseErr := time.Parse(f, isoStr); parseErr == nil { t = parsed err = nil break } else { err = parseErr } } if err != nil { return isoStr } t = t.Local() germanMonths := map[time.Month]string{ time.January: "Jan.", time.February: "Feb.", time.March: "März", time.April: "Apr.", time.May: "Mai", time.June: "Juni", time.July: "Juli", time.August: "Aug.", time.September: "Sept.", time.October: "Okt.", time.November: "Nov.", time.December: "Dez.", } mStr := germanMonths[t.Month()] if mStr == "" { mStr = t.Format("Jan") } return fmt.Sprintf("%d. %s %d - %02d:%02d Uhr", t.Day(), mStr, t.Year(), t.Hour(), t.Minute()) } type User struct { ID string `json:"id"` Email string `json:"email"` Username string `json:"username,omitempty"` PasswordHash string `json:"-"` DisplayName string `json:"displayName"` AvatarURL string `json:"avatarUrl,omitempty"` Role string `json:"role"` // admin | member IsActive bool `json:"isActive"` AlarmChannels []string `json:"alarmChannels"` // email | discord | webhook AlarmEmail string `json:"alarmEmail"` DiscordWebhookURL string `json:"discordWebhookUrl"` CustomWebhookURL string `json:"customWebhookUrl"` NotifyBeforeMinutes int `json:"notifyBeforeMinutes"` CreatedAt string `json:"createdAt"` } type UserInvite struct { ID string `json:"id"` Code string `json:"code"` Email string `json:"email,omitempty"` Role string `json:"role"` // member | admin TeamID string `json:"teamId,omitempty"` TeamName string `json:"teamName,omitempty"` CreatedBy string `json:"createdBy"` ExpiresAt string `json:"expiresAt"` UsedBy string `json:"usedBy,omitempty"` CreatedAt string `json:"createdAt"` } type ThoughtStatus string const ( StatusInbox ThoughtStatus = "inbox" StatusKept ThoughtStatus = "kept" StatusDiscarded ThoughtStatus = "discarded" StatusConverted ThoughtStatus = "converted" ) type SubTask struct { ID string `json:"id"` Title string `json:"title"` IsCompleted bool `json:"isCompleted"` CreatedAt string `json:"createdAt,omitempty"` } type Thought struct { ID string `json:"id"` UserID string `json:"userId"` Content string `json:"content"` Tags []string `json:"tags"` Priority string `json:"priority"` // low | normal | high | urgent Source string `json:"source"` // manual | voice | webhook Status ThoughtStatus `json:"status"` IsCompleted bool `json:"isCompleted"` ConvertedType string `json:"convertedType,omitempty"` // task | document | list_item ConvertedRefID string `json:"convertedRefId,omitempty"` // referenced entity ID DueDate string `json:"dueDate,omitempty"` TaskListID string `json:"taskListId,omitempty"` KanbanStatus string `json:"kanbanStatus,omitempty"` // todo | in_progress | done Notes string `json:"notes,omitempty"` Subtasks []SubTask `json:"subtasks"` AlarmSent bool `json:"alarmSent,omitempty"` SortOrder int `json:"sortOrder"` CreatedAt string `json:"createdAt"` TriagedAt string `json:"triagedAt,omitempty"` } type ThoughtReorderItem struct { ID string `json:"id"` SortOrder int `json:"sortOrder"` KanbanStatus *string `json:"kanbanStatus,omitempty"` } type ListItemReorderItem struct { ID string `json:"id"` SortOrder int `json:"sortOrder"` Category *string `json:"category,omitempty"` Content *string `json:"content,omitempty"` } type TaskListShare struct { ID string `json:"id"` TaskListID string `json:"taskListId"` TargetType string `json:"targetType"` // team | user TargetID string `json:"targetId"` TargetName string `json:"targetName,omitempty"` Email string `json:"email,omitempty"` AvatarURL string `json:"avatarUrl,omitempty"` CreatedAt string `json:"createdAt"` } type TaskListMember struct { UserID string `json:"userId"` DisplayName string `json:"displayName"` Email string `json:"email"` AvatarURL string `json:"avatarUrl,omitempty"` Role string `json:"role"` // owner | member } type KanbanColumn struct { ID string `json:"id"` Name string `json:"name"` Color string `json:"color,omitempty"` IsDone bool `json:"isDone,omitempty"` } type TaskList struct { ID string `json:"id"` UserID string `json:"userId"` SpaceID string `json:"spaceId,omitempty"` SpaceName string `json:"spaceName,omitempty"` TeamID string `json:"teamId,omitempty"` TeamName string `json:"teamName,omitempty"` OwnerName string `json:"ownerName,omitempty"` IsOwner bool `json:"isOwner"` Members []TaskListMember `json:"members,omitempty"` Shares []TaskListShare `json:"shares,omitempty"` Columns []KanbanColumn `json:"columns,omitempty"` Title string `json:"title"` Icon string `json:"icon"` Color string `json:"color"` TasksCount int `json:"tasksCount,omitempty"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` } type Organization struct { ID string `json:"id"` Name string `json:"name"` OwnerID string `json:"ownerId"` Teams []Team `json:"teams,omitempty"` CreatedAt string `json:"createdAt"` } type Team struct { ID string `json:"id"` OrgID string `json:"orgId,omitempty"` Name string `json:"name"` Description string `json:"description"` Members []TeamMember `json:"members"` CreatedAt string `json:"createdAt"` } type TeamMember struct { TeamID string `json:"teamId"` UserID string `json:"userId"` DisplayName string `json:"displayName"` Email string `json:"email"` AvatarURL string `json:"avatarUrl,omitempty"` Role string `json:"role"` // admin | member JoinedAt string `json:"joinedAt"` } type SystemSettings struct { SharingMode string `json:"sharingMode"` // open | teams_only | strict_private AllowRegistration bool `json:"allowRegistration"` InstanceName string `json:"instanceName"` SMTPHost string `json:"smtpHost"` SMTPPort string `json:"smtpPort"` SMTPUser string `json:"smtpUser"` SMTPPass string `json:"smtpPass"` SMTPFrom string `json:"smtpFrom"` SMTPTLS bool `json:"smtpTls"` SMTPConfiguredViaEnv bool `json:"smtpConfiguredViaEnv,omitempty"` } type DocumentBlock struct { ID string `json:"id"` Type string `json:"type"` // h1 | h2 | h3 | paragraph | todo | bullet | code | callout | divider | table | progress Content string `json:"content"` Checked bool `json:"checked,omitempty"` Lang string `json:"lang,omitempty"` Level int `json:"level,omitempty"` Collapsed bool `json:"collapsed,omitempty"` } type DocShare struct { ID string `json:"id"` DocID string `json:"docId"` TargetType string `json:"targetType,omitempty"` // user | team TargetID string `json:"targetId,omitempty"` TargetName string `json:"targetName,omitempty"` UserID string `json:"userId,omitempty"` UserEmail string `json:"userEmail,omitempty"` DisplayName string `json:"displayName,omitempty"` Permission string `json:"permission"` // read | write CreatedBy string `json:"createdBy"` CreatedAt string `json:"createdAt"` } type DocLockInfo struct { DocID string `json:"docId"` UserID string `json:"userId"` UserName string `json:"userName"` ExpiresAt string `json:"expiresAt"` } type Document struct { ID string `json:"id"` UserID string `json:"userId"` SpaceID string `json:"spaceId,omitempty"` Title string `json:"title"` Icon string `json:"icon"` Content string `json:"content"` Blocks []DocumentBlock `json:"blocks"` Tags []string `json:"tags"` FolderPath string `json:"folderPath,omitempty"` IsPinned bool `json:"isPinned"` IsArchived bool `json:"isArchived"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` // Collaboration & Permissions Permission string `json:"permission"` // owner | write | read IsOwner bool `json:"isOwner"` OwnerName string `json:"ownerName,omitempty"` SharedWith []DocShare `json:"sharedWith,omitempty"` } type TagSummary struct { Tag string `json:"tag"` Count int `json:"count"` } type MatchedTagBlock struct { RootBlock DocumentBlock `json:"rootBlock"` Children []DocumentBlock `json:"children"` } type TagDocumentGroup struct { DocID string `json:"docId"` Title string `json:"title"` Icon string `json:"icon"` FolderPath string `json:"folderPath"` UpdatedAt string `json:"updatedAt"` IsOwner bool `json:"isOwner"` Permission string `json:"permission"` OwnerName string `json:"ownerName,omitempty"` MatchedBlocks []MatchedTagBlock `json:"matchedBlocks"` } type TagDetails struct { Tag string `json:"tag"` NoteContent string `json:"noteContent"` NoteUpdatedAt string `json:"noteUpdatedAt,omitempty"` Documents []TagDocumentGroup `json:"documents"` TotalMatches int `json:"totalMatches"` } type ListShare struct { ID string `json:"id"` ListID string `json:"listId"` TargetType string `json:"targetType"` // team | user TargetID string `json:"targetId"` TargetName string `json:"targetName,omitempty"` Email string `json:"email,omitempty"` Role string `json:"role"` // editor | viewer CreatedBy string `json:"createdBy"` CreatedAt string `json:"createdAt"` } type ListItem struct { ID string `json:"id"` ListID string `json:"listId"` Content string `json:"content"` Category string `json:"category,omitempty"` Quantity string `json:"quantity,omitempty"` IsCompleted bool `json:"isCompleted"` CompletedBy string `json:"completedBy,omitempty"` CompletedByName string `json:"completedByName,omitempty"` SortOrder int `json:"sortOrder"` CreatedAt string `json:"createdAt"` CompletedAt string `json:"completedAt,omitempty"` } type SharedList struct { ID string `json:"id"` UserID string `json:"userId"` OwnerName string `json:"ownerName,omitempty"` IsOwner bool `json:"isOwner"` Role string `json:"role,omitempty"` // editor | viewer Title string `json:"title"` Icon string `json:"icon"` ListType string `json:"listType"` // shopping | checklist | vacation Items []ListItem `json:"items"` Shares []ListShare `json:"shares,omitempty"` UpdatedAt string `json:"updatedAt"` CreatedAt string `json:"createdAt"` } type APIKey struct { ID string `json:"id"` UserID string `json:"userId"` Name string `json:"name"` KeyPrefix string `json:"keyPrefix"` KeyHash string `json:"-"` RawKey string `json:"rawKey,omitempty"` // Only returned once on creation Scopes string `json:"scopes"` LastUsedAt string `json:"lastUsedAt,omitempty"` CreatedAt string `json:"createdAt"` } type WSMessage struct { Event string `json:"event"` // ITEM_CREATED | ITEM_UPDATED | ITEM_TOGGLED | ITEM_DELETED | LIST_CLEARED | USER_PRESENCE ListID string `json:"list_id"` Payload interface{} `json:"payload"` Timestamp string `json:"timestamp"` } type DashboardStats struct { InboxCount int `json:"inboxCount"` TasksOpenCount int `json:"tasksOpenCount"` TasksDoneCount int `json:"tasksDoneCount"` DocsCount int `json:"docsCount"` DocsTodosOpenCount int `json:"docsTodosOpenCount"` ListsCount int `json:"listsCount"` DiscardedCount int `json:"discardedCount"` } type FullExport struct { ExportedAt string `json:"exportedAt"` Version string `json:"version"` User User `json:"user"` Thoughts []Thought `json:"thoughts"` Documents []Document `json:"documents"` Lists []SharedList `json:"lists"` TaskLists []TaskList `json:"taskLists,omitempty"` }