···
# Communities PRD: Federated Forum System
-
**Last Updated:** 2025-10-07
-
Coves communities are federated, instance-scoped forums built on atProto. Each community is identified by a scoped handle (`!gaming@coves.social`) and owned by a DID, enabling future portability and community governance.
-
**V1 (MVP):** Instance-owned communities with scoped handles
-
**V2 (Post-Launch):** Cross-instance discovery and moderation signal federation
-
**V3 (Future):** Community-owned DIDs with migration capabilities via community voting
-
1. **Scoped by default:** All communities use `!name@instance.com` format
-
2. **DID-based ownership:** Communities are owned by DIDs (initially instance, eventually community)
-
3. **Web DID compatible:** Communities can use `did:web` for custom domains (e.g., `!photography@lens.club`)
-
4. **Federation-ready:** Design for cross-instance discovery and moderation from day one
-
5. **Community sovereignty:** Future path to community ownership and migration
-
## Identity & Namespace
-
### Community Handle Format
-
!my-book-club@personal.coves.io
-
"handle": "!gaming@coves.social",
-
"did": "did:web:coves.social:community:gaming",
-
"owner": "did:web:coves.social",
-
"createdBy": "did:plc:user123",
-
"hostedBy": "did:web:coves.social",
-
"created": "2025-10-07T12:00:00Z"
-
**Future: Community-Owned**
-
"handle": "!gaming@coves.social",
-
"did": "did:web:gaming.community",
-
"owner": "did:web:gaming.community",
-
"createdBy": "did:plc:user123",
-
"hostedBy": "did:web:coves.social",
-
- **No namespace conflicts:** Each instance controls its own namespace
-
- **Clear ownership:** `@instance` shows who hosts it
-
- **Decentralized:** No global registry required
-
- **Web DID ready:** Communities can become `did:web` and use custom domains
-
- **Fragmentation handled socially:** Community governance and moderation quality drives membership
-
## Visibility & Discoverability
-
- Indexed by home instance
-
- Appears in search results
-
- Listed in community directory
-
- Can be federated to other instances
-
- Accessible via direct link
-
- Not in search results
-
- Not in public directory
-
- Members can invite others
-
- Requires approval to join
-
### Discovery Configuration
-
type CommunityVisibility struct {
-
Level string // "public", "unlisted", "private"
-
AllowExternalDiscovery bool // Can other instances index this?
-
AllowedInstances []string // Whitelist (empty = all if public)
-
// Public gaming community, federate everywhere
-
"visibility": "public",
-
"allowExternalDiscovery": true,
-
// Book club, public on home instance only
-
"visibility": "public",
-
"allowExternalDiscovery": false,
-
// Private beta testing community
-
"visibility": "private",
-
"allowExternalDiscovery": false,
-
"allowedInstances": ["coves.social", "trusted.instance"]
-
## Moderation & Federation
-
### Moderation Actions (Local Only)
-
Communities can be moderated locally by the hosting instance:
-
type ModerationAction struct {
-
Action string // "delist", "quarantine", "remove"
-
BroadcastSignal bool // Share with network?
-
- Removed from search/directory
-
- Existing members can still access
-
- Not deleted, just hidden
-
- Visible with warning label
-
- "This community may violate guidelines"
-
- Can still be accessed with acknowledgment
-
- Community hidden from instance AppView
-
- Data still exists in firehose
-
- Other instances can choose to ignore removal
-
**What you can control:**
-
- What YOUR AppView indexes
-
- What moderation signals you broadcast
-
- What other instances' signals you honor
-
**What you cannot control:**
-
- Self-hosted PDS/AppView can index anything
-
- Other instances may ignore your moderation
-
- Community data lives in firehose regardless
-
**Moderation is local AppView filtering, not network-wide censorship.**
-
### Moderation Signal Federation (V2)
-
Instances can subscribe to each other's moderation feeds:
-
"moderationFeed": "did:web:coves.social:moderation",
-
"target": "did:web:coves.social:community:hate-speech",
-
"reason": "Violates community guidelines",
-
"timestamp": "2025-10-07T14:30:00Z",
-
"evidence": "https://coves.social/moderation/case/123"
-
- Auto-apply trusted instance moderation
-
- Show warnings based on signals
-
- Ignore signals entirely
-
### ✅ Completed (2025-10-08)
-
**Core Functionality:**
-
- [x] Create communities (instance-owned DID)
-
- [x] Scoped handle format (`!name@instance`)
-
- [x] Three visibility levels (public, unlisted, private)
-
- [x] Basic community metadata (name, description, rules)
-
- [x] Write-forward to PDS (communities as atProto records)
-
- [x] Jetstream consumer (index communities from firehose)
-
**Technical Infrastructure:**
-
- [x] Lexicon: `social.coves.community.profile` with `did` field (atProto compliant!)
-
- [x] DID format: `did:plc:xxx` (portable, federated)
-
- [x] PostgreSQL indexing for local communities
-
- [x] Service layer (business logic)
-
- [x] Repository layer (database)
-
- [x] Consumer layer (firehose indexing)
-
- [x] Environment config (`IS_DEV_ENV`, `PLC_DIRECTORY_URL`)
-
- [x] Fixed `record_uri` bug (now points to correct repository location)
-
- [x] Added required `did` field to lexicon (atProto compliance)
-
- [x] Consumer correctly separates community DID from repository DID
-
- [x] E2E test passes (PDS write → firehose → AppView indexing)
-
**API Endpoints (XRPC):**
-
- [x] `social.coves.community.create` (handler exists, needs testing)
-
- [ ] `social.coves.community.get` (handler exists, needs testing)
-
- [ ] `social.coves.community.list` (handler exists, needs testing)
-
- [ ] `social.coves.community.search` (handler exists, needs testing)
-
- [x] `social.coves.community.subscribe` (handler exists)
-
- [x] `social.coves.community.unsubscribe` (handler exists)
-
**Subscriptions & Memberships:**
-
- [x] Database schema (subscriptions, memberships tables)
-
- [x] Repository methods (subscribe, unsubscribe, list)
-
- [ ] Consumer processing (index subscription events from firehose)
-
- [ ] Membership tracking (convert subscription → membership on first post?)
-
### ⏳ TODO Before V1 Launch
-
- [ ] Test all XRPC endpoints end-to-end
-
- [ ] Implement OAuth middleware (protect create/update endpoints)
-
- [ ] Add authorization checks (who can create/update/delete?)
-
- [ ] Handle validation (prevent duplicate handles, validate DIDs)
-
- [ ] Rate limiting (prevent community spam)
-
**Community Discovery:**
-
- [ ] Community list endpoint (pagination, filtering)
-
- [ ] Community search (full-text search on name/description)
-
- [ ] Visibility enforcement (respect public/unlisted/private)
-
- [ ] Federation config (respect `allowExternalDiscovery`)
-
**Posts in Communities:**
- [ ] Extend `social.coves.post` lexicon with `community` field
-
- [ ] Create post endpoint (require community membership?)
-
- [ ] Feed generation (show posts in community)
- [ ] Post consumer (index community posts from firehose)
-
**Moderation (Basic):**
-
- [ ] Remove community from AppView (delist)
-
- [ ] Quarantine community (show warning)
-
- [ ] Moderation audit log
-
- [ ] Admin endpoints (for instance operators)
-
**Testing & Documentation:**
-
- [ ] Integration tests for all flows
-
- [ ] API documentation (XRPC endpoints)
-
- [ ] Deployment guide (PDS setup, environment config)
-
- [ ] Migration guide (how to upgrade from test to production)
-
- [ ] Moderation signal federation
-
- [ ] Community-owned DIDs
-
- [ ] Migration/portability
-
- [ ] Governance voting
-
- [ ] Custom domain DIDs
-
## Phase 2: Federation & Discovery
-
- Cross-instance community search
-
- Federated moderation signals
-
- Trust networks between instances
-
// Cross-instance discovery
-
type FederationConfig struct {
-
DiscoverPeers []string // Other Coves instances to index
-
TrustModerationFrom []string // Auto-apply moderation signals
-
ShareCommunitiesWith []string // Allow these instances to index ours
-
// Moderation trust network
-
type ModerationTrust struct {
-
TrustLevel string // "auto-apply", "show-warning", "ignore"
-
Categories []string // Which violations to trust ("spam", "nsfw", etc)
-
!golang@coves.social (45k members)
-
!golang@dev.forums (12k members)
-
Focused on systems programming
-
!go@programming.zone (3k members)
-
Hosted on programming.zone
-
⚠️ Flagged by trusted moderators
-
### 2025-10-08: DID Architecture & atProto Compliance
-
1. **Migrated from `did:coves` to `did:plc`**
-
- Communities now use proper PLC DIDs (portable across instances)
-
- Added `IS_DEV_ENV` flag (dev = generate without PLC registration, prod = register)
-
- Matches Bluesky's feed generator pattern
-
2. **Fixed Critical `record_uri` Bug**
-
- Problem: Consumer was setting community DID as repository owner
-
- Fix: Correctly separate community DID (entity) from repository DID (storage)
-
- Result: URIs now point to actual data location (federation works!)
-
3. **Added Required `did` Field to Lexicon**
-
- atProto research revealed communities MUST have their own DID field
-
- Matches `app.bsky.feed.generator` pattern (service has DID, record stored elsewhere)
-
- Enables future migration to community-owned repositories
-
**Architecture Insights:**
-
User Profile (Bluesky):
-
at://did:plc:user123/app.bsky.actor.profile/self
-
↑ Repository location IS the identity
-
No separate "did" field needed
-
Feed Generator (Bluesky):
-
at://did:plc:creator456/app.bsky.feed.generator/cool-feed
-
Record contains: {"did": "did:web:feedgen.service", ...}
-
↑ Service has own DID, record stored in creator's repo
-
at://did:plc:instance123/social.coves.community.profile/rkey
-
Record contains: {"did": "did:plc:community789", ...}
-
↑ Community has own DID, record stored in instance repo
-
Community (Coves V2 - Future):
-
at://did:plc:community789/social.coves.community.profile/self
-
Record contains: {"owner": "did:plc:instance123", ...}
-
↑ Community owns its own repo, instance manages it
-
1. **Keypair Management**: Coves can manage community keypairs (like Bluesky manages user keys)
-
2. **PDS Authentication**: Can create PDS accounts for communities, Coves stores credentials
-
3. **Migration Path**: Current V1 enables future V2 without breaking changes
-
- V1 (Current): Simple, ships fast, limited portability
-
- V2 (Future): Complex, true portability, matches atProto entity model
-
**Decision: Ship V1 now, plan V2 migration.**
-
## CRITICAL: DID Architecture Decision (2025-10-08)
-
### Current State: Hybrid Approach
-
**V1 Implementation (Current):**
-
Community DID: did:plc:community789 (portable identity)
-
Repository: at://did:plc:instance123/social.coves.community.profile/rkey
-
Owner: did:plc:instance123 (instance manages it)
-
"did": "did:plc:community789", // Community's portable DID
-
"owner": "did:plc:instance123", // Instance owns the repository
-
"hostedBy": "did:plc:instance123", // Where it's currently hosted
-
"createdBy": "did:plc:user456" // User who created it
-
- ✅ Community has portable DID (can be referenced across network)
-
- ✅ Record URI points to actual data location (federation works)
-
- ✅ Clear separation: community identity ≠ storage location
-
- ⚠️ Limited portability: Moving instances requires deleting/recreating record
-
### V2 Option: True Community Repositories
-
**Future Architecture (under consideration):**
-
Community DID: did:plc:community789
-
Repository: at://did:plc:community789/social.coves.community.profile/self
-
Owner: did:plc:instance123 (in metadata, not repo owner)
-
- Own PDS account (managed by Coves backend)
-
- Own signing keypair (stored by Coves, like Bluesky stores user keys)
-
- Own repository (true data portability)
-
- ✅ True portability: URI never changes when migrating
-
- ✅ Matches atProto entity model (feed generators, labelers)
-
- ✅ Community can move between instances via DID document update
-
- Coves must generate keypairs for each community
-
- Coves must create PDS accounts for each community
-
- Coves must securely store community credentials
-
- More infrastructure to manage
-
**Decision:** Start with V1 (current), plan for V2 migration path.
-
### Migration Path V1 → V2
-
When ready for true portability:
-
1. Generate keypair for existing community
-
2. Register community's DID document with PLC
-
3. Create PDS account for community (Coves manages credentials)
-
4. Migrate record from instance repo to community repo
-
5. Update AppView to index from new location
-
The `did` field in records makes this migration possible!
-
## Phase 3: Community Ownership
-
- Transfer ownership from instance to community
-
- Enable community governance
-
- Allow migration between instances
-
type CommunityGovernance struct {
-
VotingPower string // "one-person-one-vote", "reputation-weighted"
-
QuorumPercent int // % required for votes to pass
-
Moderators []string // DIDs with mod powers
-
1. Community votes on migration (e.g., from coves.social to gaming.forum)
-
2. Vote passes (66% threshold)
-
3. Community DID ownership transfers
-
4. New instance re-indexes community data from firehose
-
5. Handle updates: !gaming@gaming.forum
-
6. Old instance can keep archive or redirect
-
"community": "!gaming@gaming.forum",
-
"did": "did:web:gaming.community",
-
"previousHost": "did:web:coves.social",
-
"currentHost": "did:web:gaming.forum",
-
"transferredAt": "2025-12-15T10:00:00Z",
-
"governanceSignatures": ["sig1", "sig2", "sig3"]
-
### `social.coves.community`
-
"id": "social.coves.community",
-
"required": ["handle", "name", "createdAt"],
-
"description": "Scoped handle (!name@instance)"
-
"description": "Display name"
-
"items": {"type": "string"}
-
"enum": ["public", "unlisted", "private"],
-
"allowExternalDiscovery": {"type": "boolean", "default": true},
-
"items": {"type": "string"}
-
"description": "DID of community owner"
-
"description": "DID of user who created community"
-
"description": "DID of hosting instance"
### `social.coves.post` (Community Extension)
-
"description": "DID of community this post belongs to"
-
## Technical Architecture
-
PDS creates community record
-
Firehose broadcasts creation
-
AppView indexes community (if allowed)
-
PostgreSQL stores community metadata
-
Community appears in local search/directory
-
### Database Schema (AppView)
-
CREATE TABLE communities (
-
did TEXT UNIQUE NOT NULL,
-
handle TEXT UNIQUE NOT NULL, -- !name@instance
-
visibility TEXT NOT NULL DEFAULT 'public',
-
federation_config JSONB,
-
owner_did TEXT NOT NULL,
-
created_by_did TEXT NOT NULL,
-
hosted_by_did TEXT NOT NULL,
-
created_at TIMESTAMP NOT NULL,
-
updated_at TIMESTAMP NOT NULL,
-
member_count INTEGER DEFAULT 0,
-
post_count INTEGER DEFAULT 0
-
CREATE INDEX idx_communities_handle ON communities(handle);
-
CREATE INDEX idx_communities_visibility ON communities(visibility);
-
CREATE INDEX idx_communities_hosted_by ON communities(hosted_by_did);
-
CREATE TABLE community_moderation (
-
community_did TEXT NOT NULL REFERENCES communities(did),
-
action TEXT NOT NULL, -- 'delist', 'quarantine', 'remove'
-
instance_did TEXT NOT NULL,
-
broadcast BOOLEAN DEFAULT FALSE,
-
created_at TIMESTAMP NOT NULL
-
## API Endpoints (XRPC)
-
social.coves.community.create
-
social.coves.community.get
-
social.coves.community.update
-
social.coves.community.list
-
social.coves.community.search
-
social.coves.community.join
-
social.coves.community.leave
-
social.coves.community.transferOwnership
-
social.coves.community.proposeVote
-
social.coves.community.castVote
-
social.coves.community.migrate
-
- [ ] Communities can be created with scoped handles
-
- [ ] Posts can be made to communities
-
- [ ] Community discovery works on local instance
-
- [ ] All three visibility levels function correctly
-
- [ ] Basic moderation (delist/remove) works
-
- [ ] Cross-instance community search returns results
-
- [ ] Moderation signals are broadcast and received
-
- [ ] Trust networks prevent spam communities
-
- [ ] Community ownership can be transferred
-
- [ ] Voting system enables community decisions
-
- [ ] Communities can migrate between instances
-
## Security Considerations
-
### Every Operation Must:
-
- [ ] Validate DID ownership
-
- [ ] Check community visibility settings
-
- [ ] Verify instance authorization
-
- [ ] Use parameterized queries
-
- [ ] Rate limit community creation
-
- [ ] Log moderation actions
-
### Risks & Mitigations:
-
**Community Squatting**
-
- Risk: Instance creates popular names and sits on them
-
- Mitigation: Activity requirements (auto-archive inactive communities)
-
- Risk: Bad actors create thousands of spam communities
-
- Mitigation: Rate limits, moderation signals, trust networks
-
- Risk: Community ownership stolen via fake votes
-
- Mitigation: Governance thresholds, time locks, signature verification
-
- Risk: Private communities discovered via firehose
-
- Mitigation: Encrypt sensitive metadata, only index allowed instances
-
1. **Should we support community aliases?** (e.g., `!gaming` → `!videogames`)
-
2. **What's the minimum member count for community creation?** (prevent spam)
-
3. **How do we handle abandoned communities?** (creator leaves, no mods)
-
4. **Should communities have their own PDS?** (advanced self-hosting)
-
5. **Cross-posting between communities?** (one post in multiple communities)
-
## Migration from V1 → V2 → V3
-
### V1 to V2 (Adding Federation)
-
- Backward compatible: All V1 communities work in V2
-
- New fields added to lexicon (optional)
-
- Existing communities opt-in to federation
-
### V2 to V3 (Community Ownership)
-
- Instance can propose ownership transfer to community
-
- Community votes to accept
-
- DID ownership updates
-
- No breaking changes to existing communities
- atProto Lexicon Spec: https://atproto.com/specs/lexicon
- DID Web Spec: https://w3c-ccg.github.io/did-method-web/
- Bluesky Handle System: https://atproto.com/specs/handle
-
- Coves Builder Guide: `/docs/CLAUDE-BUILD.md`
-
- [ ] Product Lead Review
-
- [ ] Engineering Lead Review
-
- [ ] Legal/Policy Review (especially moderation aspects)
-
1. Review and approve PRD
-
2. Create V1 implementation tickets
-
3. Design lexicon schema
-
4. Build community creation flow
-
5. Implement local discovery
-
6. Write integration tests