A community based topic aggregation platform built on atproto

docs(communities): Add Communities feature PRD

Product requirements document covering:
- Feature overview and goals
- Architecture decisions (V1: instance-scoped)
- atProto federation design
- Data model and relationships
- API specifications
- Future roadmap (V2: community-owned, V3: full federation)

+748
+748
docs/PRD_COMMUNITIES.md
··· 1 + # Communities PRD: Federated Forum System 2 + 3 + **Status:** Draft 4 + **Owner:** Platform Team 5 + **Last Updated:** 2025-10-07 6 + 7 + ## Overview 8 + 9 + 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. 10 + 11 + ## Vision 12 + 13 + **V1 (MVP):** Instance-owned communities with scoped handles 14 + **V2 (Post-Launch):** Cross-instance discovery and moderation signal federation 15 + **V3 (Future):** Community-owned DIDs with migration capabilities via community voting 16 + 17 + ## Core Principles 18 + 19 + 1. **Scoped by default:** All communities use `!name@instance.com` format 20 + 2. **DID-based ownership:** Communities are owned by DIDs (initially instance, eventually community) 21 + 3. **Web DID compatible:** Communities can use `did:web` for custom domains (e.g., `!photography@lens.club`) 22 + 4. **Federation-ready:** Design for cross-instance discovery and moderation from day one 23 + 5. **Community sovereignty:** Future path to community ownership and migration 24 + 25 + ## Identity & Namespace 26 + 27 + ### Community Handle Format 28 + 29 + ``` 30 + !{name}@{instance} 31 + 32 + Examples: 33 + !gaming@coves.social 34 + !photography@lens.club 35 + !golang@dev.forums 36 + !my-book-club@personal.coves.io 37 + ``` 38 + 39 + ### DID Ownership 40 + 41 + **V1: Instance-Owned** 42 + ```json 43 + { 44 + "community": { 45 + "handle": "!gaming@coves.social", 46 + "did": "did:web:coves.social:community:gaming", 47 + "owner": "did:web:coves.social", 48 + "createdBy": "did:plc:user123", 49 + "hostedBy": "did:web:coves.social", 50 + "created": "2025-10-07T12:00:00Z" 51 + } 52 + } 53 + ``` 54 + 55 + **Future: Community-Owned** 56 + ```json 57 + { 58 + "community": { 59 + "handle": "!gaming@coves.social", 60 + "did": "did:web:gaming.community", 61 + "owner": "did:web:gaming.community", 62 + "createdBy": "did:plc:user123", 63 + "hostedBy": "did:web:coves.social", 64 + "governance": { 65 + "type": "multisig", 66 + "votingEnabled": true 67 + } 68 + } 69 + } 70 + ``` 71 + 72 + ### Why Scoped Names? 73 + 74 + - **No namespace conflicts:** Each instance controls its own namespace 75 + - **Clear ownership:** `@instance` shows who hosts it 76 + - **Decentralized:** No global registry required 77 + - **Web DID ready:** Communities can become `did:web` and use custom domains 78 + - **Fragmentation handled socially:** Community governance and moderation quality drives membership 79 + 80 + ## Visibility & Discoverability 81 + 82 + ### Visibility Tiers 83 + 84 + **Public (Default)** 85 + - Indexed by home instance 86 + - Appears in search results 87 + - Listed in community directory 88 + - Can be federated to other instances 89 + 90 + **Unlisted** 91 + - Accessible via direct link 92 + - Not in search results 93 + - Not in public directory 94 + - Members can invite others 95 + 96 + **Private** 97 + - Invite-only 98 + - Not discoverable 99 + - Not federated 100 + - Requires approval to join 101 + 102 + ### Discovery Configuration 103 + 104 + ```go 105 + type CommunityVisibility struct { 106 + Level string // "public", "unlisted", "private" 107 + AllowExternalDiscovery bool // Can other instances index this? 108 + AllowedInstances []string // Whitelist (empty = all if public) 109 + } 110 + ``` 111 + 112 + **Examples:** 113 + ```json 114 + // Public gaming community, federate everywhere 115 + { 116 + "visibility": "public", 117 + "allowExternalDiscovery": true, 118 + "allowedInstances": [] 119 + } 120 + 121 + // Book club, public on home instance only 122 + { 123 + "visibility": "public", 124 + "allowExternalDiscovery": false, 125 + "allowedInstances": [] 126 + } 127 + 128 + // Private beta testing community 129 + { 130 + "visibility": "private", 131 + "allowExternalDiscovery": false, 132 + "allowedInstances": ["coves.social", "trusted.instance"] 133 + } 134 + ``` 135 + 136 + ## Moderation & Federation 137 + 138 + ### Moderation Actions (Local Only) 139 + 140 + Communities can be moderated locally by the hosting instance: 141 + 142 + ```go 143 + type ModerationAction struct { 144 + CommunityDID string 145 + Action string // "delist", "quarantine", "remove" 146 + Reason string 147 + Instance string 148 + Timestamp time.Time 149 + BroadcastSignal bool // Share with network? 150 + } 151 + ``` 152 + 153 + **Action Types:** 154 + 155 + **Delist** 156 + - Removed from search/directory 157 + - Existing members can still access 158 + - Not deleted, just hidden 159 + 160 + **Quarantine** 161 + - Visible with warning label 162 + - "This community may violate guidelines" 163 + - Can still be accessed with acknowledgment 164 + 165 + **Remove** 166 + - Community hidden from instance AppView 167 + - Data still exists in firehose 168 + - Other instances can choose to ignore removal 169 + 170 + ### Federation Reality 171 + 172 + **What you can control:** 173 + - What YOUR AppView indexes 174 + - What moderation signals you broadcast 175 + - What other instances' signals you honor 176 + 177 + **What you cannot control:** 178 + - Self-hosted PDS/AppView can index anything 179 + - Other instances may ignore your moderation 180 + - Community data lives in firehose regardless 181 + 182 + **Moderation is local AppView filtering, not network-wide censorship.** 183 + 184 + ### Moderation Signal Federation (V2) 185 + 186 + Instances can subscribe to each other's moderation feeds: 187 + 188 + ```json 189 + { 190 + "moderationFeed": "did:web:coves.social:moderation", 191 + "action": "remove", 192 + "target": "did:web:coves.social:community:hate-speech", 193 + "reason": "Violates community guidelines", 194 + "timestamp": "2025-10-07T14:30:00Z", 195 + "evidence": "https://coves.social/moderation/case/123" 196 + } 197 + ``` 198 + 199 + Other instances can: 200 + - Auto-apply trusted instance moderation 201 + - Show warnings based on signals 202 + - Ignore signals entirely 203 + 204 + ## MVP (V1) Scope 205 + 206 + ### ✅ Completed (2025-10-08) 207 + 208 + **Core Functionality:** 209 + - [x] Create communities (instance-owned DID) 210 + - [x] Scoped handle format (`!name@instance`) 211 + - [x] Three visibility levels (public, unlisted, private) 212 + - [x] Basic community metadata (name, description, rules) 213 + - [x] Write-forward to PDS (communities as atProto records) 214 + - [x] Jetstream consumer (index communities from firehose) 215 + 216 + **Technical Infrastructure:** 217 + - [x] Lexicon: `social.coves.community.profile` with `did` field (atProto compliant!) 218 + - [x] DID format: `did:plc:xxx` (portable, federated) 219 + - [x] PostgreSQL indexing for local communities 220 + - [x] Service layer (business logic) 221 + - [x] Repository layer (database) 222 + - [x] Consumer layer (firehose indexing) 223 + - [x] Environment config (`IS_DEV_ENV`, `PLC_DIRECTORY_URL`) 224 + 225 + **Critical Fixes:** 226 + - [x] Fixed `record_uri` bug (now points to correct repository location) 227 + - [x] Added required `did` field to lexicon (atProto compliance) 228 + - [x] Consumer correctly separates community DID from repository DID 229 + - [x] E2E test passes (PDS write → firehose → AppView indexing) 230 + 231 + ### 🚧 In Progress 232 + 233 + **API Endpoints (XRPC):** 234 + - [x] `social.coves.community.create` (handler exists, needs testing) 235 + - [ ] `social.coves.community.get` (handler exists, needs testing) 236 + - [ ] `social.coves.community.list` (handler exists, needs testing) 237 + - [ ] `social.coves.community.search` (handler exists, needs testing) 238 + - [x] `social.coves.community.subscribe` (handler exists) 239 + - [x] `social.coves.community.unsubscribe` (handler exists) 240 + 241 + **Subscriptions & Memberships:** 242 + - [x] Database schema (subscriptions, memberships tables) 243 + - [x] Repository methods (subscribe, unsubscribe, list) 244 + - [ ] Consumer processing (index subscription events from firehose) 245 + - [ ] Membership tracking (convert subscription → membership on first post?) 246 + 247 + ### ⏳ TODO Before V1 Launch 248 + 249 + **Critical Path:** 250 + - [ ] Test all XRPC endpoints end-to-end 251 + - [ ] Implement OAuth middleware (protect create/update endpoints) 252 + - [ ] Add authorization checks (who can create/update/delete?) 253 + - [ ] Handle validation (prevent duplicate handles, validate DIDs) 254 + - [ ] Rate limiting (prevent community spam) 255 + 256 + **Community Discovery:** 257 + - [ ] Community list endpoint (pagination, filtering) 258 + - [ ] Community search (full-text search on name/description) 259 + - [ ] Visibility enforcement (respect public/unlisted/private) 260 + - [ ] Federation config (respect `allowExternalDiscovery`) 261 + 262 + **Posts in Communities:** 263 + - [ ] Extend `social.coves.post` lexicon with `community` field 264 + - [ ] Create post endpoint (require community membership?) 265 + - [ ] Feed generation (show posts in community) 266 + - [ ] Post consumer (index community posts from firehose) 267 + 268 + **Moderation (Basic):** 269 + - [ ] Remove community from AppView (delist) 270 + - [ ] Quarantine community (show warning) 271 + - [ ] Moderation audit log 272 + - [ ] Admin endpoints (for instance operators) 273 + 274 + **Testing & Documentation:** 275 + - [ ] Integration tests for all flows 276 + - [ ] API documentation (XRPC endpoints) 277 + - [ ] Deployment guide (PDS setup, environment config) 278 + - [ ] Migration guide (how to upgrade from test to production) 279 + 280 + ### Out of Scope (V2+) 281 + 282 + - [ ] Moderation signal federation 283 + - [ ] Community-owned DIDs 284 + - [ ] Migration/portability 285 + - [ ] Governance voting 286 + - [ ] Custom domain DIDs 287 + 288 + ## Phase 2: Federation & Discovery 289 + 290 + **Goals:** 291 + - Cross-instance community search 292 + - Federated moderation signals 293 + - Trust networks between instances 294 + 295 + **Features:** 296 + ```go 297 + // Cross-instance discovery 298 + type FederationConfig struct { 299 + DiscoverPeers []string // Other Coves instances to index 300 + TrustModerationFrom []string // Auto-apply moderation signals 301 + ShareCommunitiesWith []string // Allow these instances to index ours 302 + } 303 + 304 + // Moderation trust network 305 + type ModerationTrust struct { 306 + InstanceDID string 307 + TrustLevel string // "auto-apply", "show-warning", "ignore" 308 + Categories []string // Which violations to trust ("spam", "nsfw", etc) 309 + } 310 + ``` 311 + 312 + **User Experience:** 313 + ``` 314 + Search: "golang" 315 + 316 + Results: 317 + !golang@coves.social (45k members) 318 + Hosted on coves.social 319 + [Join] 320 + 321 + !golang@dev.forums (12k members) 322 + Hosted on dev.forums 323 + Focused on systems programming 324 + [Join] 325 + 326 + !go@programming.zone (3k members) 327 + Hosted on programming.zone 328 + ⚠️ Flagged by trusted moderators 329 + [View Details] 330 + ``` 331 + 332 + ## Implementation Log 333 + 334 + ### 2025-10-08: DID Architecture & atProto Compliance 335 + 336 + **Major Decisions:** 337 + 338 + 1. **Migrated from `did:coves` to `did:plc`** 339 + - Communities now use proper PLC DIDs (portable across instances) 340 + - Added `IS_DEV_ENV` flag (dev = generate without PLC registration, prod = register) 341 + - Matches Bluesky's feed generator pattern 342 + 343 + 2. **Fixed Critical `record_uri` Bug** 344 + - Problem: Consumer was setting community DID as repository owner 345 + - Fix: Correctly separate community DID (entity) from repository DID (storage) 346 + - Result: URIs now point to actual data location (federation works!) 347 + 348 + 3. **Added Required `did` Field to Lexicon** 349 + - atProto research revealed communities MUST have their own DID field 350 + - Matches `app.bsky.feed.generator` pattern (service has DID, record stored elsewhere) 351 + - Enables future migration to community-owned repositories 352 + 353 + **Architecture Insights:** 354 + 355 + ``` 356 + User Profile (Bluesky): 357 + at://did:plc:user123/app.bsky.actor.profile/self 358 + ↑ Repository location IS the identity 359 + No separate "did" field needed 360 + 361 + Feed Generator (Bluesky): 362 + at://did:plc:creator456/app.bsky.feed.generator/cool-feed 363 + Record contains: {"did": "did:web:feedgen.service", ...} 364 + ↑ Service has own DID, record stored in creator's repo 365 + 366 + Community (Coves V1): 367 + at://did:plc:instance123/social.coves.community.profile/rkey 368 + Record contains: {"did": "did:plc:community789", ...} 369 + ↑ Community has own DID, record stored in instance repo 370 + 371 + Community (Coves V2 - Future): 372 + at://did:plc:community789/social.coves.community.profile/self 373 + Record contains: {"owner": "did:plc:instance123", ...} 374 + ↑ Community owns its own repo, instance manages it 375 + ``` 376 + 377 + **Key Findings:** 378 + 379 + 1. **Keypair Management**: Coves can manage community keypairs (like Bluesky manages user keys) 380 + 2. **PDS Authentication**: Can create PDS accounts for communities, Coves stores credentials 381 + 3. **Migration Path**: Current V1 enables future V2 without breaking changes 382 + 383 + **Trade-offs:** 384 + 385 + - V1 (Current): Simple, ships fast, limited portability 386 + - V2 (Future): Complex, true portability, matches atProto entity model 387 + 388 + **Decision: Ship V1 now, plan V2 migration.** 389 + 390 + --- 391 + 392 + ## CRITICAL: DID Architecture Decision (2025-10-08) 393 + 394 + ### Current State: Hybrid Approach 395 + 396 + **V1 Implementation (Current):** 397 + ``` 398 + Community DID: did:plc:community789 (portable identity) 399 + Repository: at://did:plc:instance123/social.coves.community.profile/rkey 400 + Owner: did:plc:instance123 (instance manages it) 401 + 402 + Record structure: 403 + { 404 + "did": "did:plc:community789", // Community's portable DID 405 + "owner": "did:plc:instance123", // Instance owns the repository 406 + "hostedBy": "did:plc:instance123", // Where it's currently hosted 407 + "createdBy": "did:plc:user456" // User who created it 408 + } 409 + ``` 410 + 411 + **Why this matters:** 412 + - ✅ Community has portable DID (can be referenced across network) 413 + - ✅ Record URI points to actual data location (federation works) 414 + - ✅ Clear separation: community identity ≠ storage location 415 + - ⚠️ Limited portability: Moving instances requires deleting/recreating record 416 + 417 + ### V2 Option: True Community Repositories 418 + 419 + **Future Architecture (under consideration):** 420 + ``` 421 + Community DID: did:plc:community789 422 + Repository: at://did:plc:community789/social.coves.community.profile/self 423 + Owner: did:plc:instance123 (in metadata, not repo owner) 424 + 425 + Community gets: 426 + - Own PDS account (managed by Coves backend) 427 + - Own signing keypair (stored by Coves, like Bluesky stores user keys) 428 + - Own repository (true data portability) 429 + ``` 430 + 431 + **Benefits:** 432 + - ✅ True portability: URI never changes when migrating 433 + - ✅ Matches atProto entity model (feed generators, labelers) 434 + - ✅ Community can move between instances via DID document update 435 + 436 + **Complexity:** 437 + - Coves must generate keypairs for each community 438 + - Coves must create PDS accounts for each community 439 + - Coves must securely store community credentials 440 + - More infrastructure to manage 441 + 442 + **Decision:** Start with V1 (current), plan for V2 migration path. 443 + 444 + ### Migration Path V1 → V2 445 + 446 + When ready for true portability: 447 + 1. Generate keypair for existing community 448 + 2. Register community's DID document with PLC 449 + 3. Create PDS account for community (Coves manages credentials) 450 + 4. Migrate record from instance repo to community repo 451 + 5. Update AppView to index from new location 452 + 453 + The `did` field in records makes this migration possible! 454 + 455 + ## Phase 3: Community Ownership 456 + 457 + **Goals:** 458 + - Transfer ownership from instance to community 459 + - Enable community governance 460 + - Allow migration between instances 461 + 462 + **Features:** 463 + 464 + **Governance System:** 465 + ```go 466 + type CommunityGovernance struct { 467 + Enabled bool 468 + VotingPower string // "one-person-one-vote", "reputation-weighted" 469 + QuorumPercent int // % required for votes to pass 470 + Moderators []string // DIDs with mod powers 471 + } 472 + ``` 473 + 474 + **Migration Flow:** 475 + ``` 476 + 1. Community votes on migration (e.g., from coves.social to gaming.forum) 477 + 2. Vote passes (66% threshold) 478 + 3. Community DID ownership transfers 479 + 4. New instance re-indexes community data from firehose 480 + 5. Handle updates: !gaming@gaming.forum 481 + 6. Old instance can keep archive or redirect 482 + ``` 483 + 484 + **DID Transfer:** 485 + ```json 486 + { 487 + "community": "!gaming@gaming.forum", 488 + "did": "did:web:gaming.community", 489 + "previousHost": "did:web:coves.social", 490 + "currentHost": "did:web:gaming.forum", 491 + "transferredAt": "2025-12-15T10:00:00Z", 492 + "governanceSignatures": ["sig1", "sig2", "sig3"] 493 + } 494 + ``` 495 + 496 + ## Lexicon Design 497 + 498 + ### `social.coves.community` 499 + 500 + ```json 501 + { 502 + "lexicon": 1, 503 + "id": "social.coves.community", 504 + "defs": { 505 + "main": { 506 + "type": "record", 507 + "key": "tid", 508 + "record": { 509 + "type": "object", 510 + "required": ["handle", "name", "createdAt"], 511 + "properties": { 512 + "handle": { 513 + "type": "string", 514 + "description": "Scoped handle (!name@instance)" 515 + }, 516 + "name": { 517 + "type": "string", 518 + "maxLength": 64, 519 + "description": "Display name" 520 + }, 521 + "description": { 522 + "type": "string", 523 + "maxLength": 3000 524 + }, 525 + "rules": { 526 + "type": "array", 527 + "items": {"type": "string"} 528 + }, 529 + "visibility": { 530 + "type": "string", 531 + "enum": ["public", "unlisted", "private"], 532 + "default": "public" 533 + }, 534 + "federation": { 535 + "type": "object", 536 + "properties": { 537 + "allowExternalDiscovery": {"type": "boolean", "default": true}, 538 + "allowedInstances": { 539 + "type": "array", 540 + "items": {"type": "string"} 541 + } 542 + } 543 + }, 544 + "owner": { 545 + "type": "string", 546 + "description": "DID of community owner" 547 + }, 548 + "createdBy": { 549 + "type": "string", 550 + "description": "DID of user who created community" 551 + }, 552 + "hostedBy": { 553 + "type": "string", 554 + "description": "DID of hosting instance" 555 + }, 556 + "createdAt": { 557 + "type": "string", 558 + "format": "datetime" 559 + } 560 + } 561 + } 562 + } 563 + } 564 + } 565 + ``` 566 + 567 + ### `social.coves.post` (Community Extension) 568 + 569 + ```json 570 + { 571 + "properties": { 572 + "community": { 573 + "type": "string", 574 + "description": "DID of community this post belongs to" 575 + } 576 + } 577 + } 578 + ``` 579 + 580 + ## Technical Architecture 581 + 582 + ### Data Flow 583 + 584 + ``` 585 + User creates community 586 + 587 + PDS creates community record 588 + 589 + Firehose broadcasts creation 590 + 591 + AppView indexes community (if allowed) 592 + 593 + PostgreSQL stores community metadata 594 + 595 + Community appears in local search/directory 596 + ``` 597 + 598 + ### Database Schema (AppView) 599 + 600 + ```sql 601 + CREATE TABLE communities ( 602 + id SERIAL PRIMARY KEY, 603 + did TEXT UNIQUE NOT NULL, 604 + handle TEXT UNIQUE NOT NULL, -- !name@instance 605 + name TEXT NOT NULL, 606 + description TEXT, 607 + rules JSONB, 608 + visibility TEXT NOT NULL DEFAULT 'public', 609 + federation_config JSONB, 610 + owner_did TEXT NOT NULL, 611 + created_by_did TEXT NOT NULL, 612 + hosted_by_did TEXT NOT NULL, 613 + created_at TIMESTAMP NOT NULL, 614 + updated_at TIMESTAMP NOT NULL, 615 + member_count INTEGER DEFAULT 0, 616 + post_count INTEGER DEFAULT 0 617 + ); 618 + 619 + CREATE INDEX idx_communities_handle ON communities(handle); 620 + CREATE INDEX idx_communities_visibility ON communities(visibility); 621 + CREATE INDEX idx_communities_hosted_by ON communities(hosted_by_did); 622 + 623 + CREATE TABLE community_moderation ( 624 + id SERIAL PRIMARY KEY, 625 + community_did TEXT NOT NULL REFERENCES communities(did), 626 + action TEXT NOT NULL, -- 'delist', 'quarantine', 'remove' 627 + reason TEXT, 628 + instance_did TEXT NOT NULL, 629 + broadcast BOOLEAN DEFAULT FALSE, 630 + created_at TIMESTAMP NOT NULL 631 + ); 632 + ``` 633 + 634 + ## API Endpoints (XRPC) 635 + 636 + ### V1 (MVP) 637 + 638 + ``` 639 + social.coves.community.create 640 + social.coves.community.get 641 + social.coves.community.update 642 + social.coves.community.list 643 + social.coves.community.search 644 + social.coves.community.join 645 + social.coves.community.leave 646 + ``` 647 + 648 + 649 + ### V3 (Governance) 650 + 651 + ``` 652 + social.coves.community.transferOwnership 653 + social.coves.community.proposeVote 654 + social.coves.community.castVote 655 + social.coves.community.migrate 656 + ``` 657 + 658 + ## Success Metrics 659 + 660 + ### V1 (MVP) 661 + - [ ] Communities can be created with scoped handles 662 + - [ ] Posts can be made to communities 663 + - [ ] Community discovery works on local instance 664 + - [ ] All three visibility levels function correctly 665 + - [ ] Basic moderation (delist/remove) works 666 + 667 + ### V2 (Federation) 668 + - [ ] Cross-instance community search returns results 669 + - [ ] Moderation signals are broadcast and received 670 + - [ ] Trust networks prevent spam communities 671 + 672 + ### V3 (Governance) 673 + - [ ] Community ownership can be transferred 674 + - [ ] Voting system enables community decisions 675 + - [ ] Communities can migrate between instances 676 + 677 + ## Security Considerations 678 + 679 + ### Every Operation Must: 680 + - [ ] Validate DID ownership 681 + - [ ] Check community visibility settings 682 + - [ ] Verify instance authorization 683 + - [ ] Use parameterized queries 684 + - [ ] Rate limit community creation 685 + - [ ] Log moderation actions 686 + 687 + ### Risks & Mitigations: 688 + 689 + **Community Squatting** 690 + - Risk: Instance creates popular names and sits on them 691 + - Mitigation: Activity requirements (auto-archive inactive communities) 692 + 693 + **Spam Communities** 694 + - Risk: Bad actors create thousands of spam communities 695 + - Mitigation: Rate limits, moderation signals, trust networks 696 + 697 + **Migration Abuse** 698 + - Risk: Community ownership stolen via fake votes 699 + - Mitigation: Governance thresholds, time locks, signature verification 700 + 701 + **Privacy Leaks** 702 + - Risk: Private communities discovered via firehose 703 + - Mitigation: Encrypt sensitive metadata, only index allowed instances 704 + 705 + ## Open Questions 706 + 707 + 1. **Should we support community aliases?** (e.g., `!gaming` → `!videogames`) 708 + 2. **What's the minimum member count for community creation?** (prevent spam) 709 + 3. **How do we handle abandoned communities?** (creator leaves, no mods) 710 + 4. **Should communities have their own PDS?** (advanced self-hosting) 711 + 5. **Cross-posting between communities?** (one post in multiple communities) 712 + 713 + ## Migration from V1 → V2 → V3 714 + 715 + ### V1 to V2 (Adding Federation) 716 + - Backward compatible: All V1 communities work in V2 717 + - New fields added to lexicon (optional) 718 + - Existing communities opt-in to federation 719 + 720 + ### V2 to V3 (Community Ownership) 721 + - Instance can propose ownership transfer to community 722 + - Community votes to accept 723 + - DID ownership updates 724 + - No breaking changes to existing communities 725 + 726 + ## References 727 + 728 + - atProto Lexicon Spec: https://atproto.com/specs/lexicon 729 + - DID Web Spec: https://w3c-ccg.github.io/did-method-web/ 730 + - Bluesky Handle System: https://atproto.com/specs/handle 731 + - Coves Builder Guide: `/docs/CLAUDE-BUILD.md` 732 + 733 + ## Approval & Sign-Off 734 + 735 + - [ ] Product Lead Review 736 + - [ ] Engineering Lead Review 737 + - [ ] Security Review 738 + - [ ] Legal/Policy Review (especially moderation aspects) 739 + 740 + --- 741 + 742 + **Next Steps:** 743 + 1. Review and approve PRD 744 + 2. Create V1 implementation tickets 745 + 3. Design lexicon schema 746 + 4. Build community creation flow 747 + 5. Implement local discovery 748 + 6. Write integration tests