diff --git a/docs/PRD_COMMUNITIES.md b/docs/PRD_COMMUNITIES.md index d0c4326..2db42c8 100644 --- a/docs/PRD_COMMUNITIES.md +++ b/docs/PRD_COMMUNITIES.md @@ -171,6 +171,10 @@ Hosted By: did:web:coves.social (instance manages credentials) - [ ] **Monitoring Guide:** Metrics and alerting setup - [ ] **Security Checklist:** Pre-launch security audit +### Infrastructure & DNS +- [ ] **DNS Wildcard Setup:** Configure `*.communities.coves.social` for community handle resolution +- [ ] **Well-Known Endpoint:** Implement `.well-known/atproto-did` handler for `*.communities.coves.social` subdomains + --- ## Out of Scope (Future Versions) @@ -221,14 +225,15 @@ Hosted By: did:web:coves.social (instance manages credentials) **Status:** ✅ Implemented and tested **Required Fields:** -- `handle` - Scoped handle (`!gaming@coves.social`) -- `atprotoHandle` - Real atProto handle (`gaming.communities.coves.social`) -- `name` - Community name +- `handle` - atProto handle (DNS-resolvable, e.g., `gaming.communities.coves.social`) +- `name` - Short community name for !mentions (e.g., `gaming`) - `createdBy` - DID of user who created community - `hostedBy` - DID of hosting instance - `visibility` - `"public"`, `"unlisted"`, or `"private"` - `federation.allowExternalDiscovery` - Boolean +**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. + **Optional Fields:** - `displayName` - Display name for UI - `description` - Community description @@ -277,6 +282,27 @@ Hosted By: did:web:coves.social (instance manages credentials) ## Technical Decisions Log +### 2025-10-11: Single Handle Field (atProto-Compliant) +**Decision:** Use single `handle` field containing DNS-resolvable atProto handle; remove `atprotoHandle` field + +**Rationale:** +- Matches Bluesky pattern: `app.bsky.actor.profile` has one `handle` field +- Reduces confusion about which handle is "real" +- Simplifies lexicon (one field vs two) +- `!gaming@coves.social` display format is client-side UX concern, not protocol concern +- Follows separation of concerns: protocol layer uses DNS handles, UI layer formats for display + +**Implementation:** +- Lexicon: `handle` = `gaming.communities.coves.social` (DNS-resolvable) +- Client derives display: `!${name}@${instance}` from `name` + parsed instance +- Rich text facets can encode community mentions with `!` prefix for UX + +**Trade-offs Accepted:** +- Clients must parse/format for display (but already do this for `@user` mentions) +- No explicit "display handle" in record (but `displayName` serves this purpose) + +--- + ### 2025-10-10: V2 Architecture Completed - Migrated from instance-owned to community-owned repositories - Each community now has own PDS account diff --git a/docs/PRD_GOVERNANCE.md b/docs/PRD_GOVERNANCE.md index e14e4b3..21b4773 100644 --- a/docs/PRD_GOVERNANCE.md +++ b/docs/PRD_GOVERNANCE.md @@ -388,6 +388,37 @@ Communities can be co-owned by multiple entities (users, instances, DAOs) with d ## Technical Decisions Log +### 2025-10-11: Moderator Records Storage Location +**Decision:** Store moderator records in community's repository (`at://community_did/social.coves.community.moderator/{tid}`), not user's repository + +**Rationale:** +1. **Federation security**: Community's PDS can write/delete records in its own repo without cross-PDS coordination +2. **Attack resistance**: Malicious self-hosted instances cannot forge or retain moderator status after revocation +3. **Single source of truth**: Community's repo is authoritative; no need to check multiple repos + revocation lists +4. **Instant revocation**: Deleting the record immediately removes moderator status across all instances +5. **Simpler implementation**: No invitation flow, no multi-step acceptance, no revocation reconciliation + +**Security Analysis:** +- **Option B (user's repo) vulnerability**: Attacker could self-host malicious AppView that ignores revocation signals stored in community's AppView database, presenting their moderator record as "proof" of authority +- **Option A (community's repo) security**: Even malicious instances must query community's PDS for authoritative moderator list; attacker cannot forge records in community's repository + +**Alternatives Considered:** +- **User's repo**: Follows atProto pattern for relationships (like `app.bsky.graph.follow`), provides user consent model, but introduces cross-instance write complexity and security vulnerabilities +- **Hybrid (both repos)**: Assignment in community's repo + acceptance in user's repo provides consent without compromising security, but significantly increases complexity + +**Trade-offs Accepted:** +- No explicit user consent (moderators are appointed, not invited) +- Users cannot easily query "what do I moderate?" without AppView index +- Doesn't follow standard atProto relationship pattern (but matches service account pattern like feed generators) + +**Implementation Notes:** +- Moderator records are source of truth for permissions +- AppView indexes these records from firehose for efficient querying +- User consent can be added later via optional acceptance records without changing security model +- Matches Bluesky's pattern: relationships in user's repo, service configuration in service's repo + +--- + ### 2025-10-10: V1 Role-Based Model Selected **Decision:** Start with simple creator/moderator two-tier system