problemhardoodobject-oriented-design-for-stack-overflowobject oriented design for stack overflowobjectorienteddesignforstackoverflow

OOD - Stack Overflow

HardUpdated: Jan 1, 2026

Problem Statement

Stack Overflow revolutionized technical knowledge sharing by creating a gamified Q&A platform where developers collaboratively solve programming challenges. The system must support millions of users posting questions tagged with relevant technologies, providing detailed answers with code snippets and images, and engaging through upvotes, comments, and acceptance mechanisms. Unlike traditional forums, Stack Overflow employs a reputation system that rewards quality contributions with privileges (editing, moderation, bounties), fostering a self-policing community that maintains high content standards.

The platform serves diverse user personas: guest visitors searching for solutions without accounts, registered members asking questions and contributing answers to build reputation, moderators who close duplicate/off-topic questions and manage flags, admins who handle account suspensions and system-wide policies, and automated systems that award badges, track tag popularity trends, expire bounties, and send notifications. A critical challenge is preventing spam and low-quality content through progressive trust levelsβ€”new users have limited privileges until they demonstrate expertise through upvoted contributions.

Key technical challenges include: preventing duplicate votes on the same post by the same user, managing tag ecosystems with daily/weekly frequency tracking for trending technologies, implementing bounty mechanics where question authors sacrifice reputation points (non-refundable, expires after deadline) to attract expert attention, coordinating answer acceptance (only question owner can accept, only one answer accepted per question), enforcing reputation-based privileges (e.g., 15 reputation to upvote, 3,000 to vote to close), tracking badge eligibility through complex rules (e.g., "Nice Answer" for 10+ upvotes, "Guru" for accepted answer with 40+ score), and scaling search across millions of questions with full-text indexing on titles, descriptions, tags, and code blocks.

Solution

1. Requirements Analysis

Functional Requirements

User Management & Authentication

  1. Guest users can browse and search questions without authentication
  2. Registration requires email verification and profile creation (name, location, bio)
  3. Members have reputation scores tracking contribution quality
  4. Account statuses: Active, Suspended, Blocked, Deleted with audit trails
  5. Reputation-based privilege system (15 for upvote, 50 for comment, 3000 for close vote)

Question & Answer Operations 6. Members can post questions with title (150 char max), body (markdown + code blocks), and 1-5 tags 7. Questions support optional bounties (minimum 50 reputation, doubles on renewal, expires in 7 days) 8. Members can answer any open question with markdown formatting and inline images 9. Question owners can accept exactly one answer (grants 15 reputation to answerer, 2 to acceptor) 10. Questions have statuses: Open, Closed, On Hold, Deleted, Locked 11. Close reasons: Duplicate, Off-Topic, Too Broad, Primarily Opinion-Based, Unclear

Voting & Engagement 12. Members can upvote questions (+10 to author, -0 to voter) and answers (+10 to author, -0 to voter) 13. Members can downvote questions/answers (-2 to author, -1 to voter) 14. One vote per user per post, votes are anonymous, users can change votes within grace period 15. Members can comment on questions and answers (requires 50 reputation) 16. Flagging system for spam, offensive content, moderator attention (requires 15 reputation)

Tagging & Discovery 17. Tags have names, descriptions, and wiki pages managed by high-reputation users 18. Daily and weekly tag usage frequencies tracked for trending analysis 19. Tag synonyms managed by moderators (e.g., "javascript" β†’ "js") 20. Search supports filters: tags, dates, vote ranges, accepted answers, closed status

Gamification & Reputation 21. Badges awarded for achievements: bronze (easy), silver (medium), gold (hard) 22. Badge types: tag badges (100+ upvotes in specific tag), participation badges (Supporter, Critic), quality badges (Nice Answer, Great Question) 23. Reputation changes logged with event attribution (upvote, accepted answer, bounty awarded) 24. Reputation caps: +200 per day from upvotes (excluding accepts and bounties)

Moderation & Administration 25. Moderators can close, reopen, delete, undelete, lock any question 26. Close votes require 5 community members (3000+ reputation) or 1 moderator 27. Delete votes require 3 members with 10,000+ reputation 28. Admins can suspend accounts, merge duplicate accounts, destroy spam accounts 29. Edit history tracked for all posts with revision diff visualization

Notifications 30. Real-time notifications for: answer to your question, comment on your post, badge awarded, bounty expiring soon, edit to your post, moderator action 31. Email digest options: daily, weekly, real-time, never

Non-Functional Requirements

Performance

  1. Search results return within 200ms for 95th percentile queries
  2. Page load time <1 second for questions with <50 answers
  3. Vote registration acknowledged within 100ms
  4. Support 10,000 concurrent users

Scalability 5. Scale to 50+ million questions, 100+ million answers 6. Handle 1000+ questions posted per day 7. Support 50,000+ tags with synonym chains

Availability & Reliability 8. 99.9% uptime SLA (max 43 minutes downtime/month) 9. Zero data loss for accepted answers and reputation events 10. Graceful degradation during search index rebuilds

Security 11. Prevent duplicate voting through client + server-side validation 12. Rate limiting: 10 questions/day for new users, 50 for established users 13. CAPTCHA for suspicious activity patterns 14. SQL injection and XSS protection in markdown rendering

Auditability 15. All moderation actions logged with moderator ID and timestamp 16. Reputation change audit trail with event source 17. Vote fraud detection through anomaly patterns

Extensibility 18. Plugin system for new badge award rules 19. Customizable close reasons per site (Stack Overflow vs. Math Stack Exchange) 20. Internationalization support for 10+ languages

2. Use Case Diagram

graph TB
    %% Actors
    Guest["πŸ‘₯ Guest User"]
    Member["πŸ‘€ Member"]
    Moderator["πŸ›‘οΈ Moderator"]
    Admin["πŸ”§ Admin"]
    System["πŸ€– System"]
    
    %% Content Discovery (Blue)
    subgraph Discovery["πŸ” Content Discovery"]
        style Discovery fill:#E3F2FD
        UC1["Search Questions"]
        UC2["Browse by Tag"]
        UC3["View Question Details"]
        UC4["View User Profile"]
        UC5["Subscribe to Tag"]
    end
    
    %% Content Creation (Green)
    subgraph Creation["✍️ Content Creation"]
        style Creation fill:#E8F5E9
        UC6["Post Question"]
        UC7["Add Answer"]
        UC8["Add Comment"]
        UC9["Edit Own Post"]
        UC10["Delete Own Post"]
        UC11["Attach Code Snippet"]
        UC12["Upload Image"]
    end
    
    %% Voting & Engagement (Orange)
    subgraph Engagement["⭐ Voting & Engagement"]
        style Engagement fill:#FFF3E0
        UC13["Upvote Question/Answer"]
        UC14["Downvote Question/Answer"]
        UC15["Accept Answer"]
        UC16["Flag Post"]
        UC17["Bookmark Question"]
        UC18["Share Question"]
    end
    
    %% Gamification (Purple)
    subgraph Gamification["πŸ† Gamification & Reputation"]
        style Gamification fill:#F3E5F5
        UC19["Add Bounty"]
        UC20["Award Bounty"]
        UC21["Earn Badge"]
        UC22["Track Reputation"]
        UC23["View Privileges"]
    end
    
    %% Tagging (Teal)
    subgraph Tagging["🏷️ Tag Management"]
        style Tagging fill:#E0F2F1
        UC24["Create Tag"]
        UC25["Edit Tag Wiki"]
        UC26["Create Tag Synonym"]
        UC27["Track Tag Frequency"]
        UC28["View Trending Tags"]
    end
    
    %% Moderation (Red)
    subgraph Moderation["🚨 Moderation & Administration"]
        style Moderation fill:#FFEBEE
        UC29["Close Question"]
        UC30["Reopen Question"]
        UC31["Delete Question"]
        UC32["Undelete Question"]
        UC33["Lock Post"]
        UC34["Merge Duplicate Questions"]
        UC35["Review Flag Queue"]
        UC36["Suspend Account"]
        UC37["Destroy Spam Account"]
        UC38["View Audit Logs"]
    end
    
    %% Notifications (Yellow)
    subgraph Notifications["πŸ”” Notifications"]
        style Notifications fill:#FFFDE7
        UC39["Send Answer Notification"]
        UC40["Send Badge Award"]
        UC41["Send Bounty Expiry Warning"]
        UC42["Send Comment Reply"]
        UC43["Send Moderator Action Notice"]
    end
    
    %% Guest Connections
    Guest --> UC1
    Guest --> UC2
    Guest --> UC3
    Guest --> UC4
    
    %% Member Connections - Discovery
    Member --> UC1
    Member --> UC2
    Member --> UC3
    Member --> UC4
    Member --> UC5
    
    %% Member Connections - Creation
    Member --> UC6
    Member --> UC7
    Member --> UC8
    Member --> UC9
    Member --> UC10
    Member --> UC11
    Member --> UC12
    
    %% Member Connections - Engagement
    Member --> UC13
    Member --> UC14
    Member --> UC15
    Member --> UC16
    Member --> UC17
    Member --> UC18
    
    %% Member Connections - Gamification
    Member --> UC19
    Member --> UC20
    Member --> UC22
    Member --> UC23
    
    %% Member Connections - Tagging
    Member --> UC24
    Member --> UC25
    
    %% Moderator Connections (inherits Member)
    Moderator --> UC26
    Moderator --> UC29
    Moderator --> UC30
    Moderator --> UC31
    Moderator --> UC32
    Moderator --> UC33
    Moderator --> UC34
    Moderator --> UC35
    
    %% Admin Connections
    Admin --> UC36
    Admin --> UC37
    Admin --> UC38
    
    %% System Connections
    System --> UC21
    System --> UC27
    System --> UC28
    System --> UC39
    System --> UC40
    System --> UC41
    System --> UC42
    System --> UC43
    
    %% Styling
    classDef guestStyle fill:#B0BEC5,stroke:#546E7A,stroke-width:2px
    classDef memberStyle fill:#81C784,stroke:#388E3C,stroke-width:2px
    classDef modStyle fill:#FFB74D,stroke:#F57C00,stroke-width:2px
    classDef adminStyle fill:#E57373,stroke:#C62828,stroke-width:2px
    classDef systemStyle fill:#9575CD,stroke:#512DA8,stroke-width:2px
    
    class Guest guestStyle
    class Member memberStyle
    class Moderator modStyle
    class Admin adminStyle
    class System systemStyle

