6 KiB
Sojorn Backend Architecture
How Boundaries Are Enforced
Sojorn's friendliness is not aspirational—it is structural. The database itself enforces the behavioral philosophy through Row Level Security (RLS), constraints, and functions that make certain behaviors impossible, not just discouraged.
1. Blocking: Complete Disappearance
Principle: When you block someone, they disappear from your world and you from theirs.
Implementation:
- The
has_block_between(user_a, user_b)function checks if either user has blocked the other. - RLS policies prevent blocked users from:
- Seeing each other's profiles
- Seeing each other's posts
- Seeing each other's follows
- Interacting in any way
Effect: No notifications, no traces, no conflict. The system enforces separation silently.
2. Consent: Conversation Requires Mutual Follow
Principle: You cannot reply to someone unless you mutually follow each other.
Implementation:
- The
is_mutual_follow(user_a, user_b)function verifies bidirectional following. - Comments can only be created if
is_mutual_follow(commenter, post_author)returns true. - RLS policies prevent reading comments unless you are:
- The post author, OR
- A mutual follower of the post author
Effect: Unwanted replies are impossible. Conversation is opt-in by structure.
3. Exposure: Opt-In by Default
Principle: Users choose what content they see. Filtering is private and encouraged.
Implementation:
- All categories except
generalhavedefault_off = true. - Users must explicitly enable categories to see posts from them.
- RLS policies on
postscheck:- User has enabled the category, OR
- Category is not default-off AND user hasn't disabled it
Effect: Heavy topics (grief, struggle, world events) are invisible unless invited in. No algorithmic exposure.
4. Influence: Earned Slowly Through Trust
Principle: New users have limited reach and posting capacity. Trust grows with positive behavior.
Implementation:
- Each user has a
trust_statewith:harmony_score(0-100, starts at 50)tier(new, trusted, established, restricted)- Behavioral counters
- Post rate limits depend on tier:
- New: 3 posts/day
- Trusted: 10 posts/day
- Established: 25 posts/day
- Restricted: 1 post/day
- The
can_post(user_id)function enforces this before allowing inserts.
Effect: Spam and abuse are throttled by friction. Positive contributors gain capacity over time.
5. Moderation: Guidance Through Friction, Not Punishment
Principle: Sharp speech does not travel. The system gently contains hostility.
Implementation:
- Posts and comments carry
tone_labelandcis_score(content integrity score). - Content flagged as hostile:
- Has reduced reach (implemented in feed algorithms, not yet built)
- May be soft-deleted (
status = 'removed') - Triggers adjustments to author's
harmony_score
- All moderation actions are logged in
audit_logwith full transparency.
Effect: Hostility is contained, not amplified. Violators experience reduced reach before account action.
6. Non-Attachment: Nothing Is Permanent
Principle: Feeds rotate, trends fade, attention is non-possessive.
Implementation:
- No "permanence" affordances like pinned posts or evergreen content.
- Posts are timestamped and will naturally age out of feeds.
- No edit history preserved beyond
edited_attimestamp. - Soft deletes allow content to disappear without breaking audit trails.
Effect: The platform discourages attachment to metrics or viral moments. Content is transient by design.
7. Transparency: Users Are Told How Reach Works
Principle: The system does not hide how it operates.
Implementation:
trust_stateis visible to the user (their own state only via RLS).audit_logevents related to a user are readable by that user.- Rate limits, tier effects, and category mechanics are explained in-app (not yet built).
Effect: Users understand why their reach changes. No hidden algorithmic manipulation.
Database Design Summary
Core Tables
- profiles: User identity (handle, display name, bio)
- categories: Content organization with opt-in/opt-out controls
- user_category_settings: Per-user category preferences
- follows: Explicit connections (required for conversation)
- blocks: Complete bidirectional separation
Content Tables
- posts: Primary content (500 char max, categorized, moderated)
- post_metrics: Engagement counters (likes, saves, views)
- post_likes: Public appreciation (boosts)
- post_saves: Private bookmarks
- comments: Conversation within mutual-follow circles
- comment_votes: Helpful/unhelpful signals (private)
Moderation Tables
- reports: User-filed reports for review
- trust_state: Per-user trust metrics and rate limits
- audit_log: Complete transparency trail
Key Functions
has_block_between(user_a, user_b): Check for blockingis_mutual_follow(user_a, user_b): Verify mutual connectioncan_post(user_id): Rate limit enforcementadjust_harmony_score(user_id, delta, reason): Trust adjustmentslog_audit_event(actor_id, event_type, payload): Audit logging
What This Enables
- Friendliness is enforced, not suggested. The database will not allow hostile interactions.
- Boundaries are private. Blocking and filtering leave no trace visible to the blocked party.
- Consent is required. You cannot force your words into someone's space.
- Exposure is controlled. Users see only what they choose to see.
- Influence is earned. New accounts cannot spam or brigade.
- Moderation is transparent. Users know why their reach changed.
Next Steps
- Edge Functions: Implement feed generation, content moderation, and signup flows.
- Flutter Client: Build UI that reflects these structural constraints.
- Content Moderation: Integrate tone classification and integrity scoring.
- Feed Algorithms: Design reach curves based on harmony score and engagement patterns.