feat: add domain entities (Clean Architecture core)

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).
This commit is contained in:
mathias
2026-06-02 11:04:48 +00:00
parent 9268c99f5e
commit 31251a41c3
+80
View File
@@ -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
}