PyFed (PieFed) Codebase Analysis — Comprehensive Feature Specification
Project: PyFed v1.8.0-dev (PieFed) — Python Flask-based ActivityPub link aggregation platform (Lemmy/Mbin alternative) Codebase Location:
/home/user/code/python/pyfedi/Target: Threadlight — Rust-based single-instance social platform with trust-based governance, credit economy, circles, and community forking
1. Architecture Overview
1.1 Stack
- Framework: Flask + SQLAlchemy ORM
- Database: PostgreSQL (primary), SQLite (dev)
- Cache: Redis, FileSystemCache
- Queue: Celery + Redis broker
- Frontend: Jinja2 templates + HTMX + Bootstrap
- Auth: Flask-Login + JWT + OAuth (Google, Mastodon, Discord)
- Federation: ActivityPub (custom implementation)
- Search: sqlalchemy-searchable (TSVector full-text search)
1.2 Directory Layout
pyfedi/
├── app/
│ ├── activitypub/ # Federation logic (actors, routes, signature, util)
│ ├── admin/ # Admin panel (routes, forms, util, constants)
│ ├── api/alpha/ # REST API (FastAPI-backed swagger-documented API)
│ ├── auth/ # Login, registration, OAuth, passkeys, onboarding
│ ├── chat/ # Private messaging
│ ├── community/ # Community management (CRUD, moderation, wiki)
│ ├── dev/ # Developer tools
│ ├── domain/ # Domain management
│ ├── feed/ # Curated feeds (user collections of communities)
│ ├── instance/ # Instance exploration
│ ├── main/ # Home page, global routes, RSS
│ ├── post/ # Post/reply CRUD, voting, bookmarks, embeds
│ ├── search/ # Full-text search
│ ├── tag/ # Tag browsing
│ ├── topic/ # Topic-based community grouping
│ ├── user/ # Profile, settings, filters, blocks
│ ├── shared/ # Shared service layer (tasks, upload, feed, auth, etc.)
│ ├── models.py # All database models (~4273 lines)
│ ├── utils.py # Utility functions (~4602 lines)
│ ├── constants.py # App-wide constants
│ ├── inoculation.py # Media literacy / anti-radicalization resources
│ └── plugins/ # Plugin system
├── migrations/ # Alembic DB migrations
├── tests/ # Test suite
└── docs/ # Documentation
2. Content Filtering System (Multi-Layered)
2.1 Keyword Filters (Filter Model)
DB Model (app/models.py:3509-3524):
class Filter(db.Model):
id = Integer, PK
title = String(50) # User-given name
filter_home = Boolean, default=True # Apply to home feed
filter_posts = Boolean, default=True # Apply to community posts
filter_replies = Boolean, default=False # Apply to replies
hide_type = Integer, default=0 # 0 = semi-transparent, 1 = hide completely
user_id = Integer, FK->User
expire_after = Date # Optional expiration
keywords = String(500) # Newline-separated keywords
Implementation (app/utils.py:1997-2036):
- Three cached functions:
user_filters_home(),user_filters_posts(),user_filters_replies() - Each loads filters where
filter_{scope}=Trueandexpire_after > today OR expire_after IS NULL - Keywords split by newline, lowercased
hide_type == 0→ posts get semi-transparent treatment in templateshide_type == 1→ posts excluded from SQL query (template-level filtering)- Result structure:
{filter_title: {set_of_keywords}, '-1': {set_of_keywords}}where-1means “hide completely”
2.2 Content Visibility Settings (User Model)
On User model (app/models.py:959-1078):
| Field | Type | Default | Description |
|---|---|---|---|
hide_nsfw |
Integer | 1 | 0=show, 1=hide, 2=blur, 3=semi-transparent |
hide_nsfl |
Integer | 1 | Same scale |
hide_gen_ai |
Integer | 2 | 0=show, 1=hide, 2=label, 3=semi-transparent |
ignore_bots |
Integer | 0 | 0=show, 1=hide completely, 2=blur, 3=semi-transparent |
hide_low_quality |
Boolean | false | Hide posts from low_quality communities |
hide_read_posts |
Boolean | false | Hide posts user has already interacted with |
read_language_ids |
ARRAY(Integer) | [] | Only show content in these languages |
community_keyword_filter |
String(150) | ‘’ | Hide communities with these words in name |
Template-level filtering (app/templates/user/edit_filters.html):
hide_type_choices: Show, Hide completely, Blur thumbnail, Make semi-transparentai_hide_type_choices: Show, Hide completely, Label as AI, Make semi-transparent
2.3 Blocking System (4 Levels)
| Block Target | DB Model | Primary Key | Implementation |
|---|---|---|---|
| User | UserBlock |
blocker_id, blocked_id |
SQL exclusion in feed queries |
| Community | CommunityBlock |
user_id, community_id |
SQL exclusion in feed queries |
| Domain | DomainBlock |
user_id, domain_id |
Post.domain_id NOT IN blocked_domains() |
| Instance | InstanceBlock |
user_id, instance_id |
Post.instance_id NOT IN blocked_instances() |
Implementation (app/utils.py:3236-3301):
- All blocking is applied at the SQL query level in
get_deduped_post_ids() - Blocked users:
p.user_id NOT IN :blocked_accounts - Blocked communities:
p.community_id NOT IN :blocked_community_ids - Blocked domains:
(p.domain_id NOT IN :domain_ids OR p.domain_id IS NULL) - Blocked instances:
(p.instance_id NOT IN :instance_ids OR p.instance_id IS NULL) - Cached via
@cache.memoize(timeout=300)helper functions
2.4 Flair Blocking (CommunityFlairBlock)
DB Model (app/models.py:4115-4119):
class CommunityFlairBlock(db.Model):
community_id = Integer, FK->Community
community_flair_id = Integer, FK->CommunityFlair
user_id = Integer, FK->User
Users can block posts with specific flairs/tags within a community. Applied in get_deduped_post_ids():
p.id NOT IN (SELECT post_id FROM post_flair WHERE flair_id IN :blocked_flair_ids)
3. Vote / Score System
3.1 Vote Models
PostVote (app/models.py:3459-3475):
class PostVote(db.Model):
id = Integer, PK
user_id = Integer, FK->User # Who voted
author_id = Integer, FK->User # Post author (reputation target)
post_id = Integer, FK->Post
effect = Float # Vote weight (not just -1/+1)
emoji = String(50) # Emoji reaction
created_at = DateTime
PostReplyVote (app/models.py:3478-3494): Same structure for comment votes.
Vote effects are floats, enabling weighted voting systems (reputation-weighted, etc., though PyFed uses simple +/-1 in practice with float storage for future).
3.2 Vote Federating / Privacy
| Setting | Location | Effect |
|---|---|---|
federate_votes |
User setting | When false, votes only count locally, not broadcast via ActivityPub |
vote_privately |
User model | When true, votes are hidden from other users |
show_scores |
API schema | Controls display of aggregate scores |
Instance votes_are_public() |
Instance model | Returns True for Lemmy/Mbin/kbin (for compatibility) |
3.3 Downvote Controls (Granular)
Site-level (Site.enable_downvotes, Boolean, default=True):
- Master toggle: if false, no downvoting anywhere on instance
Community-level (Community.downvote_accept_mode, Integer):
DOWNVOTE_ACCEPT_NONE = -1 # No downvotes allowed
DOWNVOTE_ACCEPT_ALL = 0 # Anyone can downvote
DOWNVOTE_ACCEPT_MEMBERS = 2 # Only community members
DOWNVOTE_ACCEPT_INSTANCE= 4 # Only users from same instance
DOWNVOTE_ACCEPT_TRUSTED = 6 # Only from trusted instances
User-level restrictions (app/utils.py:1766-1807):
- Banned users can’t downvote
- Bot accounts can’t downvote
- Users with negative attitude (more downvotes than upvotes cast) can’t downvote
- Users with reputation < -10 can’t downvote
- Banned from community can’t downvote there
3.4 Vote Quota
VOTE_QUOTAconfig: max 240 votes per day (configurable)votes_cast_today(user_id): Redis counter, resets daily- Displayed on user profiles as
vote_quota_used
3.5 Reputation & Attitude
User fields:
reputation(Float): Accumulated reputation scoreattitude(Float, -1 to 1): Ratio of (upvotes_cast - downvotes_cast) / total_votes_cast- Only calculated after 10+ votes
- Used to determine if user can downvote
Reputation calculation:
- Based on recent 50 post votes + 50 comment votes
- Post authors’ reputation affected by votes on their content
- Low-quality communities marked with
low_qualityflag don’t improve reputation
3.6 Reply Visibility Thresholds
| Setting | Description |
|---|---|
reply_collapse_threshold (integer, default=-10) |
Replies scored at or below this are collapsed |
reply_hide_threshold (integer, default=-20) |
Replies scored at or below this are hidden entirely |
Comment sort options: hot, top, new, old
4. Hide Read / Hidden Posts
4.1 Read Posts Tracking
Many-to-many table (read_posts, app/models.py:928-933):
read_posts = db.Table('read_posts',
db.Column('user_id', Integer, FK->User, PK),
db.Column('read_post_id', Integer, FK->Post, PK),
db.Column('interacted_at', DateTime, indexed),
Index('ix_read_posts_user_post', 'user_id', 'read_post_id')
)
User model relationship:
User.read_post: posts the user has read/interacted withPost.read_by: users who have read this postUser.hide_read_posts(Boolean): master toggle
Hide Read in Feed Query (app/utils.py:3264-3265):
p.id NOT IN (SELECT read_post_id FROM "read_posts" WHERE user_id = :user_id)
4.2 Hidden Posts
Table (hidden_posts, app/models.py:937-942): Same structure as read_posts.
Always applied (app/utils.py:3268):
p.id NOT IN (SELECT hidden_post_id FROM "hidden_posts" WHERE user_id = :user_id)
Users can manually hide individual posts. These are always excluded from feed.
4.3 Interaction Recording
Interaction is recorded when:
- A user opens/clicks a post
- A user upvotes or downvotes a post
- This powers both
hide_read_postsand the “read history” feature
4.4 View Templates
user/read_posts.html: shows user’s read post historyuser/hidden_posts.html: shows hidden posts with unhide optionuser/_read_posts_nav.html: navigation for read/hidden posts
5. Content Moderation & Governance
5.1 Community Moderation
Community membership levels:
SUBSCRIPTION_OWNER = 3
SUBSCRIPTION_MODERATOR = 2
SUBSCRIPTION_MEMBER = 1
SUBSCRIPTION_NONMEMBER = 0
SUBSCRIPTION_PENDING = -1
SUBSCRIPTION_BANNED = -2
Moderation tools:
- Community bans (with reason, optional duration)
- Post/reply removal
- Report handling (new → escalated → resolved)
- Moderation log (audit trail)
- Content retention policies (auto-delete after N months)
- Flair management (text/color/blur-images)
- Wiki management with revision history
- Mod-only communities
5.2 Report System
Report types (constants.py):
REPORT_TYPE_USER = 0
REPORT_TYPE_POST = 1
REPORT_TYPE_REPLY = 2
REPORT_TYPE_COMMUNITY = 3
REPORT_TYPE_MESSAGE = 4
Report states: new → escalated → appealed → resolved → discarded
Report reasons (from user/forms.py):
- Breaks community rules
- Harassment
- Threatening violence
- Promoting hate/genocide
- Minor abuse/sexualization
- Sharing personal info (doxing)
- Spam
- Non-consensual intimate media
- Prohibited transaction
- Impersonation
- Copyright violation
- Trademark violation
- Self-harm/suicide
- Other
- Misinformation/disinformation
- Racism/sexism/transphobia
- Malicious reporting
5.3 Instance-level Controls
| Setting | Type | Description |
|---|---|---|
enable_downvotes |
Boolean | Master downvote toggle |
registration_mode |
String | Open / RequireApplication / Closed |
application_question |
Text | Question for registration applications |
private_instance |
Boolean | Require login to view anything |
allow_or_block_list |
Integer | 1=allowlist, 2=blocklist |
allowlist_mode |
Integer | 0=weak, 1=strong, 2=intense |
blocked_phrases |
Text | Discard incoming content with these phrases |
auto_decline_referrers |
Text | Auto-reject registrations from these referrers |
honeypot |
Boolean | Bot detection |
5.4 Inoculation System
app/inoculation.py contains educational content displayed to users about:
- Groupthink and cult dynamics
- Alt-right radicalization pipelines
- Media literacy
- Confirmation bias
- The dark side of upvotes
This is shown at registration and optionally in sidebars — a unique approach to platform responsibility.
6. Custom Feeds & Curated Collections
6.1 Feed System
Feeds are user-curated collections of communities, acting like topic-based aggregations.
Feed model (app/models.py):
- User-owned (or instance-wide)
- Can be public or private
- Auto-follow/auto-leave behavior for subscribing
- Remote feeds via ActivityPub federation
- Feeds can have parent-child hierarchy (sub-feeds)
6.2 Topic System
Topics are admin-created groupings of communities with hierarchical structure (Topic model has parent_id).
6.3 Community Features
- Private communities: Only members can view
- Local-only communities: No federation
- Encrypted communities: End-to-end encryption
- Restricted-to-mods posting: Only moderators can post
- Question/Answer mode: StackOverflow-style communities (
question_answerflag) - Default layout: Per-community layout preference
- Community themes: Visual customization per community
- Post flairs: Categorization with visual styling (text color, background color, blur images)
7. User Experience & Accessibility
7.1 Themes & Visual
- 18+ themes including accessibility-focused ones (high contrast, dyslexic font)
- Font choices: Atkinson Hyperlegible, OpenDyslexic, Inter, Roboto
- Compact UI modes (3 levels: normal/compact/ultra-compact)
- Low bandwidth mode (reduces page size)
- Code syntax highlighting (18 color schemes)
- Additional CSS injection for users and admins
7.2 Productivity Features
- Usage limits:
max_hours_per_daywith configurable change restrictions - Vote quota: Limits daily voting to prevent vote manipulation
- Scheduled posts: Posts with
scheduled_for,repeat(daily/weekly/monthly) - Post drafts: Posts with status
-1(draft) - Bookmarks: Separate for posts and replies
- Cross-posting: Track cross-posted content across communities
- User notes: Private notes about other users
- Keyboard shortcuts: Documented in
keyboard_shortcuts.html
7.3 Notification System
Granular notification subscriptions:
- User follows (when followed user posts)
- Community posts (new posts in community)
- Topic posts (new posts in topic communities)
- Post replies (new top-level comments)
- Reply replies (replies to your comments)
- Mentions
- Private messages
- Ban/unban notifications
- New moderator notifications
- Report updates
8. Key Technical Patterns
8.1 Feed Query Pipeline
The get_deduped_post_ids() function (app/utils.py:3197-3317) is the core query builder:
- View filter selection (subscribed/local/popular/all/moderating)
- Community source selection
- Following user content inclusion (optional)
- Content type filters (nsfw, nsfl, ai, bots)
- Hide read posts
- Hidden posts exclusion
- Language filter
- Blocked domains/instances/communities/users
- Community bans
- Flair blocks
- Community keyword filter
- Sort application (hot/scaled/top/new/active/old)
8.2 Vote Quota Circuit (Redis-based)
def votes_cast_today(user_id):
num = redis_client.get(f'votes_cast_{date.today()}_{user_id}')
if num is None: return 0
return int(num)
8.3 Deduplication Strategy
Cross-posts are tracked via Post.cross_posts (ARRAY of post IDs) and deduplicated in the feed query:
- Posts with the same URL are grouped
- Non-bot posts preferred over bot posts
- Post with most replies preferred
- Seen posts tracked in
seen_beforeset
9. Features Valuable for Threadlight → Detailed Recommendations
9.1 HIGH VALUE — Direct Port
9.1.1 Multi-Layered Content Filtering System
Why: Threadlight’s goal of encouraging quality engagement requires giving users granular control over their feed.
Recommended implementation:
- Keyword Filter Set: Named filters with keywords, scope (feed/community/replies), hide_type (dim, hide, blur), and optional expiration. Users can create “spoiler” or “topic avoid” filters.
- Content Toggles: NSFW, AI-generated, bot content — each with graduated visibility levels (show/dim/hide). This aligns with trust-based governance where communities self-identify content types.
- Language Filter: Filter feed to languages the user understands.
Why for Threadlight: Single-instance doesn’t need instance blocking, but user-level blocking of communities, users, and content keywords is essential for a healthy social platform. The graduated visibility concept (show → semi-transparent → blur → hide) is more nuanced than binary show/hide.
9.1.2 Hide Read / Voted Posts
Why: Reduces feed fatigue. Users who browse frequently see fresh content.
Recommended implementation:
- Track post reads, upvotes, and downvotes per user
- Optional toggle to exclude read/voted posts from feed
- Separate explicit “hide post” function
- “Read post history” page for personal reference
Why for Threadlight: With Threadlight’s credit economy, tracking what users have engaged with is already needed. Extending this to feed filtering is a small addition with huge UX benefit.
9.1.3 Reply Collapse/Hide Thresholds
Why: Users collapse/expand replies based on score. This empowers the community to self-moderate without total censorship.
Recommended implementation:
- User-configurable thresholds for collapsing and hiding replies
- Default: collapse at -10, hide at -20 (configurable)
- Works with Threadlight’s credit-based voting system
Why for Threadlight: Perfect fit for trust-based governance. Bad-faith replies don’t need deletion — they just get buried. The threshold approach gives users agency.
9.2 MEDIUM-HIGH VALUE — Adapt with Credit Economy
9.2.1 Downvote Controls (Community-Level)
Why: Communities should decide their own norms around feedback.
Recommended implementation:
- Site-level master toggle for downvotes
- Per-circle (community) downvote policy: None / Members only / Trusted only / Everyone
- User reputation/credit check: only users with positive credit ratio can downvote
Why for Threadlight: The credit economy naturally maps to this. “Who can downvote” becomes a trust function — users with proven good judgment (high credit, positive attitude) earn the right to give negative feedback.
9.2.2 Vote Privacy & Score Visibility
Why: Reduces social pressure and groupthink.
Recommended implementation:
federate_votes→ adapt toshare_votes(share with circle/community or keep private)vote_privately→hide_my_votes(don’t show my voting activity on my profile)show_scores→ configurable per-community, per-post type- Vote weighting by user reputation (already using float effect values)
Why for Threadlight: Core to “not promoting outrage”. Hidden scores reduce pile-on voting. Reputation-weighted votes reduce brigading. Makes the credit economy meaningful.
9.2.3 Vote Quota / Daily Limits
Why: Prevents vote manipulation and encourages deliberate engagement.
Recommended implementation:
- Configurable daily vote budget (e.g., 80 per day)
- Redis-based counter, resets daily
- Higher credit users could get larger budgets
Why for Threadlight: The credit economy needs scarcity. Daily vote budgets make each vote meaningful. Could tie quota to credit level (higher credit = more votes/day, aligning incentives).
9.3 MEDIUM VALUE — Community & Trust Features
9.3.1 Community Flairs with User Blocking
Why: Communities can tag posts with flairs; users can block specific flairs.
Recommended implementation:
- Circle moderators define flairs (e.g., “Politics”, “Venting”, “Humor”, “NSFW”)
- Flairs have visual styling (text color, background color, optional image blur)
- Users can block posts with specific flairs (per-circle)
- Posts auto-assigned flair based on content analysis
Why for Threadlight: Circles (Threadlight’s communities) have diverse content. Flair-blocking lets users curate their experience within a circle without leaving it.
9.3.2 Custom Feeds / Curated Collections
Why: Users can aggregate content across circles.
Recommended implementation:
- User-created “feeds” that pool posts from selected circles
- Public/private toggle
- Auto-follow/auto-leave: subscribing to a feed auto-joins the constituent circles
- Instance-wide curated feeds (staff-picked)
Why for Threadlight: Threadlight’s “circles” concept makes this natural — feeds become “meta-circles” or collections. Great for onboarding: “Here’s a starter feed of recommended circles.”
9.3.3 Question & Answer Mode
Why: Some circles benefit from StackOverflow-style structured Q&A.
Recommended implementation:
- Circle-level toggle for Q&A mode
- Accepted answer feature (
NOTIF_ANSWERnotification type) - Different sorting: unanswered first, accepted answers highlighted
Why for Threadlight: Technical circles, support circles, or knowledge-sharing circles benefit from this. It is a relatively contained feature (circle setting + accepted answer field).
9.3.4 Scheduled / Repeating Posts
Why: For regular content like daily discussions, weekly threads.
Recommended implementation:
scheduled_fordatetime for future postingrepeatmode: daily, weekly, monthlystop_repeatingend date- Draft queue (
status = -1) for pre-written content
Why for Threadlight: Circles with regular events (weekly book club, daily check-in) benefit from automatable posts. Keeps the community engaged with minimal moderation overhead.
9.4 NOTEWORTHY — Quality of Life
9.4.1 Inoculation / Media Literacy Resources
Why: Unique to PyFed — an educational content system shown at registration and in sidebars.
Recommended implementation:
- Configurable set of links/resources shown during onboarding
- Topics: critical thinking, media literacy, community guidelines
- Rotation-based display (different resource each time)
Why for Threadlight: Fits the “bringing people together” mission. Could be integrated into the credit economy (read an inoculation article → earn small credit bonus). Makes Threadlight’s trust-based governance self-reinforcing.
9.4.2 User Notes (Private Labels)
Why: Users can attach private notes to other users visible only to themselves.
Recommended implementation:
- Simple user_id → target_id → note_text mapping
- “Apply to all with same username” option (for known trolls across instances — less relevant for single-instance)
- Displayed on user hover/profile as a subtle note
Why for Threadlight: Lightweight trust tool. “I’ve had good interactions with this person” or “Reminder: this user posted bad-faith content before.” Supports the credit economy by letting users track their own trust signals.
9.4.3 Usage Time Limits
Why: Users can set daily time limit on the platform with configurable change restrictions.
Recommended implementation:
max_hours_per_daysetting- Enforce via session timing or activity tracking
- Change restriction options: anytime / 1 day / 1 month / 2 months
- Helps with compulsive usage
Why for Threadlight: Aligns with ethical platform design. If Threadlight aims to be a “quality engagement” platform, helping users manage their time is a strong signal of pro-user values.
9.4.4 Activity Logging (User-Level)
Why: Users can see their voting history, posting patterns, and platform usage.
Recommended implementation:
ActivityLogmodel tracks user activity types- Profile charts showing posting/commenting patterns (hour of day, etc.)
- Recently upvoted/downvoted posts visible on profile
Why for Threadlight: The credit economy needs transparency. Showing users their own activity patterns and vote history reinforces accountability. Could combine with credit statement (“Your votes this week earned/spent X credits”).
9.5 LOWER PRIORITY — Nice to Have
| Feature | Reason for Lower Priority |
|---|---|
| Cross-posting detection | Useful but complex; not core to Threadlight’s value prop |
| Bot detection patterns | Single-instance has fewer bot problems |
| PWAs/service workers | Nice but separate from social architecture |
| Pluggable themes | Valuable but not transformative |
| RSS feeds | Good for power users but not core |
| Full-text search | Assumed baseline for any social platform |
| Multiple code highlight themes | Low impact on community health |
10. Implementation Notes for Rust/Threadlight
10.1 Query Pattern: Layered Feed Filtering
PyFed’s get_deduped_post_ids() demonstrates a composable filter pattern:
1. Source selection (which communities/circles)
2. Include following (friends/trusted users)
3. Content filters (nsfw, ai, bots)
4. Read/explicit hide (interacted posts)
5. Language filter
6. Block list (users, communities, flairs)
7. Ban list (community bans)
8. Sort (hot, top, new, etc.)
Each layer is a SQL WHERE clause. In Rust, this maps cleanly to a builder pattern:
FeedQuery::new()
.from_circles(user.subscribed_circles())
.include_following(user.following())
.filter_nsfw(user.hide_nsfw())
.hide_read_posts(user.hide_read_posts())
.exclude_blocked_users(user.blocked_users())
.language_filter(user.languages())
.sort(Sort::Hot)
.build()
10.2 Vote as Float
PyFed stores effect as Float, not just +/-1. For Threadlight’s credit economy:
- Upvote effect could scale with voter credit:
effect = voter.credit_level * base_weight - Downvote effect could scale inversely:
effect = -(1.0 / voter.credit_level) * base_weight - This naturally weights high-credit users’ opinions more heavily
10.3 Redis Counter Pattern for Quotas
// Simple Redis-based daily quota
async fn votes_remaining(user_id: &str, redis: &Client) -> i64 {
let key = format!("vote_quota:{}:{}", user_id, today());
let used: i64 = redis.get(&key).unwrap_or(0);
let max = get_user_quota(user_id); // Higher credit = higher quota
max - used
}
10.4 Single-Instance Adaptations
Threadlight is single-instance, so skip:
- Instance federation
- Remote content fetching
- Allowlist/blocklist
- Instance-level admin for other instances
Focus instead on:
- Circle (community) level governance
- User-level trust and credit
- Platform-level defaults and policies
Appendix A: Complete DB Schema Summary (Threadlight-Relevant)
| Table | Purpose | Key Fields |
|---|---|---|
| Filter | User keyword filters | title, filter_home, filter_posts, filter_replies, hide_type, keywords, expire_after |
| UserBlock | Blocked users | blocker_id, blocked_id |
| CommunityBlock | Blocked communities | user_id, community_id |
| DomainBlock | Blocked domains | user_id, domain_id |
| CommunityFlairBlock | Blocked flairs | community_id, flair_id, user_id |
| PostVote | Post votes | user_id, post_id, effect (Float), emoji |
| PostReplyVote | Comment votes | user_id, reply_id, effect (Float) |
| read_posts | Read tracking | user_id, post_id, interacted_at |
| hidden_posts | Hidden posts | user_id, post_id |
| CommunityFlair | Post categorizations | flair, text_color, background_color, blur_images |
| Community | Circle/community | downvote_accept_mode, question_answer, private, local_only |
| User | User settings | hide_nsfw, hide_nsfl, hide_gen_ai, hide_read_posts, vote_privately, reputation, attitude |
| UserNote | Private user notes | user_id, target_id, note |
| NotificationSubscription | Notification prefs | user_id, entity_id, type (NOTIF_*) |
| ModLog | Moderation audit | user_id, action, target, community_id |
Analysis completed: July 25, 2026. PyFed version: 1.8.0-dev.
