SPEC.md
Earde — Developer communities that turn chat into lasting knowledge
1. Product goal
Build a web platform for open-source projects and other technical communities where fast conversations and durable knowledge coexist. Members can discuss questions in chat, promote useful messages into searchable forum threads, and make a single thread available in multiple related communities without duplicating its content or discussion.
A new visitor should be able to discover a project community, find a previously answered technical question, read its context, and participate if authorized.
2. Actors
- Visitor: unauthenticated reader of public communities, threads and their searchable archives.
- Member: authenticated participant who can join communities, send messages and create threads where permitted.
- Community moderator: can configure sections and channels, moderate contributions, and approve community connections and cross-community sharing.
- Platform administrator: handles platform-wide abuse, account controls and exceptional recovery.
- Project steward: a member whose authority to claim an open-source project is verified through GitHub.
One person may have several roles. Permissions must be enforced server-side, not merely by hiding controls.
3. Communities and structure
- A community has a unique slug, name, description, visibility (
publicorprivate), members and moderators. - A community has chat channels for live conversation and forum sections for durable threads.
- Public communities have publicly readable thread listings and archives. Private community data must never be disclosed to an unauthorized visitor through pages, search, API responses or live subscriptions.
- Members can navigate between a community overview, channels, sections, individual threads and search.
- Moderators can manage the structure and membership. A banned participant cannot perform actions prohibited by the ban, including through direct API requests.
4. Persistent chat
- Authorized members can send text messages to a channel. Messages have a stable identifier, author, channel and creation time.
- A message is saved durably before any live notification is sent. A failed WebSocket service must not erase or prevent retrieval of an accepted message.
- Connected readers see new messages without a page refresh when live delivery is available.
- After reconnecting, clients retrieve missed messages from a cursor-based HTTP endpoint; the combined result must not silently omit messages.
- Read authorization applies both to initial history fetches and live delivery. A participant whose private-community access has been revoked must not receive newly committed message content through an existing connection.
- A usable HTTP-only fallback remains available when the live gateway is unavailable.
Presence and typing indicators are optional enhancements; they are not sources of durable truth.
5. Chat-to-thread promotion
This is the core interaction.
- An authorized member can choose a chat message and promote it to a forum thread in an appropriate section.
- The newly created thread records the original chat message's stable identifier and offers a link back to its conversation context (subject to read permissions).
- A thread has a title, text body, original author/creator metadata, creation time and a canonical identifier. Members can add durable comments.
- Promotion does not delete or mutate the source chat message. If a promotion is retried after a network failure, it must not accidentally produce duplicate threads for the same requested operation.
- The promoted thread is indexed in the community's searchable forum archive. Future readers can discover it without scrolling through chat history.
- The interface clearly distinguishes ephemeral chat context from durable thread discussion.
6. Searchable archive
- Public thread pages are available at stable, shareable URLs and contain server-rendered, crawlable content.
- Search accepts a query and searches authorized threads by title and content; results link to canonical threads, not copies.
- Results may be ordered by relevance or recent activity, with deterministic pagination.
- Search respects community visibility, removals and moderation decisions. A private or removed item must not leak through result excerpts, counts, indexing endpoints or URL guessing.
- A reader can follow a thread's comment history and, where available, its source chat message.
The first implementation need not use a sophisticated search engine: a correct, bounded database-backed search is sufficient.
7. Connected communities and shared threads
This is the other defining interaction.
- Moderators can establish a connection between two communities, subject to approval by the relevant communities.
- An authorized moderator can share an existing eligible thread into a connected community's forum section.
- Sharing creates a placement/reference to the original thread, not a duplicated post with a separate body or comment stream.
- Both communities' listings link to the same canonical thread identity. Comments made through either placement are visible in the same discussion, subject to access rules.
- Removing a placement from one community does not delete the canonical thread or its other placements.
- Sharing must not bypass private-community authorization. A thread may only be exposed in another community when its visibility and the participating communities' policies allow that exposure.
- Duplicate placements for the same thread and destination section are rejected or idempotently handled.
8. GitHub project ownership
- A project steward may claim a GitHub repository as the basis for a project community.
- The claim is validated using a fresh, server-side GitHub authorization flow; the user's typed URL or self-declared ownership is insufficient.
- Persist GitHub's stable numeric repository identity, not just the repository name, which can change.
- The public interface distinguishes verified project association from an ordinary, unverified link.
- If verification becomes stale or is revoked, new privileged project actions must require fresh proof. Existing conversation history must not be silently rewritten or destroyed.
- The implementation must not expose or persist GitHub access tokens beyond what is strictly needed for the verification flow.
For a minimal first build, ordinary communities and chat-to-thread promotion can ship before the GitHub claim flow, but the project-ownership workflow remains part of the target product.
9. Moderation, safety and accessibility
- Authorization checks apply consistently to pages, JSON endpoints, form submissions, search and live updates.
- Moderators can remove/hide messages and threads in their jurisdiction; moderation actions have an auditable record.
- User-submitted text is escaped or sanitized on output. Script execution, unsafe links and injection through user content must not be possible.
- Mutations require authenticated authorization and CSRF protection where applicable; abuse-prone endpoints are rate-limited.
- A single user's actions cannot arbitrarily modify another community's roles, messages or threads.
- Core pages work without client-side JavaScript. Forms have labels, navigation is keyboard-accessible, and errors are actionable.
10. Minimum experience and navigation
The essential screens are:
- Community directory and community overview.
- Channel conversation with a Promote to thread action on eligible messages.
- Forum section and canonical thread page, showing origin and comments.
- Search results for public/authorized threads.
- Connected communities and shared-thread placements.
- Basic community moderation and membership controls.
Favor a clear, compact interface oriented toward technical discussions. Do not require a mobile application or a heavy client-side framework.
11. Acceptance scenarios
An implementation is satisfactory when all of these observable scenarios work:
- Public discovery: an anonymous visitor opens a public community, finds a thread via search and reads it at a stable URL.
- Private isolation: an anonymous visitor cannot see private messages or thread titles through pages, direct URLs or search.
- Send and reload: a member sends a chat message, reloads, and sees exactly the accepted text and timestamp.
- Realtime outage: the live gateway is unavailable when a message is sent; the write still succeeds and another client can catch up over HTTP.
- Promotion: a member promotes message M to thread T; T links back to M, retains the original content, and appears in forum search.
- Promotion retry: repeating the same promotion request does not silently create a second independent T.
- Thread discussion: two authorized members comment on T; both comments appear in chronological history.
- Cross-community sharing: a moderator shares T from community A into connected community B; A and B reference the same T and share one comment history.
- Placement removal: removing T from B leaves T available through A and preserves its history.
- Permission revocation: a member loses access to a private community; subsequent API reads and newly committed live messages from that community are inaccessible.
- GitHub verification: claiming a project with valid GitHub evidence succeeds, while providing only a repository URL or lacking authorization fails.
- Moderation: a removed item disappears from public listings and search; unauthorized users cannot restore it.
Test both normal operation and unauthorized/retry paths. Keep tests runnable against a clean disposable database.
12. Scope boundaries
Required product concept: communities, durable chat, searchable threads, chat-to-thread promotion, connections and canonical shared threads, access control, moderation and GitHub project verification.
Not required for an initial implementation: payments, recommendation feeds, AI-generated answers, voice/video calls, native mobile apps, federation with third-party platforms, code hosting, sophisticated full-text infrastructure, or a distributed/multi-region backend.
Implementations may choose their own programming languages, frameworks and internal architecture. The behavior and acceptance scenarios above are the contract.