What is a Thread?
A thread is a persistent conversation container. Each thread has:- Title: Human-readable name
- Owner: User who created it (
user_id) - Visibility: Access control (
private,public,unlisted) - Messages: Chat history with AI responses
Visibility Modes
Threads use three visibility levels controlling who can access them:Private
Default visibility. Only the owner can access private threads. Access Rules:- Anonymous users: ❌ 401 Unauthorized
- Authenticated non-owner: ❌ 403 Forbidden
- Owner: ✅ Full access
- Personal conversations
- Sensitive prompts
- Work-in-progress comparisons
- Default safe choice
Private threads never appear in public listings and require both authentication AND ownership verification.
Public
Anyone can access public threads (authenticated or anonymous). Access Rules:- Anonymous users: ✅ Read-only access
- Authenticated users: ✅ Read-only access
- Owner: ✅ Full access (read, update, delete)
- Sharing interesting comparisons
- Public model benchmarks
- Tutorial examples
- Community-contributed prompts
Unlisted
Accessible via direct link but not listed publicly. Access Rules:- Anyone with link: ✅ Read-only access
- Owner: ✅ Full access
- Sharing with specific people
- Semi-private comparisons
- Preview links before public release
- Controlled distribution
Visibility Comparison
| Aspect | Private | Public | Unlisted |
|---|---|---|---|
| Requires auth | Yes | No | No |
| Ownership required | Yes | No (read-only) | No (read-only) |
| Publicly listed | No | Yes | No |
| Shareable | No | Yes | Yes (with link) |
| Default | ✅ Yes | No | No |
Thread Lifecycle
Creation
User creates thread with optional title. Default visibility:
private.System assigns:- UUID as
thread_id - Authenticated user as owner (
user_id) - Current timestamp as
created_at
Messages Added
User makes chat requests with
threadId parameter.Each request writes message to thread_messages table:- Prompt text
- Model responses (single or dual)
- Comparison ID (if dual-chat)
- Timing metrics
Updates
Owner can modify:
- Title (rename conversation)
- Visibility (change access control)
thread_id, user_id, created_atSharing
Owner retrieves share URL (if visibility !=
private).Share endpoint returns:- Current visibility
- Share URL (if sharable)
canShareboolean
Why Visibility Matters
Privacy by Default
New threads default toprivate for safety. Users must explicitly choose to share.
Reasoning: Better to keep something private accidentally than expose sensitive prompts publicly.
Flexible Sharing
Three levels accommodate different sharing needs:- Don’t share:
private - Share with anyone:
public - Share selectively:
unlisted
Access Control Without Complexity
Simple model: owner has full control, others have read-only (for public/unlisted). No complex permissions: No “viewer”, “editor”, “commenter” roles. Just owner vs everyone else.Message Structure
Thread messages contain:model1* fields populated, model2* fields null
Dual-chat messages: Both model1* and model2* populated, comparisonId present
Threading Model
Linear History
Messages in a thread form a linear timeline, not a tree structure. No branching: Can’t fork conversations or have multiple branches. Why linear?- Simpler implementation
- Matches chat interface mental model
- Avoids UI complexity of thread trees
Message Ordering
Messages ordered bycreated_at timestamp (ascending).
Retrieval: Index on (thread_id, created_at) ensures efficient chronological queries.
Cascade Deletion
Deleting a thread triggers cascade deletion of related data:- Data consistency: No orphan messages
- Cleanup simplicity: One DELETE statement
- Performance: Database handles cleanup atomically
Thread Title Behavior
Default Title
If no title provided during creation:Title Updates
Owner can rename thread anytime:- No uniqueness constraint (multiple threads can have same title)
- No length validation (but UI should enforce reasonable limits)
- Empty titles allowed (defaults to “Untitled”)
Ownership Transfer
Not supported. Thread ownership is permanent. Workaround: Create new thread and copy messages (manual process). Why no transfer?- Simpler permission model
- Avoids authorization complexity
- Unclear use case for typical usage
Performance Considerations
Listing Threads
Query:SELECT * FROM threads WHERE user_id = X ORDER BY created_at DESC
Optimization: Index on (user_id, created_at) enables fast retrieval.
Pagination: API supports page and limit parameters to avoid loading all threads.
Message Retrieval
Query:SELECT * FROM thread_messages WHERE thread_id = X ORDER BY created_at ASC
Optimization: Index on (thread_id, created_at).
Potential issue: Very long threads (1000+ messages) may load slowly.
Mitigation: Consider pagination for message retrieval (not currently implemented).
Sharing Workflow
Share endpoint validates visibility before returning URL. Private threads return
canShare: false.Security Implications
Private Thread Leakage
If thread ID is guessable, attackers could try accessing private threads. Mitigation: UUIDs are cryptographically random (2^122 possible values), making guessing infeasible.Public Thread Content
Once markedpublic, thread is accessible to anyone forever (unless visibility changed back).
Consideration: Users should review content before making public.
Unlisted Discovery
Unlisted threads are “security through obscurity”. Anyone with URL can access. Not secure for: Truly sensitive data (useprivate instead)
Acceptable for: Sharing with trusted individuals
Next Steps
Chat Modes
Single vs dual chat explained
Voting System
How votes work
System Overview
Architecture decisions