Key Actors:

  • πŸ‘₯ Guest User: Unauthenticated visitors with read-only access
  • πŸ‘€ Member: Registered users who can create content and earn reputation
  • πŸ›‘οΈ Moderator: Elected community members with moderation privileges (inherits Member capabilities)
  • πŸ”§ Admin: Platform administrators with full system control
  • πŸ€– System: Automated processes for badges, notifications, and analytics

Use Case Categories:

  • πŸ” Discovery (5 use cases): Search, browse, and explore content
  • ✍️ Creation (7 use cases): Post questions, answers, comments with rich media
  • ⭐ Engagement (6 use cases): Vote, accept, flag, bookmark content
  • πŸ† Gamification (5 use cases): Bounties, badges, reputation tracking
  • 🏷️ Tagging (5 use cases): Tag creation, wiki editing, synonym management
  • 🚨 Moderation (10 use cases): Content management, user discipline, audit trails
  • πŸ”” Notifications (5 use cases): Real-time and email notifications for events

3. Class Diagram

classDiagram
    %% ====================
    %% User Management
    %% ====================
    class Account {
        <<abstract>>
        -String accountId
        -String email
        -String passwordHash
        -String name
        -String location
        -String bio
        -AccountStatus status
        -LocalDateTime createdAt
        -LocalDateTime lastLoginAt
        +authenticate(password) bool
        +resetPassword(newPassword) void
        +suspend(reason) void
    }
    
    class Guest {
        -String sessionId
        -LocalDateTime sessionStart
        +browseQuestions() List~Question~
        +search(query) List~Question~
    }
    
    class Member {
        -String memberId
        -int reputation
        -LocalDate memberSince
        -List~Badge~ badges
        -List~Privilege~ privileges
        -NotificationSettings notificationSettings
        +postQuestion(question) Question
        +addAnswer(questionId, answer) Answer
        +addComment(postId, comment) Comment
        +upvote(postId) bool
        +downvote(postId) bool
        +acceptAnswer(answerId) bool
        +addBounty(questionId, amount) Bounty
        +createTag(tag) Tag
        +hasPrivilege(privilegeType) bool
        +gainReputation(amount, reason) void
        +loseReputation(amount, reason) void
    }
    
    class Moderator {
        -LocalDate electedAt
        -List~ModerationAction~ actions
        +closeQuestion(questionId, reason) void
        +reopenQuestion(questionId) void
        +deletePost(postId) void
        +undeletePost(postId) void
        +lockPost(postId) void
        +mergeDuplicates(originalId, duplicateId) void
        +handleFlag(flagId) void
    }
    
    class Admin {
        -List~String~ permissions
        +suspendAccount(accountId, duration, reason) void
        +destroySpamAccount(accountId) void
        +viewAuditLogs(filters) List~AuditLog~
        +managePrivileges(memberId, privilege) void
        +configureCloseReasons(siteId, reasons) void
    }
    
    class AccountStatus {
        <<enumeration>>
        ACTIVE
        SUSPENDED
        BLOCKED
        DELETED
    }
    
    class Privilege {
        -String name
        -int requiredReputation
        -String description
        +check(memberReputation) bool
    }
    
    class NotificationSettings {
        -bool emailOnAnswer
        -bool emailOnComment
        -bool emailOnBadge
        -DigestFrequency digestFrequency
        +update(settings) void
    }
    
    %% ====================
    %% Content Models
    %% ====================
    class Question {
        -String questionId
        -String title
        -String body
        -int viewCount
        -int voteCount
        -QuestionStatus status
        -LocalDateTime createdAt
        -LocalDateTime updatedAt
        -LocalDateTime closedAt
        -Member author
        -List~Tag~ tags
        -List~Answer~ answers
        -List~Comment~ comments
        -List~Photo~ photos
        -Bounty bounty
        -CloseReason closeReason
        -List~Edit~ editHistory
        +addAnswer(answer) void
        +addComment(comment) void
        +addTag(tag) void
        +close(reason, moderator) void
        +reopen(moderator) void
        +acceptAnswer(answerId) bool
        +addBounty(bounty) void
        +incrementViews() void
        +calculateScore() int
    }
    
    class Answer {
        -String answerId
        -String body
        -int voteCount
        -bool isAccepted
        -LocalDateTime acceptedAt
        -LocalDateTime createdAt
        -Member author
        -Question question
        -List~Comment~ comments
        -List~Photo~ photos
        -List~Edit~ editHistory
        +accept(questionOwner) bool
        +addComment(comment) void
        +calculateScore() int
    }
    
    class Comment {
        -String commentId
        -String text
        -int voteCount
        -LocalDateTime createdAt
        -Member author
        -Post parent
        +upvote(member) bool
        +flag(member, reason) void
    }
    
    class Post {
        <<interface>>
        +vote(member, voteType) bool
        +flag(member, reason) void
        +edit(member, newContent) void
        +delete(member) void
    }
    
    class QuestionStatus {
        <<enumeration>>
        OPEN
        CLOSED
        ON_HOLD
        DELETED
        LOCKED
    }
    
    class CloseReason {
        <<enumeration>>
        DUPLICATE
        OFF_TOPIC
        TOO_BROAD
        PRIMARILY_OPINION_BASED
        UNCLEAR
        NOT_REPRODUCIBLE
    }
    
    class Photo {
        -String photoId
        -String url
        -String caption
        -long fileSize
        -LocalDateTime uploadedAt
        -Member uploader
        +delete() void
    }
    
    class Edit {
        -String editId
        -Member editor
        -String oldContent
        -String newContent
        -String editSummary
        -LocalDateTime editedAt
        +getDiff() String
        +revert() void
    }
    
    %% ====================
    %% Tagging System
    %% ====================
    class Tag {
        -String tagId
        -String name
        -String description
        -String wikiContent
        -int dailyFrequency
        -int weeklyFrequency
        -int totalQuestions
        -LocalDateTime createdAt
        -List~TagSynonym~ synonyms
        +incrementFrequency() void
        +updateWiki(content, editor) void
        +addSynonym(synonym) void
    }
    
    class TagSynonym {
        -String synonymId
        -String originalTag
        -String synonymTag
        -Member createdBy
        -LocalDateTime createdAt
        -int voteCount
        +approve() void
    }
    
    class TagSubscription {
        -Member member
        -Tag tag
        -bool emailNotifications
        -LocalDateTime subscribedAt
        +unsubscribe() void
    }
    
    %% ====================
    %% Voting System
    %% ====================
    class Vote {
        -String voteId
        -Member voter
        -Post post
        -VoteType type
        -LocalDateTime votedAt
        +reverse() void
    }
    
    class VoteType {
        <<enumeration>>
        UPVOTE
        DOWNVOTE
    }
    
    %% ====================
    %% Gamification
    %% ====================
    class Bounty {
        -String bountyId
        -int amount
        -LocalDateTime startedAt
        -LocalDateTime expiresAt
        -Member offeredBy
        -Question question
        -Answer awardedTo
        -BountyStatus status
        +award(answer) void
        +expire() void
        +renew(additionalAmount) void
    }
    
    class BountyStatus {
        <<enumeration>>
        ACTIVE
        AWARDED
        EXPIRED
        CANCELED
    }
    
    class Badge {
        -String badgeId
        -String name
        -String description
        -BadgeType type
        -BadgeLevel level
        -String iconUrl
        +award(member) void
    }
    
    class BadgeType {
        <<enumeration>>
        TAG_BASED
        PARTICIPATION
        MODERATION
        QUESTION_QUALITY
        ANSWER_QUALITY
    }
    
    class BadgeLevel {
        <<enumeration>>
        BRONZE
        SILVER
        GOLD
    }
    
    class BadgeAward {
        -String awardId
        -Badge badge
        -Member recipient
        -LocalDateTime awardedAt
        -String reason
    }
    
    class ReputationEvent {
        -String eventId
        -Member member
        -int delta
        -ReputationEventType type
        -LocalDateTime occurredAt
        -String sourceId
        +apply() void
        +rollback() void
    }
    
    class ReputationEventType {
        <<enumeration>>
        UPVOTE_QUESTION
        UPVOTE_ANSWER
        DOWNVOTE_QUESTION
        DOWNVOTE_ANSWER
        ACCEPTED_ANSWER
        ACCEPT_ANSWER
        BOUNTY_AWARDED
        BOUNTY_OFFERED
        PENALTY_SPAM
    }
    
    %% ====================
    %% Flagging & Moderation
    %% ====================
    class Flag {
        -String flagId
        -Member flagger
        -Post flaggedPost
        -FlagReason reason
        -String description
        -FlagStatus status
        -LocalDateTime flaggedAt
        -LocalDateTime resolvedAt
        -Moderator resolvedBy
        +resolve(action) void
        +dismiss() void
    }
    
    class FlagReason {
        <<enumeration>>
        SPAM
        OFFENSIVE
        LOW_QUALITY
        DUPLICATE
        NEEDS_MODERATOR_ATTENTION
    }
    
    class FlagStatus {
        <<enumeration>>
        PENDING
        HELPFUL
        DECLINED
        DISPUTED
    }
    
    class ModerationAction {
        -String actionId
        -Moderator moderator
        -String targetId
        -ActionType actionType
        -String reason
        -LocalDateTime performedAt
        +log() void
    }
    
    class ActionType {
        <<enumeration>>
        CLOSE_QUESTION
        REOPEN_QUESTION
        DELETE_POST
        UNDELETE_POST
        LOCK_POST
        UNLOCK_POST
        MERGE_DUPLICATES
    }
    
    %% ====================
    %% Notifications
    %% ====================
    class Notification {
        -String notificationId
        -Member recipient
        -NotificationType type
        -String content
        -String linkUrl
        -bool isRead
        -LocalDateTime createdAt
        +markAsRead() void
        +send() void
    }
    
    class NotificationType {
        <<enumeration>>
        ANSWER_POSTED
        COMMENT_REPLY
        BADGE_AWARDED
        BOUNTY_EXPIRING
        QUESTION_CLOSED
        EDIT_SUGGESTED
        MENTION
    }
    
    %% ====================
    %% Search & Analytics
    %% ====================
    class SearchEngine {
        <<interface>>
        +search(query, filters) SearchResult
        +indexQuestion(question) void
        +indexAnswer(answer) void
    }
    
    class SearchResult {
        -List~Question~ questions
        -int totalCount
        -int page
        -Map~String,int~ facets
        +getNextPage() SearchResult
    }
    
    class SearchFilter {
        -List~String~ tags
        -DateRange dateRange
        -VoteRange voteRange
        -bool hasAcceptedAnswer
        -bool isClosed
        +apply(questions) List~Question~
    }
    
    class Analytics {
        -Map~String,int~ tagFrequencies
        -List~TrendingTag~ trendingTags
        +updateTagFrequency(tag) void
        +calculateTrending() List~TrendingTag~
        +getUserStatistics(memberId) UserStats
    }
    
    class TrendingTag {
        -Tag tag
        -int dailyCount
        -int weeklyCount
        -double growthRate
        -int rank
    }
    
    %% ====================
    %% Relationships
    %% ====================
    Account <|-- Guest
    Account <|-- Member
    Member <|-- Moderator
    Member <|-- Admin
    
    Account --> AccountStatus
    Member --> Privilege
    Member --> NotificationSettings
    Member --> Badge : earns
    Member --> ReputationEvent : has
    
    Question --> QuestionStatus
    Question --> CloseReason
    Question --> Tag
    Question --> Answer
    Question --> Comment
    Question --> Photo
    Question --> Edit
    Question --> Bounty
    Question ..|> Post
    
    Answer --> Comment
    Answer --> Photo
    Answer --> Edit
    Answer ..|> Post
    
    Comment ..|> Post
    
    Tag --> TagSynonym
    Tag --> TagSubscription
    
    Vote --> VoteType
    Vote --> Post
    Vote --> Member
    
    Bounty --> BountyStatus
    Bounty --> Member : offered by
    Bounty --> Answer : awarded to
    
    Badge --> BadgeType
    Badge --> BadgeLevel
    BadgeAward --> Badge
    BadgeAward --> Member
    
    ReputationEvent --> ReputationEventType
    ReputationEvent --> Member
    
    Flag --> FlagReason
    Flag --> FlagStatus
    Flag --> Post
    Flag --> Member : flagger
    Flag --> Moderator : resolver
    
    ModerationAction --> ActionType
    ModerationAction --> Moderator
    
    Notification --> NotificationType
    Notification --> Member
    
    SearchResult --> Question
    SearchFilter --> SearchResult
    
    Analytics --> TrendingTag
    TrendingTag --> Tag

