commits
## ๐ Major Feature: Complete Feed System Implementation
Implements the complete Timeline and Discover feed architecture for Coves,
following atProto patterns with proper separation of concerns (handlers โ
services โ repositories). This is a foundational feature for the alpha release.
### New Features
**Timeline Feed (User-Specific)**
- `social.coves.feed.getTimeline` XRPC endpoint
- Authenticated user feed showing posts from subscribed communities
- Full architecture: Handler โ Service โ Repository
- Integration tests with cursor pagination (368 lines)
**Discover Feed (Public)**
- `social.coves.feed.getDiscover` XRPC endpoint
- Public feed showing recent posts from all communities
- Optimized for performance with documented indexing strategy
- Comprehensive security tests (273 lines)
**Shared Infrastructure**
- Created `feed_repo_base.go` (340 lines) to eliminate code duplication
- Shared lexicon definitions in `social.coves.feed.defs`
- HMAC-SHA256 signed cursors for pagination integrity
- Consistent error handling across both feeds
### Technical Improvements
**Code Quality**
- Eliminated ~700 lines of duplicate code via shared base repository
* timeline_repo.go: 426 โ 131 lines (-69% duplication)
* discover_repo.go: 383 โ 124 lines (-68% duplication)
- Consistent formatting with gofumpt
- Comprehensive inline documentation
**Security Enhancements**
- HMAC cursor signing prevents pagination tampering
- CURSOR_SECRET environment variable for production deployments
- DID format validation (must start with "did:")
- Rate limiting strategy documented (100 req/min per IP)
- Input validation at handler level
**Performance**
- Database indexes documented for optimal query performance
- Cursor-based pagination for large result sets
- Efficient joins between posts, communities, and users
### Aggregator System Updates
**Documentation**
- Documented critical alpha blocker: aggregator user registration
- Aggregators cannot post until indexed as users in AppView
- Proposed solution: `social.coves.aggregator.register` endpoint
- Quick fix alternative documented for testing
**Code Cleanup**
- Consistent formatting across aggregator codebase
- Improved test readability
- Updated PRD with alpha blockers section
### Files Changed (30 files, +2406/-308 lines)
**New Implementations**
- `internal/api/handlers/timeline/` - Timeline XRPC handler
- `internal/api/handlers/discover/` - Discover XRPC handler
- `internal/core/timeline/` - Timeline business logic
- `internal/core/discover/` - Discover business logic
- `internal/db/postgres/feed_repo_base.go` - Shared repository base
- `internal/db/postgres/timeline_repo.go` - Timeline data access
- `internal/db/postgres/discover_repo.go` - Discover data access
- `internal/atproto/lexicon/social/coves/feed/` - Feed lexicons
- `tests/integration/timeline_test.go` - Timeline integration tests
- `tests/integration/discover_test.go` - Discover integration tests
**Updated**
- `cmd/server/main.go` - Feed service initialization
- `internal/api/routes/` - Timeline and discover routes
- `docs/aggregators/PRD_AGGREGATORS.md` - Alpha blocker docs
- `tests/integration/helpers.go` - Shared test utilities
### Testing
- โ
All 11 integration tests passing
- โ
Timeline feed with authentication
- โ
Discover feed security validation
- โ
Cursor pagination integrity
- โ
Aggregator authorization flows
### Migration Path
To revert this entire feature in the future:
```bash
git revert -m 1 <this-merge-commit-id>
```
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add critical alpha blocker documentation for aggregator registration system.
Aggregators cannot post until they are indexed as users in the AppView.
Changes:
- Document aggregator user registration blocker in PRD
- Add proposed solution (registration endpoint)
- Include quick fix alternative for testing
- Code formatting cleanup across aggregator files
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## Critical Issues Fixed
- Removed unused postType/postTypes from lexicon (not implemented)
- Documented database indexes and performance characteristics
- Documented rate limiting strategy for public discover endpoint
## Important Improvements
- Eliminated ~700 lines of duplicate code via shared feed_repo_base.go
* timeline_repo.go: 426 โ 140 lines (-67%)
* discover_repo.go: 383 โ 133 lines (-65%)
- Added HMAC-SHA256 cursor integrity protection
- Created shared lexicon defs.json for feedViewPost types
- Added DID format validation in timeline handler
- Fixed error handling to use errors.Is() for wrapped errors
## Security Enhancements
- HMAC cursor signing prevents tampering
- CURSOR_SECRET environment variable for production
- DID format validation (must start with "did:")
- Rate limiting documented (100 req/min per IP)
## Code Quality
- Duplicate code: 85% โ 0%
- Consistent formatting with gofumpt (extra rules)
- Comprehensive inline documentation
- All 11 tests passing
## Files Changed
- Created: feed_repo_base.go (340 lines shared logic)
- Created: defs.json (shared lexicon types)
- Refactored: timeline_repo.go, discover_repo.go
- Enhanced: Error handlers, route documentation
- Updated: Tests to use cursor secret
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds design documentation for blob upload proxy system to enable
image/video posts in communities from external PDS users.
Problem:
Users on external PDSs cannot directly upload blobs to community-owned
PDS repositories because they lack authentication credentials for the
community's PDS.
Solution:
Coves AppView acts as an authenticated proxy for blob uploads via
social.coves.blob.uploadForCommunity endpoint.
Flow:
1. User uploads blob to AppView
2. AppView validates user can post to community
3. AppView uses community's PDS credentials to upload blob
4. AppView returns CID to user
5. User creates post record referencing the CID
6. Post and blob both live in community's PDS
Status: Design documented, implementation TODO
Priority: CRITICAL for Beta - Required for rich media posts
Implementation checklist includes:
- Handler endpoint
- User authorization validation
- Community credential management
- Upload proxy logic
- Security measures (size limits, content-type validation, rate limiting)
Updates PRD_KAGI_NEWS_RSS.md with Phase 1 implementation results:
Status changes:
- Status: Implementation Phase โ Phase 1 Complete - Ready for Deployment
- Added comprehensive implementation summary section
- All 7 components marked as COMPLETE with test results
Documentation updates:
- Verified feed structure (3 H3 sections only)
- Timeline is website-only feature (not in RSS feed)
- Historical context woven into summary/highlights
- All components updated with implementation status
Test results documented:
- 57 tests passing with 83% coverage
- Detailed breakdown by component
- Test fixtures and strategies documented
Success metrics reorganized:
- Phase 1: Implementation - COMPLETE โ
- Phase 2: Integration Testing - IN PROGRESS
- Phase 3: Alpha Deployment - planned
- Phase 4: Beta - planned
Added "What's Next" section:
- Immediate next steps for integration testing
- Open questions to resolve (DID creation, auth flow)
- Clear path to deployment
Key findings:
- Feed structure is stable and well-formed
- All essential data available in RSS feed
- Ready for Coves API integration
Adds all necessary configuration and deployment files:
Configuration:
- config.example.yaml: Example feed-to-community mappings
- .env.example: Environment variable template for credentials
- requirements.txt: Python dependencies (feedparser, bs4, requests, etc.)
- pytest.ini: Test configuration with coverage settings
Deployment:
- crontab: CRON schedule for daily feed fetching (1 PM UTC)
- README.md: Setup instructions, deployment guide, testing
Setup process:
1. Copy config.example.yaml to config.yaml and configure feeds
2. Set environment variables (AGGREGATOR_DID, credentials)
3. Install dependencies: pip install -r requirements.txt
4. Run tests: pytest
5. Deploy with docker-compose (planned for Phase 2)
Ready for integration testing with live Coves API.
Adds 57 tests with 83% code coverage across all components:
Test coverage by component:
- RSS Fetcher (5 tests): fetch, retry, timeout, invalid XML
- HTML Parser (8 tests): all sections, missing sections, full story
- Rich Text Formatter (10 tests): facets, UTF-8, multi-byte chars
- State Manager (12 tests): deduplication, rolling window, persistence
- Config Manager (3 tests): YAML validation, env vars
- Main Orchestrator (9 tests): E2E flow, error isolation, dry-run
- E2E Tests (6 skipped): require live Coves API
Test results: 57 passed, 6 skipped, 1 warning in 8.76s
Fixtures:
- Real Kagi News RSS item with all sections (sample_rss_item.xml)
- Used to validate parser against actual feed structure
All tests use pytest with mocking for HTTP requests (responses library).
Implements Phase 1 of the Kagi News aggregator system, a reference
implementation for the Coves aggregator architecture.
Core components:
- RSS Fetcher: Fetches feeds with retry logic and error handling
- HTML Parser: Extracts structured data from Kagi's HTML descriptions
(summary, highlights, perspectives, quotes, sources)
- Rich Text Formatter: Formats content with proper Coves facets
- State Manager: JSON-based deduplication with rolling window
- Config Manager: YAML configuration with environment variable support
- Coves Client: HTTP client for authentication and post creation
- Main Orchestrator: Coordinates all components with error isolation
Key features:
- Verified feed structure: 3 H3 sections (Highlights, Perspectives, Sources)
- Historical context woven into summary/highlights
- UTF-8 byte position calculation for facets
- Feed-level and item-level error isolation
- Structured logging throughout
Implementation uses Python 3.11+ with:
- feedparser for RSS parsing
- beautifulsoup4 for HTML extraction
- requests for HTTP operations
- pyyaml for configuration
This merge brings the complete Phase 1 implementation of the Aggregators system,
enabling autonomous services to authenticate and post content to authorized communities.
Key Features:
- Aggregator service registration and authentication
- Community moderator authorization workflow
- Rate limiting (10 posts/hour per community)
- Auto-updating stats via database triggers
- XRPC query endpoints (getServices, getAuthorizations, listForCommunity)
- Jetstream consumer for indexing aggregator records from firehose
- Comprehensive integration and E2E test coverage
All tests passing with complete PDS and AppView verification.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update all aggregator documentation to reflect successful completion
of Phase 1 implementation.
PRD_AGGREGATORS.md:
- Updated Phase 1 status: โ
COMPLETE
- Marked all components as complete with checkmarks
- Added E2E test validation to component list
- Documented deferred Phase 2 items (write-forward operations)
- Updated milestone status to ACHIEVED
CLAUDE.md:
- Updated project instructions for aggregator development context
Key achievements documented:
โ
All lexicon schemas implemented and validated
โ
Database migrations with optimized indexes and triggers
โ
Complete repository layer with bulk operations
โ
Service layer with validation and rate limiting
โ
Post creation integration with dual auth flow
โ
XRPC query endpoints (getServices, getAuthorizations, listForCommunity)
โ
Jetstream consumer indexing from firehose
โ
Comprehensive integration and E2E tests
โ
Records verified in both PDS and AppView
Phase 1 complete:
- Aggregators can authenticate via JWT
- Aggregators can post to authorized communities
- Rate limiting enforced (10 posts/hour per community)
- Query endpoints available for discovery
- Security validated (unauthorized posts rejected)
- Complete data flow: PDS โ Jetstream โ AppView โ XRPC
Phase 2 deferred:
- Write-forward operations (enable, disable, updateConfig)
- SDK development
- Reference implementation (RSS aggregator)
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Consolidate duplicate test helper functions and fix test issues
discovered during aggregator development.
helpers.go:
- Consolidated createSimpleTestJWT() (removed duplicates from post_e2e_test.go)
- Consolidated generateTID() (removed duplicates)
- Added createPDSAccount() for E2E tests
- Added writePDSRecord() for E2E tests
- All helpers now shared across test files
post_e2e_test.go:
- Removed duplicate helper functions (now in helpers.go)
- Cleaned up unused imports (auth, base64, jwt)
- Fixed import order
community_identifier_resolution_test.go:
- Fixed PDS URL default from port 3000 โ 3001
- Matches actual dev PDS configuration (.env.dev)
- Test now passes with running PDS
auth.go middleware:
- Minor logging improvements for auth failures
Test results:
โ
TestCommunityIdentifierResolution: NOW PASSES (was failing)
โ
All aggregator tests: PASSING
โ
All community tests: PASSING
โ TestPostCreation_Basic: Still failing (pre-existing auth context issue)
Overall test suite:
- 74 out of 75 tests passing (98.7% pass rate)
- Only failure is pre-existing auth context issue in old test
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add complete test coverage for aggregator system with repository,
service, and end-to-end validation.
aggregator_test.go - Integration tests:
- TestAggregatorRepository_Create: Upsert logic, field mapping
- TestAggregatorRepository_IsAggregator: Fast existence checks
- TestAggregatorAuthorization_Create: Authorization with audit trail
- TestAggregatorAuthorization_IsAuthorized: Fast authorization checks
- TestAggregatorService_PostCreationIntegration: Authorization validation
- TestAggregatorService_RateLimiting: 10 posts/hour enforcement
- TestAggregatorPostService_Integration: Aggregator vs user detection
- TestAggregatorTriggers: Database trigger stats updates
aggregator_e2e_test.go - End-to-end validation:
Complete data flow testing across all components:
Part 1: Service Declaration
- Create aggregator account on PDS
- Write service record to PDS
- Simulate Jetstream event
- Verify indexed in AppView DB
- โ
Verified: Record exists on PDS (curl) AND in AppView (SQL)
Part 2: Authorization
- Create community account on PDS
- Write authorization record to PDS
- Index via Jetstream consumer
- Verify in AppView DB
- โ
Verified: Record exists on PDS (curl) AND in AppView (SQL)
Part 3: Post Creation
- Aggregator creates post via XRPC endpoint
- Post written to PDS
- Indexed via Jetstream
- Verify in AppView DB with aggregator attribution
- โ
Verified: Post on PDS (curl) AND in AppView (SQL)
Part 4: Rate Limiting
- Create 10 posts (at limit)
- 11th post rejected with 429 status
- โ
Rate limiting enforced correctly
Part 5: XRPC Query Endpoints
- getServices (basic and detailed views)
- getAuthorizations (nested aggregator object)
- listForCommunity (aggregators for community)
- โ
All endpoints return correct data
Part 6: Security
- Unauthorized aggregator posts rejected
- โ
Security validation working
Part 7: Idempotent Indexing
- Duplicate Jetstream events handled gracefully
- โ
Idempotency working
Part 8: Authorization Disable
- Disable authorization
- Post rejected after disable
- โ
Enable/disable workflow working
Test results:
โ
All 10+ test suites passing
โ
Records verified in both PDS and AppView
โ
Complete data flow validated
โ
Security checks validated
โ
Rate limiting validated
โ
XRPC endpoints validated
Coverage:
- Repository operations
- Service layer business logic
- Post integration flow
- Jetstream consumer indexing
- XRPC handler responses
- Database triggers
- End-to-end PDS โ Jetstream โ AppView flow
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Integrate aggregator components into server initialization and
register XRPC endpoints.
Changes to cmd/server/main.go:
- Initialize aggregator repository
- Initialize aggregator service (with community service dependency)
- Update post service to include aggregator service
- Register aggregator XRPC routes (3 query endpoints)
- Start aggregator Jetstream consumer in background goroutine
- Add comprehensive startup logging
Server startup output:
โ
Aggregator service initialized
Started Jetstream aggregator consumer: ws://localhost:6008/subscribe?...
- Indexing: social.coves.aggregator.service (service declarations)
- Indexing: social.coves.aggregator.authorization (authorization records)
Aggregator XRPC endpoints registered (query endpoints public)
Architecture:
- Aggregator service depends on: aggregator repo, community service
- Post service depends on: aggregator service (for auth checks)
- Jetstream consumer runs independently, indexes to DB via repository
- XRPC handlers call service layer methods
Phase 1 complete:
โ
Aggregators can authenticate (via JWT)
โ
Aggregators can post to authorized communities
โ
Rate limiting enforced (10 posts/hour per community)
โ
Query endpoints available for discovery
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement Jetstream consumer to index aggregator service declarations
and authorization records from the firehose in real-time.
aggregator_consumer.go:
- Handles social.coves.aggregator.service records (create/update/delete)
- Handles social.coves.aggregator.authorization records (create/update/delete)
- Upsert logic for both create and update operations
- Delete by URI for authorization cleanup
- Validation:
* Service rkey must be "self" (canonical location)
* communityDid in authorization must match repo DID (prevents forgery)
* did in service must match repo DID (prevents DID spoofing)
* Required fields validation
- Avatar blob extraction from atProto blob ref
- createdAt parsing from RFC3339 with fallback
aggregator_jetstream_connector.go:
- WebSocket connection management with auto-reconnect
- Ping/pong keepalive
- Graceful error handling (continues on parsing errors)
- Filters for wanted collections
Jetstream URL:
ws://localhost:6008/subscribe?wantedCollections=social.coves.aggregator.service&wantedCollections=social.coves.aggregator.authorization
Indexed to database:
- aggregators table (stats auto-updated via triggers)
- aggregator_authorizations table (unique constraint on aggregator+community)
Security:
- DID validation prevents impersonation
- communityDid validation prevents authorization forgery
- Graceful error handling prevents consumer crashes
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement XRPC query endpoints for aggregator discovery and
authorization management.
Handlers (internal/api/handlers/aggregator/):
- get_services.go: Fetch aggregator details by DIDs
* Supports detailed=true for stats (communities_using, posts_created)
* Returns aggregatorView or aggregatorViewDetailed union type
* Bulk query optimization for multiple DIDs
- get_authorizations.go: List communities using an aggregator
* Nested aggregatorView in response (lexicon compliance)
* Supports enabledOnly filter and pagination
- list_for_community.go: List aggregators for a community
* Accepts at-identifier (DID or handle) for community
* Returns authorizationView with config
* Supports enabledOnly filter and pagination
- errors.go: Error handling with domain error mapping
* Maps domain errors to appropriate HTTP status codes
* 404 for not found, 400 for validation, 501 for not implemented
Routes (internal/api/routes/aggregator.go):
- GET /xrpc/social.coves.aggregator.getServices?dids=...
- GET /xrpc/social.coves.aggregator.getAuthorizations?aggregatorDid=...
- GET /xrpc/social.coves.aggregator.listForCommunity?community=...
Features:
- Query parameter parsing with validation
- Domain model to API view conversion
- JSON response formatting matching lexicon
- Proper HTTP status codes (404, 400, 500, 501)
- Config unmarshal from JSONB to interface{}
Deferred to Phase 2:
- Write endpoints (enable, disable, updateConfig) return 501 Not Implemented
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Modify post creation flow to support aggregator posting with
server-side validation and rate limiting.
Changes to internal/core/posts/service.go:
- Server-side aggregator detection via database query
- Dual validation flow:
* Aggregators: Authorization + rate limits, skip membership checks
* Users: Existing visibility/membership validation
- Post tracking after successful creation for rate limiting
- Clear logging to distinguish aggregator vs user posts
Changes to internal/core/posts/errors.go:
- Added ErrRateLimitExceeded for aggregator rate limiting
Changes to internal/api/handlers/post/errors.go:
- Map both aggregators.ErrRateLimitExceeded and posts.ErrRateLimitExceeded to 429
Security:
- DID extracted from JWT (cryptographically verified)
- Database lookup confirms aggregator status (no client-provided flag)
- Authorization checked against indexed records from firehose
- Rate limiting: 10 posts/hour per community per aggregator
Flow:
1. Extract DID from JWT (verified by auth middleware)
2. Query: Is this DID an aggregator? (database lookup)
3a. If aggregator: Check authorization + rate limits
3b. If user: Check community membership/visibility
4. Write post to PDS
5. If aggregator: Record post for rate limiting
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement complete repository layer for aggregator data access with
optimized queries and bulk operations.
Domain models (internal/core/aggregators/):
- aggregator.go: Aggregator and Authorization domain types
- interfaces.go: Repository and Service interfaces
- errors.go: Domain-specific errors with IsXxx helpers
Repository (internal/db/postgres/aggregator_repo.go):
- CRUD operations for aggregators and authorizations
- Fast IsAggregator() check using EXISTS query
- Fast IsAuthorized() check with optimized partial index
- Bulk GetAggregatorsByDIDs() for efficient multi-DID queries
- Post tracking for rate limiting
- Upsert logic with ON CONFLICT for Jetstream indexing
- Delete by URI for Jetstream delete operations
Performance:
- Uses idx_aggregator_auth_lookup for <5ms authorization checks
- Uses idx_aggregator_posts_rate_limit for fast rate limit queries
- Parameterized queries throughout (no SQL injection risk)
- Bulk operations reduce N+1 query problems
Dependencies:
- Added gojsonschema for config validation
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Create comprehensive database schema for aggregator system with
3 tables, 2 triggers, and optimized indexes.
Tables:
- aggregators: Service declarations indexed from Jetstream
- aggregator_authorizations: Community authorizations
- aggregator_posts: Rate limiting tracking (AppView-only)
Key features:
- Optimized indexes for <5ms authorization checks
- Partial indexes WHERE enabled=true for performance
- Foreign keys with CASCADE delete
- Auto-updating stats via triggers
Triggers:
- update_aggregator_communities_count: Tracks communities_using
- update_aggregator_posts_count: Tracks posts_created
Security:
- Audit trail fields (created_by, disabled_by, disabled_at)
- Unique constraint on (aggregator_did, community_did)
- NOT NULL constraints on required fields
Performance:
- idx_aggregator_auth_lookup: Fast (aggregator, community, enabled) checks
- idx_aggregator_posts_rate_limit: Fast rate limit queries
- idx_aggregators_created_at: Sorting by creation date
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add complete lexicon definitions for the aggregator system following
atProto patterns (Feed Generator + Labeler model).
Records (2):
- service.json: Aggregator service declaration with config schema
- authorization.json: Community authorization with enabled status
Procedures (3):
- enable.json: Enable aggregator for community (moderator only)
- disable.json: Disable aggregator
- updateConfig.json: Update aggregator configuration
Queries (3):
- getServices.json: Fetch aggregator details by DIDs
- getAuthorizations.json: List communities using aggregator
- listForCommunity.json: List aggregators for community
Definitions:
- aggregatorView: Basic aggregator metadata
- aggregatorViewDetailed: Aggregator with stats
- authorizationView: Authorization from community perspective
- communityAuthView: Authorization from aggregator perspective
Design decisions:
- Removed aggregatorType enum (too rigid for alpha)
- Used JSON Schema for configSchema (validation + UI generation)
- Followed Bluesky feed generator patterns
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds complete community feed infrastructure with sort algorithms and XRPC endpoints.
Summary of changes:
- Core feed service with hot/new/top sorting algorithms
- PostgreSQL repository with optimized queries
- XRPC handler for social.coves.feed.getCommunity
- PostView types for rich feed responses
- Comprehensive integration tests
- Documentation for feeds and future aggregators
Key features:
โ
Public feed endpoint (no auth required for reading)
โ
Multiple sort algorithms (hot, new, top)
โ
Cursor-based pagination
โ
Proper input validation and error handling
โ
Full test coverage
This implements the read path for community feeds per atProto patterns.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
New Tests:
- TestGetCommunityFeed_BasicRetrieval: Verifies feed endpoint works
- TestGetCommunityFeed_SortOrders: Tests hot/new/top algorithms
- TestGetCommunityFeed_Pagination: Validates cursor-based paging
- TestGetCommunityFeed_EmptyFeed: Handles communities with no posts
- TestGetCommunityFeed_LimitValidation: Ensures limit clamping works
Test Fix:
- community_consumer_test.go: Changed collection from app.bsky.feed.post
to app.bsky.communityFeed.post to better demonstrate non-Coves namespace
filtering (the test verifies we ignore non-social.coves.community.* events)
Test Coverage:
- Feed retrieval with real post data
- Sort algorithm behavior
- Pagination edge cases
- Input validation
- Error handling
All tests use the shared test infrastructure (SetupTestDB, test user helpers)
and follow integration test patterns.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Comprehensive documentation for feed systems and future aggregator features:
New Documentation:
- COMMUNITY_FEEDS.md: Complete guide to feed architecture and implementation
- aggregators/PRD_AGGREGATORS.md: Product spec for RSS/aggregator features
- aggregators/PRD_KAGI_NEWS_RSS.md: Kagi News integration design
Updated:
- PRD_POSTS.md: Refined post creation flow and security model
Feed Documentation Coverage:
- Architecture overview (service โ repo โ postgres)
- Sort algorithms (hot, new, top)
- Query optimization and indexing strategy
- Security considerations
- API examples and usage
Aggregator PRDs:
- RSS feed generation per community
- External content aggregation
- Kagi News integration patterns
- Federation considerations
These docs provide context for current feed implementation and roadmap
for future aggregator features.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extends post types to support feed views and updates lexicon definitions:
Post Types Added:
- PostView: Full post representation with all metadata for feeds
- AuthorView: Author info (DID, handle, displayName, avatar, reputation)
- CommunityRef: Minimal community reference in posts
- PostStats: Aggregated statistics (votes, comments, shares)
- ViewerState: User's relationship with post (votes, saves, tags)
Lexicon Updates:
- social.coves.post.get: Restructured postView definition
- social.coves.feed.getCommunity: Updated query parameters and response
These types align with atProto patterns:
- Follows app.bsky.feed.defs#feedViewPost structure
- Supports viewer-specific state
- Enables efficient feed rendering
- Provides all data clients need in single request
The PostView types are used by feed endpoints to return rich post data.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Integrates community feed functionality into the main server:
- Initialize CommunityFeedRepository with database connection
- Initialize CommunityFeedService with dependencies
- Register feed XRPC routes (public endpoints)
- Add startup logging for feed service
Dependency injection flow:
feedRepo โ db
feedService โ feedRepo + communityService
feedHandler โ feedService
Routes registered:
- GET /xrpc/social.coves.feed.getCommunity (public)
The feed service is now live and ready to serve community feeds.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements the HTTP handler layer for social.coves.feed.getCommunity:
- GetCommunityHandler: XRPC endpoint handler with proper validation
- Query parameter parsing: community, sort, limit, cursor
- Error handling: Proper XRPC error responses (InvalidRequest, NotFound)
- Route registration: Public endpoint (no auth required for reading)
Security:
- Input validation for all query parameters
- Limit clamping (max 100 posts per request)
- Community existence verification
- No sensitive data exposure in error messages
Handler flow:
1. Parse and validate query parameters
2. Call feed service
3. Transform to XRPC response format
4. Return JSON with proper headers
This implements the read path for community feeds per atProto patterns.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements the core service layer and database repository for community feeds:
- CommunityFeedService: Orchestrates feed retrieval with sorting and pagination
- FeedRepository: PostgreSQL queries for post aggregation and filtering
- Feed types: FeedOptions, FeedResponse, SortOrder enums
- Error types: Proper error handling for feed operations
Architecture:
- Service layer handles business logic and coordinates with community service
- Repository performs efficient SQL queries with proper indexing
- Supports multiple sort algorithms (hot, new, top)
- Pagination via cursor-based approach
Security:
- All queries use parameterized statements
- Input validation in service layer
- Proper error wrapping for debugging
This is the foundation for social.coves.feed.getCommunity XRPC endpoint.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements Alpha post creation feature with full write-forward to community
PDS and real-time Jetstream indexing.
Features:
- POST /xrpc/social.coves.post.create endpoint
- Write-forward architecture (posts written to community's PDS repository)
- Real-time AppView indexing via Jetstream consumer
- Comprehensive security validation (auth, repository ownership, FK integrity)
- Support for all 4 at-identifier formats (DIDs, canonical, @-prefixed, scoped)
- Database schema with proper indexing (migration 011)
- Full integration test suite (service, repository, handler, E2E with live PDS)
Implementation:
- Domain layer: Post models, service, validation
- Repository layer: PostgreSQL with JSON support
- Handler layer: XRPC endpoint with OAuth auth
- Consumer layer: Jetstream real-time indexing with security checks
- 13 commits, 30+ files, ~2,700 lines
Deferred to Beta:
- Content rules validation
- Post read operations (get, list)
- Post update/delete operations
- Voting system
See docs/PRD_POSTS.md for complete status.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update lexicon validation tests to handle post record types:
- Add social.coves.post.record to test cases
- Verify at-identifier format for community field
- Validate author field (required DID)
Ensures lexicon validation works correctly for new post records.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Move duplicate helper functions from multiple test files to helpers.go:
- authenticateWithPDS() - Used by post e2e tests
- contains() / anySubstring() - String utilities
- Import standardization across test files
Benefits:
- Eliminates code duplication across 6+ test files
- Centralizes test utilities for easier maintenance
- Improves test readability (focus on test logic, not helpers)
All tests continue to pass with consolidated helpers.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Minor formatting cleanup:
- Align struct field comments consistently
- No functional changes
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add SetTestUserDID() function to inject user DID into context for testing.
Purpose:
- Mock authenticated users in integration tests without full OAuth flow
- Used by post handler tests to simulate authenticated requests
- Marked with comment: "ONLY be used in tests"
This enables testing authenticated endpoints (like post creation)
without requiring real PDS authentication in test environment.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update PRD_POSTS.md with implementation status:
- Add "Implementation Status" section showing completed work
- Mark Alpha CREATE features as complete (โ
)
- Mark Beta features as deferred (โ ๏ธ)
- Update all sections with checkmarks and status
- Add database schema status (migration 011 complete)
- Update success metrics (Alpha checklist complete)
- Reference IMPLEMENTATION_POST_CREATION.md for details
Completed (Alpha):
โ
Post creation endpoint with write-forward to community PDS
โ
Handler with authentication, validation, security checks
โ
Service layer with token refresh and community resolution
โ
PostgreSQL repository with proper indexing
โ
Jetstream consumer for real-time indexing
โ
E2E tests (service, repository, handler, live PDS+Jetstream)
โ
All 4 at-identifier formats supported
Deferred (Beta):
โ ๏ธ Content rules validation
โ ๏ธ Post read operations (get, list)
โ ๏ธ Post update/edit operations
โ ๏ธ Post deletion
โ ๏ธ Voting system
Update other PRDs:
- PRD_BACKLOG: Add post creation to completed items
- PRD_COMMUNITIES: Reference post integration
- PRD_GOVERNANCE: Note content rules deferred to Beta
PRDs now accurately reflect codebase state.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add social.coves.post lexicon definitions:
1. social.coves.post.record
- Post record schema for community repositories
- Fields: community (at-identifier), author (did), title, content
- Rich text support: facets for mentions/links
- Embed support: images, video, external, record
- Content labels: nsfw, spoiler, violence
- Federation fields: originalAuthor, federatedFrom (future)
- Location support (future)
- Author field REQUIRED (added after PR review)
2. social.coves.post.create
- XRPC procedure for post creation
- Input: matches record schema (minus author - server-populated)
- Output: uri (AT-URI), cid (content ID)
- Errors: InvalidRequest, AuthRequired, NotAuthorized, Banned
3. social.coves.post.get
- XRPC query for fetching single post (future)
- Input: uri (AT-URI)
- Output: post view with stats
Update community profile and feed lexicons:
- Reference post record type
- Update descriptions for post integration
All lexicons follow atProto conventions and use at-identifier
format for community references (supports DIDs and handles).
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add 4 test files covering full post creation flow:
1. post_creation_test.go - Service layer tests (11 subtests)
- Happy path with DID and handle resolution
- Validation: missing fields, invalid formats, length limits
- Content label validation (nsfw, spoiler, violence)
- Repository tests: create, duplicate URI handling
2. post_e2e_test.go - TRUE end-to-end test
- Part 1: Write-forward to live PDS
- Part 2: Real Jetstream WebSocket consumption
- Verifies complete cycle: HTTP โ PDS โ Jetstream โ AppView DB
- Tests ~1 second indexing latency
- Requires live PDS and Jetstream services
3. post_handler_test.go - Handler security tests (10+ subtests)
- Reject client-provided authorDid (impersonation prevention)
- Require authentication (401 on missing token)
- Request body size limit (1MB DoS prevention)
- Malformed JSON handling
- All 4 at-identifier formats (DIDs, canonical, @-prefixed, scoped)
- Unicode/emoji support
- SQL injection prevention
4. helpers.go - Test utilities
- JWT token generation for test users
All tests passing. Coverage includes security, validation,
business logic, and real-time indexing.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Wire up post creation feature in main server:
1. Initialize post service
- Create post repository (PostgreSQL)
- Create post service with community service integration
- Configure with default PDS URL
2. Register XRPC routes
- POST /xrpc/social.coves.post.create
- Requires OAuth authentication via middleware
3. Start Jetstream consumer for posts
- WebSocket URL: ws://localhost:6008/subscribe
- Collection filter: social.coves.post.record
- Runs in background goroutine
- Indexes CREATE operations (UPDATE/DELETE deferred)
Environment variables:
- POST_JETSTREAM_URL: Override default Jetstream endpoint
Initialization order ensures postRepo created before consumer.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Export community service methods for post creation:
- EnsureFreshToken() - Auto-refresh PDS tokens before write operations
- GetByDID() - Direct repository access for post service
These methods enable posts service to:
1. Fetch community from AppView by DID
2. Ensure fresh PDS credentials before writing to community repo
3. Use community's access token for PDS write-forward
Changes:
- Made ensureFreshToken() public as EnsureFreshToken()
- Added GetByDID() wrapper for repository access
- No functional changes, just visibility
Supports write-forward architecture where posts are written to
community's PDS repository using community's credentials.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add PostEventConsumer for AppView indexing:
- Listen for social.coves.post.record CREATE events via WebSocket
- Parse post records from Jetstream firehose
- Index posts into AppView database
- Handle UPDATE/DELETE deferred until those features exist
Security validation:
- Verify repository DID matches community DID (prevents fake posts)
- Verify community exists in AppView (foreign key integrity)
- Verify author exists in AppView (foreign key integrity)
- Idempotent indexing (safe for Jetstream replays)
Add PostJetstreamConnector:
- Dedicated WebSocket connector for post events
- Collection filter: social.coves.post.record
- Separate from CommunityJetstreamConnector (different event types)
Posts are indexed with ~1 second latency from PDS write.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add POST /xrpc/social.coves.post.create endpoint:
- Authentication required via OAuth middleware
- Validate request body size (1MB limit for DoS prevention)
- Validate at-identifier format for community field
- Reject client-provided authorDid (security)
- Set authorDid from authenticated JWT
- Error mapping for lexicon-compliant responses
Handler security features:
- Body size limit prevents DoS
- Author impersonation prevented
- All 4 at-identifier formats supported
- Proper error codes (400, 401, 403, 404, 500)
Route registration integrates with auth middleware.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add migration 011: posts table with indexes
- Add foreign keys to users and communities
- Add indexes for common query patterns (community feed, author, score)
- Add PostgreSQL repository implementation
- Add Create() and GetByURI() methods
- Add JSON serialization for facets, embeds, labels
Posts table supports:
- AT-URI, CID, rkey for atProto compliance
- Title, content, facets, embed, labels
- Vote counts and score (denormalized for performance)
- Soft delete with deleted_at timestamp
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add Post domain model with AppView database representation
- Add CreatePostRequest/Response for XRPC endpoint
- Add PostRecord for PDS write-forward
- Add Service and Repository interfaces
- Add error types (ValidationError, ContentRuleViolation)
- Add service implementation with PDS write-forward
- Add validation for content length, labels, at-identifiers
Part of Alpha post creation feature.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Complete implementation of community handle naming convention change
with comprehensive PR review fixes.
This merge includes:
- Critical bug fixes for identifier resolution
- Comprehensive test coverage (31 test cases, all passing)
- Database migration for .communities โ .community transition
- Input validation and error handling improvements
- Support for self-hosted instances
All PR review comments addressed:
โ
GetDisplayHandle() bug fixed for multi-part domains
โ
Case sensitivity bug fixed in resolveScopedIdentifier
โ
Comprehensive input validation (DNS labels, domain format)
โ
100% test coverage for new code
โ
Database migration script with rollback
โ
Improved error messages with identifier context
โ
NewPDSAccountProvisioner argument order corrected
โ
Removed hardcoded coves.social from tests
Test Results:
- 31 identifier resolution tests: PASS
- All integration tests: PASS
- E2E tests with real PDS: PASS
- Regression tests: PASS
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update development environment configuration and Go module dependencies.
Changes:
- Update .env.dev with latest environment variables
- Update docker-compose.dev.yml configuration
- Run go mod tidy to clean up dependencies
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update Product Requirements Document to document the singular
.community. naming convention.
Changes:
- Update handle format examples
- Document identifier resolution features
- Update API examples with new handle format
This ensures documentation matches the implemented handle format
and provides clear examples for developers.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update all integration tests to use singular .community. naming convention
instead of .communities.
Tests updated:
- E2E community creation and XRPC endpoint tests
- HostedBy security validation tests
- Community provisioning tests
- Service integration tests
- V2 validation tests
- Token refresh tests
Changes:
- Update expected handle formats in assertions
- Update test fixtures to use new convention
- Ensure regex patterns match .community. format
All tests passing with new handle format.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update PDS provisioning and Jetstream consumer to generate handles
using singular .community. instead of .communities.
Changes:
- PDSAccountProvisioner: Generate {name}.community.{domain} handles
- JetstreamConsumer: Parse and validate new handle format
- Update handle extraction logic for consistency
Example handle formats:
- gardening.community.coves.social
- gaming.community.coves.social
This maintains consistency with the lexicon schema update and aligns
with AT Protocol naming conventions.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update AT Protocol lexicon schema and test data to use singular
.community. instead of .communities. in handle format.
Changes:
- Update profile.json lexicon schema with new handle pattern
- Update test fixtures to use singular convention
- Update lexicon validation tests
This aligns with AT Protocol naming standards where all record types
use singular form (e.g., app.bsky.feed.post, app.bsky.graph.follow).
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add production-ready migration script to update existing community handles
from plural (.communities.) to singular (.community.) format.
Migration features:
- Safe UPDATE using REPLACE for targeted changes
- Verification checks to ensure migration completion
- Rollback script for emergency reversion
- Error handling with informative messages
Example transformations:
- gardening.communities.coves.social โ gardening.community.coves.social
- gaming.communities.coves.social โ gaming.community.coves.social
This migration is required for the .communities โ .community naming
convention change to align with AT Protocol lexicon standards
(all record types use singular form).
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add 31 test cases covering all identifier resolution code paths:
TestCommunityIdentifierResolution (14 E2E tests):
- DID format resolution (3 tests)
- Canonical handle format (3 tests)
- At-identifier format (2 tests)
- Scoped format !name@instance (5 tests)
- Edge cases (4 tests)
TestResolveScopedIdentifier_InputValidation (9 tests):
- Reject special characters, spaces, invalid DNS labels
- Reject names starting/ending with hyphens
- Reject names exceeding 63 character DNS limit
- Accept valid alphanumeric names with hyphens/numbers
- Validate domain format
TestGetDisplayHandle (5 tests):
- Standard two-part domains
- Multi-part TLDs (e.g., .co.uk)
- Subdomain instances
- Malformed input graceful fallback
TestIdentifierResolution_ErrorContext (3 tests):
- Verify error messages include identifier for debugging
- Verify DID, handle, and scoped errors provide context
Fixes:
- Use environment variables for configuration (no hardcoded coves.social)
- Correct NewPDSAccountProvisioner argument order (instanceDomain, pdsURL)
- Support self-hosted instances via INSTANCE_DOMAIN env var
All tests passing with real PDS integration.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Critical fixes:
- Fix GetDisplayHandle() to handle multi-part domains correctly using string.Index
- Add DNS label validation (RFC 1035) with isValidDNSLabel helper
- Add domain format validation with isValidDomain helper
- Normalize instanceDomain to lowercase for case-insensitive lookup
- Improve error messages to include identifier context for debugging
Validation improvements:
- Reject special characters in community names
- Enforce DNS label length limits (1-63 chars)
- Prevent names starting/ending with hyphens
- Validate domain format before lookup
Bug fixes:
- GetDisplayHandle now correctly parses handles with multi-part TLDs (e.g., coves.co.uk)
- resolveScopedIdentifier properly normalizes domain case (!gardening@Coves.social works)
- Error messages now include the identifier that failed resolution
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This file was already removed in the feature branch but needs to be
cleaned up from the working directory.
Membership tracking is AppView-only data, not atProto records.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Comprehensive lexicon extensibility fixes to ensure alpha-readiness
and future-proof schema evolution without requiring V2 migrations.
Key Changes:
- Fixed all closed enums โ knownValues (moderationType, visibility, sort)
- Made moderator roles and permissions extensible
- Added authentication documentation to all endpoints
- Removed invalid membership record references
- Documented technical decisions in PRD_GOVERNANCE.md
This locks down the lexicon schemas for alpha while enabling future
beta features (sortition moderation, new visibility modes, moderator
tiers) without breaking changes.
Per atProto style guide (bluesky-social/atproto#4245): enum sets
cannot be extended without breaking schema evolution rules.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Membership tracking is AppView-only data, not atProto records.
Changes:
- Removed membershipUri field from community.get viewerState
- Updated member field description to clarify it's AppView-computed
- Removed membership lexicon file (already deleted)
- Removed membership test data files (already deleted)
Rationale:
- Membership/reputation is indexed from user activity, not explicit records
- No need for AT-URI reference to non-existent record type
- Clarifies that membership status is computed by AppView, not stored in repo
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Per atProto style guide: endpoint descriptions should mention if
authentication is required and whether responses are personalized.
Changes:
- create.json: Added "Requires authentication."
- update.json: Added "Requires authentication and moderator/admin permissions."
- subscribe.json: Added "Requires authentication."
- unsubscribe.json: Added "Requires authentication."
- get.json: Added "Authentication optional; viewer state will be included if authenticated."
- list.json: Added "Authentication optional; viewer state will be included if authenticated."
This improves developer experience by making auth requirements
explicit without requiring documentation lookup.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
BREAKING: This is a pre-alpha schema fix. Must be applied before any
moderator records are created.
Changes to social.coves.community.moderator:
- Change role from enum to knownValues (enables future role types)
- Change permissions from enum to knownValues (enables new permissions)
- Add maxLength: 64 to both fields per atProto style guide
Future extensibility examples:
- Roles: "owner", "trainee", "emeritus"
- Permissions: "manage_bots", "manage_flairs", "manage_automoderator"
Documented in PRD_GOVERNANCE.md:
- Technical decision rationale
- atProto style guide reference
- Future beta phase extensibility plan
- Security considerations
This enables Beta Phase 2 (Moderator Tiers & Permissions) without
requiring V2 schema migration or breaking existing records.
Per atProto style guide (bluesky-social/atproto#4245): enum sets
cannot be extended without breaking schema evolution rules.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change sort from closed enum to knownValues
- Add maxLength: 64 per atProto style guide
This enables future sort algorithms without breaking changes:
- "trending" - Recent activity spike detection
- "recommended" - Personalized AI recommendations
- "nearby" - Geo-based sorting
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change visibility from closed enum to knownValues
- Apply to community.profile (record), create, and update endpoints
- Add maxLength: 64 per atProto style guide
This enables future visibility modes without breaking changes:
- "followers-only" - Only subscribers can see
- "instance-only" - Only same-instance users
- "invite-only" - Requires invite code
Files changed:
- community/profile.json (record schema)
- community/create.json (procedure)
- community/update.json (procedure)
Per atProto style guide: closed enums block schema evolution.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change moderationType from closed enum to knownValues
- Add to required fields (critical before alpha - can't add required later)
- Add default value "moderator" for alpha simplicity
- Add maxLength constraint per atProto style guide
This enables future moderation types without schema migration:
- "sortition" - Community tribunal (Beta Phase 1)
- "instance-labeler" - Instance moderation service
- "third-party-labeler" - External moderation DID
Per atProto style guide: enum sets cannot be extended without breaking
schema evolution. knownValues provides flexible alternative.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements Phase 1 did:web domain verification to prevent domain
impersonation attacks in the Coves federated community system.
This PR addresses all code review feedback across 3 rounds:
Round 1 - Performance & Security:
โ
P0: Multi-part TLD support (fixes .co.uk, .com.au blocking)
โ
HTTP client connection pooling
โ
Bounded LRU cache implementation
โ
Rate limiting for DoS protection
Round 2 - Critical Bug Fixes:
โ
Memory leak (unbounded cache โ bounded LRU)
โ
Deadlock (manual locks โ thread-safe LRU)
โ
Missing timeout (added 15s overall timeout)
Round 3 - Optimizations:
โ
Cache TTL cleanup (removes expired entries)
โ
Struct field alignment (performance)
โ
All linter issues resolved
Security Impact:
- Prevents malicious instances from claiming communities for domains
they don't control (e.g., evil.com claiming @gaming@nintendo.com)
- Verifies hostedBy domain matches community handle domain
- Optional .well-known/did.json verification for cryptographic proof
- Soft-fail on network errors (resilience)
Test Coverage:
- 13 new security test cases (all passing)
- 42+ total tests (all passing)
- Multi-part TLD support verified (.co.uk, .com.au, .org.uk, .ac.uk)
Code Quality:
โ
All linter checks passing
โ
All code properly formatted
โ
Clean build (no warnings)
โ
Production-ready
๐ค Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Adds comprehensive test coverage for hostedBy domain verification,
including multi-part TLD support and security attack scenarios.
Test Coverage:
TestHostedByVerification_DomainMatching:
- โ
Rejects communities with mismatched hostedBy domains
- โ
Accepts communities with matching hostedBy domains
- โ
Rejects non-did:web format hostedBy values
- โ
Skip verification flag bypasses all checks (dev mode)
TestExtractDomainFromHandle:
- โ
DNS-style handles with subdomains
- โ
Simple two-part domains
- โ
Multi-part subdomains
- โ
Multi-part TLD: .co.uk (critical fix validation)
- โ
Multi-part TLD: .com.au (critical fix validation)
- โ
Multi-part TLD: .org.uk, .ac.uk
- โ
Correctly rejects incorrect TLD extraction (e.g., did:web:co.uk)
- โ
Domain mismatch detection
Security Attack Scenarios Tested:
1. Domain impersonation (evil.com claiming nintendo.com) - BLOCKED
2. Non-did:web hostedBy spoofing - BLOCKED
3. Multi-part TLD domain extraction failures - FIXED
All tests passing (9/9 multi-part TLD tests).
Co-Authored-By: Claude <noreply@anthropic.com>
## ๐ Major Feature: Complete Feed System Implementation
Implements the complete Timeline and Discover feed architecture for Coves,
following atProto patterns with proper separation of concerns (handlers โ
services โ repositories). This is a foundational feature for the alpha release.
### New Features
**Timeline Feed (User-Specific)**
- `social.coves.feed.getTimeline` XRPC endpoint
- Authenticated user feed showing posts from subscribed communities
- Full architecture: Handler โ Service โ Repository
- Integration tests with cursor pagination (368 lines)
**Discover Feed (Public)**
- `social.coves.feed.getDiscover` XRPC endpoint
- Public feed showing recent posts from all communities
- Optimized for performance with documented indexing strategy
- Comprehensive security tests (273 lines)
**Shared Infrastructure**
- Created `feed_repo_base.go` (340 lines) to eliminate code duplication
- Shared lexicon definitions in `social.coves.feed.defs`
- HMAC-SHA256 signed cursors for pagination integrity
- Consistent error handling across both feeds
### Technical Improvements
**Code Quality**
- Eliminated ~700 lines of duplicate code via shared base repository
* timeline_repo.go: 426 โ 131 lines (-69% duplication)
* discover_repo.go: 383 โ 124 lines (-68% duplication)
- Consistent formatting with gofumpt
- Comprehensive inline documentation
**Security Enhancements**
- HMAC cursor signing prevents pagination tampering
- CURSOR_SECRET environment variable for production deployments
- DID format validation (must start with "did:")
- Rate limiting strategy documented (100 req/min per IP)
- Input validation at handler level
**Performance**
- Database indexes documented for optimal query performance
- Cursor-based pagination for large result sets
- Efficient joins between posts, communities, and users
### Aggregator System Updates
**Documentation**
- Documented critical alpha blocker: aggregator user registration
- Aggregators cannot post until indexed as users in AppView
- Proposed solution: `social.coves.aggregator.register` endpoint
- Quick fix alternative documented for testing
**Code Cleanup**
- Consistent formatting across aggregator codebase
- Improved test readability
- Updated PRD with alpha blockers section
### Files Changed (30 files, +2406/-308 lines)
**New Implementations**
- `internal/api/handlers/timeline/` - Timeline XRPC handler
- `internal/api/handlers/discover/` - Discover XRPC handler
- `internal/core/timeline/` - Timeline business logic
- `internal/core/discover/` - Discover business logic
- `internal/db/postgres/feed_repo_base.go` - Shared repository base
- `internal/db/postgres/timeline_repo.go` - Timeline data access
- `internal/db/postgres/discover_repo.go` - Discover data access
- `internal/atproto/lexicon/social/coves/feed/` - Feed lexicons
- `tests/integration/timeline_test.go` - Timeline integration tests
- `tests/integration/discover_test.go` - Discover integration tests
**Updated**
- `cmd/server/main.go` - Feed service initialization
- `internal/api/routes/` - Timeline and discover routes
- `docs/aggregators/PRD_AGGREGATORS.md` - Alpha blocker docs
- `tests/integration/helpers.go` - Shared test utilities
### Testing
- โ
All 11 integration tests passing
- โ
Timeline feed with authentication
- โ
Discover feed security validation
- โ
Cursor pagination integrity
- โ
Aggregator authorization flows
### Migration Path
To revert this entire feature in the future:
```bash
git revert -m 1 <this-merge-commit-id>
```
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add critical alpha blocker documentation for aggregator registration system.
Aggregators cannot post until they are indexed as users in the AppView.
Changes:
- Document aggregator user registration blocker in PRD
- Add proposed solution (registration endpoint)
- Include quick fix alternative for testing
- Code formatting cleanup across aggregator files
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## Critical Issues Fixed
- Removed unused postType/postTypes from lexicon (not implemented)
- Documented database indexes and performance characteristics
- Documented rate limiting strategy for public discover endpoint
## Important Improvements
- Eliminated ~700 lines of duplicate code via shared feed_repo_base.go
* timeline_repo.go: 426 โ 140 lines (-67%)
* discover_repo.go: 383 โ 133 lines (-65%)
- Added HMAC-SHA256 cursor integrity protection
- Created shared lexicon defs.json for feedViewPost types
- Added DID format validation in timeline handler
- Fixed error handling to use errors.Is() for wrapped errors
## Security Enhancements
- HMAC cursor signing prevents tampering
- CURSOR_SECRET environment variable for production
- DID format validation (must start with "did:")
- Rate limiting documented (100 req/min per IP)
## Code Quality
- Duplicate code: 85% โ 0%
- Consistent formatting with gofumpt (extra rules)
- Comprehensive inline documentation
- All 11 tests passing
## Files Changed
- Created: feed_repo_base.go (340 lines shared logic)
- Created: defs.json (shared lexicon types)
- Refactored: timeline_repo.go, discover_repo.go
- Enhanced: Error handlers, route documentation
- Updated: Tests to use cursor secret
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds design documentation for blob upload proxy system to enable
image/video posts in communities from external PDS users.
Problem:
Users on external PDSs cannot directly upload blobs to community-owned
PDS repositories because they lack authentication credentials for the
community's PDS.
Solution:
Coves AppView acts as an authenticated proxy for blob uploads via
social.coves.blob.uploadForCommunity endpoint.
Flow:
1. User uploads blob to AppView
2. AppView validates user can post to community
3. AppView uses community's PDS credentials to upload blob
4. AppView returns CID to user
5. User creates post record referencing the CID
6. Post and blob both live in community's PDS
Status: Design documented, implementation TODO
Priority: CRITICAL for Beta - Required for rich media posts
Implementation checklist includes:
- Handler endpoint
- User authorization validation
- Community credential management
- Upload proxy logic
- Security measures (size limits, content-type validation, rate limiting)
Updates PRD_KAGI_NEWS_RSS.md with Phase 1 implementation results:
Status changes:
- Status: Implementation Phase โ Phase 1 Complete - Ready for Deployment
- Added comprehensive implementation summary section
- All 7 components marked as COMPLETE with test results
Documentation updates:
- Verified feed structure (3 H3 sections only)
- Timeline is website-only feature (not in RSS feed)
- Historical context woven into summary/highlights
- All components updated with implementation status
Test results documented:
- 57 tests passing with 83% coverage
- Detailed breakdown by component
- Test fixtures and strategies documented
Success metrics reorganized:
- Phase 1: Implementation - COMPLETE โ
- Phase 2: Integration Testing - IN PROGRESS
- Phase 3: Alpha Deployment - planned
- Phase 4: Beta - planned
Added "What's Next" section:
- Immediate next steps for integration testing
- Open questions to resolve (DID creation, auth flow)
- Clear path to deployment
Key findings:
- Feed structure is stable and well-formed
- All essential data available in RSS feed
- Ready for Coves API integration
Adds all necessary configuration and deployment files:
Configuration:
- config.example.yaml: Example feed-to-community mappings
- .env.example: Environment variable template for credentials
- requirements.txt: Python dependencies (feedparser, bs4, requests, etc.)
- pytest.ini: Test configuration with coverage settings
Deployment:
- crontab: CRON schedule for daily feed fetching (1 PM UTC)
- README.md: Setup instructions, deployment guide, testing
Setup process:
1. Copy config.example.yaml to config.yaml and configure feeds
2. Set environment variables (AGGREGATOR_DID, credentials)
3. Install dependencies: pip install -r requirements.txt
4. Run tests: pytest
5. Deploy with docker-compose (planned for Phase 2)
Ready for integration testing with live Coves API.
Adds 57 tests with 83% code coverage across all components:
Test coverage by component:
- RSS Fetcher (5 tests): fetch, retry, timeout, invalid XML
- HTML Parser (8 tests): all sections, missing sections, full story
- Rich Text Formatter (10 tests): facets, UTF-8, multi-byte chars
- State Manager (12 tests): deduplication, rolling window, persistence
- Config Manager (3 tests): YAML validation, env vars
- Main Orchestrator (9 tests): E2E flow, error isolation, dry-run
- E2E Tests (6 skipped): require live Coves API
Test results: 57 passed, 6 skipped, 1 warning in 8.76s
Fixtures:
- Real Kagi News RSS item with all sections (sample_rss_item.xml)
- Used to validate parser against actual feed structure
All tests use pytest with mocking for HTTP requests (responses library).
Implements Phase 1 of the Kagi News aggregator system, a reference
implementation for the Coves aggregator architecture.
Core components:
- RSS Fetcher: Fetches feeds with retry logic and error handling
- HTML Parser: Extracts structured data from Kagi's HTML descriptions
(summary, highlights, perspectives, quotes, sources)
- Rich Text Formatter: Formats content with proper Coves facets
- State Manager: JSON-based deduplication with rolling window
- Config Manager: YAML configuration with environment variable support
- Coves Client: HTTP client for authentication and post creation
- Main Orchestrator: Coordinates all components with error isolation
Key features:
- Verified feed structure: 3 H3 sections (Highlights, Perspectives, Sources)
- Historical context woven into summary/highlights
- UTF-8 byte position calculation for facets
- Feed-level and item-level error isolation
- Structured logging throughout
Implementation uses Python 3.11+ with:
- feedparser for RSS parsing
- beautifulsoup4 for HTML extraction
- requests for HTTP operations
- pyyaml for configuration
This merge brings the complete Phase 1 implementation of the Aggregators system,
enabling autonomous services to authenticate and post content to authorized communities.
Key Features:
- Aggregator service registration and authentication
- Community moderator authorization workflow
- Rate limiting (10 posts/hour per community)
- Auto-updating stats via database triggers
- XRPC query endpoints (getServices, getAuthorizations, listForCommunity)
- Jetstream consumer for indexing aggregator records from firehose
- Comprehensive integration and E2E test coverage
All tests passing with complete PDS and AppView verification.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update all aggregator documentation to reflect successful completion
of Phase 1 implementation.
PRD_AGGREGATORS.md:
- Updated Phase 1 status: โ
COMPLETE
- Marked all components as complete with checkmarks
- Added E2E test validation to component list
- Documented deferred Phase 2 items (write-forward operations)
- Updated milestone status to ACHIEVED
CLAUDE.md:
- Updated project instructions for aggregator development context
Key achievements documented:
โ
All lexicon schemas implemented and validated
โ
Database migrations with optimized indexes and triggers
โ
Complete repository layer with bulk operations
โ
Service layer with validation and rate limiting
โ
Post creation integration with dual auth flow
โ
XRPC query endpoints (getServices, getAuthorizations, listForCommunity)
โ
Jetstream consumer indexing from firehose
โ
Comprehensive integration and E2E tests
โ
Records verified in both PDS and AppView
Phase 1 complete:
- Aggregators can authenticate via JWT
- Aggregators can post to authorized communities
- Rate limiting enforced (10 posts/hour per community)
- Query endpoints available for discovery
- Security validated (unauthorized posts rejected)
- Complete data flow: PDS โ Jetstream โ AppView โ XRPC
Phase 2 deferred:
- Write-forward operations (enable, disable, updateConfig)
- SDK development
- Reference implementation (RSS aggregator)
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Consolidate duplicate test helper functions and fix test issues
discovered during aggregator development.
helpers.go:
- Consolidated createSimpleTestJWT() (removed duplicates from post_e2e_test.go)
- Consolidated generateTID() (removed duplicates)
- Added createPDSAccount() for E2E tests
- Added writePDSRecord() for E2E tests
- All helpers now shared across test files
post_e2e_test.go:
- Removed duplicate helper functions (now in helpers.go)
- Cleaned up unused imports (auth, base64, jwt)
- Fixed import order
community_identifier_resolution_test.go:
- Fixed PDS URL default from port 3000 โ 3001
- Matches actual dev PDS configuration (.env.dev)
- Test now passes with running PDS
auth.go middleware:
- Minor logging improvements for auth failures
Test results:
โ
TestCommunityIdentifierResolution: NOW PASSES (was failing)
โ
All aggregator tests: PASSING
โ
All community tests: PASSING
โ TestPostCreation_Basic: Still failing (pre-existing auth context issue)
Overall test suite:
- 74 out of 75 tests passing (98.7% pass rate)
- Only failure is pre-existing auth context issue in old test
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add complete test coverage for aggregator system with repository,
service, and end-to-end validation.
aggregator_test.go - Integration tests:
- TestAggregatorRepository_Create: Upsert logic, field mapping
- TestAggregatorRepository_IsAggregator: Fast existence checks
- TestAggregatorAuthorization_Create: Authorization with audit trail
- TestAggregatorAuthorization_IsAuthorized: Fast authorization checks
- TestAggregatorService_PostCreationIntegration: Authorization validation
- TestAggregatorService_RateLimiting: 10 posts/hour enforcement
- TestAggregatorPostService_Integration: Aggregator vs user detection
- TestAggregatorTriggers: Database trigger stats updates
aggregator_e2e_test.go - End-to-end validation:
Complete data flow testing across all components:
Part 1: Service Declaration
- Create aggregator account on PDS
- Write service record to PDS
- Simulate Jetstream event
- Verify indexed in AppView DB
- โ
Verified: Record exists on PDS (curl) AND in AppView (SQL)
Part 2: Authorization
- Create community account on PDS
- Write authorization record to PDS
- Index via Jetstream consumer
- Verify in AppView DB
- โ
Verified: Record exists on PDS (curl) AND in AppView (SQL)
Part 3: Post Creation
- Aggregator creates post via XRPC endpoint
- Post written to PDS
- Indexed via Jetstream
- Verify in AppView DB with aggregator attribution
- โ
Verified: Post on PDS (curl) AND in AppView (SQL)
Part 4: Rate Limiting
- Create 10 posts (at limit)
- 11th post rejected with 429 status
- โ
Rate limiting enforced correctly
Part 5: XRPC Query Endpoints
- getServices (basic and detailed views)
- getAuthorizations (nested aggregator object)
- listForCommunity (aggregators for community)
- โ
All endpoints return correct data
Part 6: Security
- Unauthorized aggregator posts rejected
- โ
Security validation working
Part 7: Idempotent Indexing
- Duplicate Jetstream events handled gracefully
- โ
Idempotency working
Part 8: Authorization Disable
- Disable authorization
- Post rejected after disable
- โ
Enable/disable workflow working
Test results:
โ
All 10+ test suites passing
โ
Records verified in both PDS and AppView
โ
Complete data flow validated
โ
Security checks validated
โ
Rate limiting validated
โ
XRPC endpoints validated
Coverage:
- Repository operations
- Service layer business logic
- Post integration flow
- Jetstream consumer indexing
- XRPC handler responses
- Database triggers
- End-to-end PDS โ Jetstream โ AppView flow
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Integrate aggregator components into server initialization and
register XRPC endpoints.
Changes to cmd/server/main.go:
- Initialize aggregator repository
- Initialize aggregator service (with community service dependency)
- Update post service to include aggregator service
- Register aggregator XRPC routes (3 query endpoints)
- Start aggregator Jetstream consumer in background goroutine
- Add comprehensive startup logging
Server startup output:
โ
Aggregator service initialized
Started Jetstream aggregator consumer: ws://localhost:6008/subscribe?...
- Indexing: social.coves.aggregator.service (service declarations)
- Indexing: social.coves.aggregator.authorization (authorization records)
Aggregator XRPC endpoints registered (query endpoints public)
Architecture:
- Aggregator service depends on: aggregator repo, community service
- Post service depends on: aggregator service (for auth checks)
- Jetstream consumer runs independently, indexes to DB via repository
- XRPC handlers call service layer methods
Phase 1 complete:
โ
Aggregators can authenticate (via JWT)
โ
Aggregators can post to authorized communities
โ
Rate limiting enforced (10 posts/hour per community)
โ
Query endpoints available for discovery
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement Jetstream consumer to index aggregator service declarations
and authorization records from the firehose in real-time.
aggregator_consumer.go:
- Handles social.coves.aggregator.service records (create/update/delete)
- Handles social.coves.aggregator.authorization records (create/update/delete)
- Upsert logic for both create and update operations
- Delete by URI for authorization cleanup
- Validation:
* Service rkey must be "self" (canonical location)
* communityDid in authorization must match repo DID (prevents forgery)
* did in service must match repo DID (prevents DID spoofing)
* Required fields validation
- Avatar blob extraction from atProto blob ref
- createdAt parsing from RFC3339 with fallback
aggregator_jetstream_connector.go:
- WebSocket connection management with auto-reconnect
- Ping/pong keepalive
- Graceful error handling (continues on parsing errors)
- Filters for wanted collections
Jetstream URL:
ws://localhost:6008/subscribe?wantedCollections=social.coves.aggregator.service&wantedCollections=social.coves.aggregator.authorization
Indexed to database:
- aggregators table (stats auto-updated via triggers)
- aggregator_authorizations table (unique constraint on aggregator+community)
Security:
- DID validation prevents impersonation
- communityDid validation prevents authorization forgery
- Graceful error handling prevents consumer crashes
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement XRPC query endpoints for aggregator discovery and
authorization management.
Handlers (internal/api/handlers/aggregator/):
- get_services.go: Fetch aggregator details by DIDs
* Supports detailed=true for stats (communities_using, posts_created)
* Returns aggregatorView or aggregatorViewDetailed union type
* Bulk query optimization for multiple DIDs
- get_authorizations.go: List communities using an aggregator
* Nested aggregatorView in response (lexicon compliance)
* Supports enabledOnly filter and pagination
- list_for_community.go: List aggregators for a community
* Accepts at-identifier (DID or handle) for community
* Returns authorizationView with config
* Supports enabledOnly filter and pagination
- errors.go: Error handling with domain error mapping
* Maps domain errors to appropriate HTTP status codes
* 404 for not found, 400 for validation, 501 for not implemented
Routes (internal/api/routes/aggregator.go):
- GET /xrpc/social.coves.aggregator.getServices?dids=...
- GET /xrpc/social.coves.aggregator.getAuthorizations?aggregatorDid=...
- GET /xrpc/social.coves.aggregator.listForCommunity?community=...
Features:
- Query parameter parsing with validation
- Domain model to API view conversion
- JSON response formatting matching lexicon
- Proper HTTP status codes (404, 400, 500, 501)
- Config unmarshal from JSONB to interface{}
Deferred to Phase 2:
- Write endpoints (enable, disable, updateConfig) return 501 Not Implemented
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Modify post creation flow to support aggregator posting with
server-side validation and rate limiting.
Changes to internal/core/posts/service.go:
- Server-side aggregator detection via database query
- Dual validation flow:
* Aggregators: Authorization + rate limits, skip membership checks
* Users: Existing visibility/membership validation
- Post tracking after successful creation for rate limiting
- Clear logging to distinguish aggregator vs user posts
Changes to internal/core/posts/errors.go:
- Added ErrRateLimitExceeded for aggregator rate limiting
Changes to internal/api/handlers/post/errors.go:
- Map both aggregators.ErrRateLimitExceeded and posts.ErrRateLimitExceeded to 429
Security:
- DID extracted from JWT (cryptographically verified)
- Database lookup confirms aggregator status (no client-provided flag)
- Authorization checked against indexed records from firehose
- Rate limiting: 10 posts/hour per community per aggregator
Flow:
1. Extract DID from JWT (verified by auth middleware)
2. Query: Is this DID an aggregator? (database lookup)
3a. If aggregator: Check authorization + rate limits
3b. If user: Check community membership/visibility
4. Write post to PDS
5. If aggregator: Record post for rate limiting
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement complete repository layer for aggregator data access with
optimized queries and bulk operations.
Domain models (internal/core/aggregators/):
- aggregator.go: Aggregator and Authorization domain types
- interfaces.go: Repository and Service interfaces
- errors.go: Domain-specific errors with IsXxx helpers
Repository (internal/db/postgres/aggregator_repo.go):
- CRUD operations for aggregators and authorizations
- Fast IsAggregator() check using EXISTS query
- Fast IsAuthorized() check with optimized partial index
- Bulk GetAggregatorsByDIDs() for efficient multi-DID queries
- Post tracking for rate limiting
- Upsert logic with ON CONFLICT for Jetstream indexing
- Delete by URI for Jetstream delete operations
Performance:
- Uses idx_aggregator_auth_lookup for <5ms authorization checks
- Uses idx_aggregator_posts_rate_limit for fast rate limit queries
- Parameterized queries throughout (no SQL injection risk)
- Bulk operations reduce N+1 query problems
Dependencies:
- Added gojsonschema for config validation
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Create comprehensive database schema for aggregator system with
3 tables, 2 triggers, and optimized indexes.
Tables:
- aggregators: Service declarations indexed from Jetstream
- aggregator_authorizations: Community authorizations
- aggregator_posts: Rate limiting tracking (AppView-only)
Key features:
- Optimized indexes for <5ms authorization checks
- Partial indexes WHERE enabled=true for performance
- Foreign keys with CASCADE delete
- Auto-updating stats via triggers
Triggers:
- update_aggregator_communities_count: Tracks communities_using
- update_aggregator_posts_count: Tracks posts_created
Security:
- Audit trail fields (created_by, disabled_by, disabled_at)
- Unique constraint on (aggregator_did, community_did)
- NOT NULL constraints on required fields
Performance:
- idx_aggregator_auth_lookup: Fast (aggregator, community, enabled) checks
- idx_aggregator_posts_rate_limit: Fast rate limit queries
- idx_aggregators_created_at: Sorting by creation date
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add complete lexicon definitions for the aggregator system following
atProto patterns (Feed Generator + Labeler model).
Records (2):
- service.json: Aggregator service declaration with config schema
- authorization.json: Community authorization with enabled status
Procedures (3):
- enable.json: Enable aggregator for community (moderator only)
- disable.json: Disable aggregator
- updateConfig.json: Update aggregator configuration
Queries (3):
- getServices.json: Fetch aggregator details by DIDs
- getAuthorizations.json: List communities using aggregator
- listForCommunity.json: List aggregators for community
Definitions:
- aggregatorView: Basic aggregator metadata
- aggregatorViewDetailed: Aggregator with stats
- authorizationView: Authorization from community perspective
- communityAuthView: Authorization from aggregator perspective
Design decisions:
- Removed aggregatorType enum (too rigid for alpha)
- Used JSON Schema for configSchema (validation + UI generation)
- Followed Bluesky feed generator patterns
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds complete community feed infrastructure with sort algorithms and XRPC endpoints.
Summary of changes:
- Core feed service with hot/new/top sorting algorithms
- PostgreSQL repository with optimized queries
- XRPC handler for social.coves.feed.getCommunity
- PostView types for rich feed responses
- Comprehensive integration tests
- Documentation for feeds and future aggregators
Key features:
โ
Public feed endpoint (no auth required for reading)
โ
Multiple sort algorithms (hot, new, top)
โ
Cursor-based pagination
โ
Proper input validation and error handling
โ
Full test coverage
This implements the read path for community feeds per atProto patterns.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
New Tests:
- TestGetCommunityFeed_BasicRetrieval: Verifies feed endpoint works
- TestGetCommunityFeed_SortOrders: Tests hot/new/top algorithms
- TestGetCommunityFeed_Pagination: Validates cursor-based paging
- TestGetCommunityFeed_EmptyFeed: Handles communities with no posts
- TestGetCommunityFeed_LimitValidation: Ensures limit clamping works
Test Fix:
- community_consumer_test.go: Changed collection from app.bsky.feed.post
to app.bsky.communityFeed.post to better demonstrate non-Coves namespace
filtering (the test verifies we ignore non-social.coves.community.* events)
Test Coverage:
- Feed retrieval with real post data
- Sort algorithm behavior
- Pagination edge cases
- Input validation
- Error handling
All tests use the shared test infrastructure (SetupTestDB, test user helpers)
and follow integration test patterns.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Comprehensive documentation for feed systems and future aggregator features:
New Documentation:
- COMMUNITY_FEEDS.md: Complete guide to feed architecture and implementation
- aggregators/PRD_AGGREGATORS.md: Product spec for RSS/aggregator features
- aggregators/PRD_KAGI_NEWS_RSS.md: Kagi News integration design
Updated:
- PRD_POSTS.md: Refined post creation flow and security model
Feed Documentation Coverage:
- Architecture overview (service โ repo โ postgres)
- Sort algorithms (hot, new, top)
- Query optimization and indexing strategy
- Security considerations
- API examples and usage
Aggregator PRDs:
- RSS feed generation per community
- External content aggregation
- Kagi News integration patterns
- Federation considerations
These docs provide context for current feed implementation and roadmap
for future aggregator features.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extends post types to support feed views and updates lexicon definitions:
Post Types Added:
- PostView: Full post representation with all metadata for feeds
- AuthorView: Author info (DID, handle, displayName, avatar, reputation)
- CommunityRef: Minimal community reference in posts
- PostStats: Aggregated statistics (votes, comments, shares)
- ViewerState: User's relationship with post (votes, saves, tags)
Lexicon Updates:
- social.coves.post.get: Restructured postView definition
- social.coves.feed.getCommunity: Updated query parameters and response
These types align with atProto patterns:
- Follows app.bsky.feed.defs#feedViewPost structure
- Supports viewer-specific state
- Enables efficient feed rendering
- Provides all data clients need in single request
The PostView types are used by feed endpoints to return rich post data.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Integrates community feed functionality into the main server:
- Initialize CommunityFeedRepository with database connection
- Initialize CommunityFeedService with dependencies
- Register feed XRPC routes (public endpoints)
- Add startup logging for feed service
Dependency injection flow:
feedRepo โ db
feedService โ feedRepo + communityService
feedHandler โ feedService
Routes registered:
- GET /xrpc/social.coves.feed.getCommunity (public)
The feed service is now live and ready to serve community feeds.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements the HTTP handler layer for social.coves.feed.getCommunity:
- GetCommunityHandler: XRPC endpoint handler with proper validation
- Query parameter parsing: community, sort, limit, cursor
- Error handling: Proper XRPC error responses (InvalidRequest, NotFound)
- Route registration: Public endpoint (no auth required for reading)
Security:
- Input validation for all query parameters
- Limit clamping (max 100 posts per request)
- Community existence verification
- No sensitive data exposure in error messages
Handler flow:
1. Parse and validate query parameters
2. Call feed service
3. Transform to XRPC response format
4. Return JSON with proper headers
This implements the read path for community feeds per atProto patterns.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements the core service layer and database repository for community feeds:
- CommunityFeedService: Orchestrates feed retrieval with sorting and pagination
- FeedRepository: PostgreSQL queries for post aggregation and filtering
- Feed types: FeedOptions, FeedResponse, SortOrder enums
- Error types: Proper error handling for feed operations
Architecture:
- Service layer handles business logic and coordinates with community service
- Repository performs efficient SQL queries with proper indexing
- Supports multiple sort algorithms (hot, new, top)
- Pagination via cursor-based approach
Security:
- All queries use parameterized statements
- Input validation in service layer
- Proper error wrapping for debugging
This is the foundation for social.coves.feed.getCommunity XRPC endpoint.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements Alpha post creation feature with full write-forward to community
PDS and real-time Jetstream indexing.
Features:
- POST /xrpc/social.coves.post.create endpoint
- Write-forward architecture (posts written to community's PDS repository)
- Real-time AppView indexing via Jetstream consumer
- Comprehensive security validation (auth, repository ownership, FK integrity)
- Support for all 4 at-identifier formats (DIDs, canonical, @-prefixed, scoped)
- Database schema with proper indexing (migration 011)
- Full integration test suite (service, repository, handler, E2E with live PDS)
Implementation:
- Domain layer: Post models, service, validation
- Repository layer: PostgreSQL with JSON support
- Handler layer: XRPC endpoint with OAuth auth
- Consumer layer: Jetstream real-time indexing with security checks
- 13 commits, 30+ files, ~2,700 lines
Deferred to Beta:
- Content rules validation
- Post read operations (get, list)
- Post update/delete operations
- Voting system
See docs/PRD_POSTS.md for complete status.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update lexicon validation tests to handle post record types:
- Add social.coves.post.record to test cases
- Verify at-identifier format for community field
- Validate author field (required DID)
Ensures lexicon validation works correctly for new post records.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Move duplicate helper functions from multiple test files to helpers.go:
- authenticateWithPDS() - Used by post e2e tests
- contains() / anySubstring() - String utilities
- Import standardization across test files
Benefits:
- Eliminates code duplication across 6+ test files
- Centralizes test utilities for easier maintenance
- Improves test readability (focus on test logic, not helpers)
All tests continue to pass with consolidated helpers.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add SetTestUserDID() function to inject user DID into context for testing.
Purpose:
- Mock authenticated users in integration tests without full OAuth flow
- Used by post handler tests to simulate authenticated requests
- Marked with comment: "ONLY be used in tests"
This enables testing authenticated endpoints (like post creation)
without requiring real PDS authentication in test environment.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update PRD_POSTS.md with implementation status:
- Add "Implementation Status" section showing completed work
- Mark Alpha CREATE features as complete (โ
)
- Mark Beta features as deferred (โ ๏ธ)
- Update all sections with checkmarks and status
- Add database schema status (migration 011 complete)
- Update success metrics (Alpha checklist complete)
- Reference IMPLEMENTATION_POST_CREATION.md for details
Completed (Alpha):
โ
Post creation endpoint with write-forward to community PDS
โ
Handler with authentication, validation, security checks
โ
Service layer with token refresh and community resolution
โ
PostgreSQL repository with proper indexing
โ
Jetstream consumer for real-time indexing
โ
E2E tests (service, repository, handler, live PDS+Jetstream)
โ
All 4 at-identifier formats supported
Deferred (Beta):
โ ๏ธ Content rules validation
โ ๏ธ Post read operations (get, list)
โ ๏ธ Post update/edit operations
โ ๏ธ Post deletion
โ ๏ธ Voting system
Update other PRDs:
- PRD_BACKLOG: Add post creation to completed items
- PRD_COMMUNITIES: Reference post integration
- PRD_GOVERNANCE: Note content rules deferred to Beta
PRDs now accurately reflect codebase state.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add social.coves.post lexicon definitions:
1. social.coves.post.record
- Post record schema for community repositories
- Fields: community (at-identifier), author (did), title, content
- Rich text support: facets for mentions/links
- Embed support: images, video, external, record
- Content labels: nsfw, spoiler, violence
- Federation fields: originalAuthor, federatedFrom (future)
- Location support (future)
- Author field REQUIRED (added after PR review)
2. social.coves.post.create
- XRPC procedure for post creation
- Input: matches record schema (minus author - server-populated)
- Output: uri (AT-URI), cid (content ID)
- Errors: InvalidRequest, AuthRequired, NotAuthorized, Banned
3. social.coves.post.get
- XRPC query for fetching single post (future)
- Input: uri (AT-URI)
- Output: post view with stats
Update community profile and feed lexicons:
- Reference post record type
- Update descriptions for post integration
All lexicons follow atProto conventions and use at-identifier
format for community references (supports DIDs and handles).
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add 4 test files covering full post creation flow:
1. post_creation_test.go - Service layer tests (11 subtests)
- Happy path with DID and handle resolution
- Validation: missing fields, invalid formats, length limits
- Content label validation (nsfw, spoiler, violence)
- Repository tests: create, duplicate URI handling
2. post_e2e_test.go - TRUE end-to-end test
- Part 1: Write-forward to live PDS
- Part 2: Real Jetstream WebSocket consumption
- Verifies complete cycle: HTTP โ PDS โ Jetstream โ AppView DB
- Tests ~1 second indexing latency
- Requires live PDS and Jetstream services
3. post_handler_test.go - Handler security tests (10+ subtests)
- Reject client-provided authorDid (impersonation prevention)
- Require authentication (401 on missing token)
- Request body size limit (1MB DoS prevention)
- Malformed JSON handling
- All 4 at-identifier formats (DIDs, canonical, @-prefixed, scoped)
- Unicode/emoji support
- SQL injection prevention
4. helpers.go - Test utilities
- JWT token generation for test users
All tests passing. Coverage includes security, validation,
business logic, and real-time indexing.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Wire up post creation feature in main server:
1. Initialize post service
- Create post repository (PostgreSQL)
- Create post service with community service integration
- Configure with default PDS URL
2. Register XRPC routes
- POST /xrpc/social.coves.post.create
- Requires OAuth authentication via middleware
3. Start Jetstream consumer for posts
- WebSocket URL: ws://localhost:6008/subscribe
- Collection filter: social.coves.post.record
- Runs in background goroutine
- Indexes CREATE operations (UPDATE/DELETE deferred)
Environment variables:
- POST_JETSTREAM_URL: Override default Jetstream endpoint
Initialization order ensures postRepo created before consumer.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Export community service methods for post creation:
- EnsureFreshToken() - Auto-refresh PDS tokens before write operations
- GetByDID() - Direct repository access for post service
These methods enable posts service to:
1. Fetch community from AppView by DID
2. Ensure fresh PDS credentials before writing to community repo
3. Use community's access token for PDS write-forward
Changes:
- Made ensureFreshToken() public as EnsureFreshToken()
- Added GetByDID() wrapper for repository access
- No functional changes, just visibility
Supports write-forward architecture where posts are written to
community's PDS repository using community's credentials.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add PostEventConsumer for AppView indexing:
- Listen for social.coves.post.record CREATE events via WebSocket
- Parse post records from Jetstream firehose
- Index posts into AppView database
- Handle UPDATE/DELETE deferred until those features exist
Security validation:
- Verify repository DID matches community DID (prevents fake posts)
- Verify community exists in AppView (foreign key integrity)
- Verify author exists in AppView (foreign key integrity)
- Idempotent indexing (safe for Jetstream replays)
Add PostJetstreamConnector:
- Dedicated WebSocket connector for post events
- Collection filter: social.coves.post.record
- Separate from CommunityJetstreamConnector (different event types)
Posts are indexed with ~1 second latency from PDS write.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add POST /xrpc/social.coves.post.create endpoint:
- Authentication required via OAuth middleware
- Validate request body size (1MB limit for DoS prevention)
- Validate at-identifier format for community field
- Reject client-provided authorDid (security)
- Set authorDid from authenticated JWT
- Error mapping for lexicon-compliant responses
Handler security features:
- Body size limit prevents DoS
- Author impersonation prevented
- All 4 at-identifier formats supported
- Proper error codes (400, 401, 403, 404, 500)
Route registration integrates with auth middleware.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add migration 011: posts table with indexes
- Add foreign keys to users and communities
- Add indexes for common query patterns (community feed, author, score)
- Add PostgreSQL repository implementation
- Add Create() and GetByURI() methods
- Add JSON serialization for facets, embeds, labels
Posts table supports:
- AT-URI, CID, rkey for atProto compliance
- Title, content, facets, embed, labels
- Vote counts and score (denormalized for performance)
- Soft delete with deleted_at timestamp
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add Post domain model with AppView database representation
- Add CreatePostRequest/Response for XRPC endpoint
- Add PostRecord for PDS write-forward
- Add Service and Repository interfaces
- Add error types (ValidationError, ContentRuleViolation)
- Add service implementation with PDS write-forward
- Add validation for content length, labels, at-identifiers
Part of Alpha post creation feature.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Complete implementation of community handle naming convention change
with comprehensive PR review fixes.
This merge includes:
- Critical bug fixes for identifier resolution
- Comprehensive test coverage (31 test cases, all passing)
- Database migration for .communities โ .community transition
- Input validation and error handling improvements
- Support for self-hosted instances
All PR review comments addressed:
โ
GetDisplayHandle() bug fixed for multi-part domains
โ
Case sensitivity bug fixed in resolveScopedIdentifier
โ
Comprehensive input validation (DNS labels, domain format)
โ
100% test coverage for new code
โ
Database migration script with rollback
โ
Improved error messages with identifier context
โ
NewPDSAccountProvisioner argument order corrected
โ
Removed hardcoded coves.social from tests
Test Results:
- 31 identifier resolution tests: PASS
- All integration tests: PASS
- E2E tests with real PDS: PASS
- Regression tests: PASS
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update development environment configuration and Go module dependencies.
Changes:
- Update .env.dev with latest environment variables
- Update docker-compose.dev.yml configuration
- Run go mod tidy to clean up dependencies
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update Product Requirements Document to document the singular
.community. naming convention.
Changes:
- Update handle format examples
- Document identifier resolution features
- Update API examples with new handle format
This ensures documentation matches the implemented handle format
and provides clear examples for developers.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update all integration tests to use singular .community. naming convention
instead of .communities.
Tests updated:
- E2E community creation and XRPC endpoint tests
- HostedBy security validation tests
- Community provisioning tests
- Service integration tests
- V2 validation tests
- Token refresh tests
Changes:
- Update expected handle formats in assertions
- Update test fixtures to use new convention
- Ensure regex patterns match .community. format
All tests passing with new handle format.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update PDS provisioning and Jetstream consumer to generate handles
using singular .community. instead of .communities.
Changes:
- PDSAccountProvisioner: Generate {name}.community.{domain} handles
- JetstreamConsumer: Parse and validate new handle format
- Update handle extraction logic for consistency
Example handle formats:
- gardening.community.coves.social
- gaming.community.coves.social
This maintains consistency with the lexicon schema update and aligns
with AT Protocol naming conventions.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update AT Protocol lexicon schema and test data to use singular
.community. instead of .communities. in handle format.
Changes:
- Update profile.json lexicon schema with new handle pattern
- Update test fixtures to use singular convention
- Update lexicon validation tests
This aligns with AT Protocol naming standards where all record types
use singular form (e.g., app.bsky.feed.post, app.bsky.graph.follow).
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add production-ready migration script to update existing community handles
from plural (.communities.) to singular (.community.) format.
Migration features:
- Safe UPDATE using REPLACE for targeted changes
- Verification checks to ensure migration completion
- Rollback script for emergency reversion
- Error handling with informative messages
Example transformations:
- gardening.communities.coves.social โ gardening.community.coves.social
- gaming.communities.coves.social โ gaming.community.coves.social
This migration is required for the .communities โ .community naming
convention change to align with AT Protocol lexicon standards
(all record types use singular form).
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add 31 test cases covering all identifier resolution code paths:
TestCommunityIdentifierResolution (14 E2E tests):
- DID format resolution (3 tests)
- Canonical handle format (3 tests)
- At-identifier format (2 tests)
- Scoped format !name@instance (5 tests)
- Edge cases (4 tests)
TestResolveScopedIdentifier_InputValidation (9 tests):
- Reject special characters, spaces, invalid DNS labels
- Reject names starting/ending with hyphens
- Reject names exceeding 63 character DNS limit
- Accept valid alphanumeric names with hyphens/numbers
- Validate domain format
TestGetDisplayHandle (5 tests):
- Standard two-part domains
- Multi-part TLDs (e.g., .co.uk)
- Subdomain instances
- Malformed input graceful fallback
TestIdentifierResolution_ErrorContext (3 tests):
- Verify error messages include identifier for debugging
- Verify DID, handle, and scoped errors provide context
Fixes:
- Use environment variables for configuration (no hardcoded coves.social)
- Correct NewPDSAccountProvisioner argument order (instanceDomain, pdsURL)
- Support self-hosted instances via INSTANCE_DOMAIN env var
All tests passing with real PDS integration.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Critical fixes:
- Fix GetDisplayHandle() to handle multi-part domains correctly using string.Index
- Add DNS label validation (RFC 1035) with isValidDNSLabel helper
- Add domain format validation with isValidDomain helper
- Normalize instanceDomain to lowercase for case-insensitive lookup
- Improve error messages to include identifier context for debugging
Validation improvements:
- Reject special characters in community names
- Enforce DNS label length limits (1-63 chars)
- Prevent names starting/ending with hyphens
- Validate domain format before lookup
Bug fixes:
- GetDisplayHandle now correctly parses handles with multi-part TLDs (e.g., coves.co.uk)
- resolveScopedIdentifier properly normalizes domain case (!gardening@Coves.social works)
- Error messages now include the identifier that failed resolution
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Comprehensive lexicon extensibility fixes to ensure alpha-readiness
and future-proof schema evolution without requiring V2 migrations.
Key Changes:
- Fixed all closed enums โ knownValues (moderationType, visibility, sort)
- Made moderator roles and permissions extensible
- Added authentication documentation to all endpoints
- Removed invalid membership record references
- Documented technical decisions in PRD_GOVERNANCE.md
This locks down the lexicon schemas for alpha while enabling future
beta features (sortition moderation, new visibility modes, moderator
tiers) without breaking changes.
Per atProto style guide (bluesky-social/atproto#4245): enum sets
cannot be extended without breaking schema evolution rules.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Membership tracking is AppView-only data, not atProto records.
Changes:
- Removed membershipUri field from community.get viewerState
- Updated member field description to clarify it's AppView-computed
- Removed membership lexicon file (already deleted)
- Removed membership test data files (already deleted)
Rationale:
- Membership/reputation is indexed from user activity, not explicit records
- No need for AT-URI reference to non-existent record type
- Clarifies that membership status is computed by AppView, not stored in repo
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Per atProto style guide: endpoint descriptions should mention if
authentication is required and whether responses are personalized.
Changes:
- create.json: Added "Requires authentication."
- update.json: Added "Requires authentication and moderator/admin permissions."
- subscribe.json: Added "Requires authentication."
- unsubscribe.json: Added "Requires authentication."
- get.json: Added "Authentication optional; viewer state will be included if authenticated."
- list.json: Added "Authentication optional; viewer state will be included if authenticated."
This improves developer experience by making auth requirements
explicit without requiring documentation lookup.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
BREAKING: This is a pre-alpha schema fix. Must be applied before any
moderator records are created.
Changes to social.coves.community.moderator:
- Change role from enum to knownValues (enables future role types)
- Change permissions from enum to knownValues (enables new permissions)
- Add maxLength: 64 to both fields per atProto style guide
Future extensibility examples:
- Roles: "owner", "trainee", "emeritus"
- Permissions: "manage_bots", "manage_flairs", "manage_automoderator"
Documented in PRD_GOVERNANCE.md:
- Technical decision rationale
- atProto style guide reference
- Future beta phase extensibility plan
- Security considerations
This enables Beta Phase 2 (Moderator Tiers & Permissions) without
requiring V2 schema migration or breaking existing records.
Per atProto style guide (bluesky-social/atproto#4245): enum sets
cannot be extended without breaking schema evolution rules.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change sort from closed enum to knownValues
- Add maxLength: 64 per atProto style guide
This enables future sort algorithms without breaking changes:
- "trending" - Recent activity spike detection
- "recommended" - Personalized AI recommendations
- "nearby" - Geo-based sorting
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change visibility from closed enum to knownValues
- Apply to community.profile (record), create, and update endpoints
- Add maxLength: 64 per atProto style guide
This enables future visibility modes without breaking changes:
- "followers-only" - Only subscribers can see
- "instance-only" - Only same-instance users
- "invite-only" - Requires invite code
Files changed:
- community/profile.json (record schema)
- community/create.json (procedure)
- community/update.json (procedure)
Per atProto style guide: closed enums block schema evolution.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change moderationType from closed enum to knownValues
- Add to required fields (critical before alpha - can't add required later)
- Add default value "moderator" for alpha simplicity
- Add maxLength constraint per atProto style guide
This enables future moderation types without schema migration:
- "sortition" - Community tribunal (Beta Phase 1)
- "instance-labeler" - Instance moderation service
- "third-party-labeler" - External moderation DID
Per atProto style guide: enum sets cannot be extended without breaking
schema evolution. knownValues provides flexible alternative.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements Phase 1 did:web domain verification to prevent domain
impersonation attacks in the Coves federated community system.
This PR addresses all code review feedback across 3 rounds:
Round 1 - Performance & Security:
โ
P0: Multi-part TLD support (fixes .co.uk, .com.au blocking)
โ
HTTP client connection pooling
โ
Bounded LRU cache implementation
โ
Rate limiting for DoS protection
Round 2 - Critical Bug Fixes:
โ
Memory leak (unbounded cache โ bounded LRU)
โ
Deadlock (manual locks โ thread-safe LRU)
โ
Missing timeout (added 15s overall timeout)
Round 3 - Optimizations:
โ
Cache TTL cleanup (removes expired entries)
โ
Struct field alignment (performance)
โ
All linter issues resolved
Security Impact:
- Prevents malicious instances from claiming communities for domains
they don't control (e.g., evil.com claiming @gaming@nintendo.com)
- Verifies hostedBy domain matches community handle domain
- Optional .well-known/did.json verification for cryptographic proof
- Soft-fail on network errors (resilience)
Test Coverage:
- 13 new security test cases (all passing)
- 42+ total tests (all passing)
- Multi-part TLD support verified (.co.uk, .com.au, .org.uk, .ac.uk)
Code Quality:
โ
All linter checks passing
โ
All code properly formatted
โ
Clean build (no warnings)
โ
Production-ready
๐ค Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Adds comprehensive test coverage for hostedBy domain verification,
including multi-part TLD support and security attack scenarios.
Test Coverage:
TestHostedByVerification_DomainMatching:
- โ
Rejects communities with mismatched hostedBy domains
- โ
Accepts communities with matching hostedBy domains
- โ
Rejects non-did:web format hostedBy values
- โ
Skip verification flag bypasses all checks (dev mode)
TestExtractDomainFromHandle:
- โ
DNS-style handles with subdomains
- โ
Simple two-part domains
- โ
Multi-part subdomains
- โ
Multi-part TLD: .co.uk (critical fix validation)
- โ
Multi-part TLD: .com.au (critical fix validation)
- โ
Multi-part TLD: .org.uk, .ac.uk
- โ
Correctly rejects incorrect TLD extraction (e.g., did:web:co.uk)
- โ
Domain mismatch detection
Security Attack Scenarios Tested:
1. Domain impersonation (evil.com claiming nintendo.com) - BLOCKED
2. Non-did:web hostedBy spoofing - BLOCKED
3. Multi-part TLD domain extraction failures - FIXED
All tests passing (9/9 multi-part TLD tests).
Co-Authored-By: Claude <noreply@anthropic.com>