+12
-13
cmd/server/main.go
·········
·········
+1
-2
internal/api/handlers/aggregator/errors.go
+1
-2
internal/api/handlers/aggregator/get_services.go
+1
-2
internal/api/handlers/aggregator/list_for_community.go
+1
-2
internal/api/handlers/comments/errors.go
+2
-3
internal/api/handlers/comments/get_comments.go
+1
-2
internal/api/handlers/comments/middleware.go
+1
-2
internal/api/handlers/comments/service_adapter.go
+2
-3
internal/api/handlers/community/block.go
+2
-3
internal/api/handlers/community/create.go
+1
-2
internal/api/handlers/community/errors.go
+1
-2
internal/api/handlers/community/get.go
+1
-2
internal/api/handlers/community/list.go
+1
-2
internal/api/handlers/community/search.go
+2
-3
internal/api/handlers/community/subscribe.go
+2
-3
internal/api/handlers/community/update.go
+1
-2
internal/api/handlers/communityFeed/errors.go
+1
-2
internal/api/handlers/communityFeed/get_community.go
+1
-2
internal/api/handlers/discover/errors.go
+1
-2
internal/api/handlers/discover/get_discover.go
+2
-3
internal/api/handlers/post/create.go
+2
-3
internal/api/handlers/post/errors.go
+1
-2
internal/api/handlers/timeline/errors.go
+2
-3
internal/api/handlers/timeline/get_timeline.go
+1
-2
internal/api/middleware/auth.go
+1
-2
internal/api/routes/user.go
+1
-2
internal/atproto/jetstream/aggregator_consumer.go
+2
-3
internal/atproto/jetstream/comment_consumer.go
+3
-4
internal/atproto/jetstream/community_consumer.go
······
······
+3
-4
internal/atproto/jetstream/post_consumer.go
······
+2
-3
internal/atproto/jetstream/user_consumer.go
+3
-4
internal/atproto/jetstream/vote_consumer.go
+1
-2
internal/core/aggregators/service.go
+50
-37
internal/core/comments/comment_service.go
·········
·········+// DATA INTEGRITY: Community should always exist for posts. If missing, it indicates orphaned data.
+15
-16
internal/core/comments/comment_service_test.go
······-listByParentWithHotRankFunc func(ctx context.Context, parentURI string, sort string, timeframe string, limit int, cursor *string) ([]*Comment, *string, error)listByParentsBatchFunc func(ctx context.Context, parentURIs []string, sort string, limitPerParent int) (map[string][]*Comment, error)getVoteStateForCommentsFunc func(ctx context.Context, viewerDID string, commentURIs []string) (map[string]interface{}, error)······-func createTestComment(uri string, commenterDID string, commenterHandle string, rootURI string, parentURI string, replyCount int) *Comment {·········comment1 := createTestComment("at://did:plc:commenter123/comment/1", commenterDID, "commenter.test", postURI, postURI, 0)comment2 := createTestComment("at://did:plc:commenter123/comment/2", commenterDID, "commenter.test", postURI, postURI, 0)-commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI string, sort string, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···-commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI string, sort string, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···-commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI string, sort string, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···comment1 := createTestComment("at://did:plc:commenter123/comment/1", commenterDID, "commenter.test", postURI, postURI, 0)-commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI string, sort string, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···comment1 := createTestComment("at://did:plc:commenter123/comment/1", commenterDID, "commenter.test", postURI, postURI, 0)-commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI string, sort string, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···-commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI string, sort string, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···
······+listByParentWithHotRankFunc func(ctx context.Context, parentURI, sort, timeframe string, limit int, cursor *string) ([]*Comment, *string, error)listByParentsBatchFunc func(ctx context.Context, parentURIs []string, sort string, limitPerParent int) (map[string][]*Comment, error)getVoteStateForCommentsFunc func(ctx context.Context, viewerDID string, commentURIs []string) (map[string]interface{}, error)······+func createTestComment(uri, commenterDID, commenterHandle, rootURI, parentURI string, replyCount int) *Comment {·········comment1 := createTestComment("at://did:plc:commenter123/comment/1", commenterDID, "commenter.test", postURI, postURI, 0)comment2 := createTestComment("at://did:plc:commenter123/comment/2", commenterDID, "commenter.test", postURI, postURI, 0)+commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI, sort, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···+commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI, sort, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···+commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI, sort, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···comment1 := createTestComment("at://did:plc:commenter123/comment/1", commenterDID, "commenter.test", postURI, postURI, 0)+commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI, sort, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···comment1 := createTestComment("at://did:plc:commenter123/comment/1", commenterDID, "commenter.test", postURI, postURI, 0)+commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI, sort, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···+commentRepo.listByParentWithHotRankFunc = func(ctx context.Context, parentURI, sort, timeframe string, limit int, cursor *string) ([]*Comment, *string, error) {···
+1
-2
internal/core/communities/service.go
+1
-2
internal/core/communityFeeds/service.go
+1
-2
internal/core/communityFeeds/types.go
+1
-2
internal/core/discover/types.go
+1
internal/core/posts/post.go
+3
-4
internal/core/posts/service.go
+1
-2
internal/core/timeline/types.go
+1
-2
internal/core/users/service.go
+1
-2
internal/db/postgres/aggregator_repo.go
+1
-2
internal/db/postgres/comment_repo.go
+1
-2
internal/db/postgres/community_repo.go
+1
-2
internal/db/postgres/community_repo_blocks.go
+1
-2
internal/db/postgres/community_repo_memberships.go
+1
-2
internal/db/postgres/community_repo_subscriptions.go
+3
-4
internal/db/postgres/discover_repo.go
·········
······+p.community_did, c.handle as community_handle, c.name as community_name, c.avatar_cid as community_avatar,···+p.community_did, c.handle as community_handle, c.name as community_name, c.avatar_cid as community_avatar,
+17
-334
internal/db/postgres/feed_repo.go
···"hot": `(p.score / POWER(EXTRACT(EPOCH FROM (NOW() - p.created_at))/3600 + 2, 1.5)) DESC, p.created_at DESC, p.uri DESC`,···-const hotRankExpression = `(p.score / POWER(EXTRACT(EPOCH FROM (NOW() - p.created_at))/3600 + 2, 1.5))`func (r *postgresFeedRepo) GetCommunityFeed(ctx context.Context, req communityFeeds.GetCommunityFeedRequest) ([]*communityFeeds.FeedViewPost, *string, error) {·········-func (r *postgresFeedRepo) parseCursor(cursor *string, sort string) (string, []interface{}, error) {-filter := `AND (p.score < $3 OR (p.score = $3 AND p.created_at < $4) OR (p.score = $3 AND p.created_at = $4 AND p.uri < $5))`-filter := fmt.Sprintf(`AND ((%s < $3 OR (%s = $3 AND p.created_at < $4) OR (%s = $3 AND p.created_at = $4 AND p.uri < $5)) AND p.uri != $6)`,-func (r *postgresFeedRepo) buildCursor(post *posts.PostView, sort string, hotRank float64) string {-cursorStr = fmt.Sprintf("%s%s%s", post.CreatedAt.Format(time.RFC3339Nano), delimiter, post.URI)-cursorStr = fmt.Sprintf("%d%s%s%s%s", score, delimiter, post.CreatedAt.Format(time.RFC3339Nano), delimiter, post.URI)-cursorStr = fmt.Sprintf("%s%s%s%s%s", hotRankStr, delimiter, post.CreatedAt.Format(time.RFC3339Nano), delimiter, post.URI)-func (r *postgresFeedRepo) scanFeedViewPost(rows *sql.Rows) (*communityFeeds.FeedViewPost, float64, error) {-// TODO(feed-generator): Implement viewer state (saved, voted, blocked) in feed generator skeleton
···"hot": `(p.score / POWER(EXTRACT(EPOCH FROM (NOW() - p.created_at))/3600 + 2, 1.5)) DESC, p.created_at DESC, p.uri DESC`,···+const communityFeedHotRankExpression = `(p.score / POWER(EXTRACT(EPOCH FROM (NOW() - p.created_at))/3600 + 2, 1.5))`+feedRepoBase: newFeedRepoBase(db, communityFeedHotRankExpression, communityFeedSortClauses, cursorSecret),func (r *postgresFeedRepo) GetCommunityFeed(ctx context.Context, req communityFeeds.GetCommunityFeedRequest) ([]*communityFeeds.FeedViewPost, *string, error) {···+p.community_did, c.handle as community_handle, c.name as community_name, c.avatar_cid as community_avatar,+p.community_did, c.handle as community_handle, c.name as community_name, c.avatar_cid as community_avatar,······
+15
-3
internal/db/postgres/feed_repo_base.go
··················
··················
+1
-2
internal/db/postgres/post_repo.go
+3
-4
internal/db/postgres/timeline_repo.go
·········
······+p.community_did, c.handle as community_handle, c.name as community_name, c.avatar_cid as community_avatar,···+p.community_did, c.handle as community_handle, c.name as community_name, c.avatar_cid as community_avatar,
+1
-2
internal/db/postgres/user_repo.go
+1
-2
internal/db/postgres/vote_repo.go
+1
-2
internal/db/postgres/vote_repo_test.go
+4
-5
tests/e2e/user_signup_test.go
······
······
+10
-11
tests/integration/aggregator_e2e_test.go
······
······
+3
-4
tests/integration/aggregator_test.go
+3
-4
tests/integration/comment_consumer_test.go
+3
-4
tests/integration/comment_query_test.go
······
······
+4
-5
tests/integration/comment_vote_test.go
···
···
+2
-3
tests/integration/community_blocking_test.go
+4
-5
tests/integration/community_consumer_test.go
···
···
+2
-3
tests/integration/community_credentials_test.go
+8
-9
tests/integration/community_e2e_test.go
······
······
+2
-3
tests/integration/community_hostedby_security_test.go
+2
-3
tests/integration/community_identifier_resolution_test.go
+2
-3
tests/integration/community_provisioning_test.go
+2
-3
tests/integration/community_repo_test.go
+2
-3
tests/integration/community_service_integration_test.go
+3
-4
tests/integration/community_v2_validation_test.go
···// TestCommunityConsumer_V2RKeyValidation tests that only V2 communities (rkey="self") are accepted
···// TestCommunityConsumer_V2RKeyValidation tests that only V2 communities (rkey="self") are accepted
+2
-3
tests/integration/discover_test.go
+20
-15
tests/integration/feed_test.go
·······································
·······································
+2
-3
tests/integration/helpers.go
+1
-2
tests/integration/identity_resolution_test.go
+3
-4
tests/integration/jetstream_consumer_test.go
+4
-5
tests/integration/post_creation_test.go
···
···
+8
-9
tests/integration/post_e2e_test.go
······
······
+5
-6
tests/integration/post_handler_test.go
···
···
+2
-3
tests/integration/subscription_indexing_test.go
+3
-4
tests/integration/timeline_test.go
+2
-3
tests/integration/token_refresh_test.go
···// TestTokenRefresh_ExpirationDetection tests the NeedsRefresh function with various token states
+4
-5
tests/integration/user_test.go
······
······