Key Design Modules:

  1. User Management (8 classes): Account hierarchy, privileges, notification settings
  2. Content Models (7 classes): Question, Answer, Comment with rich editing and media
  3. Tagging System (3 classes): Tags with synonyms and subscriptions
  4. Voting System (2 classes): Vote tracking with type differentiation
  5. Gamification (7 classes): Bounties, badges, reputation events
  6. Moderation (4 classes): Flags, moderation actions, audit trails
  7. Notifications (2 classes): Event-driven notifications with preferences
  8. Search & Analytics (5 classes): Full-text search, trending analysis

Total Classes: 50+ classes demonstrating comprehensive domain modeling

4. Activity Diagrams

Activity: Post New Question with Bounty

flowchart TD
    Start([Member clicks 'Ask Question']) --> CheckPriv{Has 'Ask' privilege?<br/>Reputation β‰₯ 1}
    CheckPriv -- No --> ShowError1[Show error:<br/>'Need 1 reputation']
    ShowError1 --> End1([End])
    
    CheckPriv -- Yes --> EnterTitle[Enter title<br/>Max 150 characters]
    EnterTitle --> EnterBody[Enter body with<br/>markdown + code blocks]
    EnterBody --> SelectTags[Select 1-5 tags]
    SelectTags --> ValidateTags{Tags valid?}
    
    ValidateTags -- Invalid tag --> CreateTag{Create new tag?<br/>Requires 1500 reputation}
    CreateTag -- No --> SelectTags
    CreateTag -- Yes --> ValidateTags
    
    ValidateTags -- Valid --> AddBounty{Add bounty?}
    AddBounty -- No --> ReviewPreview[Review preview]
    
    AddBounty -- Yes --> CheckBountyRep{Reputation β‰₯ 75?<br/>Minimum bounty = 50}
    CheckBountyRep -- No --> ShowError2[Show error:<br/>'Need 75 reputation']
    ShowError2 --> ReviewPreview
    
    CheckBountyRep -- Yes --> EnterBounty[Enter bounty amount<br/>50, 100, 200, 300, 400, 500]
    EnterBounty --> SetExpiry[Set expiry:<br/>7 days from now]
    SetExpiry --> DeductRep[Deduct reputation<br/>immediately]
    DeductRep --> ReviewPreview
    
    ReviewPreview --> Submit[Submit question]
    Submit --> Validate{Passes spam<br/>detection?}
    
    Validate -- Failed --> ShowError3[Reject: Rate limit<br/>or spam detected]
    ShowError3 --> End2([End])
    
    Validate -- Passed --> CreateQuestion[Create Question entity<br/>Status = OPEN]
    CreateQuestion --> IndexQuestion[Index for search<br/>Title + body + tags]
    IndexQuestion --> UpdateTagFreq[Update tag<br/>daily/weekly frequency]
    UpdateTagFreq --> CreateNotif[Create notifications<br/>for tag subscribers]
    
    CreateNotif --> CheckBountyCreated{Bounty created?}
    CheckBountyCreated -- Yes --> ScheduleExpiry[Schedule bounty<br/>expiry job for 7 days]
    ScheduleExpiry --> RecordRepEvent[Record reputation event:<br/>BOUNTY_OFFERED]
    RecordRepEvent --> ShowSuccess[Show success:<br/>Redirect to question]
    
    CheckBountyCreated -- No --> ShowSuccess
    ShowSuccess --> End3([End])

Activity: Vote on Question or Answer

flowchart TD
    Start([Member clicks upvote/downvote]) --> CheckPriv{Has 'Vote Up'<br/>privilege?<br/>Rep β‰₯ 15}
    CheckPriv -- No --> ShowError1[Show error:<br/>'Need 15 reputation to upvote']
    ShowError1 --> End1([End])
    
    CheckPriv -- Yes --> CheckDownvote{Is downvote?}
    CheckDownvote -- Yes --> CheckDownPriv{Has 'Vote Down'<br/>privilege?<br/>Rep β‰₯ 125}
    CheckDownPriv -- No --> ShowError2[Show error:<br/>'Need 125 reputation to downvote']
    ShowError2 --> End2([End])
    
    CheckDownPriv -- Yes --> ProceedVote1[Proceed]
    CheckDownvote -- No --> ProceedVote1
    
    ProceedVote1 --> CheckDuplicate{Already voted<br/>on this post?}
    CheckDuplicate -- Yes --> CheckReverse{Same vote type?}
    
    CheckReverse -- Yes --> RemoveVote[Remove vote:<br/>Reverse reputation]
    RemoveVote --> UpdateScore1[Update post<br/>vote count]
    UpdateScore1 --> RecordRepEvent1[Record reputation<br/>event reversal]
    RecordRepEvent1 --> ShowSuccess1[Show updated count]
    ShowSuccess1 --> End3([End])
    
    CheckReverse -- No --> ChangeVote[Change vote:<br/>Adjust reputation]
    ChangeVote --> UpdateScore2[Update post<br/>vote count by Β±2]
    UpdateScore2 --> RecordRepEvent2[Record reputation<br/>event change]
    RecordRepEvent2 --> ShowSuccess2[Show updated count]
    ShowSuccess2 --> End4([End])
    
    CheckDuplicate -- No --> CheckDailyLimit{Daily reputation<br/>cap reached?<br/>+200 max}
    CheckDailyLimit -- Yes --> WarnLimit[Warn: Vote counts<br/>but no reputation gain]
    CheckDailyLimit -- No --> ProceedVote2[Proceed]
    WarnLimit --> ProceedVote2
    
    ProceedVote2 --> CreateVote[Create Vote entity:<br/>Member + Post + VoteType]
    CreateVote --> UpdateScore3[Update post<br/>vote count]
    
    UpdateScore3 --> VoteType{Vote type?}
    VoteType -- Upvote Question --> AuthorGain1[Author gains<br/>+10 reputation]
    VoteType -- Upvote Answer --> AuthorGain2[Author gains<br/>+10 reputation]
    VoteType -- Downvote Question --> AuthorLoss1[Author loses<br/>-2 reputation]
    VoteType -- Downvote Answer --> AuthorLoss2[Author loses<br/>-2 reputation]
    
    AuthorGain1 --> VoterCost{Downvote?}
    AuthorGain2 --> VoterCost
    AuthorLoss1 --> VoterCost
    AuthorLoss2 --> VoterCost
    
    VoterCost -- Yes --> VoterLoss[Voter loses<br/>-1 reputation]
    VoterCost -- No --> RecordRepEvent3[Record reputation<br/>events]
    VoterLoss --> RecordRepEvent3
    
    RecordRepEvent3 --> CheckBadge{Check badge<br/>eligibility?}
    CheckBadge -- Post score β‰₯ 10 --> AwardBadge[Award 'Nice Answer/<br/>Question' badge]
    CheckBadge -- Post score β‰₯ 25 --> AwardBadge
    AwardBadge --> ShowSuccess3[Show updated count]
    CheckBadge -- No --> ShowSuccess3
    ShowSuccess3 --> End5([End])

Activity: Accept Answer (Question Owner)

