A community based topic aggregation platform built on atproto
1# Communities PRD: Federated Forum System 2 3**Status:** In Development 4**Owner:** Platform Team 5**Last Updated:** 2025-10-16 6 7## Overview 8 9Coves communities are federated, instance-scoped forums built on atProto. Each community is identified by a scoped handle (`!gaming@coves.social`) and owns its own atProto repository, enabling true portability and decentralized governance. 10 11## Architecture Evolution 12 13### ✅ V2 Architecture (Current - 2025-10-10) 14 15**Communities own their own repositories:** 16- Each community has its own DID (`did:plc:xxx`) 17- Each community owns its own atProto repository (`at://community_did/...`) 18- Each community has its own PDS account (managed by Coves backend) 19- Communities are truly portable - can migrate between instances by updating DID document 20 21**Repository Structure:** 22``` 23Repository: at://did:plc:community789/social.coves.community.profile/self 24Owner: did:plc:community789 (community owns itself) 25Hosted By: did:web:coves.social (instance manages credentials) 26``` 27 28**Key Benefits:** 29- ✅ True atProto compliance (matches feed generators, labelers) 30- ✅ Portable URIs (never change when migrating instances) 31- ✅ Self-owned identity model 32- ✅ Standard rkey="self" for singleton profiles 33 34--- 35 36## ✅ Completed Features (2025-10-10) 37 38### Core Infrastructure 39- [x] **V2 Architecture:** Communities own their own repositories 40- [x] **PDS Account Provisioning:** Automatic account creation for each community 41- [x] **Credential Management:** Secure storage of community PDS credentials 42- [x] **Encryption at Rest:** PostgreSQL pgcrypto for sensitive credentials 43- [x] **Write-Forward Pattern:** Service → PDS → Firehose → AppView 44- [x] **Jetstream Consumer:** Real-time indexing from firehose 45- [x] **V2 Validation:** Strict rkey="self" enforcement (no V1 compatibility) 46 47### Security & Data Protection 48- [x] **Encrypted Credentials:** Access/refresh tokens encrypted in database 49- [x] **Credential Persistence:** PDS credentials survive server restarts 50- [x] **JSON Exclusion:** Credentials never exposed in API responses (`json:"-"` tags) 51- [x] **Password Hashing:** bcrypt for PDS account passwords 52- [x] **Timeout Handling:** 30s timeout for write operations, 10s for reads 53 54### Database Schema 55- [x] **Communities Table:** Full metadata with V2 credential columns 56- [x] **Subscriptions Table:** Lightweight feed following 57- [x] **Memberships Table:** Active participation tracking 58- [x] **Moderation Table:** Local moderation actions 59- [x] **Encryption Keys Table:** Secure key management for pgcrypto 60- [x] **Indexes:** Optimized for search, visibility filtering, and lookups 61 62### Service Layer 63- [x] **CreateCommunity:** Provisions PDS account, creates record, persists credentials 64- [x] **UpdateCommunity:** Uses community's own credentials (not instance credentials) 65- [x] **GetCommunity:** Fetches from AppView DB with decrypted credentials 66- [x] **ListCommunities:** Pagination, filtering, sorting 67- [x] **SearchCommunities:** Full-text search on name/description 68- [x] **Subscribe/Unsubscribe:** Create subscription records 69- [x] **Handle Validation:** Scoped handle format (`!name@instance`) 70- [x] **DID Generation:** Uses `did:plc` for portability 71 72### Jetstream Consumer 73- [x] **Profile Events:** Create, update, delete community profiles 74- [x] **Subscription Events:** Index user subscriptions to communities 75- [x] **V2 Enforcement:** Reject non-"self" rkeys (no V1 communities) 76- [x] **Self-Ownership Validation:** Verify owner_did == did 77- [x] **Error Handling:** Graceful handling of malformed events 78 79### Testing Coverage 80- [x] **Integration Tests:** Full CRUD operations 81- [x] **Credential Tests:** Persistence, encryption, decryption 82- [x] **V2 Validation Tests:** Rkey enforcement, self-ownership 83- [x] **Consumer Tests:** Firehose event processing 84- [x] **Repository Tests:** Database operations 85- [x] **Unit Tests:** Service layer logic, timeout handling 86 87--- 88 89## 🚧 In Progress / Needs Testing 90 91### XRPC API Endpoints 92**Status:** All core endpoints E2E tested! ✅ 93 94**✅ E2E Tested (via community_e2e_test.go):** 95- [x] `social.coves.community.create` - Full E2E test with real PDS 96- [x] `social.coves.community.get` - E2E test validates HTTP endpoint 97- [x] `social.coves.community.list` - E2E test with pagination/filtering 98- [x] `social.coves.community.update` - E2E test verifies write-forward + PDS update 99- [x] `social.coves.community.subscribe` - E2E test verifies subscription in user's repo 100- [x] `social.coves.community.unsubscribe` - E2E test verifies PDS deletion 101 102**📍 Post-Alpha:** 103- [ ] `social.coves.community.search` - Handler exists, defer E2E testing to post-alpha 104 105**✅ OAuth Authentication Complete (2025-10-16):** 106- User access tokens now flow through middleware → handlers → service 107- Subscribe/unsubscribe operations use correct user-scoped credentials 108- All E2E tests validate real PDS authentication with user tokens 109 110--- 111 112## ⚠️ Alpha Blockers (Must Complete Before Alpha Launch) 113 114### Critical Missing Features 115- [ ] **Community Blocking:** Users can block communities from their feeds 116 - Lexicon: ❌ Need new record type (extend `social.coves.actor.block` or create new) 117 - Service: ❌ No implementation (`BlockCommunity()` / `UnblockCommunity()`) 118 - Handler: ❌ No endpoints 119 - Repository: ❌ No methods 120 - **Impact:** Users have no way to hide unwanted communities 121 122### ✅ Critical Infrastructure - RESOLVED (2025-10-16) 123- [x] **✅ Subscription Indexing & ContentVisibility - COMPLETE** 124 - **Status:** Subscriptions now fully indexed in AppView with feed slider support 125 - **Completed:** 2025-10-16 126 - **What Was Fixed:** 127 1. ✅ Fixed critical collection name bug (`social.coves.actor.subscription``social.coves.community.subscription`) 128 2. ✅ Implemented ContentVisibility (1-5 slider) across all layers (handler, service, consumer, repository) 129 3. ✅ Production Jetstream consumer now running ([cmd/server/main.go:220-243](cmd/server/main.go#L220-L243)) 130 4. ✅ Migration 008 adds `content_visibility` column with defaults and constraints 131 5. ✅ Atomic subscriber count updates (SubscribeWithCount/UnsubscribeWithCount) 132 6. ✅ DELETE operations properly handled (unsubscribe indexing) 133 7. ✅ Idempotent operations (safe for Jetstream event replays) 134 8. ✅ atProto naming compliance: singular namespace + `subject` field 135 - **Impact:** 136 - ✅ Users CAN subscribe/unsubscribe (writes to their PDS repo) 137 - ✅ AppView INDEXES subscriptions from Jetstream in real-time 138 - ✅ Can query user's subscriptions (data persisted with contentVisibility) 139 - ✅ Feed generation ENABLED (know who's subscribed with visibility preferences) 140 - ✅ Subscriber counts accurate (atomic updates) 141 - **Testing:** 142 - ✅ 13 comprehensive integration tests (subscription_indexing_test.go) - ALL PASSING 143 - ✅ Enhanced E2E tests verify complete flow (HTTP → PDS → Jetstream → AppView) 144 - ✅ ContentVisibility clamping tested (0→1, 10→5, defaults to 3) 145 - ✅ Idempotency verified (duplicate events handled gracefully) 146 - **Files:** 147 - Implementation Doc: [docs/IMPLEMENTATION_SUBSCRIPTION_INDEXING.md](docs/IMPLEMENTATION_SUBSCRIPTION_INDEXING.md) 148 - Lexicon: [internal/atproto/lexicon/social/coves/community/subscription.json](internal/atproto/lexicon/social/coves/community/subscription.json) 149 - Consumer: [internal/atproto/jetstream/community_consumer.go](internal/atproto/jetstream/community_consumer.go) 150 - Connector: [internal/atproto/jetstream/community_jetstream_connector.go](internal/atproto/jetstream/community_jetstream_connector.go) 151 - Migration: [internal/db/migrations/008_add_content_visibility_to_subscriptions.sql](internal/db/migrations/008_add_content_visibility_to_subscriptions.sql) 152 - Tests: [tests/integration/subscription_indexing_test.go](tests/integration/subscription_indexing_test.go) 153 154### Critical Security (High Priority) 155- [x] **OAuth Authentication:** ✅ COMPLETE - User access tokens flow end-to-end 156 - ✅ Middleware stores user access token in context 157 - ✅ Handlers extract and pass token to service 158 - ✅ Service uses user token for user repo operations (subscribe/unsubscribe) 159 - ✅ All E2E tests pass with real PDS authentication 160 - **Completed:** 2025-10-16 161 162- [ ] **Token Refresh Logic:** Auto-refresh expired PDS access tokens 163 - **Impact:** Communities break after ~2 hours when tokens expire 164 - **See:** [PRD_BACKLOG.md P1 Priority](docs/PRD_BACKLOG.md#L31-L38) 165 166--- 167 168## 📍 Beta Features (High Priority - Post Alpha) 169 170### Posts in Communities 171**Status:** Lexicon designed, implementation TODO 172**Priority:** HIGHEST for Beta 1 173 174- [ ] `social.coves.post` already has `community` field ✅ 175- [ ] Create post endpoint (decide: membership validation?) 176- [ ] Feed generation for community posts 177- [ ] Post consumer (index community posts from firehose) 178- [ ] Community post count tracking 179- [ ] Decide membership requirements for posting 180 181**Without posts, communities exist but can't be used!** 182 183--- 184 185## 📍 Beta Features (Lower Priority) 186 187### Membership System 188**Status:** Lexicon exists, design decisions needed 189**Deferred:** Answer design questions before implementing 190 191- [ ] Decide: Auto-join on first post vs explicit join? 192- [ ] Decide: Reputation tracking in lexicon vs AppView only? 193- [ ] Implement membership record creation (if explicit join) 194- [ ] Member lists endpoint 195- [ ] Reputation tracking (if in lexicon) 196 197### Community Management 198- [ ] **Community Deletion:** Soft delete / permanent delete 199- [ ] **Wiki System:** Lexicon exists, no implementation 200- [ ] **Advanced Rules:** Separate rules records, moderation config 201- [ ] **Moderator Management:** Assign/remove moderators (governance work) 202- [ ] **Categories:** REMOVE from lexicon and code (not needed) 203 204### User Features 205- [ ] **Saved Items:** Save posts/comments for later 206- [ ] **User Flairs:** Per-community user flair (design TBD) 207 208### Instance Moderation 209- [ ] **Delist Community:** Remove from search/directory 210- [ ] **Quarantine Community:** Show warning label 211- [ ] **Remove Community:** Hide from instance AppView 212- [ ] **Moderation Audit Log:** Track all moderation actions 213 214--- 215 216## ⏳ TODO Before V1 Production Launch 217 218### Community Discovery & Visibility 219- [ ] **Visibility Enforcement:** Respect public/unlisted/private settings in listings 220- [ ] **Federation Config:** Honor `allowExternalDiscovery` flag 221- [ ] **Search Relevance:** Implement ranking algorithm (members, activity, etc.) 222- [ ] **Directory Endpoint:** Public community directory with filters 223- [ ] **Rate Limiting:** Prevent community creation spam (e.g., 5 per user per hour) 224- [ ] **Handle Collision Detection:** Prevent duplicate community handles 225- [ ] **DID Validation:** Verify DIDs before accepting create requests 226 227### Token Refresh & Resilience 228- [ ] **Retry Mechanism:** Retry failed PDS calls with backoff 229- [ ] **Credential Rotation:** Periodic password rotation for security 230- [ ] **Error Recovery:** Graceful degradation if PDS is unavailable 231 232### Performance & Scaling 233- [ ] **Database Indexes:** Verify all common queries are indexed 234- [ ] **Query Optimization:** Review N+1 query patterns 235- [ ] **Caching Strategy:** Cache frequently accessed communities 236- [ ] **Pagination Limits:** Enforce max results per request 237- [ ] **Connection Pooling:** Optimize PDS HTTP client reuse 238 239### Documentation & Deployment 240- [ ] **API Documentation:** OpenAPI/Swagger specs for all endpoints 241- [ ] **Deployment Guide:** Production setup instructions 242- [ ] **Migration Guide:** How to upgrade from test to production 243- [ ] **Monitoring Guide:** Metrics and alerting setup 244- [ ] **Security Checklist:** Pre-launch security audit 245 246### Infrastructure & DNS 247- [ ] **DNS Wildcard Setup:** Configure `*.communities.coves.social` for community handle resolution 248- [ ] **Well-Known Endpoint:** Implement `.well-known/atproto-did` handler for `*.communities.coves.social` subdomains 249 250--- 251 252## Out of Scope (Future Versions) 253 254### V3: Federation & Discovery 255- [ ] Cross-instance community search 256- [ ] Federated moderation signals 257- [ ] Trust networks between instances 258- [ ] Moderation signal subscription 259 260### V4: Community Governance 261- [ ] Community-owned governance (voting on moderators) 262- [ ] Migration voting (community votes to move instances) 263- [ ] Custom domain DIDs (`did:web:gaming.community`) 264- [ ] Governance thresholds and time locks 265 266--- 267 268## Recent Critical Fixes (2025-10-10) 269 270### Security & Credential Management 271**Issue:** PDS credentials were created but never persisted 272**Fix:** Service layer now immediately persists credentials via `repo.Create()` 273**Impact:** Communities can now be updated after creation (credentials survive restarts) 274 275**Issue:** Credentials stored in plaintext in PostgreSQL 276**Fix:** Added pgcrypto encryption for access/refresh tokens 277**Impact:** Database compromise no longer exposes active tokens 278 279**Issue:** UpdateCommunity used instance credentials instead of community credentials 280**Fix:** Changed to use `existing.DID` and `existing.PDSAccessToken` 281**Impact:** Updates now correctly authenticate as the community itself 282 283### V2 Architecture Enforcement 284**Issue:** Consumer accepted V1 communities with TID-based rkeys 285**Fix:** Strict validation - only rkey="self" accepted 286**Impact:** No legacy V1 data in production 287 288**Issue:** PDS write operations timed out (10s too short) 289**Fix:** Dynamic timeout - writes get 30s, reads get 10s 290**Impact:** Community creation no longer fails on slow PDS operations 291 292--- 293 294## Lexicon Summary 295 296### `social.coves.community.profile` 297**Status:** ✅ Implemented and tested 298 299**Required Fields:** 300- `handle` - atProto handle (DNS-resolvable, e.g., `gaming.communities.coves.social`) 301- `name` - Short community name for !mentions (e.g., `gaming`) 302- `createdBy` - DID of user who created community 303- `hostedBy` - DID of hosting instance 304- `visibility` - `"public"`, `"unlisted"`, or `"private"` 305- `federation.allowExternalDiscovery` - Boolean 306 307**Note:** The `!gaming@coves.social` format is derived client-side from `name` + instance for UI display. The `handle` field contains only the DNS-resolvable atProto handle. 308 309**Optional Fields:** 310- `displayName` - Display name for UI 311- `description` - Community description 312- `descriptionFacets` - Rich text annotations 313- `avatar` - Blob reference for avatar image 314- `banner` - Blob reference for banner image 315- `moderationType` - `"moderator"` or `"sortition"` 316- `contentWarnings` - Array of content warning types 317- `memberCount` - Cached count 318- `subscriberCount` - Cached count 319 320### `social.coves.community.subscription` 321**Status:** ✅ Schema exists, consumer TODO 322 323**Fields:** 324- `community` - DID of community being subscribed to 325- `subscribedAt` - Timestamp 326 327### `social.coves.post` (Community Extension) 328**Status:** ⏳ TODO 329 330**New Field:** 331- `community` - Optional DID of community this post belongs to 332 333--- 334 335## Success Metrics 336 337### Pre-Launch Checklist 338- [ ] All XRPC endpoints have E2E tests 339- [ ] OAuth authentication working on all protected endpoints 340- [ ] Rate limiting prevents abuse 341- [ ] Communities can be created, updated, searched, and subscribed to 342- [ ] Jetstream consumer indexes events in < 1 second 343- [ ] Database handles 10,000+ communities without performance issues 344- [ ] Security audit completed 345 346### V1 Launch Goals 347- Communities can be created with scoped handles 348- Posts can be made to communities (when implemented) 349- Community discovery works on local instance 350- All three visibility levels function correctly 351- Basic moderation (delist/remove) works 352 353--- 354 355## Technical Decisions Log 356 357### 2025-10-11: Single Handle Field (atProto-Compliant) 358**Decision:** Use single `handle` field containing DNS-resolvable atProto handle; remove `atprotoHandle` field 359 360**Rationale:** 361- Matches Bluesky pattern: `app.bsky.actor.profile` has one `handle` field 362- Reduces confusion about which handle is "real" 363- Simplifies lexicon (one field vs two) 364- `!gaming@coves.social` display format is client-side UX concern, not protocol concern 365- Follows separation of concerns: protocol layer uses DNS handles, UI layer formats for display 366 367**Implementation:** 368- Lexicon: `handle` = `gaming.communities.coves.social` (DNS-resolvable) 369- Client derives display: `!${name}@${instance}` from `name` + parsed instance 370- Rich text facets can encode community mentions with `!` prefix for UX 371 372**Trade-offs Accepted:** 373- Clients must parse/format for display (but already do this for `@user` mentions) 374- No explicit "display handle" in record (but `displayName` serves this purpose) 375 376--- 377 378### 2025-10-10: V2 Architecture Completed 379- Migrated from instance-owned to community-owned repositories 380- Each community now has own PDS account 381- Credentials encrypted at rest using pgcrypto 382- Strict V2 enforcement (no V1 compatibility) 383 384### 2025-10-08: DID Architecture & atProto Compliance 385- Migrated from `did:coves` to `did:plc` (portable DIDs) 386- Added required `did` field to lexicon 387- Fixed critical `record_uri` bug 388- Matches Bluesky feed generator pattern 389 390--- 391 392## References 393 394- atProto Lexicon Spec: https://atproto.com/specs/lexicon 395- DID Web Spec: https://w3c-ccg.github.io/did-method-web/ 396- Bluesky Handle System: https://atproto.com/specs/handle 397- PLC Directory: https://plc.directory