A community based topic aggregation platform built on atproto
1package communities
2
3import (
4 "time"
5)
6
7// Community represents a Coves community indexed from the firehose
8// Communities are federated, instance-scoped forums built on atProto
9type Community struct {
10 ID int `json:"id" db:"id"`
11 DID string `json:"did" db:"did"` // Permanent community identifier (did:plc:xxx)
12 Handle string `json:"handle" db:"handle"` // Scoped handle (!gaming@coves.social)
13 Name string `json:"name" db:"name"` // Short name (local part of handle)
14 DisplayName string `json:"displayName" db:"display_name"` // Display name for UI
15 Description string `json:"description" db:"description"` // Community description
16 DescriptionFacets []byte `json:"descriptionFacets,omitempty" db:"description_facets"` // Rich text annotations (JSONB)
17
18 // Media
19 AvatarCID string `json:"avatarCid,omitempty" db:"avatar_cid"` // CID of avatar image
20 BannerCID string `json:"bannerCid,omitempty" db:"banner_cid"` // CID of banner image
21
22 // Ownership
23 OwnerDID string `json:"ownerDid" db:"owner_did"` // V2: same as DID (community owns itself)
24 CreatedByDID string `json:"createdByDid" db:"created_by_did"` // User who created the community
25 HostedByDID string `json:"hostedByDid" db:"hosted_by_did"` // Instance hosting this community
26
27 // V2: PDS Account Credentials (NEVER expose in public API responses!)
28 PDSEmail string `json:"-" db:"pds_email"` // System email for PDS account
29 PDSPasswordHash string `json:"-" db:"pds_password_hash"` // bcrypt hash for re-authentication
30 PDSAccessToken string `json:"-" db:"pds_access_token"` // JWT for API calls (expires)
31 PDSRefreshToken string `json:"-" db:"pds_refresh_token"` // For refreshing sessions
32 PDSURL string `json:"-" db:"pds_url"` // PDS hosting this community's repo
33
34 // Visibility & Federation
35 Visibility string `json:"visibility" db:"visibility"` // public, unlisted, private
36 AllowExternalDiscovery bool `json:"allowExternalDiscovery" db:"allow_external_discovery"` // Can other instances index?
37
38 // Moderation
39 ModerationType string `json:"moderationType,omitempty" db:"moderation_type"` // moderator, sortition
40 ContentWarnings []string `json:"contentWarnings,omitempty" db:"content_warnings"` // NSFW, violence, spoilers
41
42 // Statistics (cached counts)
43 MemberCount int `json:"memberCount" db:"member_count"`
44 SubscriberCount int `json:"subscriberCount" db:"subscriber_count"`
45 PostCount int `json:"postCount" db:"post_count"`
46
47 // Federation metadata (future: Lemmy interop)
48 FederatedFrom string `json:"federatedFrom,omitempty" db:"federated_from"` // lemmy, coves
49 FederatedID string `json:"federatedId,omitempty" db:"federated_id"` // Original ID on source platform
50
51 // Timestamps
52 CreatedAt time.Time `json:"createdAt" db:"created_at"`
53 UpdatedAt time.Time `json:"updatedAt" db:"updated_at"`
54
55 // AT-Proto metadata
56 RecordURI string `json:"recordUri,omitempty" db:"record_uri"` // AT-URI of community profile record
57 RecordCID string `json:"recordCid,omitempty" db:"record_cid"` // CID of community profile record
58}
59
60// Subscription represents a lightweight feed follow (user subscribes to see posts)
61type Subscription struct {
62 ID int `json:"id" db:"id"`
63 UserDID string `json:"userDid" db:"user_did"`
64 CommunityDID string `json:"communityDid" db:"community_did"`
65 SubscribedAt time.Time `json:"subscribedAt" db:"subscribed_at"`
66
67 // AT-Proto metadata (subscription is a record in user's repo)
68 RecordURI string `json:"recordUri,omitempty" db:"record_uri"`
69 RecordCID string `json:"recordCid,omitempty" db:"record_cid"`
70}
71
72// Membership represents active participation with reputation tracking
73type Membership struct {
74 ID int `json:"id" db:"id"`
75 UserDID string `json:"userDid" db:"user_did"`
76 CommunityDID string `json:"communityDid" db:"community_did"`
77 ReputationScore int `json:"reputationScore" db:"reputation_score"` // Gained through participation
78 ContributionCount int `json:"contributionCount" db:"contribution_count"` // Posts + comments + actions
79 JoinedAt time.Time `json:"joinedAt" db:"joined_at"`
80 LastActiveAt time.Time `json:"lastActiveAt" db:"last_active_at"`
81
82 // Moderation status
83 IsBanned bool `json:"isBanned" db:"is_banned"`
84 IsModerator bool `json:"isModerator" db:"is_moderator"`
85}
86
87// ModerationAction represents a moderation action taken against a community
88type ModerationAction struct {
89 ID int `json:"id" db:"id"`
90 CommunityDID string `json:"communityDid" db:"community_did"`
91 Action string `json:"action" db:"action"` // delist, quarantine, remove
92 Reason string `json:"reason,omitempty" db:"reason"`
93 InstanceDID string `json:"instanceDid" db:"instance_did"` // Which instance took this action
94 Broadcast bool `json:"broadcast" db:"broadcast"` // Share signal with network?
95 CreatedAt time.Time `json:"createdAt" db:"created_at"`
96 ExpiresAt *time.Time `json:"expiresAt,omitempty" db:"expires_at"` // Optional: temporary moderation
97}
98
99// CreateCommunityRequest represents input for creating a new community
100type CreateCommunityRequest struct {
101 Name string `json:"name"`
102 DisplayName string `json:"displayName,omitempty"`
103 Description string `json:"description"`
104 AvatarBlob []byte `json:"avatarBlob,omitempty"` // Raw image data
105 BannerBlob []byte `json:"bannerBlob,omitempty"` // Raw image data
106 Rules []string `json:"rules,omitempty"`
107 Categories []string `json:"categories,omitempty"`
108 Language string `json:"language,omitempty"`
109 Visibility string `json:"visibility"` // public, unlisted, private
110 AllowExternalDiscovery bool `json:"allowExternalDiscovery"`
111 CreatedByDID string `json:"createdByDid"` // User creating the community
112 HostedByDID string `json:"hostedByDid"` // Instance hosting the community
113}
114
115// UpdateCommunityRequest represents input for updating community metadata
116type UpdateCommunityRequest struct {
117 CommunityDID string `json:"communityDid"`
118 UpdatedByDID string `json:"updatedByDid"` // User making the update (for authorization)
119 DisplayName *string `json:"displayName,omitempty"`
120 Description *string `json:"description,omitempty"`
121 AvatarBlob []byte `json:"avatarBlob,omitempty"`
122 BannerBlob []byte `json:"bannerBlob,omitempty"`
123 Visibility *string `json:"visibility,omitempty"`
124 AllowExternalDiscovery *bool `json:"allowExternalDiscovery,omitempty"`
125 ModerationType *string `json:"moderationType,omitempty"`
126 ContentWarnings []string `json:"contentWarnings,omitempty"`
127}
128
129// ListCommunitiesRequest represents query parameters for listing communities
130type ListCommunitiesRequest struct {
131 Limit int `json:"limit"`
132 Offset int `json:"offset"`
133 Visibility string `json:"visibility,omitempty"` // Filter by visibility
134 HostedBy string `json:"hostedBy,omitempty"` // Filter by hosting instance
135 SortBy string `json:"sortBy,omitempty"` // created_at, member_count, post_count
136 SortOrder string `json:"sortOrder,omitempty"` // asc, desc
137}
138
139// SearchCommunitiesRequest represents query parameters for searching communities
140type SearchCommunitiesRequest struct {
141 Query string `json:"query"` // Search term
142 Limit int `json:"limit"`
143 Offset int `json:"offset"`
144 Visibility string `json:"visibility,omitempty"` // Filter by visibility
145}