flowchart TD
    Start([Question owner clicks<br/>'Accept Answer']) --> CheckOwner{Is question owner?}
    CheckOwner -- No --> ShowError1[Show error:<br/>'Only question owner can accept']
    ShowError1 --> End1([End])
    
    CheckOwner -- Yes --> CheckStatus{Question status?}
    CheckStatus -- CLOSED/DELETED --> ShowError2[Show error:<br/>'Cannot accept on closed question']
    ShowError2 --> End2([End])
    
    CheckStatus -- OPEN --> CheckPrevious{Already has<br/>accepted answer?}
    CheckPrevious -- Yes --> UnacceptPrevious[Unaccept previous answer:<br/>isAccepted = false]
    UnacceptPrevious --> ReversePrevRep[Reverse reputation:<br/>-15 to previous answerer<br/>-2 to question owner]
    ReversePrevRep --> RecordUnaccept[Record reputation events:<br/>UNACCEPT_ANSWER]
    RecordUnaccept --> ProceedAccept[Proceed to accept new]
    
    CheckPrevious -- No --> ProceedAccept
    
    ProceedAccept --> AcceptAnswer[Set answer.isAccepted = true<br/>Set acceptedAt timestamp]
    AcceptAnswer --> GrantAnswererRep[Answerer gains<br/>+15 reputation]
    GrantAnswererRep --> GrantOwnerRep[Question owner gains<br/>+2 reputation]
    GrantOwnerRep --> RecordRepEvents[Record reputation events:<br/>ACCEPTED_ANSWER,<br/>ACCEPT_ANSWER]
    
    RecordRepEvents --> CheckBounty{Question has<br/>active bounty?}
    CheckBounty -- Yes --> AwardBounty[Award bounty to answerer:<br/>Add bounty amount to rep]
    AwardBounty --> MarkBountyAwarded[Mark bounty.status<br/>= AWARDED]
    MarkBountyAwarded --> RecordBountyEvent[Record reputation event:<br/>BOUNTY_AWARDED]
    RecordBountyEvent --> NotifyAnswerer1[Notify answerer:<br/>'Answer accepted + Bounty']
    
    CheckBounty -- No --> NotifyAnswerer2[Notify answerer:<br/>'Answer accepted']
    
    NotifyAnswerer1 --> CheckBadges{Check badge<br/>eligibility}
    NotifyAnswerer2 --> CheckBadges
    
    CheckBadges --> AnswererScore{Answer score β‰₯ 40?}
    AnswererScore -- Yes --> AwardGuru[Award 'Guru'<br/>gold badge]
    AwardGuru --> ShowSuccess[Show 'Accepted' checkmark<br/>in green]
    AnswererScore -- No --> ShowSuccess
    ShowSuccess --> End3([End])

Key Activity Flows:

  1. Post Question with Bounty (32 nodes): Validates privileges, creates question with optional bounty, indexes for search, schedules expiry job, updates tag frequencies, creates notifications

  2. Vote on Question/Answer (24 nodes): Checks vote privileges, prevents duplicate votes, enforces daily reputation cap, updates scores, applies reputation changes to both author and voter, triggers badge awards

  3. Accept Answer (22 nodes): Validates ownership, handles previous acceptance reversal, grants reputation, automatically awards bounty if active, triggers badge checks (Guru badge), sends notifications

5. Java Implementation

Below is a comprehensive Java implementation demonstrating design patterns, SOLID principles, and production-ready code.

Enumerations and Value Objects

// Status enumerations
public enum AccountStatus {
    ACTIVE, SUSPENDED, BLOCKED, DELETED
}

public enum QuestionStatus {
    OPEN, CLOSED, ON_HOLD, DELETED, LOCKED
}

public enum CloseReason {
    DUPLICATE("This question has been asked before"),
    OFF_TOPIC("This question doesn't appear to be about programming"),
    TOO_BROAD("This question is too broad to answer"),
    PRIMARILY_OPINION_BASED("This question is likely to solicit opinion"),
    UNCLEAR("This question is unclear or not useful"),
    NOT_REPRODUCIBLE("Unable to reproduce the problem");
    
    private final String description;
    
    CloseReason(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
}

public enum VoteType {
    UPVOTE(1), DOWNVOTE(-1);
    
    private final int value;
    
    VoteType(int value) {
        this.value = value;
    }
    
    public int getValue() {
        return value;
    }
}

public enum BountyStatus {
    ACTIVE, AWARDED, EXPIRED, CANCELED
}

public enum BadgeLevel {
    BRONZE(1), SILVER(2), GOLD(3);
    
    private final int tier;
    
    BadgeLevel(int tier) {
        this.tier = tier;
    }
    
    public int getTier() {
        return tier;
    }
}

public enum BadgeType {
    TAG_BASED,           // e.g., "Java Expert"
    PARTICIPATION,       // e.g., "Supporter", "Critic"
    MODERATION,          // e.g., "Deputy", "Marshal"
    QUESTION_QUALITY,    // e.g., "Nice Question", "Great Question"
    ANSWER_QUALITY       // e.g., "Nice Answer", "Guru"
}

public enum ReputationEventType {
    UPVOTE_QUESTION(10, 0),
    UPVOTE_ANSWER(10, 0),
    DOWNVOTE_QUESTION(-2, -1),
    DOWNVOTE_ANSWER(-2, -1),
    ACCEPTED_ANSWER(15, 0),      // Answerer gains
    ACCEPT_ANSWER(2, 0),          // Question owner gains
    BOUNTY_AWARDED(0, 0),         // Variable amount
    BOUNTY_OFFERED(0, 0),         // Deducts bounty amount
    PENALTY_SPAM(-100, 0);
    
    private final int authorDelta;
    private final int voterDelta;
    
    ReputationEventType(int authorDelta, int voterDelta) {
        this.authorDelta = authorDelta;
        this.voterDelta = voterDelta;
    }
    
    public int getAuthorDelta() {
        return authorDelta;
    }
    
    public int getVoterDelta() {
        return voterDelta;
    }
}

public enum FlagReason {
    SPAM, OFFENSIVE, LOW_QUALITY, DUPLICATE, NEEDS_MODERATOR_ATTENTION
}

public enum FlagStatus {
    PENDING, HELPFUL, DECLINED, DISPUTED
}

public enum NotificationType {
    ANSWER_POSTED, COMMENT_REPLY, BADGE_AWARDED, 
    BOUNTY_EXPIRING, QUESTION_CLOSED, EDIT_SUGGESTED, MENTION
}

User Management with Strategy Pattern for Privileges

import java.time.*;
import java.util.*;

// Privilege checking with Strategy pattern
public class Privilege {
    private final String name;
    private final int requiredReputation;
    private final String description;
    
    public Privilege(String name, int requiredReputation, String description) {
        this.name = name;
        this.requiredReputation = requiredReputation;
        this.description = description;
    }
    
    public boolean check(int memberReputation) {
        return memberReputation >= requiredReputation;
    }
    
    // Common privileges as constants
    public static final Privilege UPVOTE = new Privilege("Upvote", 15, "Vote up questions and answers");
    public static final Privilege DOWNVOTE = new Privilege("Downvote", 125, "Vote down questions and answers");
    public static final Privilege COMMENT = new Privilege("Comment", 50, "Leave comments on any post");
    public static final Privilege CREATE_TAG = new Privilege("Create Tag", 1500, "Create new tags");
    public static final Privilege VOTE_TO_CLOSE = new Privilege("Vote to Close", 3000, "Vote to close questions");
    public static final Privilege DELETE_VOTE = new Privilege("Delete Vote", 10000, "Vote to delete questions");
}

public abstract class Account {
    protected final String accountId;
    protected final String email;
    protected String passwordHash;
    protected String name;
    protected String location;
    protected String bio;
    protected AccountStatus status;
    protected final LocalDateTime createdAt;
    protected LocalDateTime lastLoginAt;
    
    public Account(String accountId, String email, String passwordHash, String name) {
        this.accountId = accountId;
        this.email = email;
        this.passwordHash = passwordHash;
        this.name = name;
        this.status = AccountStatus.ACTIVE;
        this.createdAt = LocalDateTime.now();
    }
    
    public boolean authenticate(String password) {
        return this.passwordHash.equals(hashPassword(password));
    }
    
    private String hashPassword(String password) {
        // Use BCrypt in production
        return password; // Simplified
    }
    
    public void resetPassword(String newPassword) {
        this.passwordHash = hashPassword(newPassword);
    }
    
    public void suspend(String reason) {
        this.status = AccountStatus.SUSPENDED;
    }
    
    public String getAccountId() { return accountId; }
    public AccountStatus getStatus() { return status; }
}

public class Member extends Account {
    private final String memberId;
    private int reputation;
    private final LocalDate memberSince;
    private final List<Badge> badges;
    private final List<Vote> votes;
    private final List<ReputationEvent> reputationHistory;
    
    public Member(String accountId, String email, String passwordHash, 
                  String name, String memberId) {
        super(accountId, email, passwordHash, name);
        this.memberId = memberId;
        this.reputation = 1; // Starting reputation
        this.memberSince = LocalDate.now();
        this.badges = new ArrayList<>();
        this.votes = new ArrayList<>();
        this.reputationHistory = new ArrayList<>();
    }
    
    public boolean hasPrivilege(Privilege privilege) {
        return privilege.check(this.reputation);
    }
    
    public void gainReputation(int amount, ReputationEventType type, String sourceId) {
        this.reputation += amount;
        ReputationEvent event = new ReputationEvent(this, amount, type, sourceId);
        this.reputationHistory.add(event);
    }
    
    public void loseReputation(int amount, ReputationEventType type, String sourceId) {
        this.reputation = Math.max(1, this.reputation - amount); // Never go below 1
        ReputationEvent event = new ReputationEvent(this, -amount, type, sourceId);
        this.reputationHistory.add(event);
    }
    
    public void awardBadge(Badge badge) {
        if (!badges.contains(badge)) {
            badges.add(badge);
        }
    }
    
    public int getReputation() { return reputation; }
    public String getMemberId() { return memberId; }
    public List<Badge> getBadges() { return Collections.unmodifiableList(badges); }
}

public class Moderator extends Member {
    private final LocalDate electedAt;
    private final List<ModerationAction> actions;
    
    public Moderator(String accountId, String email, String passwordHash,
                     String name, String memberId) {
        super(accountId, email, passwordHash, name, memberId);
        this.electedAt = LocalDate.now();
        this.actions = new ArrayList<>();
    }
    
    public void closeQuestion(Question question, CloseReason reason) {
        question.close(reason, this);
        logAction(new ModerationAction(this, question.getQuestionId(), 
                  ModerationActionType.CLOSE_QUESTION, reason.getDescription()));
    }
    
    public void reopenQuestion(Question question) {
        question.reopen(this);
        logAction(new ModerationAction(this, question.getQuestionId(),
                  ModerationActionType.REOPEN_QUESTION, "Reopened by moderator"));
    }
    
    public void deletePost(Post post) {
        post.delete(this);
        logAction(new ModerationAction(this, post.getPostId(),
                  ModerationActionType.DELETE_POST, "Deleted by moderator"));
    }
    
    private void logAction(ModerationAction action) {
        actions.add(action);
    }
}

public class Admin extends Member {
    private final Set<String> permissions;
    
    public Admin(String accountId, String email, String passwordHash,
                 String name, String memberId) {
        super(accountId, email, passwordHash, name, memberId);
        this.permissions = new HashSet<>();
        initializePermissions();
    }
    
    private void initializePermissions() {
        permissions.add("SUSPEND_ACCOUNT");
        permissions.add("DESTROY_ACCOUNT");
        permissions.add("MANAGE_PRIVILEGES");
        permissions.add("VIEW_AUDIT_LOGS");
    }
    
