angee.social.backends
Feed backend contract — poll an external platform for public posts.
A :class:~angee.social.models.Feed (an integrate.Integration child + Bridge) selects one FeedBackend by registry key. The backend does the per-platform transport + parse — fetch_posts returns neutral :class:ParsedPost rows. Each post's core (thread/message/parts) reuses messaging's neutral :class:~angee.messaging.backends.ParsedMessage, so the idempotent (platform, external_id) upsert, the Part/Fragment tree, and thread resolution stay owned by Message.objects.ingest — social never forks that write path. A post adds the social overlay: rolled-up :class:ParsedMetrics, per-actor :class:ParsedReaction\s, and cross-post :class:ParsedRelation\s that the :class:~angee.social.models.Feed maps onto PostMetrics, the reused messaging.Reaction table, and the shared messaging.MessageEdge graph.
Source addons (social_integrate_youtube/…_facebook) contribute concrete backends; the manual null-object keeps ANGEE_SOCIAL_FEED_BACKEND_CLASSES non-empty when no source is installed.
ParsedMetrics
@dataclass(frozen=True)
class ParsedMetrics()Rolled-up public engagement counters parsed for one post.
ParsedReaction
@dataclass(frozen=True)
class ParsedReaction()One attributed reaction on a post (a like/repost or an emoji).
ParsedRelation
@dataclass(frozen=True)
class ParsedRelation()One declared cross-post relation from this post to another post.
dst_external_id names the related post by its platform id; the map resolves both endpoints and writes the edge onto the shared messaging.MessageEdge graph. kind is a messaging.MessageEdge.EdgeKind value (mention / crosspost / forward / quote).
ParsedPost
@dataclass(frozen=True)
class ParsedPost()One public post parsed from a feed — the message core plus the social overlay.
message is the neutral messaging shape (its external_id is the idempotency key, in_reply_to carries the parent post id). is_original_post marks a top-level post (no parent). The overlay is optional and applied after the core lands.
FeedBackend
class FeedBackend(BridgeImpl, HttpClientMixin)Abstract backend that fetches and parses a public feed source.
self.bridge is the Feed row — its config carries the source settings and self.bridge.credential authenticates — and self.http is the shared SSRF-pinned client. Incremental state lives on self.bridge.cursor.
fetch_posts
def fetch_posts() -> list[ParsedPost]Return new posts since the feed cursor as neutral dataclasses.
ManualFeedBackend
class ManualFeedBackend(FeedBackend)The null-object default: a feed with no source backend ingests nothing.
Keeps ANGEE_SOCIAL_FEED_BACKEND_CLASSES non-empty when no source addon is installed (ImplClassField requires a non-empty registry), so the GraphQL enum is never empty and a draft feed always has a selectable backend.
fetch_posts
def fetch_posts() -> list[ParsedPost]Return no posts — a manual feed is populated by hand.