diff --git a/internal/domain/domain.go b/internal/domain/domain.go new file mode 100644 index 0000000..8b0f1eb --- /dev/null +++ b/internal/domain/domain.go @@ -0,0 +1,80 @@ +// Package domain holds Tapir's core entities. It depends on nothing outside +// the standard library — no providers, no storage, no AI. See docs/data-model.md. +package domain + +import "time" + +// Provider identifies a video platform. +type Provider string + +const ( + ProviderYouTube Provider = "youtube" + ProviderVimeo Provider = "vimeo" +) + +// TranscriptSource records how a transcript was obtained (or that there was none). +type TranscriptSource string + +const ( + SourceCaptions TranscriptSource = "captions" + SourceNone TranscriptSource = "none" +) + +// User is the Tapir-side profile. At Stage 0 there is exactly one. +type User struct { + ID string + DisplayName string + CreatedAt time.Time +} + +// Subscription is a watched channel on a connected account. +type Subscription struct { + ID string + UserID string + ConnectionID string + ChannelID string + ChannelTitle string + Active bool +} + +// Video is a single video seen for a user (per-user, not globally deduped — +// see docs/data-model.md and DECISIONS.md "Rejected alternatives"). +type Video struct { + ID string + UserID string + SubscriptionID string + Provider Provider + ProviderVideoID string + Title string + URL string + PublishedAt time.Time + SeenAt time.Time +} + +// Transcript is the text of a video (or a record that none was available). +type Transcript struct { + VideoID string + UserID string + Source TranscriptSource + Language string + Content string // empty when Source == SourceNone +} + +// HasText reports whether the transcript carries usable text. +func (t Transcript) HasText() bool { + return t.Source != SourceNone && t.Content != "" +} + +// Summary is the produced output for a video. +type Summary struct { + ID string + UserID string + VideoID string + Summary string + Highlights []string + Takeaways []string + AIProvider string // "local" | "anthropic" | "openai" | "gemini" + AIModel string + FallbackUsed bool + CreatedAt time.Time +}