    public void suspendAccount(Account account, Duration duration, String reason) {
        if (permissions.contains("SUSPEND_ACCOUNT")) {
            account.suspend(reason);
        }
    }
    
    public void destroySpamAccount(Account account) {
        if (permissions.contains("DESTROY_ACCOUNT")) {
            // Permanently delete account and all content
        }
    }
}

Content Models with Template Method Pattern

import java.util.concurrent.atomic.AtomicInteger;

// Post interface for polymorphism
public interface Post {
    String getPostId();
    Member getAuthor();
    int getVoteCount();
    void vote(Member voter, VoteType type);
    void flag(Member flagger, FlagReason reason);
    void delete(Moderator moderator);
}

public class Question implements Post {
    private final String questionId;
    private final String title;
    private String body;
    private final Member author;
    private QuestionStatus status;
    private CloseReason closeReason;
    private final LocalDateTime createdAt;
    private LocalDateTime updatedAt;
    private LocalDateTime closedAt;
    private int viewCount;
    private final AtomicInteger voteCount;
    private final List<Tag> tags;
    private final List<Answer> answers;
    private final List<Comment> comments;
    private final List<Photo> photos;
    private Bounty bounty;
    private final List<Edit> editHistory;
    
    public Question(String questionId, String title, String body, Member author) {
        this.questionId = questionId;
        this.title = title;
        this.body = body;
        this.author = author;
        this.status = QuestionStatus.OPEN;
        this.createdAt = LocalDateTime.now();
        this.updatedAt = LocalDateTime.now();
        this.viewCount = 0;
        this.voteCount = new AtomicInteger(0);
        this.tags = new ArrayList<>();
        this.answers = new ArrayList<>();
        this.comments = new ArrayList<>();
        this.photos = new ArrayList<>();
        this.editHistory = new ArrayList<>();
    }
    
    public void addAnswer(Answer answer) {
        if (status == QuestionStatus.OPEN) {
            answers.add(answer);
        } else {
            throw new IllegalStateException("Cannot add answer to non-open question");
        }
    }
    
    public void addComment(Comment comment) {
        comments.add(comment);
    }
    
    public void addTag(Tag tag) {
        if (tags.size() < 5) {
            tags.add(tag);
            tag.incrementFrequency();
        }
    }
    
    public void close(CloseReason reason, Moderator moderator) {
        this.status = QuestionStatus.CLOSED;
        this.closeReason = reason;
        this.closedAt = LocalDateTime.now();
    }
    
    public void reopen(Moderator moderator) {
        if (status == QuestionStatus.CLOSED) {
            this.status = QuestionStatus.OPEN;
            this.closedAt = null;
        }
    }
    
    public boolean acceptAnswer(String answerId, Member acceptor) {
        if (!acceptor.equals(author)) {
            return false;
        }
        
        // Unaccept previous answer if exists
        answers.stream()
               .filter(Answer::isAccepted)
               .forEach(a -> a.unaccept());
        
        // Accept new answer
        answers.stream()
               .filter(a -> a.getAnswerId().equals(answerId))
               .findFirst()
               .ifPresent(Answer::accept);
        
        return true;
    }
    
    public void addBounty(Bounty bounty) {
        if (this.bounty != null && this.bounty.getStatus() == BountyStatus.ACTIVE) {
            throw new IllegalStateException("Question already has active bounty");
        }
        this.bounty = bounty;
    }
    
    public void incrementViews() {
        this.viewCount++;
    }
    
    @Override
    public void vote(Member voter, VoteType type) {
        // Check if already voted
        // Create Vote entity
        // Update vote count
        voteCount.addAndGet(type.getValue());
    }
    
    @Override
    public void flag(Member flagger, FlagReason reason) {
        // Create Flag entity for moderator review
    }
    
    @Override
    public void delete(Moderator moderator) {
        this.status = QuestionStatus.DELETED;
    }
    
    public int calculateScore() {
        return voteCount.get();
    }
    
    @Override
    public String getPostId() { return questionId; }
    @Override
    public Member getAuthor() { return author; }
    @Override
    public int getVoteCount() { return voteCount.get(); }
    public String getQuestionId() { return questionId; }
    public QuestionStatus getStatus() { return status; }
    public List<Answer> getAnswers() { return Collections.unmodifiableList(answers); }
}

public class Answer implements Post {
    private final String answerId;
    private String body;
    private final Member author;
    private final Question question;
    private boolean isAccepted;
    private LocalDateTime acceptedAt;
    private final LocalDateTime createdAt;
    private final AtomicInteger voteCount;
    private final List<Comment> comments;
    private final List<Photo> photos;
    private final List<Edit> editHistory;
    
    public Answer(String answerId, String body, Member author, Question question) {
        this.answerId = answerId;
        this.body = body;
        this.author = author;
        this.question = question;
        this.isAccepted = false;
        this.createdAt = LocalDateTime.now();
        this.voteCount = new AtomicInteger(0);
        this.comments = new ArrayList<>();
        this.photos = new ArrayList<>();
        this.editHistory = new ArrayList<>();
    }
    
    public void accept() {
        this.isAccepted = true;
        this.acceptedAt = LocalDateTime.now();
        
        // Award reputation
        author.gainReputation(15, ReputationEventType.ACCEPTED_ANSWER, answerId);
        question.getAuthor().gainReputation(2, ReputationEventType.ACCEPT_ANSWER, answerId);
        
        // Award bounty if exists
        if (question.bounty != null && question.bounty.getStatus() == BountyStatus.ACTIVE) {
            question.bounty.award(this);
        }
    }
    
    public void unaccept() {
        if (isAccepted) {
            this.isAccepted = false;
            this.acceptedAt = null;
            
            // Reverse reputation
            author.loseReputation(15, ReputationEventType.ACCEPTED_ANSWER, answerId);
            question.getAuthor().loseReputation(2, ReputationEventType.ACCEPT_ANSWER, answerId);
        }
    }
    
    public void addComment(Comment comment) {
        comments.add(comment);
    }
    
    @Override
    public void vote(Member voter, VoteType type) {
        voteCount.addAndGet(type.getValue());
    }
    
    @Override
    public void flag(Member flagger, FlagReason reason) {
        // Create Flag entity
    }
    
    @Override
    public void delete(Moderator moderator) {
        // Mark as deleted
    }
    
    public int calculateScore() {
        return voteCount.get();
    }
    
    @Override
    public String getPostId() { return answerId; }
    @Override
    public Member getAuthor() { return author; }
    @Override
    public int getVoteCount() { return voteCount.get(); }
    public String getAnswerId() { return answerId; }
    public boolean isAccepted() { return isAccepted; }
}

public class Comment {
    private final String commentId;
    private final String text;
    private final Member author;
    private final Post parent;
    private final LocalDateTime createdAt;
    private final AtomicInteger voteCount;
    
    public Comment(String commentId, String text, Member author, Post parent) {
        this.commentId = commentId;
        this.text = text;
        this.author = author;
        this.parent = parent;
        this.createdAt = LocalDateTime.now();
        this.voteCount = new AtomicInteger(0);
    }
    
    public void upvote(Member voter) {
        voteCount.incrementAndGet();
    }
    
    public String getCommentId() { return commentId; }
}

Gamification System

public class Badge {
    private final String badgeId;
    private final String name;
    private final String description;
    private final BadgeType type;
    private final BadgeLevel level;
    private final String iconUrl;
    
    public Badge(String badgeId, String name, String description, 
                 BadgeType type, BadgeLevel level) {
        this.badgeId = badgeId;
        this.name = name;
        this.description = description;
        this.type = type;
        this.level = level;
        this.iconUrl = "/badges/" + badgeId + ".png";
    }
    
    public void award(Member recipient) {
        recipient.awardBadge(this);
    }
    
    // Predefined badges
    public static final Badge NICE_ANSWER = new Badge(
        "nice-answer", "Nice Answer", "Answer score of 10 or more",
        BadgeType.ANSWER_QUALITY, BadgeLevel.BRONZE
    );
    
    public static final Badge GURU = new Badge(
        "guru", "Guru", "Accepted answer with score of 40 or more",
        BadgeType.ANSWER_QUALITY, BadgeLevel.GOLD
    );
}

public class Bounty {
    private final String bountyId;
    private final int amount;
    private final LocalDateTime startedAt;
    private final LocalDateTime expiresAt;
    private final Member offeredBy;
    private final Question question;
    private Answer awardedTo;
    private BountyStatus status;
    
    public Bounty(String bountyId, int amount, Member offeredBy, Question question) {
        if (amount < 50) {
            throw new IllegalArgumentException("Minimum bounty is 50 reputation");
        }
        
        this.bountyId = bountyId;
        this.amount = amount;
        this.offeredBy = offeredBy;
        this.question = question;
        this.startedAt = LocalDateTime.now();
        this.expiresAt = startedAt.plusDays(7);
        this.status = BountyStatus.ACTIVE;
        
        // Deduct reputation immediately
        offeredBy.loseReputation(amount, ReputationEventType.BOUNTY_OFFERED, bountyId);
    }
    
    public void award(Answer answer) {
        if (status != BountyStatus.ACTIVE) {
            throw new IllegalStateException("Bounty is not active");
        }
        
        this.awardedTo = answer;
        this.status = BountyStatus.AWARDED;
        
        // Grant reputation to answerer
        answer.getAuthor().gainReputation(amount, ReputationEventType.BOUNTY_AWARDED, bountyId);
    }
    
    public void expire() {
        if (status == BountyStatus.ACTIVE) {
            this.status = BountyStatus.EXPIRED;
            // Reputation is not refunded
        }
    }
    
    public BountyStatus getStatus() { return status; }
}

public class ReputationEvent {
    private final String eventId;
    private final Member member;
    private final int delta;
    private final ReputationEventType type;
    private final LocalDateTime occurredAt;
    private final String sourceId; // Question/Answer/Bounty ID
    
    public ReputationEvent(Member member, int delta, 
                          ReputationEventType type, String sourceId) {
        this.eventId = UUID.randomUUID().toString();
        this.member = member;
        this.delta = delta;
        this.type = type;
        this.sourceId = sourceId;
        this.occurredAt = LocalDateTime.now();
    }
}

Supporting Classes

public class Tag {
    private final String tagId;
    private final String name;
    private String description;
    private String wikiContent;
    private int dailyFrequency;
    private int weeklyFrequency;
    private int totalQuestions;
    private final LocalDateTime createdAt;
    
