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. 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"` // ViewerHasReshared is true when the calling user has reshared this // post. Hydrated by the service layer after the repo returns posts; // always false for anonymous viewers (no viewer = no reshare state). // Drives the post-card "Reshare ↔ Send" swap on the frontend. ViewerHasReshared bool `json:"viewer_has_reshared"` // ResharedAt is the timestamp at which the feed owner reshared this // post. Non-nil only for rows that appear in a profile feed because // the profile owner reshared them (i.e. the row comes from the // post_reshares union branch of ListByUser / ListByHandle). // Authored-by-feed-owner rows leave this nil. Drives the // "↻ Reshared" badge in the post card. ResharedAt *time.Time `json:"reshared_at,omitempty"` } // 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 }