package model import "time" // Post is a public quote on a user's feed. Caption is the verbatim selected // text from the knowledgebase; SourceURL links back to the page the user // was reading. Images are loaded separately via PostImage rows. // // Reshares are real Post rows owned by the resharer, with // ResharedFromPostID pointing to the canonical original. Likes, comments, // and images all hang off the post's own id, so they diverge naturally // across reshare boundaries — no parallel "per-resharer" tables. type Post struct { ID string `json:"id"` UserID string `json:"user_id"` Caption string `json:"caption"` SourceURL string `json:"source_url"` SourceTitle string `json:"source_title"` Images []PostImage `json:"images"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` // Author info — populated by repo joins for feed listings. AuthorName string `json:"author_name,omitempty"` AuthorHandle string `json:"author_handle,omitempty"` AuthorAvatarURL *string `json:"author_avatar_url,omitempty"` // Reshare attribution. ResharedFromPostID is non-nil when this post // is a reshare; the four `Original*` fields carry the canonical // post's author info so the frontend can render a // "Reshared from @handle" link without an extra round-trip. ResharedFromPostID *string `json:"reshared_from_post_id,omitempty"` OriginalAuthorName *string `json:"original_author_name,omitempty"` OriginalAuthorHandle *string `json:"original_author_handle,omitempty"` OriginalAuthorAvatar *string `json:"original_author_avatar_url,omitempty"` // ViewerHasReshared is true when the calling user has reshared the // canonical version of this post. Hydrated by the service layer // after the repo returns posts; always false for anonymous viewers. // Drives the post-card "Reshare ↔ Send" swap on the frontend. ViewerHasReshared bool `json:"viewer_has_reshared"` } // PostImage represents one attached image on a post. type PostImage struct { ID string `json:"id"` URL string `json:"url"` Position int `json:"position"` } // Bookmark is a private "save my place" marker. type Bookmark struct { ID string `json:"id"` UserID string `json:"user_id"` SourceURL string `json:"source_url"` SourceTitle string `json:"source_title"` Excerpt *string `json:"excerpt,omitempty"` Note *string `json:"note,omitempty"` CreatedAt time.Time `json:"created_at"` } // CollectionRecord is a user-curated group of posts. // // Renamed to avoid colliding with the legacy `Collection` model in user.go // from when bookmarks/collections were sketched out earlier. Once that old // model is unused we can drop it; for now this keeps both compiling. type CollectionRecord struct { ID string `json:"id"` UserID string `json:"user_id"` Title string `json:"title"` Description *string `json:"description,omitempty"` CoverURL *string `json:"cover_url,omitempty"` IsPublic bool `json:"is_public"` ItemCount int `json:"item_count"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // PublicProfile is what /u/{handle} returns — the parts of a User safe to // expose to anyone, plus aggregate counts and the user's posts. type PublicProfile struct { Handle string `json:"handle"` Name string `json:"name"` AvatarURL *string `json:"avatar_url"` JoinedAt time.Time `json:"joined_at"` PostCount int `json:"post_count"` BookmarkCount int `json:"-"` // never serialized — private }