    public Tag(String tagId, String name, String description) {
        this.tagId = tagId;
        this.name = name;
        this.description = description;
        this.createdAt = LocalDateTime.now();
        this.dailyFrequency = 0;
        this.weeklyFrequency = 0;
        this.totalQuestions = 0;
    }
    
    public void incrementFrequency() {
        this.dailyFrequency++;
        this.weeklyFrequency++;
        this.totalQuestions++;
    }
    
    public String getName() { return name; }
}

public class Photo {
    private final String photoId;
    private final String url;
    private final String caption;
    private final long fileSize;
    private final LocalDateTime uploadedAt;
    private final Member uploader;
    
    public Photo(String photoId, String url, Member uploader) {
        this.photoId = photoId;
        this.url = url;
        this.uploader = uploader;
        this.caption = "";
        this.fileSize = 0;
        this.uploadedAt = LocalDateTime.now();
    }
    
    public void delete() {
        // Delete from storage
    }
}

public class Edit {
    private final String editId;
    private final Member editor;
    private final String oldContent;
    private final String newContent;
    private final String editSummary;
    private final LocalDateTime editedAt;
    
    public Edit(Member editor, String oldContent, String newContent, String editSummary) {
        this.editId = UUID.randomUUID().toString();
        this.editor = editor;
        this.oldContent = oldContent;
        this.newContent = newContent;
        this.editSummary = editSummary;
        this.editedAt = LocalDateTime.now();
    }
    
    public String getDiff() {
        // Return diff between old and new content
        return "Diff implementation";
    }
}

public class Vote {
    private final String voteId;
    private final Member voter;
    private final Post post;
    private final VoteType type;
    private final LocalDateTime votedAt;
    
    public Vote(Member voter, Post post, VoteType type) {
        this.voteId = UUID.randomUUID().toString();
        this.voter = voter;
        this.post = post;
        this.type = type;
        this.votedAt = LocalDateTime.now();
    }
}

public enum ModerationActionType {
    CLOSE_QUESTION, REOPEN_QUESTION, DELETE_POST, 
    UNDELETE_POST, LOCK_POST, UNLOCK_POST, MERGE_DUPLICATES
}

public class ModerationAction {
    private final String actionId;
    private final Moderator moderator;
    private final String targetId;
    private final ModerationActionType actionType;
    private final String reason;
    private final LocalDateTime performedAt;
    
    public ModerationAction(Moderator moderator, String targetId,
                           ModerationActionType actionType, String reason) {
        this.actionId = UUID.randomUUID().toString();
        this.moderator = moderator;
        this.targetId = targetId;
        this.actionType = actionType;
        this.reason = reason;
        this.performedAt = LocalDateTime.now();
    }
}

This Java implementation demonstrates:

  • Strategy Pattern: Privilege checking system
  • Template Method: Post interface with polymorphic behavior
  • State Pattern: Question status lifecycle
  • Observer Pattern: Reputation events and notifications
  • SOLID Principles: Single responsibility, open-closed, dependency inversion

6. Python Implementation

Below is a comprehensive Python implementation with type hints, dataclasses, and Pythonic patterns.

from enum import Enum, auto
from typing import List, Dict, Optional, Protocol, Set
from dataclasses import dataclass, field
from abc import ABC, abstractmethod
from datetime import datetime, timedelta, date
import uuid
from threading import Lock

# =====================
# Enumerations
# =====================

class AccountStatus(Enum):
    ACTIVE = auto()
    SUSPENDED = auto()
    BLOCKED = auto()
    DELETED = auto()

class QuestionStatus(Enum):
    OPEN = auto()
    CLOSED = auto()
    ON_HOLD = auto()
    DELETED = auto()
    LOCKED = auto()

class CloseReason(Enum):
    DUPLICATE = ("This question has been asked before",)
    OFF_TOPIC = ("This question doesn't appear to be about programming",)
    TOO_BROAD = ("This question is too broad to answer",)
    PRIMARILY_OPINION_BASED = ("This question is likely to solicit opinion",)
    UNCLEAR = ("This question is unclear or not useful",)
    NOT_REPRODUCIBLE = ("Unable to reproduce the problem",)
    
    def __init__(self, description: str):
        self.description = description

class VoteType(Enum):
    UPVOTE = 1
    DOWNVOTE = -1
    
    @property
    def value_delta(self) -> int:
        return self.value

class BountyStatus(Enum):
    ACTIVE = auto()
    AWARDED = auto()
    EXPIRED = auto()
    CANCELED = auto()

class BadgeLevel(Enum):
    BRONZE = 1
    SILVER = 2
    GOLD = 3

class BadgeType(Enum):
    TAG_BASED = auto()
    PARTICIPATION = auto()
    MODERATION = auto()
    QUESTION_QUALITY = auto()
    ANSWER_QUALITY = auto()

class ReputationEventType(Enum):
    """Reputation event types with author and voter deltas."""
    UPVOTE_QUESTION = (10, 0)
    UPVOTE_ANSWER = (10, 0)
    DOWNVOTE_QUESTION = (-2, -1)
    DOWNVOTE_ANSWER = (-2, -1)
    ACCEPTED_ANSWER = (15, 0)
    ACCEPT_ANSWER = (2, 0)
    BOUNTY_AWARDED = (0, 0)  # Variable
    BOUNTY_OFFERED = (0, 0)   # Variable
    PENALTY_SPAM = (-100, 0)
    
    def __init__(self, author_delta: int, voter_delta: int):
        self.author_delta = author_delta
        self.voter_delta = voter_delta

class FlagReason(Enum):
    SPAM = auto()
    OFFENSIVE = auto()
    LOW_QUALITY = auto()
    DUPLICATE = auto()
    NEEDS_MODERATOR_ATTENTION = auto()

class FlagStatus(Enum):
    PENDING = auto()
    HELPFUL = auto()
    DECLINED = auto()
    DISPUTED = auto()

class NotificationType(Enum):
    ANSWER_POSTED = auto()
    COMMENT_REPLY = auto()
    BADGE_AWARDED = auto()
    BOUNTY_EXPIRING = auto()
    QUESTION_CLOSED = auto()
    EDIT_SUGGESTED = auto()
    MENTION = auto()

class ModerationActionType(Enum):
    CLOSE_QUESTION = auto()
    REOPEN_QUESTION = auto()
    DELETE_POST = auto()
    UNDELETE_POST = auto()
    LOCK_POST = auto()
    UNLOCK_POST = auto()
    MERGE_DUPLICATES = auto()

# =====================
# Value Objects & DTOs
# =====================

@dataclass(frozen=True)
class Privilege:
    """Privilege with reputation requirement."""
    name: str
    required_reputation: int
    description: str
    
    def check(self, member_reputation: int) -> bool:
        """Check if member has sufficient reputation."""
        return member_reputation >= self.required_reputation

# Common privileges as constants
PRIVILEGE_UPVOTE = Privilege("Upvote", 15, "Vote up questions and answers")
PRIVILEGE_DOWNVOTE = Privilege("Downvote", 125, "Vote down questions and answers")
PRIVILEGE_COMMENT = Privilege("Comment", 50, "Leave comments on any post")
PRIVILEGE_CREATE_TAG = Privilege("Create Tag", 1500, "Create new tags")
PRIVILEGE_VOTE_TO_CLOSE = Privilege("Vote to Close", 3000, "Vote to close questions")
PRIVILEGE_DELETE_VOTE = Privilege("Delete Vote", 10000, "Vote to delete questions")

@dataclass
class NotificationSettings:
    """User notification preferences."""
    email_on_answer: bool = True
    email_on_comment: bool = True
    email_on_badge: bool = True
    digest_frequency: str = "daily"  # daily, weekly, real-time, never
    
    def update(self, **kwargs) -> None:
        for key, value in kwargs.items():
            if hasattr(self, key):
                setattr(self, key, value)

# =====================
# User Management
# =====================

class Account(ABC):
    """Base account with authentication."""
    
    def __init__(self, account_id: str, email: str, password_hash: str, name: str):
        self.account_id = account_id
        self.email = email
        self.password_hash = password_hash
        self.name = name
        self.location: Optional[str] = None
        self.bio: Optional[str] = None
        self.status = AccountStatus.ACTIVE
        self.created_at = datetime.now()
        self.last_login_at: Optional[datetime] = None
    
    def authenticate(self, password: str) -> bool:
        """Verify password."""
        return self.password_hash == self._hash_password(password)
    
    def _hash_password(self, password: str) -> str:
        """Hash password (use bcrypt in production)."""
        return password  # Simplified
    
    def reset_password(self, new_password: str) -> None:
        """Reset password."""
        self.password_hash = self._hash_password(new_password)
    
    def suspend(self, reason: str) -> None:
        """Suspend account."""
        self.status = AccountStatus.SUSPENDED


class Member(Account):
    """Registered member with reputation and privileges."""
    
    def __init__(self, account_id: str, email: str, password_hash: str, 
                 name: str, member_id: str):
        super().__init__(account_id, email, password_hash, name)
        self.member_id = member_id
        self.reputation = 1  # Starting reputation
        self.member_since = date.today()
        self.badges: List['Badge'] = []
        self.votes: List['Vote'] = []
        self.reputation_history: List['ReputationEvent'] = []
        self.notification_settings = NotificationSettings()
        self._reputation_lock = Lock()
    
    def has_privilege(self, privilege: Privilege) -> bool:
        """Check if member has required privilege."""
        return privilege.check(self.reputation)
    
    def gain_reputation(self, amount: int, event_type: ReputationEventType, 
                       source_id: str) -> None:
        """Gain reputation points."""
        with self._reputation_lock:
            self.reputation += amount
            event = ReputationEvent(self, amount, event_type, source_id)
            self.reputation_history.append(event)
    
    def lose_reputation(self, amount: int, event_type: ReputationEventType,
                       source_id: str) -> None:
        """Lose reputation points (minimum 1)."""
        with self._reputation_lock:
            self.reputation = max(1, self.reputation - amount)
            event = ReputationEvent(self, -amount, event_type, source_id)
            self.reputation_history.append(event)
    
    def award_badge(self, badge: 'Badge') -> None:
        """Award badge to member."""
        if badge not in self.badges:
            self.badges.append(badge)


class Moderator(Member):
    """Moderator with additional privileges."""
    
