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:
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user