From 31251a41c34a51233757d37a42f7767d6474aef8 Mon Sep 17 00:00:00 2001 From: mathias Date: Tue, 2 Jun 2026 11:04:48 +0000 Subject: [PATCH] feat: add domain entities (Clean Architecture core) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure domain types matching docs/data-model.md: User, Subscription, Video, Transcript, Summary, plus Provider and TranscriptSource enums. Stdlib-only, no outward dependencies — the innermost layer. Video carries user_id per the per-user-isolation decision (no global dedup). --- internal/domain/domain.go | 80 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 internal/domain/domain.go 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 +}