    def __init__(self, account_id: str, email: str, password_hash: str,
                 name: str, member_id: str):
        super().__init__(account_id, email, password_hash, name, member_id)
        self.elected_at = date.today()
        self.actions: List['ModerationAction'] = []
    
    def close_question(self, question: 'Question', reason: CloseReason) -> None:
        """Close question with reason."""
        question.close(reason, self)
        self._log_action(ModerationAction(
            self, question.question_id, ModerationActionType.CLOSE_QUESTION,
            reason.description
        ))
    
    def reopen_question(self, question: 'Question') -> None:
        """Reopen closed question."""
        question.reopen(self)
        self._log_action(ModerationAction(
            self, question.question_id, ModerationActionType.REOPEN_QUESTION,
            "Reopened by moderator"
        ))
    
    def delete_post(self, post: 'Post') -> None:
        """Delete post."""
        post.delete(self)
        self._log_action(ModerationAction(
            self, post.post_id, ModerationActionType.DELETE_POST,
            "Deleted by moderator"
        ))
    
    def _log_action(self, action: 'ModerationAction') -> None:
        """Log moderation action."""
        self.actions.append(action)


class Admin(Member):
    """Administrator with full system control."""
    
    def __init__(self, account_id: str, email: str, password_hash: str,
                 name: str, member_id: str):
        super().__init__(account_id, email, password_hash, name, member_id)
        self.permissions: Set[str] = {
            "SUSPEND_ACCOUNT",
            "DESTROY_ACCOUNT",
            "MANAGE_PRIVILEGES",
            "VIEW_AUDIT_LOGS"
        }
    
    def suspend_account(self, account: Account, duration: timedelta, 
                       reason: str) -> None:
        """Suspend account for duration."""
        if "SUSPEND_ACCOUNT" in self.permissions:
            account.suspend(reason)
    
    def destroy_spam_account(self, account: Account) -> None:
        """Permanently destroy spam account."""
        if "DESTROY_ACCOUNT" in self.permissions:
            account.status = AccountStatus.DELETED


# =====================
# Content Models
# =====================

class Post(Protocol):
    """Protocol for votable, flaggable content."""
    
    @property
    def post_id(self) -> str: ...
    
    @property
    def author(self) -> Member: ...
    
    @property
    def vote_count(self) -> int: ...
    
    def vote(self, voter: Member, vote_type: VoteType) -> None: ...
    
    def flag(self, flagger: Member, reason: FlagReason) -> None: ...
    
    def delete(self, moderator: Moderator) -> None: ...


class Question:
    """Question with answers, comments, tags."""
    
    def __init__(self, question_id: str, title: str, body: str, author: Member):
        self.question_id = question_id
        self.title = title
        self.body = body
        self.author = author
        self.status = QuestionStatus.OPEN
        self.close_reason: Optional[CloseReason] = None
        self.created_at = datetime.now()
        self.updated_at = datetime.now()
        self.closed_at: Optional[datetime] = None
        self.view_count = 0
        self._vote_count = 0
        self._vote_lock = Lock()
        self.tags: List['Tag'] = []
        self.answers: List['Answer'] = []
        self.comments: List['Comment'] = []
        self.photos: List['Photo'] = []
        self.bounty: Optional['Bounty'] = None
        self.edit_history: List['Edit'] = []
    
    @property
    def post_id(self) -> str:
        return self.question_id
    
    @property
    def vote_count(self) -> int:
        return self._vote_count
    
    def add_answer(self, answer: 'Answer') -> None:
        """Add answer to question."""
        if self.status == QuestionStatus.OPEN:
            self.answers.append(answer)
        else:
            raise ValueError("Cannot add answer to non-open question")
    
    def add_comment(self, comment: 'Comment') -> None:
        """Add comment to question."""
        self.comments.append(comment)
    
    def add_tag(self, tag: 'Tag') -> None:
        """Add tag (max 5)."""
        if len(self.tags) < 5:
            self.tags.append(tag)
            tag.increment_frequency()
    
    def close(self, reason: CloseReason, moderator: Moderator) -> None:
        """Close question with reason."""
        self.status = QuestionStatus.CLOSED
        self.close_reason = reason
        self.closed_at = datetime.now()
    
    def reopen(self, moderator: Moderator) -> None:
        """Reopen closed question."""
        if self.status == QuestionStatus.CLOSED:
            self.status = QuestionStatus.OPEN
            self.closed_at = None
    
    def accept_answer(self, answer_id: str, acceptor: Member) -> bool:
        """Accept answer (only question owner)."""
        if acceptor != self.author:
            return False
        
        # Unaccept previous
        for answer in self.answers:
            if answer.is_accepted:
                answer.unaccept()
        
        # Accept new
        for answer in self.answers:
            if answer.answer_id == answer_id:
                answer.accept(self.bounty)
                return True
        
        return False
    
    def add_bounty(self, bounty: 'Bounty') -> None:
        """Add bounty to question."""
        if self.bounty and self.bounty.status == BountyStatus.ACTIVE:
            raise ValueError("Question already has active bounty")
        self.bounty = bounty
    
    def increment_views(self) -> None:
        """Increment view count."""
        self.view_count += 1
    
    def vote(self, voter: Member, vote_type: VoteType) -> None:
        """Register vote."""
        with self._vote_lock:
            self._vote_count += vote_type.value_delta
    
    def flag(self, flagger: Member, reason: FlagReason) -> None:
        """Flag for moderation."""
        pass  # Create Flag entity
    
    def delete(self, moderator: Moderator) -> None:
        """Delete question."""
        self.status = QuestionStatus.DELETED
    
    def calculate_score(self) -> int:
        """Calculate question score."""
        return self._vote_count


class Answer:
    """Answer to a question."""
    
    def __init__(self, answer_id: str, body: str, author: Member, 
                 question: Question):
        self.answer_id = answer_id
        self.body = body
        self.author = author
        self.question = question
        self.is_accepted = False
        self.accepted_at: Optional[datetime] = None
        self.created_at = datetime.now()
        self._vote_count = 0
        self._vote_lock = Lock()
        self.comments: List['Comment'] = []
        self.photos: List['Photo'] = []
        self.edit_history: List['Edit'] = []
    
    @property
    def post_id(self) -> str:
        return self.answer_id
    
    @property
    def vote_count(self) -> int:
        return self._vote_count
    
    def accept(self, bounty: Optional['Bounty'] = None) -> None:
        """Accept this answer."""
        self.is_accepted = True
        self.accepted_at = datetime.now()
        
        # Award reputation
        self.author.gain_reputation(
            15, ReputationEventType.ACCEPTED_ANSWER, self.answer_id
        )
        self.question.author.gain_reputation(
            2, ReputationEventType.ACCEPT_ANSWER, self.answer_id
        )
        
        # Award bounty if exists
        if bounty and bounty.status == BountyStatus.ACTIVE:
            bounty.award(self)
    
    def unaccept(self) -> None:
        """Unaccept answer."""
        if self.is_accepted:
            self.is_accepted = False
            self.accepted_at = None
            
            # Reverse reputation
            self.author.lose_reputation(
                15, ReputationEventType.ACCEPTED_ANSWER, self.answer_id
            )
            self.question.author.lose_reputation(
                2, ReputationEventType.ACCEPT_ANSWER, self.answer_id
            )
    
    def add_comment(self, comment: 'Comment') -> None:
        """Add comment to answer."""
        self.comments.append(comment)
    
    def vote(self, voter: Member, vote_type: VoteType) -> None:
        """Register vote."""
        with self._vote_lock:
            self._vote_count += vote_type.value_delta
    
    def flag(self, flagger: Member, reason: FlagReason) -> None:
        """Flag for moderation."""
        pass
    
    def delete(self, moderator: Moderator) -> None:
        """Delete answer."""
        pass
    
    def calculate_score(self) -> int:
        """Calculate answer score."""
        return self._vote_count


@dataclass
class Comment:
    """Comment on question or answer."""
    comment_id: str
    text: str
    author: Member
    parent: Post
    created_at: datetime = field(default_factory=datetime.now)
    vote_count: int = 0
    
    def upvote(self, voter: Member) -> None:
        """Upvote comment."""
        self.vote_count += 1


# =====================
# Gamification
# =====================

@dataclass
class Badge:
    """Achievement badge."""
    badge_id: str
    name: str
    description: str
    badge_type: BadgeType
    level: BadgeLevel
    icon_url: str = field(init=False)
    
    def __post_init__(self):
        self.icon_url = f"/badges/{self.badge_id}.png"
    
    def award(self, recipient: Member) -> None:
        """Award badge to member."""
        recipient.award_badge(self)

# Predefined badges
BADGE_NICE_ANSWER = Badge(
    "nice-answer", "Nice Answer", "Answer score of 10 or more",
    BadgeType.ANSWER_QUALITY, BadgeLevel.BRONZE
)

BADGE_GURU = Badge(
    "guru", "Guru", "Accepted answer with score of 40 or more",
    BadgeType.ANSWER_QUALITY, BadgeLevel.GOLD
)


class Bounty:
    """Reputation bounty on question."""
    
    def __init__(self, bounty_id: str, amount: int, offered_by: Member,
                 question: Question):
        if amount < 50:
            raise ValueError("Minimum bounty is 50 reputation")
        
        self.bounty_id = bounty_id
        self.amount = amount
        self.offered_by = offered_by
        self.question = question
        self.started_at = datetime.now()
        self.expires_at = self.started_at + timedelta(days=7)
        self.awarded_to: Optional[Answer] = None
        self.status = BountyStatus.ACTIVE
        
        # Deduct reputation immediately
        offered_by.lose_reputation(
            amount, ReputationEventType.BOUNTY_OFFERED, bounty_id
        )
    
    def award(self, answer: Answer) -> None:
        """Award bounty to answer."""
        if self.status != BountyStatus.ACTIVE:
            raise ValueError("Bounty is not active")
        
        self.awarded_to = answer
        self.status = BountyStatus.AWARDED
        
        # Grant reputation
        answer.author.gain_reputation(
            self.amount, ReputationEventType.BOUNTY_AWARDED, self.bounty_id
        )
    
    def expire(self) -> None:
        """Expire bounty (no refund)."""
        if self.status == BountyStatus.ACTIVE:
            self.status = BountyStatus.EXPIRED


@dataclass
class ReputationEvent:
    """Reputation change event."""
    event_id: str = field(default_factory=lambda: str(uuid.uuid4()))
    member: Member = field(repr=False)
    delta: int
    event_type: ReputationEventType
    source_id: str
    occurred_at: datetime = field(default_factory=datetime.now)


# =====================
# Supporting Classes
# =====================

class Tag:
    """Question tag."""
    
    def __init__(self, tag_id: str, name: str, description: str):
        self.tag_id = tag_id
        self.name = name
        self.description = description
        self.wiki_content = ""
        self.daily_frequency = 0
        self.weekly_frequency = 0
        self.total_questions = 0
        self.created_at = datetime.now()
    
    def increment_frequency(self) -> None:
        """Increment usage frequency."""
        self.daily_frequency += 1
        self.weekly_frequency += 1
        self.total_questions += 1


@dataclass
class Photo:
    """Image attachment."""
    photo_id: str
    url: str
    uploader: Member
    caption: str = ""
    file_size: int = 0
    uploaded_at: datetime = field(default_factory=datetime.now)
    
    def delete(self) -> None:
        """Delete photo from storage."""
        pass


@dataclass
class Edit:
    """Edit history record."""
    edit_id: str
    editor: Member
    old_content: str
    new_content: str
    edit_summary: str
    edited_at: datetime = field(default_factory=datetime.now)
    
    def get_diff(self) -> str:
        """Get diff between old and new."""
        return "Diff implementation"


@dataclass
class Vote:
    """Vote on post."""
    vote_id: str
    voter: Member
    post: Post
    vote_type: VoteType
    voted_at: datetime = field(default_factory=datetime.now)


@dataclass
class ModerationAction:
    """Moderation action log."""
    action_id: str = field(default_factory=lambda: str(uuid.uuid4()))
    moderator: Moderator
    target_id: str
    action_type: ModerationActionType
    reason: str
    performed_at: datetime = field(default_factory=datetime.now)

This Python implementation demonstrates:

  • Type Hints: Full type annotations for IDE support and type checking
  • Dataclasses: Reduced boilerplate for value objects
  • Protocols: Structural subtyping for Post interface
  • Enums: Type-safe constants with additional properties
  • Thread Safety: Lock-based synchronization for vote counts and reputation
  • Pythonic Patterns: Properties, context managers, clean interfaces

7. Key Design Decisions

1. Reputation-Based Privilege System (Strategy Pattern)

Decision: Use Strategy pattern for privilege checking rather than hardcoded if-statements.

Rationale: Stack Overflow has ~50 different privileges tied to reputation thresholds. Hardcoding checks (if reputation >= 15 for upvote, >= 125 for downvote, etc.) leads to duplicated logic and difficult maintenance when thresholds change.

Implementation:

@dataclass(frozen=True)
class Privilege:
    name: str
    required_reputation: int
    description: str
    
    def check(self, member_reputation: int) -> bool:
        return member_reputation >= self.required_reputation

# Predefined privileges
PRIVILEGE_UPVOTE = Privilege("Upvote", 15, "Vote up questions and answers")
PRIVILEGE_DOWNVOTE = Privilege("Downvote", 125, "Vote down questions and answers")

# Usage
if member.has_privilege(PRIVILEGE_UPVOTE):
    member.upvote(question)

Benefits: Centralized privilege definitions, easy to add new privileges, testable in isolation, privilege thresholds can be configured per site (Stack Overflow vs. Math Stack Exchange).

2. Atomic Vote Counting with Thread Safety

Decision: Use AtomicInteger in Java and Lock in Python for vote counts to prevent race conditions.

Rationale: Multiple users can vote on the same post simultaneously. Without synchronization, vote count updates could be lost (classic read-modify-write race condition). Using database-level locking would hurt performance at scale.

Implementation:

public class Question {
    private final AtomicInteger voteCount = new AtomicInteger(0);
    
    public void vote(Member voter, VoteType type) {
        voteCount.addAndGet(type.getValue());  // Atomic increment/decrement
    }
}

Benefits: Thread-safe without database locks, high concurrency, eventual consistency acceptable for vote counts (non-critical data).

3. Immutable Bounty Deduction (Event Sourcing)

Decision: Deduct bounty reputation immediately upon creation and never refund, even if bounty expires.

Rationale: Prevents gaming the system (posting bounty, getting attention, canceling before expiry). Matches Stack Overflow's actual policy: "Bounties are non-refundable."

Implementation:

class Bounty:
    def __init__(self, amount: int, offered_by: Member, question: Question):
        # Deduct reputation immediately
        offered_by.lose_reputation(amount, ReputationEventType.BOUNTY_OFFERED, bounty_id)
        
    def expire(self) -> None:
        # No refund
        self.status = BountyStatus.EXPIRED

Benefits: Incentivizes quality questions (users won't waste reputation), prevents abuse, simple auditing.

4. Single Answer Acceptance with Reversal

Decision: Allow only one accepted answer per question, with ability to change acceptance (reversing previous reputation).

Rationale: Accepted answer indicates "this solved my problem" - having multiple defeats the purpose. Allowing change accommodates better answers posted later.

Implementation:

public boolean acceptAnswer(String answerId, Member acceptor) {
    if (!acceptor.equals(author)) return false;
    
    // Unaccept previous
    answers.stream()
           .filter(Answer::isAccepted)
           .forEach(a -> a.unaccept());  // Reverses reputation
    
    // Accept new
    answers.stream()
           .filter(a -> a.getAnswerId().equals(answerId))
           .findFirst()
           .ifPresent(Answer::accept);   // Grants reputation
    
    return true;
}

Benefits: Clear "solution" indicator, reputation accuracy, prevents multiple acceptances.

5. Tag Frequency Tracking with Dual Metrics

Decision: Track both daily and weekly tag frequencies separately, reset on schedule.

Rationale: Daily frequency identifies trending technologies (e.g., new framework release causes spike). Weekly frequency smooths noise for stable trends.

Implementation:

class Tag:
    def __init__(self, name: str):
        self.daily_frequency = 0   # Reset daily
        self.weekly_frequency = 0  # Reset weekly
        self.total_questions = 0   # Never reset
    
    def increment_frequency(self) -> None:
        self.daily_frequency += 1
        self.weekly_frequency += 1
        self.total_questions += 1

# Scheduled job
def reset_daily_frequencies():
    for tag in all_tags:
        tag.daily_frequency = 0

Benefits: Detects trends quickly (daily), provides stable view (weekly), historical data (total).

6. Close Reason Enumeration with Descriptions

Decision: Model close reasons as enum with embedded descriptions rather than freeform text.

Rationale: Standardized close reasons improve categorization for analytics, provide consistent user messaging, prevent arbitrary moderator text.

Implementation:

public enum CloseReason {
    DUPLICATE("This question has been asked before"),
    OFF_TOPIC("This question doesn't appear to be about programming"),
    TOO_BROAD("This question is too broad to answer");
    
    private final String description;
    
    CloseReason(String description) {
        this.description = description;
    }
}

Benefits: Standardized moderation, analytics on close reason distribution, localizable descriptions.

7. Edit History with Diff Tracking

Decision: Store complete edit history with old/new content for every post edit.

Rationale: Transparency requirement - users should see what changed. Anti-vandalism - rollback to any previous version. Regulatory compliance in some jurisdictions.

Implementation:

@dataclass
class Edit:
    edit_id: str
    editor: Member
    old_content: str
    new_content: str
    edit_summary: str
    edited_at: datetime
    
    def get_diff(self) -> str:
        # Return line-by-line diff
        return diff_algorithm(self.old_content, self.new_content)

class Question:
    def edit(self, editor: Member, new_body: str, summary: str) -> None:
        edit = Edit(uuid4(), editor, self.body, new_body, summary)
        self.edit_history.append(edit)
        self.body = new_body

Benefits: Full audit trail, vandalism prevention, community trust, rollback capability.

8. Moderation Action Logging

Decision: Log all moderator actions (close, delete, lock) with moderator ID, target, reason, timestamp.

Rationale: Accountability for moderators, audit trail for admins, dispute resolution ("Why was my question closed?"), analytics on moderation patterns.

Implementation:

public class Moderator extends Member {
    private final List<ModerationAction> actions = new ArrayList<>();
    
    public void closeQuestion(Question question, CloseReason reason) {
        question.close(reason, this);
        logAction(new ModerationAction(
            this, 
            question.getQuestionId(),
            ModerationActionType.CLOSE_QUESTION,
            reason.getDescription()
        ));
    }
}

Benefits: Moderator accountability, dispute resolution data, abuse detection.

9. Badge Award Automation with Rule Engine

Decision: Decouple badge award logic from core domain models using rule engine pattern.

Rationale: Badge rules are complex and change frequently (e.g., "Nice Answer" requires answer score β‰₯ 10). Embedding logic in Answer class violates Single Responsibility Principle.

Implementation:

class BadgeRule(ABC):
    @abstractmethod
    def evaluate(self, context: Dict) -> Optional[Badge]:
        pass

class NiceAnswerRule(BadgeRule):
    def evaluate(self, context: Dict) -> Optional[Badge]:
        answer = context.get('answer')
        if answer and answer.calculate_score() >= 10:
            return BADGE_NICE_ANSWER
        return None

class BadgeEngine:
    def __init__(self):
        self.rules = [NiceAnswerRule(), GuruRule(), ...]
    
    def check_badges(self, event: ReputationEvent) -> List[Badge]:
        context = {'answer': event.source}
        return [badge for rule in self.rules 
                if (badge := rule.evaluate(context))]

Benefits: Easy to add new badges, testable rules, separation of concerns, plugin architecture.

10. Daily Reputation Cap with Exclusions

Decision: Limit reputation gain from upvotes to +200 per day, but exclude accepted answers and bounties.

Rationale: Prevents reputation inflation from viral posts ("reached front page, got 1000 upvotes"). Excludes accepts/bounties to reward genuine problem-solving over popularity.

Implementation:

public class Member {
    private static final int DAILY_REP_CAP = 200;
    
    public void gainReputation(int amount, ReputationEventType type, String sourceId) {
        if (type == UPVOTE_QUESTION || type == UPVOTE_ANSWER) {
            int todayGained = calculateTodayGained();
            if (todayGained >= DAILY_REP_CAP) {
                // Log but don't award
                return;
            }
            amount = Math.min(amount, DAILY_REP_CAP - todayGained);
        }
        // No cap for ACCEPTED_ANSWER, BOUNTY_AWARDED
        this.reputation += amount;
    }
}

Benefits: Prevents reputation inflation, rewards quality over quantity, incentivizes helping over self-promotion.

Comments