OOD - Facebook
Problem Statement
You are tasked with designing the architecture for a large-scale social networking platform that connects billions of users worldwide. The platform must enable rich social interactions including profile management, bidirectional and asymmetric relationships (friends vs. followers), multimedia content sharing, real-time messaging, community building through groups and pages, and intelligent content distribution through personalized news feeds.
The system serves as the digital town square where individuals share life moments, businesses build audiences, communities organize around shared interests, and global conversations unfold. It must handle massive concurrent activity: millions of posts per hour, billions of feed impressions daily, real-time message delivery across continents, and instantaneous notifications for social interactions. The platform needs sophisticated content visibility controls through privacy settings and audience targeting, intelligent friend suggestions through graph analysis, and comprehensive search capabilities across people, content, and communities.
Critical architectural challenges include designing a scalable news feed algorithm that ranks and personalizes billions of content items, implementing efficient graph traversal for relationship queries (mutual friends, connection paths, community detection), maintaining low-latency message delivery in a distributed environment, ensuring content privacy while enabling viral distribution, and providing real-time notifications without overwhelming users. The system must also support moderation workflows, handle spam and abuse detection, manage multimedia storage and delivery, and provide analytics for user engagement patterns.
Requirements Analysis
Functional Requirements
-
User Identity and Profile Management:
- Register accounts with email/phone verification
- Create rich profiles with biographical information, work history, education, interests
- Upload and manage profile photos, cover photos, and multimedia albums
- Control profile visibility with granular privacy settings
- Manage account settings, security preferences, and session management
-
Social Graph and Relationships:
- Send, accept, reject, and cancel friend requests
- Maintain bidirectional friend connections
- Follow users asymmetrically (without mutual friendship)
- Unfriend or block users
- View mutual friends and connection paths
- Get intelligent friend suggestions based on network proximity
-
Content Creation and Sharing:
- Create text posts with rich formatting
- Attach photos, videos, and files to posts
- Tag friends and locations in posts
- Share external links with preview cards
- Define post visibility (Public, Friends, Custom lists, Only Me)
- Schedule posts for future publishing
- Edit and delete posts with version history
-
Social Interactions:
- Like, love, or react to posts and comments
- Comment on posts with nested replies (threading)
- Share posts to own timeline or via messaging
- Save posts for later viewing
- Report inappropriate content
- Hide posts from feed
-
Groups and Communities:
- Create public, closed, or secret groups
- Join groups with admin approval for closed groups
- Post content within groups
- Assign member roles (Admin, Moderator, Member)
- Manage group settings, rules, and membership
- Discover groups through recommendations
-
Pages and Public Figures:
- Create pages for businesses, celebrities, organizations
- Publish content as a page
- Gain followers (asymmetric relationship)
- Review and respond to page recommendations
- Manage page roles and permissions
- Access page analytics and insights
-
Messaging System:
- Send one-on-one messages
- Create group conversations
- Send multimedia messages (photos, videos, voice notes)
- Real-time delivery with read receipts
- Message search and archival
- Mute or delete conversations
-
News Feed and Content Discovery:
- Personalized feed ranking based on relevance and engagement
- Filter feed by content type (posts, photos, videos)
- "See First" priority for specific friends or pages
- Chronological vs. algorithmic feed options
- Trending topics and hashtags
-
Notifications:
- Real-time notifications for social interactions (likes, comments, shares, tags)
- Friend request and acceptance notifications
- New message alerts
- Group activity notifications
- Birthday reminders
- Notification preferences and muting
-
Search and Discovery:
- Search users by name, email, or phone
- Search posts by keywords or hashtags
- Find groups by name or topic
- Discover pages by category
- Search within conversations
- People You May Know suggestions
-
Privacy and Security:
- Create custom privacy lists (Close Friends, Acquaintances, Restricted)
- Control who sees posts, photos, friend list, and profile details
- Review tags before they appear on timeline
- Control who can send friend requests or messages
- Two-factor authentication
- Active session management
-
Moderation and Safety:
- Report content for violating community standards
- Admin tools to review reported content
- Suspend or ban accounts
- Content takedown workflows
- Appeal processes
Non-Functional Requirements
- Performance: News feed load time < 1 second; message delivery latency < 100ms; notification delivery < 500ms
- Scalability: Support 3 billion+ users; handle 500,000+ posts/second; deliver 10 billion+ feed impressions/day
- Availability: 99.99% uptime; graceful degradation during peak traffic
- Consistency: Strong consistency for friend relationships and messages; eventual consistency acceptable for feed updates
- Security: End-to-end encryption for messages; secure authentication; protection against CSRF, XSS, SQL injection
- Privacy: Compliance with GDPR, CCPA; user data export and deletion; transparency in data usage
- Reliability: Zero data loss for messages and posts; durable storage with replication
- Observability: Real-time metrics, logging, and alerting for system health
Use Case Diagram
graph TB subgraph Actors A1[👤 User] A2[👥 Group Admin] A3[📄 Page Manager] A4[👮 Content Moderator] A5[🖥️ System] end subgraph "Profile & Identity" UC1[📝 Create Profile] UC2[✏️ Edit Profile] UC3[🔐 Manage Privacy] UC4[📸 Upload Photos] end subgraph "Social Connections" UC5[🤝 Send Friend Request] UC6[✅ Accept/Reject Request] UC7[👁️ Follow User] UC8[🚫 Block User] UC9[💡 View Friend Suggestions] end subgraph "Content Creation" UC10[📰 Create Post] UC11[💬 Add Comment] UC12[❤️ React to Content] UC13[🔄 Share Post] UC14[🏷️ Tag Friends] end subgraph "Groups & Communities" UC15[➕ Create Group] UC16[🚪 Join Group] UC17[📢 Post in Group] UC18[⚙️ Manage Group Settings] end subgraph "Pages" UC19[📄 Create Page] UC20[📣 Publish as Page] UC21[⭐ Follow Page] UC22[💭 Add Page Review] end subgraph "Messaging" UC23[✉️ Send Message] UC24[👥 Create Group Chat] UC25[📎 Send Media] UC26[🔍 Search Messages] end subgraph "Feed & Discovery" UC27[📱 View News Feed] UC28[🔍 Search Content] UC29[🎯 Discover Pages/Groups] end subgraph "Notifications" UC30[🔔 Send Notification] UC31[🔕 Manage Preferences] end subgraph "Moderation" UC32[🚩 Report Content] UC33[🛡️ Review Reports] UC34[⛔ Suspend Account] end A1 --> UC1 A1 --> UC2 A1 --> UC3 A1 --> UC4 A1 --> UC5 A1 --> UC6 A1 --> UC7 A1 --> UC8 A1 --> UC9 A1 --> UC10 A1 --> UC11 A1 --> UC12 A1 --> UC13 A1 --> UC14 A1 --> UC27 A1 --> UC28 A1 --> UC29 A1 --> UC23 A1 --> UC32 A2 --> UC15 A2 --> UC16 A2 --> UC17 A2 --> UC18 A3 --> UC19 A3 --> UC20 A3 --> UC21 A3 --> UC22 A4 --> UC33 A4 --> UC34 A5 --> UC30 UC10 --> A5 UC11 --> A5 UC5 --> A5 UC23 --> A5 style UC1 fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style UC2 fill:#e1f5fe,stroke:#0288d1,stroke-width:2px style UC3 fill:#b3e5fc,stroke:#0277bd,stroke-width:2px style UC4 fill:#81d4fa,stroke:#01579b,stroke-width:2px style UC5 fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px style UC6 fill:#a5d6a7,stroke:#388e3c,stroke-width:2px style UC7 fill:#81c784,stroke:#43a047,stroke-width:2px style UC8 fill:#ffcdd2,stroke:#c62828,stroke-width:2px style UC9 fill:#fff9c4,stroke:#f9a825,stroke-width:2px style UC10 fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style UC11 fill:#e1bee7,stroke:#8e24aa,stroke-width:2px style UC12 fill:#ce93d8,stroke:#6a1b9a,stroke-width:2px style UC13 fill:#ba68c8,stroke:#4a148c,stroke-width:2px style UC14 fill:#ab47bc,stroke:#4a148c,stroke-width:2px style UC15 fill:#fff3e0,stroke:#ef6c00,stroke-width:2px style UC16 fill:#ffe0b2,stroke:#e65100,stroke-width:2px style UC17 fill:#ffcc80,stroke:#ef6c00,stroke-width:2px style UC18 fill:#ffb74d,stroke:#e65100,stroke-width:2px style UC19 fill:#e0f2f1,stroke:#00695c,stroke-width:2px style UC20 fill:#b2dfdb,stroke:#00796b,stroke-width:2px style UC21 fill:#80cbc4,stroke:#00897b,stroke-width:2px style UC22 fill:#4db6ac,stroke:#00695c,stroke-width:2px style UC23 fill:#f1f8e9,stroke:#558b2f,stroke-width:2px style UC24 fill:#dcedc8,stroke:#689f38,stroke-width:2px style UC25 fill:#c5e1a5,stroke:#7cb342,stroke-width:2px style UC26 fill:#aed581,stroke:#558b2f,stroke-width:2px style UC27 fill:#fce4ec,stroke:#c2185b,stroke-width:2px style UC28 fill:#f8bbd0,stroke:#ad1457,stroke-width:2px style UC29 fill:#f48fb1,stroke:#880e4f,stroke-width:2px style UC30 fill:#fff8e1,stroke:#f57f17,stroke-width:2px style UC31 fill:#ffecb3,stroke:#ff6f00,stroke-width:2px style UC32 fill:#ffebee,stroke:#b71c1c,stroke-width:2px style UC33 fill:#ef9a9a,stroke:#c62828,stroke-width:2px style UC34 fill:#e57373,stroke:#b71c1c,stroke-width:2px
Class Diagram
The design incorporates several key patterns:
- Strategy Pattern: Different feed ranking algorithms (Chronological, EdgeRank, Engagement-based)
- Observer Pattern: Real-time notifications for user activities
- State Pattern: Account states (Active, Suspended, Deactivated, Deleted)
- Factory Pattern: Creating different content types (TextPost, PhotoPost, VideoPost, LinkPost)
- Composite Pattern: Nested comment threads
- Facade Pattern: Unified search interface across multiple indexes
classDiagram %% Core Identity class UserAccount { <<abstract>> -UUID accountId -String email -String passwordHash -DateTime createdAt -AccountState state -SecuritySettings security +authenticate(password) +deactivate() +reactivate() +changePassword() } class AccountState { <<interface>> +handleLogin() +allowPosting() +transitionTo(AccountState) } class ActiveState { +handleLogin() +allowPosting() } class SuspendedState { +handleLogin() +allowPosting() } class DeactivatedState { +handleLogin() +allowPosting() } class DeletedState { +handleLogin() +allowPosting() } class RegularUser { -UserProfile profile -SocialGraph connections -List~Post~ timeline -List~Conversation~ messages -NotificationCenter notifications +createPost(content) +sendFriendRequest(user) +sendMessage(recipient, text) } class Administrator { -List~Permission~ permissions +reviewReport(reportId) +suspendAccount(userId) +deleteContent(contentId) } %% Profile class UserProfile { -PersonalInfo info -List~WorkExperience~ workHistory -List~Education~ educationHistory -List~MediaItem~ photos -PrivacySettings privacy -DateTime lastUpdated +updateBio(text) +addWorkExperience(work) +addEducation(edu) +setProfilePicture(photo) } class PersonalInfo { -String fullName -Date birthDate -Gender gender -String hometown -String currentCity -RelationshipStatus status } class WorkExperience { -String company -String position -String location -Date startDate -Date endDate -String description } class Education { -String institution -String degree -String fieldOfStudy -int graduationYear } class PrivacySettings { -VisibilityLevel profileVisibility -VisibilityLevel postsVisibility -VisibilityLevel friendListVisibility -List~PrivacyList~ customLists +updateSetting(key, value) +canView(viewer, resource) } class PrivacyList { -UUID listId -String name -List~RegularUser~ members +addMember(user) +removeMember(user) } %% Social Graph class SocialGraph { -List~Friendship~ friends -List~Following~ followings -List~FriendRequest~ pendingRequests -List~RegularUser~ blockedUsers +sendFriendRequest(user) +acceptRequest(requestId) +rejectRequest(requestId) +unfriend(user) +follow(user) +unfollow(user) +getMutualFriends(user) +getSuggestions() } class Friendship { -RegularUser user1 -RegularUser user2 -DateTime establishedAt -FriendshipStrength strength +calculateStrength() } class Following { -RegularUser follower -RegularUser followee -DateTime since -boolean notificationsEnabled } class FriendRequest { -UUID requestId -RegularUser sender -RegularUser recipient -RequestStatus status -DateTime sentAt +accept() +reject() +cancel() } class RequestStatus { <<enumeration>> PENDING ACCEPTED REJECTED CANCELLED } %% Content - Factory Pattern class ContentFactory { <<interface>> +createPost(type, data) } class PostFactory { +createPost(type, data) -createTextPost() -createPhotoPost() -createVideoPost() -createLinkPost() } class Post { <<abstract>> -UUID postId -RegularUser author -String content -DateTime createdAt -DateTime editedAt -VisibilityLevel visibility -List~Comment~ comments -List~Reaction~ reactions -int shareCount -List~RegularUser~ taggedUsers +edit(newContent) +delete() +addComment(comment) +react(user, reactionType) +share(user) } class TextPost { -String text -String formattedText } class PhotoPost { -List~Photo~ photos -String caption } class VideoPost { -Video video -String caption -String thumbnail } class LinkPost { -String url -LinkPreview preview } class Comment { -UUID commentId -RegularUser author -String text -DateTime createdAt -List~Comment~ replies -List~Reaction~ reactions +addReply(comment) +react(user, reactionType) +delete() } class Reaction { -RegularUser user -ReactionType type -DateTime timestamp } class ReactionType { <<enumeration>> LIKE LOVE HAHA WOW SAD ANGRY } %% Groups class Group { -UUID groupId -String name -String description -GroupType type -RegularUser creator -List~GroupMember~ members -List~Post~ posts -GroupSettings settings -DateTime createdAt +addMember(user, role) +removeMember(user) +createPost(post) +updateSettings(settings) } class GroupType { <<enumeration>> PUBLIC CLOSED SECRET } class GroupMember { -RegularUser user -GroupRole role -DateTime joinedAt +promoteToAdmin() +demote() } class GroupRole { <<enumeration>> MEMBER MODERATOR ADMIN } %% Pages class Page { -UUID pageId -String name -String description -PageCategory category -List~RegularUser~ admins -List~RegularUser~ followers -List~Post~ posts -List~PageReview~ reviews -PageAnalytics analytics +publishPost(post) +addFollower(user) +respondToReview(reviewId, response) } class PageReview { -UUID reviewId -RegularUser author -int rating -String text -DateTime createdAt -String adminResponse } class PageAnalytics { -int totalReach -int engagement -int newFollowers -Map~Date, Metrics~ dailyMetrics +getInsights(dateRange) } %% Messaging class Conversation { -UUID conversationId -List~RegularUser~ participants -List~Message~ messages -DateTime createdAt -DateTime lastActivity +sendMessage(message) +addParticipant(user) +removeParticipant(user) +markAsRead(user) } class Message { -UUID messageId -RegularUser sender -String content -DateTime sentAt -Map~RegularUser, DateTime~ readReceipts -List~MediaAttachment~ attachments +markAsRead(user) +delete() } class MediaAttachment { -UUID attachmentId -MediaType type -String url -int size } %% News Feed - Strategy Pattern class NewsFeed { -RegularUser user -FeedRankingStrategy rankingStrategy -List~Post~ cachedFeed -DateTime lastUpdated +refreshFeed() +setRankingStrategy(strategy) +getNextPage() } class FeedRankingStrategy { <<interface>> +rankPosts(posts, user) } class ChronologicalRanking { +rankPosts(posts, user) } class EdgeRankAlgorithm { +rankPosts(posts, user) -calculateAffinity(user, author) -calculateWeight(postType) -calculateTimeDecay(postAge) } class EngagementBasedRanking { +rankPosts(posts, user) -predictEngagement(post, user) } %% Notifications - Observer Pattern class NotificationCenter { -RegularUser user -List~Notification~ notifications -NotificationSettings settings +subscribe(eventType, handler) +unsubscribe(eventType) +sendNotification(notification) +markAsRead(notificationId) } class Notification { -UUID notificationId -NotificationType type -RegularUser recipient -RegularUser actor -NotificationContent content -DateTime createdAt -boolean read +markAsRead() } class NotificationType { <<enumeration>> FRIEND_REQUEST FRIEND_ACCEPTED POST_LIKED POST_COMMENTED POST_SHARED MENTIONED_IN_POST MENTIONED_IN_COMMENT MESSAGE_RECEIVED GROUP_INVITED BIRTHDAY_REMINDER } class NotificationPublisher { -List~NotificationObserver~ observers +subscribe(observer) +unsubscribe(observer) +notifyObservers(event) } class NotificationObserver { <<interface>> +onEvent(event) } class PushNotificationService { +onEvent(event) +sendPush(device, message) } class EmailNotificationService { +onEvent(event) +sendEmail(address, subject, body) } class InAppNotificationService { +onEvent(event) +deliverInApp(userId, notification) } %% Search - Facade Pattern class SearchFacade { -UserSearchIndex userIndex -PostSearchIndex postIndex -GroupSearchIndex groupIndex -PageSearchIndex pageIndex +search(query, filters) +searchUsers(query) +searchPosts(query) +searchGroups(query) +searchPages(query) } class SearchIndex { <<abstract>> #Map~String, Set~UUID~~ index +indexDocument(doc) +search(query) +removeDocument(docId) } class UserSearchIndex { +indexDocument(doc) +search(query) +searchByName(name) +searchByEmail(email) } class PostSearchIndex { +indexDocument(doc) +search(query) +searchByKeyword(keyword) +searchByHashtag(tag) } class GraphTraversal { +findShortestPath(user1, user2) +findMutualFriends(user1, user2) +suggestFriends(user, limit) +detectCommunities() } %% Moderation class ContentReport { -UUID reportId -RegularUser reporter -ReportableContent content -ReportReason reason -String details -ReportStatus status -Administrator assignedTo -DateTime createdAt +assign(admin) +resolve(action) } class ReportStatus { <<enumeration>> PENDING UNDER_REVIEW RESOLVED DISMISSED } class ModerationAction { -UUID actionId -Administrator moderator -ReportableContent content -ActionType actionType -String reason -DateTime executedAt +execute() +revert() } class ReportableContent { <<interface>> +getContentId() +getAuthor() +takedown() } %% Relationships UserAccount <|-- RegularUser UserAccount <|-- Administrator UserAccount --> AccountState AccountState <|.. ActiveState AccountState <|.. SuspendedState AccountState <|.. DeactivatedState AccountState <|.. DeletedState RegularUser *-- UserProfile RegularUser *-- SocialGraph RegularUser *-- NotificationCenter RegularUser *-- NewsFeed UserProfile --> PersonalInfo UserProfile *-- WorkExperience UserProfile *-- Education UserProfile --> PrivacySettings PrivacySettings *-- PrivacyList PrivacyList --> RegularUser SocialGraph *-- Friendship SocialGraph *-- Following SocialGraph *-- FriendRequest Friendship --> RegularUser Following --> RegularUser FriendRequest --> RegularUser FriendRequest --> RequestStatus ContentFactory <|.. PostFactory PostFactory ..> Post Post <|-- TextPost Post <|-- PhotoPost Post <|-- VideoPost Post <|-- LinkPost Post *-- Comment Post *-- Reaction Post --> RegularUser Comment *-- Comment Comment *-- Reaction Reaction --> ReactionType Group --> GroupType Group *-- GroupMember Group *-- Post GroupMember --> RegularUser GroupMember --> GroupRole Page *-- PageReview Page --> PageAnalytics Page *-- Post PageReview --> RegularUser Conversation *-- Message Conversation --> RegularUser Message --> RegularUser Message *-- MediaAttachment NewsFeed --> FeedRankingStrategy FeedRankingStrategy <|.. ChronologicalRanking FeedRankingStrategy <|.. EdgeRankAlgorithm FeedRankingStrategy <|.. EngagementBasedRanking NotificationCenter *-- Notification Notification --> NotificationType Notification --> RegularUser NotificationPublisher --> NotificationObserver NotificationObserver <|.. PushNotificationService NotificationObserver <|.. EmailNotificationService NotificationObserver <|.. InAppNotificationService SearchFacade --> UserSearchIndex SearchFacade --> PostSearchIndex SearchFacade --> GroupSearchIndex SearchFacade --> PageSearchIndex SearchIndex <|-- UserSearchIndex SearchIndex <|-- PostSearchIndex ContentReport --> ReportableContent ContentReport --> ReportStatus ContentReport --> RegularUser ContentReport --> Administrator ModerationAction --> Administrator ModerationAction --> ReportableContent Post ..|> ReportableContent Comment ..|> ReportableContent
Activity Diagrams
1. Friend Request and Connection Flow
This diagram shows the complete flow of sending, receiving, and processing friend requests, including validation, notification, and mutual friend discovery.
graph TD Start([User Initiates Friend Request]) --> CheckAuth{User Authenticated?} CheckAuth -->|No| AuthError[Return Authentication Error] CheckAuth -->|Yes| CheckSelf{Target is Self?} CheckSelf -->|Yes| SelfError[Return Cannot Friend Self Error] CheckSelf -->|No| CheckBlocked{Users Blocked Each Other?} CheckBlocked -->|Yes| BlockedError[Return Blocked Error] CheckBlocked -->|No| CheckExisting{Friendship Already Exists?} CheckExisting -->|Yes| AlreadyFriendsError[Return Already Friends Error] CheckExisting -->|No| CheckPending{Request Already Pending?} CheckPending -->|Yes| PendingError[Return Duplicate Request Error] CheckPending -->|No| CheckPrivacy{Target Accepts Requests?} CheckPrivacy -->|No| PrivacyError[Return Privacy Settings Block] CheckPrivacy -->|Yes| CreateRequest[Create FriendRequest Object] CreateRequest --> SetMetadata[Set Sender, Recipient, Timestamp, PENDING Status] SetMetadata --> PersistRequest[Persist Request to Database] PersistRequest --> NotifyRecipient[Publish Friend Request Event] NotifyRecipient --> CreateNotification[NotificationCenter Creates Notification] CreateNotification --> SendPush[Push Notification Sent] SendPush --> SendEmail[Email Notification Sent] SendEmail --> UpdateInApp[In-App Notification Updated] UpdateInApp --> WaitForResponse{Recipient Action} WaitForResponse -->|Accept| ValidateAccept{Request Still Pending?} ValidateAccept -->|No| ExpiredError[Return Request Expired Error] ValidateAccept -->|Yes| CreateFriendship[Create Friendship Object] CreateFriendship --> LinkUsers[Link user1 ↔ user2] LinkUsers --> SetTimestamp[Set establishedAt Timestamp] SetTimestamp --> UpdateStatus[Update Request Status to ACCEPTED] UpdateStatus --> AddToGraph1[Add to Sender's SocialGraph] AddToGraph1 --> AddToGraph2[Add to Recipient's SocialGraph] AddToGraph2 --> NotifyAcceptance[Notify Sender of Acceptance] NotifyAcceptance --> TriggerFeedUpdate[Trigger News Feed Update] TriggerFeedUpdate --> CalculateMutual[Calculate Mutual Friends] CalculateMutual --> UpdateSuggestions[Update Friend Suggestions for Both] UpdateSuggestions --> RecalculateStrength[Calculate Friendship Strength] RecalculateStrength --> Success1([Connection Established]) WaitForResponse -->|Reject| ValidateReject{Request Still Pending?} ValidateReject -->|No| ExpiredError2[Return Request Expired Error] ValidateReject -->|Yes| UpdateStatusRejected[Update Request Status to REJECTED] UpdateStatusRejected --> NotifyRejection[Optionally Notify Sender] NotifyRejection --> RemoveRequest[Archive Request] RemoveRequest --> Success2([Request Rejected]) WaitForResponse -->|Cancel| ValidateCancel{Sender Can Cancel?} ValidateCancel -->|No| CancelError[Return Permission Error] ValidateCancel -->|Yes| UpdateStatusCancelled[Update Request Status to CANCELLED] UpdateStatusCancelled --> RemoveNotification[Remove Recipient Notification] RemoveNotification --> Success3([Request Cancelled]) WaitForResponse -->|Ignore| Timeout{Request Expired?} Timeout -->|Yes| AutoArchive[Auto-Archive Request] AutoArchive --> Success4([Request Expired]) Timeout -->|No| KeepPending[Keep in Pending State] KeepPending --> WaitForResponse AuthError --> End([End]) SelfError --> End BlockedError --> End AlreadyFriendsError --> End PendingError --> End PrivacyError --> End ExpiredError --> End ExpiredError2 --> End CancelError --> End Success1 --> End Success2 --> End Success3 --> End Success4 --> End style Start fill:#4caf50,stroke:#2e7d32,stroke-width:3px,color:#fff style End fill:#f44336,stroke:#c62828,stroke-width:3px,color:#fff style CheckAuth fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CheckSelf fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CheckBlocked fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CheckExisting fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CheckPending fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CheckPrivacy fill:#fff9c4,stroke:#f9a825,stroke-width:2px style WaitForResponse fill:#e1bee7,stroke:#8e24aa,stroke-width:2px style ValidateAccept fill:#fff9c4,stroke:#f9a825,stroke-width:2px style ValidateReject fill:#fff9c4,stroke:#f9a825,stroke-width:2px style ValidateCancel fill:#fff9c4,stroke:#f9a825,stroke-width:2px style Timeout fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CreateFriendship fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px style NotifyRecipient fill:#bbdefb,stroke:#1976d2,stroke-width:2px style CalculateMutual fill:#b2dfdb,stroke:#00695c,stroke-width:2px style UpdateSuggestions fill:#b2dfdb,stroke:#00695c,stroke-width:2px style Success1 fill:#4caf50,stroke:#2e7d32,stroke-width:3px,color:#fff style Success2 fill:#ff9800,stroke:#e65100,stroke-width:3px,color:#fff style Success3 fill:#ff9800,stroke:#e65100,stroke-width:3px,color:#fff style Success4 fill:#9e9e9e,stroke:#424242,stroke-width:3px,color:#fff
2. News Feed Generation and Ranking
This diagram illustrates the personalized news feed generation process using the EdgeRank algorithm, including content aggregation, filtering, ranking, and caching.
graph TD Start([User Opens News Feed]) --> CheckCache{Feed Cache Valid?} CheckCache -->|Valid & Fresh| ServeCached[Serve Cached Feed] ServeCached --> End1([Display Feed]) CheckCache -->|Expired or Missing| LoadUserProfile[Load User Profile & Preferences] LoadUserProfile --> GetStrategy[Get Feed Ranking Strategy] GetStrategy --> CheckStrategyType{Strategy Type?} CheckStrategyType -->|Chronological| UseChronological[Use Chronological Ranking] CheckStrategyType -->|EdgeRank| UseEdgeRank[Use EdgeRank Algorithm] CheckStrategyType -->|Engagement-Based| UseEngagement[Use Engagement Prediction] UseChronological --> AggregateContent[Aggregate Content Sources] UseEdgeRank --> AggregateContent UseEngagement --> AggregateContent AggregateContent --> GetFriendPosts[Get Posts from Friends] GetFriendPosts --> GetFollowingPosts[Get Posts from Followed Users] GetFollowingPosts --> GetPagePosts[Get Posts from Followed Pages] GetPagePosts --> GetGroupPosts[Get Posts from Joined Groups] GetGroupPosts --> ApplyPrivacy[Apply Privacy Filters] ApplyPrivacy --> FilterBlocked[Filter Blocked Users] FilterBlocked --> FilterHidden[Filter Hidden Content] FilterHidden --> FilterReported[Filter Reported/Removed Content] FilterReported --> ContentPool[Candidate Content Pool] ContentPool --> CheckRankingStrategy{Which Strategy?} CheckRankingStrategy -->|Chronological| SortByTime[Sort by Timestamp DESC] SortByTime --> TakeTop100[Take Top 100 Posts] TakeTop100 --> CacheFeed[Cache Generated Feed] CheckRankingStrategy -->|EdgeRank| CalculateEdgeRank[Calculate EdgeRank Scores] CalculateEdgeRank --> ForEachPost{For Each Post} ForEachPost --> CalcAffinity[Calculate Affinity Score] CalcAffinity --> CountInteractions[Count Previous Interactions with Author] CountInteractions --> CheckMutualFriends[Check Mutual Friends] CheckMutualFriends --> CheckMessageHistory[Check Message History] CheckMessageHistory --> CheckProfileViews[Check Profile View Frequency] CheckProfileViews --> ComputeAffinity[Compute Affinity = f interactions, mutuals, messages] ComputeAffinity --> CalcWeight[Calculate Weight Score] CalcWeight --> IdentifyPostType{Post Type?} IdentifyPostType -->|Photo/Video| HighWeight[Weight = 1.0] IdentifyPostType -->|Link| MediumWeight[Weight = 0.7] IdentifyPostType -->|Text Only| LowWeight[Weight = 0.5] HighWeight --> CalcTimeDecay[Calculate Time Decay] MediumWeight --> CalcTimeDecay LowWeight --> CalcTimeDecay CalcTimeDecay --> GetPostAge[Get Post Age in Hours] GetPostAge --> ApplyDecayFunction[Apply Decay = e^-age/24] ApplyDecayFunction --> ComputeEdgeRank[EdgeRank = Affinity × Weight × TimeDecay] ComputeEdgeRank --> CheckMorePosts{More Posts?} CheckMorePosts -->|Yes| ForEachPost CheckMorePosts -->|No| SortByEdgeRank[Sort by EdgeRank Score DESC] SortByEdgeRank --> TakeTop100EdgeRank[Take Top 100 Posts] TakeTop100EdgeRank --> CacheFeed CheckRankingStrategy -->|Engagement| PredictEngagement[Predict Engagement Probability] PredictEngagement --> LoadMLModel[Load ML Engagement Model] LoadMLModel --> ExtractFeatures[Extract Features: Author, Type, Length, Media, Reactions] ExtractFeatures --> RunInference[Run Model Inference] RunInference --> SortByPrediction[Sort by Predicted Engagement DESC] SortByPrediction --> TakeTop100ML[Take Top 100 Posts] TakeTop100ML --> CacheFeed CacheFeed --> SetTTL[Set Cache TTL = 5 minutes] SetTTL --> PreloadMedia[Preload Media URLs] PreloadMedia --> MarkSeen[Mark Posts as Seen] MarkSeen --> LogImpression[Log Feed Impression Event] LogImpression --> ServeRankedFeed[Serve Ranked Feed to User] ServeRankedFeed --> UserScrolls{User Scrolls?} UserScrolls -->|Load More| Paginate[Fetch Next Page from Cache] Paginate --> UserScrolls UserScrolls -->|Refresh| InvalidateCache[Invalidate Cache] InvalidateCache --> Start UserScrolls -->|Close| End2([End]) End1 --> FinalEnd([End]) End2 --> FinalEnd style Start fill:#4caf50,stroke:#2e7d32,stroke-width:3px,color:#fff style FinalEnd fill:#f44336,stroke:#c62828,stroke-width:3px,color:#fff style End1 fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#fff style End2 fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#fff style CheckCache fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CheckStrategyType fill:#e1bee7,stroke:#8e24aa,stroke-width:2px style CheckRankingStrategy fill:#e1bee7,stroke:#8e24aa,stroke-width:2px style UserScrolls fill:#fff9c4,stroke:#f9a825,stroke-width:2px style UseEdgeRank fill:#bbdefb,stroke:#1976d2,stroke-width:2px style CalculateEdgeRank fill:#b2dfdb,stroke:#00695c,stroke-width:2px style ForEachPost fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CheckMorePosts fill:#fff9c4,stroke:#f9a825,stroke-width:2px style IdentifyPostType fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CalcAffinity fill:#ffe0b2,stroke:#ef6c00,stroke-width:2px style CalcWeight fill:#ffe0b2,stroke:#ef6c00,stroke-width:2px style CalcTimeDecay fill:#ffe0b2,stroke:#ef6c00,stroke-width:2px style ComputeEdgeRank fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px style CacheFeed fill:#ce93d8,stroke:#6a1b9a,stroke-width:2px
3. Real-Time Messaging with Delivery Confirmation
This diagram shows the end-to-end message delivery flow with real-time websocket notifications, read receipts, and offline message queuing.
graph TD Start([User Composes Message]) --> ValidateRecipient{Valid Recipient?} ValidateRecipient -->|No| RecipientError[Return Invalid Recipient Error] ValidateRecipient -->|Yes| CheckBlocked{Recipient Blocked Sender?} CheckBlocked -->|Yes| BlockedError[Return Blocked Error] CheckBlocked -->|No| GetConversation{Conversation Exists?} GetConversation -->|Yes| LoadConversation[Load Existing Conversation] GetConversation -->|No| CreateConversation[Create New Conversation] CreateConversation --> AddParticipants[Add Sender & Recipient as Participants] AddParticipants --> SetMetadata[Set Created Timestamp, Last Activity] SetMetadata --> PersistConversation[Persist Conversation to DB] PersistConversation --> LoadConversation LoadConversation --> CreateMessage[Create Message Object] CreateMessage --> SetMessageData[Set Sender, Content, Timestamp, UUID] SetMessageData --> CheckAttachments{Has Attachments?} CheckAttachments -->|Yes| ValidateAttachments{Attachments Valid?} ValidateAttachments -->|No| AttachmentError[Return Invalid Attachment Error] ValidateAttachments -->|Yes| UploadToStorage[Upload to Media Storage] UploadToStorage --> GenerateURLs[Generate CDN URLs] GenerateURLs --> AttachToMessage[Attach Media URLs to Message] CheckAttachments -->|No| AttachToMessage AttachToMessage --> PersistMessage[Persist Message to DB] PersistMessage --> AddToConversation[Add Message to Conversation.messages] AddToConversation --> UpdateLastActivity[Update Conversation.lastActivity] UpdateLastActivity --> IndexMessage[Index Message for Search] IndexMessage --> CheckRecipientStatus{Recipient Online?} CheckRecipientStatus -->|Yes| GetWebSocket[Get Recipient WebSocket Connection] GetWebSocket --> SendRealTime[Send Message via WebSocket] SendRealTime --> DeliveryAck{Delivery Acknowledged?} DeliveryAck -->|Yes| MarkDelivered[Mark Message as Delivered] MarkDelivered --> NotifyDelivery[Send Delivery Receipt to Sender] NotifyDelivery --> DisplayMessage[Display Message to Recipient] DisplayMessage --> WaitForRead{Message Viewed?} WaitForRead -->|Yes| MarkAsRead[Mark Message as Read] MarkAsRead --> RecordReadReceipt[Record ReadReceipt with Timestamp] RecordReadReceipt --> SendReadReceipt[Send Read Receipt to Sender] SendReadReceipt --> UpdateSenderUI[Update Sender UI with Double Check] UpdateSenderUI --> Success1([Message Delivered & Read]) WaitForRead -->|No| WaitTimeout{Timeout Reached?} WaitTimeout -->|No| WaitForRead WaitTimeout -->|Yes| Success2([Message Delivered but Unread]) DeliveryAck -->|No| RetryDelivery{Retry Count < 3?} RetryDelivery -->|Yes| WaitRetry[Wait 2 Seconds] WaitRetry --> SendRealTime RetryDelivery -->|No| QueueForOffline[Queue for Offline Delivery] CheckRecipientStatus -->|No| QueueForOffline QueueForOffline --> StoreInQueue[Store in Offline Message Queue] StoreInQueue --> CreatePushNotif[Create Push Notification] CreatePushNotif --> GetDeviceTokens[Get Recipient Device Tokens] GetDeviceTokens --> SendPush[Send Push Notification] SendPush --> CreateEmailNotif[Create Email Notification] CreateEmailNotif --> CheckEmailPrefs{Email Notifications Enabled?} CheckEmailPrefs -->|Yes| SendEmail[Send Email Notification] CheckEmailPrefs -->|No| SkipEmail[Skip Email] SendEmail --> WaitForOnline{Recipient Comes Online?} SkipEmail --> WaitForOnline WaitForOnline -->|Yes| DeliverQueued[Deliver Queued Messages] DeliverQueued --> GetWebSocket WaitForOnline -->|No| KeepInQueue{Queue Age < 30 Days?} KeepInQueue -->|Yes| WaitForOnline KeepInQueue -->|No| ArchiveMessage[Archive Old Message] ArchiveMessage --> Success3([Message Archived]) RecipientError --> End([End]) BlockedError --> End AttachmentError --> End Success1 --> End Success2 --> End Success3 --> End style Start fill:#4caf50,stroke:#2e7d32,stroke-width:3px,color:#fff style End fill:#f44336,stroke:#c62828,stroke-width:3px,color:#fff style ValidateRecipient fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CheckBlocked fill:#fff9c4,stroke:#f9a825,stroke-width:2px style GetConversation fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CheckAttachments fill:#fff9c4,stroke:#f9a825,stroke-width:2px style ValidateAttachments fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CheckRecipientStatus fill:#e1bee7,stroke:#8e24aa,stroke-width:2px style DeliveryAck fill:#fff9c4,stroke:#f9a825,stroke-width:2px style WaitForRead fill:#fff9c4,stroke:#f9a825,stroke-width:2px style WaitTimeout fill:#fff9c4,stroke:#f9a825,stroke-width:2px style RetryDelivery fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CheckEmailPrefs fill:#fff9c4,stroke:#f9a825,stroke-width:2px style WaitForOnline fill:#fff9c4,stroke:#f9a825,stroke-width:2px style KeepInQueue fill:#fff9c4,stroke:#f9a825,stroke-width:2px style CreateMessage fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px style SendRealTime fill:#bbdefb,stroke:#1976d2,stroke-width:2px style SendPush fill:#ffcc80,stroke:#ef6c00,stroke-width:2px style MarkAsRead fill:#b2dfdb,stroke:#00695c,stroke-width:2px style Success1 fill:#4caf50,stroke:#2e7d32,stroke-width:3px,color:#fff style Success2 fill:#ff9800,stroke:#e65100,stroke-width:3px,color:#fff style Success3 fill:#9e9e9e,stroke:#424242,stroke-width:3px,color:#fff
Implementation
Java Implementation
package com.socialnetwork.core;
import java.time.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;
/**
* Core domain value objects and enumerations
*/
enum AccountStatus {
ACTIVE, SUSPENDED, DEACTIVATED, DELETED
}
enum VisibilityLevel {
PUBLIC, FRIENDS, FRIENDS_OF_FRIENDS, CUSTOM, ONLY_ME
}
enum Gender {
MALE, FEMALE, NON_BINARY, PREFER_NOT_TO_SAY
}
enum RelationshipStatus {
SINGLE, IN_A_RELATIONSHIP, ENGAGED, MARRIED, COMPLICATED, DIVORCED, WIDOWED
}
enum RequestStatus {
PENDING, ACCEPTED, REJECTED, CANCELLED
}
enum ReactionType {
LIKE, LOVE, HAHA, WOW, SAD, ANGRY
}
enum GroupType {
PUBLIC, CLOSED, SECRET
}
enum GroupRole {
MEMBER, MODERATOR, ADMIN
}
enum PageCategory {
BUSINESS, CELEBRITY, COMMUNITY, ENTERTAINMENT, ORGANIZATION, BRAND, LOCAL_BUSINESS
}
enum MediaType {
PHOTO, VIDEO, AUDIO, DOCUMENT
}
enum NotificationType {
FRIEND_REQUEST, FRIEND_ACCEPTED, POST_LIKED, POST_COMMENTED, POST_SHARED,
MENTIONED_IN_POST, MENTIONED_IN_COMMENT, MESSAGE_RECEIVED,
GROUP_INVITED, BIRTHDAY_REMINDER
}
enum ReportReason {
SPAM, HARASSMENT, HATE_SPEECH, VIOLENCE, NUDITY, FALSE_INFORMATION, OTHER
}
enum ReportStatus {
PENDING, UNDER_REVIEW, RESOLVED, DISMISSED
}
enum ActionType {
WARN, REMOVE_CONTENT, SUSPEND_ACCOUNT, BAN_ACCOUNT, DISMISS
}
/**
* State Pattern: Account state management
*/
interface AccountState {
boolean handleLogin();
boolean allowPosting();
AccountState transitionTo(AccountStatus status);
}
class ActiveState implements AccountState {
@Override
public boolean handleLogin() {
return true;
}
@Override
public boolean allowPosting() {
return true;
}
@Override
public AccountState transitionTo(AccountStatus status) {
switch (status) {
case SUSPENDED: return new SuspendedState();
case DEACTIVATED: return new DeactivatedState();
case DELETED: return new DeletedState();
default: return this;
}
}
}
class SuspendedState implements AccountState {
@Override
public boolean handleLogin() {
throw new IllegalStateException("Account is suspended");
}
@Override
public boolean allowPosting() {
return false;
}
@Override
public AccountState transitionTo(AccountStatus status) {
if (status == AccountStatus.ACTIVE) {
return new ActiveState();
}
return this;
}
}
class DeactivatedState implements AccountState {
@Override
public boolean handleLogin() {
return true; // Can reactivate by logging in
}
@Override
public boolean allowPosting() {
return false;
}
@Override
public AccountState transitionTo(AccountStatus status) {
if (status == AccountStatus.ACTIVE) {
return new ActiveState();
}
return this;
}
}
class DeletedState implements AccountState {
@Override
public boolean handleLogin() {
throw new IllegalStateException("Account has been deleted");
}
@Override
public boolean allowPosting() {
return false;
}
@Override
public AccountState transitionTo(AccountStatus status) {
return this; // Cannot transition from deleted
}
}
/**
* Core identity and profile classes
*/
class SecuritySettings {
private boolean twoFactorEnabled;
private Set<String> trustedDevices;
private LocalDateTime lastPasswordChange;
public SecuritySettings() {
this.twoFactorEnabled = false;
this.trustedDevices = new HashSet<>();
this.lastPasswordChange = LocalDateTime.now();
}
public void enableTwoFactor() {
this.twoFactorEnabled = true;
}
public void addTrustedDevice(String deviceId) {
trustedDevices.add(deviceId);
}
}
abstract class UserAccount {
protected UUID accountId;
protected String email;
protected String passwordHash;
protected LocalDateTime createdAt;
protected AccountState state;
protected SecuritySettings security;
public UserAccount(String email, String password) {
this.accountId = UUID.randomUUID();
this.email = email;
this.passwordHash = hashPassword(password);
this.createdAt = LocalDateTime.now();
this.state = new ActiveState();
this.security = new SecuritySettings();
}
public boolean authenticate(String password) {
return state.handleLogin() &&
hashPassword(password).equals(passwordHash);
}
public void deactivate() {
this.state = state.transitionTo(AccountStatus.DEACTIVATED);
}
public void reactivate() {
this.state = state.transitionTo(AccountStatus.ACTIVE);
}
public void changePassword(String newPassword) {
this.passwordHash = hashPassword(newPassword);
this.security.lastPasswordChange = LocalDateTime.now();
}
private String hashPassword(String password) {
// In production: use BCrypt or Argon2
return Integer.toString(password.hashCode());
}
public UUID getAccountId() {
return accountId;
}
public String getEmail() {
return email;
}
}
class PersonalInfo {
private String fullName;
private LocalDate birthDate;
private Gender gender;
private String hometown;
private String currentCity;
private RelationshipStatus status;
public PersonalInfo(String fullName, LocalDate birthDate) {
this.fullName = fullName;
this.birthDate = birthDate;
}
public String getFullName() {
return fullName;
}
public int getAge() {
return Period.between(birthDate, LocalDate.now()).getYears();
}
}
class WorkExperience {
private String company;
private String position;
private String location;
private LocalDate startDate;
private LocalDate endDate;
private String description;
public WorkExperience(String company, String position, LocalDate startDate) {
this.company = company;
this.position = position;
this.startDate = startDate;
}
public void end(LocalDate endDate) {
this.endDate = endDate;
}
}
class Education {
private String institution;
private String degree;
private String fieldOfStudy;
private int graduationYear;
public Education(String institution, String degree, String field, int year) {
this.institution = institution;
this.degree = degree;
this.fieldOfStudy = field;
this.graduationYear = year;
}
}
class PrivacyList {
private UUID listId;
private String name;
private Set<RegularUser> members;
public PrivacyList(String name) {
this.listId = UUID.randomUUID();
this.name = name;
this.members = new HashSet<>();
}
public void addMember(RegularUser user) {
members.add(user);
}
public void removeMember(RegularUser user) {
members.remove(user);
}
public boolean contains(RegularUser user) {
return members.contains(user);
}
}
class PrivacySettings {
private VisibilityLevel profileVisibility;
private VisibilityLevel postsVisibility;
private VisibilityLevel friendListVisibility;
private Map<String, PrivacyList> customLists;
public PrivacySettings() {
this.profileVisibility = VisibilityLevel.FRIENDS;
this.postsVisibility = VisibilityLevel.FRIENDS;
this.friendListVisibility = VisibilityLevel.FRIENDS;
this.customLists = new HashMap<>();
// Default lists
customLists.put("close_friends", new PrivacyList("Close Friends"));
customLists.put("acquaintances", new PrivacyList("Acquaintances"));
customLists.put("restricted", new PrivacyList("Restricted"));
}
public void updateSetting(String key, VisibilityLevel value) {
switch (key) {
case "profile": profileVisibility = value; break;
case "posts": postsVisibility = value; break;
case "friends": friendListVisibility = value; break;
}
}
public boolean canView(RegularUser viewer, String resourceType) {
// Simplified visibility check
VisibilityLevel level = getVisibilityFor(resourceType);
switch (level) {
case PUBLIC: return true;
case ONLY_ME: return false;
case FRIENDS: // Would check if viewer is friend
case CUSTOM: // Would check custom lists
default: return false;
}
}
private VisibilityLevel getVisibilityFor(String resource) {
switch (resource) {
case "profile": return profileVisibility;
case "posts": return postsVisibility;
case "friends": return friendListVisibility;
default: return VisibilityLevel.FRIENDS;
}
}
}
class MediaItem {
private UUID itemId;
private String url;
private MediaType type;
private LocalDateTime uploadedAt;
public MediaItem(String url, MediaType type) {
this.itemId = UUID.randomUUID();
this.url = url;
this.type = type;
this.uploadedAt = LocalDateTime.now();
}
}
class UserProfile {
private PersonalInfo info;
private List<WorkExperience> workHistory;
private List<Education> educationHistory;
private List<MediaItem> photos;
private PrivacySettings privacy;
private LocalDateTime lastUpdated;
public UserProfile(PersonalInfo info) {
this.info = info;
this.workHistory = new ArrayList<>();
this.educationHistory = new ArrayList<>();
this.photos = new ArrayList<>();
this.privacy = new PrivacySettings();
this.lastUpdated = LocalDateTime.now();
}
public void updateBio(String text) {
// Bio update logic
this.lastUpdated = LocalDateTime.now();
}
public void addWorkExperience(WorkExperience work) {
workHistory.add(work);
this.lastUpdated = LocalDateTime.now();
}
public void addEducation(Education edu) {
educationHistory.add(edu);
this.lastUpdated = LocalDateTime.now();
}
public void setProfilePicture(MediaItem photo) {
photos.add(0, photo);
this.lastUpdated = LocalDateTime.now();
}
public PersonalInfo getInfo() {
return info;
}
}
/**
* Social graph relationships
*/
enum FriendshipStrength {
WEAK, MODERATE, STRONG
}
class Friendship {
private RegularUser user1;
private RegularUser user2;
private LocalDateTime establishedAt;
private FriendshipStrength strength;
public Friendship(RegularUser u1, RegularUser u2) {
this.user1 = u1;
this.user2 = u2;
this.establishedAt = LocalDateTime.now();
this.strength = calculateStrength();
}
public FriendshipStrength calculateStrength() {
// Simplified: would analyze interaction frequency, messages, etc.
return FriendshipStrength.MODERATE;
}
public RegularUser getOtherUser(RegularUser user) {
return user.equals(user1) ? user2 : user1;
}
}
class Following {
private RegularUser follower;
private RegularUser followee;
private LocalDateTime since;
private boolean notificationsEnabled;
public Following(RegularUser follower, RegularUser followee) {
this.follower = follower;
this.followee = followee;
this.since = LocalDateTime.now();
this.notificationsEnabled = true;
}
}
class FriendRequest {
private UUID requestId;
private RegularUser sender;
private RegularUser recipient;
private RequestStatus status;
private LocalDateTime sentAt;
public FriendRequest(RegularUser sender, RegularUser recipient) {
this.requestId = UUID.randomUUID();
this.sender = sender;
this.recipient = recipient;
this.status = RequestStatus.PENDING;
this.sentAt = LocalDateTime.now();
}
public void accept() {
if (status != RequestStatus.PENDING) {
throw new IllegalStateException("Request not pending");
}
this.status = RequestStatus.ACCEPTED;
}
public void reject() {
if (status != RequestStatus.PENDING) {
throw new IllegalStateException("Request not pending");
}
this.status = RequestStatus.REJECTED;
}
public void cancel() {
if (status != RequestStatus.PENDING) {
throw new IllegalStateException("Request not pending");
}
this.status = RequestStatus.CANCELLED;
}
public RequestStatus getStatus() {
return status;
}
public RegularUser getSender() {
return sender;
}
public RegularUser getRecipient() {
return recipient;
}
}
class SocialGraph {
private List<Friendship> friends;
private List<Following> followings;
private List<FriendRequest> pendingRequests;
private Set<RegularUser> blockedUsers;
public SocialGraph() {
this.friends = new ArrayList<>();
this.followings = new ArrayList<>();
this.pendingRequests = new ArrayList<>();
this.blockedUsers = new HashSet<>();
}
public void sendFriendRequest(RegularUser user, RegularUser target) {
if (blockedUsers.contains(target)) {
throw new IllegalArgumentException("Cannot send request to blocked user");
}
FriendRequest request = new FriendRequest(user, target);
pendingRequests.add(request);
}
public void acceptRequest(UUID requestId) {
FriendRequest request = findRequest(requestId);
request.accept();
// Create friendship
Friendship friendship = new Friendship(request.getSender(), request.getRecipient());
friends.add(friendship);
// Remove from pending
pendingRequests.remove(request);
}
public void rejectRequest(UUID requestId) {
FriendRequest request = findRequest(requestId);
request.reject();
pendingRequests.remove(request);
}
public void unfriend(RegularUser user) {
friends.removeIf(f -> f.getOtherUser(null) != null &&
f.getOtherUser(null).equals(user));
}
public void follow(RegularUser follower, RegularUser followee) {
followings.add(new Following(follower, followee));
}
public void unfollow(RegularUser followee) {
followings.removeIf(f -> f.followee.equals(followee));
}
public Set<RegularUser> getMutualFriends(RegularUser user) {
// Simplified implementation
return new HashSet<>();
}
public List<RegularUser> getSuggestions() {
// Would implement friend-of-friend algorithm
return new ArrayList<>();
}
private FriendRequest findRequest(UUID requestId) {
return pendingRequests.stream()
.filter(r -> r.requestId.equals(requestId))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Request not found"));
}
public List<Friendship> getFriends() {
return friends;
}
}
/**
* Factory Pattern: Post creation
*/
interface ContentFactory {
Post createPost(String type, Map<String, Object> data);
}
class PostFactory implements ContentFactory {
@Override
public Post createPost(String type, Map<String, Object> data) {
RegularUser author = (RegularUser) data.get("author");
String content = (String) data.get("content");
switch (type.toLowerCase()) {
case "text":
return createTextPost(author, content);
case "photo":
@SuppressWarnings("unchecked")
List<String> photos = (List<String>) data.get("photos");
return createPhotoPost(author, content, photos);
case "video":
String video = (String) data.get("video");
return createVideoPost(author, content, video);
case "link":
String url = (String) data.get("url");
return createLinkPost(author, content, url);
default:
throw new IllegalArgumentException("Unknown post type: " + type);
}
}
private TextPost createTextPost(RegularUser author, String text) {
return new TextPost(author, text);
}
private PhotoPost createPhotoPost(RegularUser author, String caption, List<String> photoUrls) {
return new PhotoPost(author, caption, photoUrls);
}
private VideoPost createVideoPost(RegularUser author, String caption, String videoUrl) {
return new VideoPost(author, caption, videoUrl);
}
private LinkPost createLinkPost(RegularUser author, String content, String url) {
return new LinkPost(author, content, url);
}
}
/**
* Content classes
*/
class Reaction {
private RegularUser user;
private ReactionType type;
private LocalDateTime timestamp;
public Reaction(RegularUser user, ReactionType type) {
this.user = user;
this.type = type;
this.timestamp = LocalDateTime.now();
}
}
class Comment {
private UUID commentId;
private RegularUser author;
private String text;
private LocalDateTime createdAt;
private List<Comment> replies;
private List<Reaction> reactions;
public Comment(RegularUser author, String text) {
this.commentId = UUID.randomUUID();
this.author = author;
this.text = text;
this.createdAt = LocalDateTime.now();
this.replies = new ArrayList<>();
this.reactions = new ArrayList<>();
}
public void addReply(Comment reply) {
replies.add(reply);
}
public void react(RegularUser user, ReactionType type) {
// Remove existing reaction from this user
reactions.removeIf(r -> r.user.equals(user));
// Add new reaction
reactions.add(new Reaction(user, type));
}
public void delete() {
// Soft delete implementation
}
}
abstract class Post {
protected UUID postId;
protected RegularUser author;
protected String content;
protected LocalDateTime createdAt;
protected LocalDateTime editedAt;
protected VisibilityLevel visibility;
protected List<Comment> comments;
protected List<Reaction> reactions;
protected int shareCount;
protected List<RegularUser> taggedUsers;
public Post(RegularUser author, String content) {
this.postId = UUID.randomUUID();
this.author = author;
this.content = content;
this.createdAt = LocalDateTime.now();
this.visibility = VisibilityLevel.FRIENDS;
this.comments = new ArrayList<>();
this.reactions = new ArrayList<>();
this.shareCount = 0;
this.taggedUsers = new ArrayList<>();
}
public void edit(String newContent) {
this.content = newContent;
this.editedAt = LocalDateTime.now();
}
public void delete() {
// Soft delete implementation
}
public void addComment(Comment comment) {
comments.add(comment);
}
public void react(RegularUser user, ReactionType type) {
reactions.removeIf(r -> r.user.equals(user));
reactions.add(new Reaction(user, type));
}
public void share(RegularUser user) {
shareCount++;
}
public UUID getPostId() {
return postId;
}
public RegularUser getAuthor() {
return author;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public int getTotalEngagement() {
return reactions.size() + comments.size() + shareCount;
}
}
class TextPost extends Post {
private String formattedText;
public TextPost(RegularUser author, String text) {
super(author, text);
this.formattedText = text;
}
}
class PhotoPost extends Post {
private List<String> photoUrls;
public PhotoPost(RegularUser author, String caption, List<String> photos) {
super(author, caption);
this.photoUrls = new ArrayList<>(photos);
}
}
class VideoPost extends Post {
private String videoUrl;
private String thumbnailUrl;
public VideoPost(RegularUser author, String caption, String video) {
super(author, caption);
this.videoUrl = video;
this.thumbnailUrl = video + "_thumb.jpg";
}
}
class LinkPost extends Post {
private String url;
private String previewTitle;
private String previewImage;
public LinkPost(RegularUser author, String content, String url) {
super(author, content);
this.url = url;
// Would fetch preview data
}
}
/**
* Strategy Pattern: Feed ranking algorithms
*/
interface FeedRankingStrategy {
List<Post> rankPosts(List<Post> posts, RegularUser user);
}
class ChronologicalRanking implements FeedRankingStrategy {
@Override
public List<Post> rankPosts(List<Post> posts, RegularUser user) {
return posts.stream()
.sorted((p1, p2) -> p2.getCreatedAt().compareTo(p1.getCreatedAt()))
.collect(Collectors.toList());
}
}
class EdgeRankAlgorithm implements FeedRankingStrategy {
@Override
public List<Post> rankPosts(List<Post> posts, RegularUser user) {
Map<Post, Double> scores = new HashMap<>();
for (Post post : posts) {
double affinity = calculateAffinity(user, post.getAuthor());
double weight = calculateWeight(post);
double timeDecay = calculateTimeDecay(post);
double edgeRank = affinity * weight * timeDecay;
scores.put(post, edgeRank);
}
return scores.entrySet().stream()
.sorted((e1, e2) -> Double.compare(e2.getValue(), e1.getValue()))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
private double calculateAffinity(RegularUser user, RegularUser author) {
// Simplified: would analyze interaction history
return 0.7;
}
private double calculateWeight(Post post) {
if (post instanceof PhotoPost || post instanceof VideoPost) {
return 1.0;
} else if (post instanceof LinkPost) {
return 0.7;
}
return 0.5;
}
private double calculateTimeDecay(Post post) {
long hoursOld = Duration.between(post.getCreatedAt(), LocalDateTime.now()).toHours();
return Math.exp(-hoursOld / 24.0);
}
}
class EngagementBasedRanking implements FeedRankingStrategy {
@Override
public List<Post> rankPosts(List<Post> posts, RegularUser user) {
return posts.stream()
.sorted((p1, p2) -> Integer.compare(
predictEngagement(p2, user),
predictEngagement(p1, user)))
.collect(Collectors.toList());
}
private int predictEngagement(Post post, RegularUser user) {
// Simplified ML prediction
return post.getTotalEngagement();
}
}
/**
* News Feed
*/
class NewsFeed {
private RegularUser user;
private FeedRankingStrategy rankingStrategy;
private List<Post> cachedFeed;
private LocalDateTime lastUpdated;
public NewsFeed(RegularUser user) {
this.user = user;
this.rankingStrategy = new EdgeRankAlgorithm();
this.cachedFeed = new ArrayList<>();
}
public void refreshFeed() {
// Aggregate posts from friends, followings, pages, groups
List<Post> allPosts = new ArrayList<>();
// ... collect posts ...
this.cachedFeed = rankingStrategy.rankPosts(allPosts, user);
this.lastUpdated = LocalDateTime.now();
}
public void setRankingStrategy(FeedRankingStrategy strategy) {
this.rankingStrategy = strategy;
refreshFeed();
}
public List<Post> getNextPage(int page, int pageSize) {
int start = page * pageSize;
int end = Math.min(start + pageSize, cachedFeed.size());
return cachedFeed.subList(start, end);
}
}
/**
* Observer Pattern: Notifications
*/
class Notification {
private UUID notificationId;
private NotificationType type;
private RegularUser recipient;
private RegularUser actor;
private String content;
private LocalDateTime createdAt;
private boolean read;
public Notification(NotificationType type, RegularUser recipient,
RegularUser actor, String content) {
this.notificationId = UUID.randomUUID();
this.type = type;
this.recipient = recipient;
this.actor = actor;
this.content = content;
this.createdAt = LocalDateTime.now();
this.read = false;
}
public void markAsRead() {
this.read = true;
}
}
interface NotificationObserver {
void onEvent(Notification notification);
}
class PushNotificationService implements NotificationObserver {
@Override
public void onEvent(Notification notification) {
// Send push notification
System.out.println("Push: " + notification.content);
}
}
class EmailNotificationService implements NotificationObserver {
@Override
public void onEvent(Notification notification) {
// Send email
System.out.println("Email: " + notification.content);
}
}
class InAppNotificationService implements NotificationObserver {
@Override
public void onEvent(Notification notification) {
// Update in-app notification center
System.out.println("In-App: " + notification.content);
}
}
class NotificationPublisher {
private List<NotificationObserver> observers;
public NotificationPublisher() {
this.observers = new ArrayList<>();
}
public void subscribe(NotificationObserver observer) {
observers.add(observer);
}
public void unsubscribe(NotificationObserver observer) {
observers.remove(observer);
}
public void notifyObservers(Notification notification) {
for (NotificationObserver observer : observers) {
observer.onEvent(notification);
}
}
}
class NotificationCenter {
private RegularUser user;
private List<Notification> notifications;
private NotificationPublisher publisher;
public NotificationCenter(RegularUser user) {
this.user = user;
this.notifications = new ArrayList<>();
this.publisher = new NotificationPublisher();
// Subscribe default services
publisher.subscribe(new PushNotificationService());
publisher.subscribe(new EmailNotificationService());
publisher.subscribe(new InAppNotificationService());
}
public void sendNotification(Notification notification) {
notifications.add(notification);
publisher.notifyObservers(notification);
}
public void markAsRead(UUID notificationId) {
notifications.stream()
.filter(n -> n.notificationId.equals(notificationId))
.findFirst()
.ifPresent(Notification::markAsRead);
}
}
/**
* Main user classes
*/
class RegularUser extends UserAccount {
private UserProfile profile;
private SocialGraph connections;
private List<Post> timeline;
private List<Conversation> messages;
private NotificationCenter notifications;
private NewsFeed newsFeed;
public RegularUser(String email, String password, PersonalInfo info) {
super(email, password);
this.profile = new UserProfile(info);
this.connections = new SocialGraph();
this.timeline = new ArrayList<>();
this.messages = new ArrayList<>();
this.notifications = new NotificationCenter(this);
this.newsFeed = new NewsFeed(this);
}
public Post createPost(String type, Map<String, Object> data) {
data.put("author", this);
PostFactory factory = new PostFactory();
Post post = factory.createPost(type, data);
timeline.add(post);
return post;
}
public void sendFriendRequest(RegularUser target) {
connections.sendFriendRequest(this, target);
// Notify target
Notification notif = new Notification(
NotificationType.FRIEND_REQUEST,
target,
this,
profile.getInfo().getFullName() + " sent you a friend request"
);
target.notifications.sendNotification(notif);
}
public void sendMessage(RegularUser recipient, String text) {
// Find or create conversation
Conversation conv = messages.stream()
.filter(c -> c.hasParticipant(recipient))
.findFirst()
.orElseGet(() -> new Conversation(Arrays.asList(this, recipient)));
Message msg = new Message(this, text);
conv.sendMessage(msg);
}
public UserProfile getProfile() {
return profile;
}
public SocialGraph getConnections() {
return connections;
}
public NewsFeed getNewsFeed() {
return newsFeed;
}
}
class Administrator extends UserAccount {
private Set<String> permissions;
public Administrator(String email, String password) {
super(email, password);
this.permissions = new HashSet<>(Arrays.asList(
"REVIEW_REPORTS", "SUSPEND_ACCOUNTS", "DELETE_CONTENT", "BAN_USERS"
));
}
public void reviewReport(UUID reportId) {
// Review content report
}
public void suspendAccount(UUID userId) {
// Suspend user account
}
public void deleteContent(UUID contentId) {
// Delete violating content
}
}
/**
* Groups and Pages
*/
class GroupMember {
private RegularUser user;
private GroupRole role;
private LocalDateTime joinedAt;
public GroupMember(RegularUser user, GroupRole role) {
this.user = user;
this.role = role;
this.joinedAt = LocalDateTime.now();
}
public void promoteToAdmin() {
this.role = GroupRole.ADMIN;
}
public void demote() {
this.role = GroupRole.MEMBER;
}
}
class Group {
private UUID groupId;
private String name;
private String description;
private GroupType type;
private RegularUser creator;
private List<GroupMember> members;
private List<Post> posts;
private LocalDateTime createdAt;
public Group(String name, String description, GroupType type, RegularUser creator) {
this.groupId = UUID.randomUUID();
this.name = name;
this.description = description;
this.type = type;
this.creator = creator;
this.members = new ArrayList<>();
this.posts = new ArrayList<>();
this.createdAt = LocalDateTime.now();
// Add creator as admin
members.add(new GroupMember(creator, GroupRole.ADMIN));
}
public void addMember(RegularUser user, GroupRole role) {
members.add(new GroupMember(user, role));
}
public void removeMember(RegularUser user) {
members.removeIf(m -> m.user.equals(user));
}
public void createPost(Post post) {
posts.add(post);
}
}
class PageReview {
private UUID reviewId;
private RegularUser author;
private int rating;
private String text;
private LocalDateTime createdAt;
private String adminResponse;
public PageReview(RegularUser author, int rating, String text) {
this.reviewId = UUID.randomUUID();
this.author = author;
this.rating = Math.max(1, Math.min(5, rating));
this.text = text;
this.createdAt = LocalDateTime.now();
}
public void respond(String response) {
this.adminResponse = response;
}
}
class Page {
private UUID pageId;
private String name;
private String description;
private PageCategory category;
private List<RegularUser> admins;
private Set<RegularUser> followers;
private List<Post> posts;
private List<PageReview> reviews;
public Page(String name, String description, PageCategory category) {
this.pageId = UUID.randomUUID();
this.name = name;
this.description = description;
this.category = category;
this.admins = new ArrayList<>();
this.followers = new HashSet<>();
this.posts = new ArrayList<>();
this.reviews = new ArrayList<>();
}
public void publishPost(Post post) {
posts.add(post);
}
public void addFollower(RegularUser user) {
followers.add(user);
}
public void respondToReview(UUID reviewId, String response) {
reviews.stream()
.filter(r -> r.reviewId.equals(reviewId))
.findFirst()
.ifPresent(r -> r.respond(response));
}
}
/**
* Messaging
*/
class MediaAttachment {
private UUID attachmentId;
private MediaType type;
private String url;
private int size;
public MediaAttachment(MediaType type, String url, int size) {
this.attachmentId = UUID.randomUUID();
this.type = type;
this.url = url;
this.size = size;
}
}
class Message {
private UUID messageId;
private RegularUser sender;
private String content;
private LocalDateTime sentAt;
private Map<RegularUser, LocalDateTime> readReceipts;
private List<MediaAttachment> attachments;
public Message(RegularUser sender, String content) {
this.messageId = UUID.randomUUID();
this.sender = sender;
this.content = content;
this.sentAt = LocalDateTime.now();
this.readReceipts = new HashMap<>();
this.attachments = new ArrayList<>();
}
public void markAsRead(RegularUser user) {
readReceipts.put(user, LocalDateTime.now());
}
public void delete() {
// Soft delete
}
}
class Conversation {
private UUID conversationId;
private List<RegularUser> participants;
private List<Message> messages;
private LocalDateTime createdAt;
private LocalDateTime lastActivity;
public Conversation(List<RegularUser> participants) {
this.conversationId = UUID.randomUUID();
this.participants = new ArrayList<>(participants);
this.messages = new ArrayList<>();
this.createdAt = LocalDateTime.now();
this.lastActivity = LocalDateTime.now();
}
public void sendMessage(Message message) {
messages.add(message);
this.lastActivity = LocalDateTime.now();
}
public void addParticipant(RegularUser user) {
participants.add(user);
}
public void removeParticipant(RegularUser user) {
participants.remove(user);
}
public void markAsRead(RegularUser user) {
for (Message msg : messages) {
if (!msg.sender.equals(user)) {
msg.markAsRead(user);
}
}
}
public boolean hasParticipant(RegularUser user) {
return participants.contains(user);
}
}
/**
* Facade Pattern: Search
*/
abstract class SearchIndex {
protected Map<String, Set<UUID>> index;
public SearchIndex() {
this.index = new HashMap<>();
}
public abstract void indexDocument(Object doc);
public abstract List<?> search(String query);
public void removeDocument(UUID docId) {
index.values().forEach(set -> set.remove(docId));
}
}
class UserSearchIndex extends SearchIndex {
private Map<UUID, RegularUser> users;
public UserSearchIndex() {
super();
this.users = new HashMap<>();
}
@Override
public void indexDocument(Object doc) {
RegularUser user = (RegularUser) doc;
users.put(user.getAccountId(), user);
String name = user.getProfile().getInfo().getFullName().toLowerCase();
for (String word : name.split("\\s+")) {
index.computeIfAbsent(word, k -> new HashSet<>())
.add(user.getAccountId());
}
}
@Override
public List<RegularUser> search(String query) {
Set<UUID> results = index.getOrDefault(query.toLowerCase(), new HashSet<>());
return results.stream()
.map(users::get)
.collect(Collectors.toList());
}
}
class PostSearchIndex extends SearchIndex {
private Map<UUID, Post> posts;
public PostSearchIndex() {
super();
this.posts = new HashMap<>();
}
@Override
public void indexDocument(Object doc) {
Post post = (Post) doc;
posts.put(post.getPostId(), post);
String content = post.content.toLowerCase();
for (String word : content.split("\\s+")) {
index.computeIfAbsent(word, k -> new HashSet<>())
.add(post.getPostId());
}
}
@Override
public List<Post> search(String query) {
Set<UUID> results = index.getOrDefault(query.toLowerCase(), new HashSet<>());
return results.stream()
.map(posts::get)
.collect(Collectors.toList());
}
}
class SearchFacade {
private UserSearchIndex userIndex;
private PostSearchIndex postIndex;
public SearchFacade() {
this.userIndex = new UserSearchIndex();
this.postIndex = new PostSearchIndex();
}
public Map<String, List<?>> search(String query) {
Map<String, List<?>> results = new HashMap<>();
results.put("users", userIndex.search(query));
results.put("posts", postIndex.search(query));
return results;
}
public List<RegularUser> searchUsers(String query) {
return userIndex.search(query);
}
public List<Post> searchPosts(String query) {
return postIndex.search(query);
}
}
/**
* Graph Traversal for friend suggestions
*/
class GraphTraversal {
public List<RegularUser> suggestFriends(RegularUser user, int limit) {
// BFS to find friends of friends
Set<RegularUser> visited = new HashSet<>();
Map<RegularUser, Integer> mutualCount = new HashMap<>();
visited.add(user);
// Level 1: Direct friends
Set<RegularUser> directFriends = user.getConnections().getFriends().stream()
.map(f -> f.getOtherUser(user))
.collect(Collectors.toSet());
visited.addAll(directFriends);
// Level 2: Friends of friends
for (RegularUser friend : directFriends) {
Set<RegularUser> friendsOfFriend = friend.getConnections().getFriends().stream()
.map(f -> f.getOtherUser(friend))
.filter(u -> !visited.contains(u))
.collect(Collectors.toSet());
for (RegularUser candidate : friendsOfFriend) {
mutualCount.merge(candidate, 1, Integer::sum);
}
}
// Sort by mutual friend count and return top N
return mutualCount.entrySet().stream()
.sorted((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue()))
.limit(limit)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
public int findShortestPath(RegularUser user1, RegularUser user2) {
// BFS to find shortest path
if (user1.equals(user2)) return 0;
Queue<RegularUser> queue = new LinkedList<>();
Map<RegularUser, Integer> distances = new HashMap<>();
queue.offer(user1);
distances.put(user1, 0);
while (!queue.isEmpty()) {
RegularUser current = queue.poll();
int distance = distances.get(current);
Set<RegularUser> neighbors = current.getConnections().getFriends().stream()
.map(f -> f.getOtherUser(current))
.collect(Collectors.toSet());
for (RegularUser neighbor : neighbors) {
if (!distances.containsKey(neighbor)) {
distances.put(neighbor, distance + 1);
queue.offer(neighbor);
if (neighbor.equals(user2)) {
return distance + 1;
}
}
}
}
return -1; // No path found
}
}
/**
* Moderation
*/
interface ReportableContent {
UUID getContentId();
RegularUser getAuthor();
void takedown();
}
class ContentReport {
private UUID reportId;
private RegularUser reporter;
private ReportableContent content;
private ReportReason reason;
private String details;
private ReportStatus status;
private Administrator assignedTo;
private LocalDateTime createdAt;
public ContentReport(RegularUser reporter, ReportableContent content,
ReportReason reason, String details) {
this.reportId = UUID.randomUUID();
this.reporter = reporter;
this.content = content;
this.reason = reason;
this.details = details;
this.status = ReportStatus.PENDING;
this.createdAt = LocalDateTime.now();
}
public void assign(Administrator admin) {
this.assignedTo = admin;
this.status = ReportStatus.UNDER_REVIEW;
}
public void resolve(ActionType action) {
this.status = ReportStatus.RESOLVED;
// Execute moderation action
}
}
/**
* Demo usage
*/
class SocialNetworkDemo {
public static void main(String[] args) {
// Create users
PersonalInfo aliceInfo = new PersonalInfo("Alice Smith", LocalDate.of(1990, 5, 15));
PersonalInfo bobInfo = new PersonalInfo("Bob Johnson", LocalDate.of(1988, 8, 20));
RegularUser alice = new RegularUser("[email protected]", "password123", aliceInfo);
RegularUser bob = new RegularUser("[email protected]", "password456", bobInfo);
// Alice sends friend request to Bob
alice.sendFriendRequest(bob);
// Bob accepts (simulated)
// In real system, Bob would call acceptRequest on his SocialGraph
// Alice creates a post
Map<String, Object> postData = new HashMap<>();
postData.put("content", "Hello, world! This is my first post.");
Post post = alice.createPost("text", postData);
// Bob reacts to Alice's post
post.react(bob, ReactionType.LIKE);
// Bob comments
Comment comment = new Comment(bob, "Great post, Alice!");
post.addComment(comment);
// Alice sends a message to Bob
alice.sendMessage(bob, "Hey Bob, thanks for the like!");
// Create a group
Group developers = new Group("Java Developers",
"A community for Java enthusiasts",
GroupType.PUBLIC,
alice);
developers.addMember(bob, GroupRole.MEMBER);
// Search functionality
SearchFacade search = new SearchFacade();
search.userIndex.indexDocument(alice);
search.userIndex.indexDocument(bob);
search.postIndex.indexDocument(post);
List<RegularUser> searchResults = search.searchUsers("Alice");
System.out.println("Found " + searchResults.size() + " users matching 'Alice'");
// Friend suggestions
GraphTraversal graph = new GraphTraversal();
List<RegularUser> suggestions = graph.suggestFriends(alice, 10);
System.out.println("Friend suggestions for Alice: " + suggestions.size());
System.out.println("\nSocial Network System demonstration completed!");
}
}
Python Implementation
"""
Social Networking Platform - Python Implementation
Demonstrates OOD patterns: State, Strategy, Observer, Factory, Composite, Facade
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import List, Dict, Set, Optional, Protocol, Any
from abc import ABC, abstractmethod
from enum import Enum, auto
from datetime import datetime, date, timedelta
from uuid import UUID, uuid4
from collections import defaultdict, deque
import hashlib
import math
# ==================== Enumerations ====================
class AccountStatus(Enum):
ACTIVE = auto()
SUSPENDED = auto()
DEACTIVATED = auto()
DELETED = auto()
class VisibilityLevel(Enum):
PUBLIC = auto()
FRIENDS = auto()
FRIENDS_OF_FRIENDS = auto()
CUSTOM = auto()
ONLY_ME = auto()
class Gender(Enum):
MALE = auto()
FEMALE = auto()
NON_BINARY = auto()
PREFER_NOT_TO_SAY = auto()
class RelationshipStatus(Enum):
SINGLE = auto()
IN_A_RELATIONSHIP = auto()
ENGAGED = auto()
MARRIED = auto()
COMPLICATED = auto()
DIVORCED = auto()
WIDOWED = auto()
class RequestStatus(Enum):
PENDING = auto()
ACCEPTED = auto()
REJECTED = auto()
CANCELLED = auto()
class ReactionType(Enum):
LIKE = auto()
LOVE = auto()
HAHA = auto()
WOW = auto()
SAD = auto()
ANGRY = auto()
class GroupType(Enum):
PUBLIC = auto()
CLOSED = auto()
SECRET = auto()
class GroupRole(Enum):
MEMBER = auto()
MODERATOR = auto()
ADMIN = auto()
class PageCategory(Enum):
BUSINESS = auto()
CELEBRITY = auto()
COMMUNITY = auto()
ENTERTAINMENT = auto()
ORGANIZATION = auto()
BRAND = auto()
LOCAL_BUSINESS = auto()
class MediaType(Enum):
PHOTO = auto()
VIDEO = auto()
AUDIO = auto()
DOCUMENT = auto()
class NotificationType(Enum):
FRIEND_REQUEST = auto()
FRIEND_ACCEPTED = auto()
POST_LIKED = auto()
POST_COMMENTED = auto()
POST_SHARED = auto()
MENTIONED_IN_POST = auto()
MENTIONED_IN_COMMENT = auto()
MESSAGE_RECEIVED = auto()
GROUP_INVITED = auto()
BIRTHDAY_REMINDER = auto()
class ReportReason(Enum):
SPAM = auto()
HARASSMENT = auto()
HATE_SPEECH = auto()
VIOLENCE = auto()
NUDITY = auto()
FALSE_INFORMATION = auto()
OTHER = auto()
class ReportStatus(Enum):
PENDING = auto()
UNDER_REVIEW = auto()
RESOLVED = auto()
DISMISSED = auto()
class FriendshipStrength(Enum):
WEAK = auto()
MODERATE = auto()
STRONG = auto()
# ==================== State Pattern ====================
class AccountState(Protocol):
"""Protocol for account state management"""
def handle_login(self) -> bool: ...
def allow_posting(self) -> bool: ...
def transition_to(self, status: AccountStatus) -> AccountState: ...
@dataclass
class ActiveState:
def handle_login(self) -> bool:
return True
def allow_posting(self) -> bool:
return True
def transition_to(self, status: AccountStatus) -> AccountState:
if status == AccountStatus.SUSPENDED:
return SuspendedState()
elif status == AccountStatus.DEACTIVATED:
return DeactivatedState()
elif status == AccountStatus.DELETED:
return DeletedState()
return self
@dataclass
class SuspendedState:
def handle_login(self) -> bool:
raise Exception("Account is suspended")
def allow_posting(self) -> bool:
return False
def transition_to(self, status: AccountStatus) -> AccountState:
if status == AccountStatus.ACTIVE:
return ActiveState()
return self
@dataclass
class DeactivatedState:
def handle_login(self) -> bool:
return True # Can reactivate by logging in
def allow_posting(self) -> bool:
return False
def transition_to(self, status: AccountStatus) -> AccountState:
if status == AccountStatus.ACTIVE:
return ActiveState()
return self
@dataclass
class DeletedState:
def handle_login(self) -> bool:
raise Exception("Account has been deleted")
def allow_posting(self) -> bool:
return False
def transition_to(self, status: AccountStatus) -> AccountState:
return self # Cannot transition from deleted
# ==================== Core Identity ====================
@dataclass
class SecuritySettings:
two_factor_enabled: bool = False
trusted_devices: Set[str] = field(default_factory=set)
last_password_change: datetime = field(default_factory=datetime.now)
def enable_two_factor(self) -> None:
self.two_factor_enabled = True
def add_trusted_device(self, device_id: str) -> None:
self.trusted_devices.add(device_id)
class UserAccount(ABC):
def __init__(self, email: str, password: str):
self.account_id: UUID = uuid4()
self.email: str = email
self.password_hash: str = self._hash_password(password)
self.created_at: datetime = datetime.now()
self.state: AccountState = ActiveState()
self.security: SecuritySettings = SecuritySettings()
def authenticate(self, password: str) -> bool:
return (self.state.handle_login() and
self._hash_password(password) == self.password_hash)
def deactivate(self) -> None:
self.state = self.state.transition_to(AccountStatus.DEACTIVATED)
def reactivate(self) -> None:
self.state = self.state.transition_to(AccountStatus.ACTIVE)
def change_password(self, new_password: str) -> None:
self.password_hash = self._hash_password(new_password)
self.security.last_password_change = datetime.now()
@staticmethod
def _hash_password(password: str) -> str:
return hashlib.sha256(password.encode()).hexdigest()
# ==================== Profile ====================
@dataclass
class PersonalInfo:
full_name: str
birth_date: date
gender: Optional[Gender] = None
hometown: Optional[str] = None
current_city: Optional[str] = None
relationship_status: Optional[RelationshipStatus] = None
def get_age(self) -> int:
today = date.today()
return today.year - self.birth_date.year - (
(today.month, today.day) < (self.birth_date.month, self.birth_date.day)
)
@dataclass
class WorkExperience:
company: str
position: str
start_date: date
location: Optional[str] = None
end_date: Optional[date] = None
description: Optional[str] = None
def end(self, end_date: date) -> None:
self.end_date = end_date
@dataclass
class Education:
institution: str
degree: str
field_of_study: str
graduation_year: int
@dataclass
class PrivacyList:
list_id: UUID = field(default_factory=uuid4)
name: str = ""
members: Set[RegularUser] = field(default_factory=set)
def add_member(self, user: RegularUser) -> None:
self.members.add(user)
def remove_member(self, user: RegularUser) -> None:
self.members.discard(user)
def contains(self, user: RegularUser) -> bool:
return user in self.members
@dataclass
class PrivacySettings:
profile_visibility: VisibilityLevel = VisibilityLevel.FRIENDS
posts_visibility: VisibilityLevel = VisibilityLevel.FRIENDS
friend_list_visibility: VisibilityLevel = VisibilityLevel.FRIENDS
custom_lists: Dict[str, PrivacyList] = field(default_factory=dict)
def __post_init__(self):
if not self.custom_lists:
self.custom_lists = {
'close_friends': PrivacyList(name="Close Friends"),
'acquaintances': PrivacyList(name="Acquaintances"),
'restricted': PrivacyList(name="Restricted")
}
def update_setting(self, key: str, value: VisibilityLevel) -> None:
if key == 'profile':
self.profile_visibility = value
elif key == 'posts':
self.posts_visibility = value
elif key == 'friends':
self.friend_list_visibility = value
def can_view(self, viewer: RegularUser, resource_type: str) -> bool:
level = self._get_visibility_for(resource_type)
if level == VisibilityLevel.PUBLIC:
return True
elif level == VisibilityLevel.ONLY_ME:
return False
# Simplified - would check actual friendship
return False
def _get_visibility_for(self, resource: str) -> VisibilityLevel:
mapping = {
'profile': self.profile_visibility,
'posts': self.posts_visibility,
'friends': self.friend_list_visibility
}
return mapping.get(resource, VisibilityLevel.FRIENDS)
@dataclass
class MediaItem:
item_id: UUID = field(default_factory=uuid4)
url: str = ""
media_type: MediaType = MediaType.PHOTO
uploaded_at: datetime = field(default_factory=datetime.now)
@dataclass
class UserProfile:
info: PersonalInfo
work_history: List[WorkExperience] = field(default_factory=list)
education_history: List[Education] = field(default_factory=list)
photos: List[MediaItem] = field(default_factory=list)
privacy: PrivacySettings = field(default_factory=PrivacySettings)
last_updated: datetime = field(default_factory=datetime.now)
def update_bio(self, text: str) -> None:
self.last_updated = datetime.now()
def add_work_experience(self, work: WorkExperience) -> None:
self.work_history.append(work)
self.last_updated = datetime.now()
def add_education(self, edu: Education) -> None:
self.education_history.append(edu)
self.last_updated = datetime.now()
def set_profile_picture(self, photo: MediaItem) -> None:
self.photos.insert(0, photo)
self.last_updated = datetime.now()
# ==================== Social Graph ====================
@dataclass
class Friendship:
user1: RegularUser
user2: RegularUser
established_at: datetime = field(default_factory=datetime.now)
strength: FriendshipStrength = FriendshipStrength.MODERATE
def calculate_strength(self) -> FriendshipStrength:
# Simplified - would analyze interactions
return FriendshipStrength.MODERATE
def get_other_user(self, user: RegularUser) -> Optional[RegularUser]:
if user == self.user1:
return self.user2
elif user == self.user2:
return self.user1
return None
@dataclass
class Following:
follower: RegularUser
followee: RegularUser
since: datetime = field(default_factory=datetime.now)
notifications_enabled: bool = True
@dataclass
class FriendRequest:
request_id: UUID = field(default_factory=uuid4)
sender: Optional[RegularUser] = None
recipient: Optional[RegularUser] = None
status: RequestStatus = RequestStatus.PENDING
sent_at: datetime = field(default_factory=datetime.now)
def accept(self) -> None:
if self.status != RequestStatus.PENDING:
raise Exception("Request not pending")
self.status = RequestStatus.ACCEPTED
def reject(self) -> None:
if self.status != RequestStatus.PENDING:
raise Exception("Request not pending")
self.status = RequestStatus.REJECTED
def cancel(self) -> None:
if self.status != RequestStatus.PENDING:
raise Exception("Request not pending")
self.status = RequestStatus.CANCELLED
@dataclass
class SocialGraph:
friends: List[Friendship] = field(default_factory=list)
followings: List[Following] = field(default_factory=list)
pending_requests: List[FriendRequest] = field(default_factory=list)
blocked_users: Set[RegularUser] = field(default_factory=set)
def send_friend_request(self, user: RegularUser, target: RegularUser) -> None:
if target in self.blocked_users:
raise Exception("Cannot send request to blocked user")
request = FriendRequest(sender=user, recipient=target)
self.pending_requests.append(request)
def accept_request(self, request_id: UUID) -> None:
request = self._find_request(request_id)
request.accept()
friendship = Friendship(user1=request.sender, user2=request.recipient)
self.friends.append(friendship)
self.pending_requests.remove(request)
def reject_request(self, request_id: UUID) -> None:
request = self._find_request(request_id)
request.reject()
self.pending_requests.remove(request)
def unfriend(self, user: RegularUser) -> None:
self.friends = [f for f in self.friends
if f.get_other_user(user) != user]
def follow(self, follower: RegularUser, followee: RegularUser) -> None:
self.followings.append(Following(follower=follower, followee=followee))
def unfollow(self, followee: RegularUser) -> None:
self.followings = [f for f in self.followings
if f.followee != followee]
def get_mutual_friends(self, user: RegularUser) -> Set[RegularUser]:
# Simplified implementation
return set()
def get_suggestions(self) -> List[RegularUser]:
# Would implement friend-of-friend algorithm
return []
def _find_request(self, request_id: UUID) -> FriendRequest:
for req in self.pending_requests:
if req.request_id == request_id:
return req
raise Exception("Request not found")
# ==================== Factory Pattern ====================
class ContentFactory(Protocol):
"""Protocol for content creation"""
def create_post(self, post_type: str, data: Dict[str, Any]) -> Post: ...
@dataclass
class PostFactory:
def create_post(self, post_type: str, data: Dict[str, Any]) -> Post:
author = data['author']
content = data.get('content', '')
if post_type == 'text':
return TextPost(author=author, content=content)
elif post_type == 'photo':
return PhotoPost(author=author, content=content,
photo_urls=data.get('photos', []))
elif post_type == 'video':
return VideoPost(author=author, content=content,
video_url=data.get('video', ''))
elif post_type == 'link':
return LinkPost(author=author, content=content,
url=data.get('url', ''))
else:
raise ValueError(f"Unknown post type: {post_type}")
# ==================== Content ====================
@dataclass
class Reaction:
user: RegularUser
reaction_type: ReactionType
timestamp: datetime = field(default_factory=datetime.now)
@dataclass
class Comment:
comment_id: UUID = field(default_factory=uuid4)
author: Optional[RegularUser] = None
text: str = ""
created_at: datetime = field(default_factory=datetime.now)
replies: List[Comment] = field(default_factory=list)
reactions: List[Reaction] = field(default_factory=list)
def add_reply(self, reply: Comment) -> None:
self.replies.append(reply)
def react(self, user: RegularUser, reaction_type: ReactionType) -> None:
# Remove existing reaction from this user
self.reactions = [r for r in self.reactions if r.user != user]
self.reactions.append(Reaction(user=user, reaction_type=reaction_type))
def delete(self) -> None:
pass # Soft delete
@dataclass
class Post(ABC):
post_id: UUID = field(default_factory=uuid4)
author: Optional[RegularUser] = None
content: str = ""
created_at: datetime = field(default_factory=datetime.now)
edited_at: Optional[datetime] = None
visibility: VisibilityLevel = VisibilityLevel.FRIENDS
comments: List[Comment] = field(default_factory=list)
reactions: List[Reaction] = field(default_factory=list)
share_count: int = 0
tagged_users: List[RegularUser] = field(default_factory=list)
def edit(self, new_content: str) -> None:
self.content = new_content
self.edited_at = datetime.now()
def delete(self) -> None:
pass # Soft delete
def add_comment(self, comment: Comment) -> None:
self.comments.append(comment)
def react(self, user: RegularUser, reaction_type: ReactionType) -> None:
self.reactions = [r for r in self.reactions if r.user != user]
self.reactions.append(Reaction(user=user, reaction_type=reaction_type))
def share(self, user: RegularUser) -> None:
self.share_count += 1
def get_total_engagement(self) -> int:
return len(self.reactions) + len(self.comments) + self.share_count
@dataclass
class TextPost(Post):
formatted_text: str = ""
def __post_init__(self):
if not self.formatted_text:
self.formatted_text = self.content
@dataclass
class PhotoPost(Post):
photo_urls: List[str] = field(default_factory=list)
@dataclass
class VideoPost(Post):
video_url: str = ""
thumbnail_url: str = ""
def __post_init__(self):
if not self.thumbnail_url and self.video_url:
self.thumbnail_url = self.video_url + "_thumb.jpg"
@dataclass
class LinkPost(Post):
url: str = ""
preview_title: str = ""
preview_image: str = ""
# ==================== Strategy Pattern ====================
class FeedRankingStrategy(Protocol):
"""Protocol for feed ranking algorithms"""
def rank_posts(self, posts: List[Post], user: RegularUser) -> List[Post]: ...
@dataclass
class ChronologicalRanking:
def rank_posts(self, posts: List[Post], user: RegularUser) -> List[Post]:
return sorted(posts, key=lambda p: p.created_at, reverse=True)
@dataclass
class EdgeRankAlgorithm:
def rank_posts(self, posts: List[Post], user: RegularUser) -> List[Post]:
scores: Dict[Post, float] = {}
for post in posts:
affinity = self._calculate_affinity(user, post.author)
weight = self._calculate_weight(post)
time_decay = self._calculate_time_decay(post)
edge_rank = affinity * weight * time_decay
scores[post] = edge_rank
return sorted(posts, key=lambda p: scores.get(p, 0), reverse=True)
def _calculate_affinity(self, user: RegularUser, author: Optional[RegularUser]) -> float:
# Simplified - would analyze interaction history
return 0.7
def _calculate_weight(self, post: Post) -> float:
if isinstance(post, (PhotoPost, VideoPost)):
return 1.0
elif isinstance(post, LinkPost):
return 0.7
return 0.5
def _calculate_time_decay(self, post: Post) -> float:
hours_old = (datetime.now() - post.created_at).total_seconds() / 3600
return math.exp(-hours_old / 24.0)
@dataclass
class EngagementBasedRanking:
def rank_posts(self, posts: List[Post], user: RegularUser) -> List[Post]:
return sorted(posts,
key=lambda p: self._predict_engagement(p, user),
reverse=True)
def _predict_engagement(self, post: Post, user: RegularUser) -> int:
# Simplified ML prediction
return post.get_total_engagement()
@dataclass
class NewsFeed:
user: RegularUser
ranking_strategy: FeedRankingStrategy = field(default_factory=EdgeRankAlgorithm)
cached_feed: List[Post] = field(default_factory=list)
last_updated: Optional[datetime] = None
def refresh_feed(self) -> None:
# Aggregate posts from friends, followings, pages, groups
all_posts: List[Post] = []
# ... collect posts ...
self.cached_feed = self.ranking_strategy.rank_posts(all_posts, self.user)
self.last_updated = datetime.now()
def set_ranking_strategy(self, strategy: FeedRankingStrategy) -> None:
self.ranking_strategy = strategy
self.refresh_feed()
def get_next_page(self, page: int, page_size: int) -> List[Post]:
start = page * page_size
end = min(start + page_size, len(self.cached_feed))
return self.cached_feed[start:end]
# ==================== Observer Pattern ====================
@dataclass
class Notification:
notification_id: UUID = field(default_factory=uuid4)
notification_type: NotificationType = NotificationType.POST_LIKED
recipient: Optional[RegularUser] = None
actor: Optional[RegularUser] = None
content: str = ""
created_at: datetime = field(default_factory=datetime.now)
read: bool = False
def mark_as_read(self) -> None:
self.read = True
class NotificationObserver(Protocol):
"""Protocol for notification delivery"""
def on_event(self, notification: Notification) -> None: ...
@dataclass
class PushNotificationService:
def on_event(self, notification: Notification) -> None:
print(f"Push: {notification.content}")
@dataclass
class EmailNotificationService:
def on_event(self, notification: Notification) -> None:
print(f"Email: {notification.content}")
@dataclass
class InAppNotificationService:
def on_event(self, notification: Notification) -> None:
print(f"In-App: {notification.content}")
@dataclass
class NotificationPublisher:
observers: List[NotificationObserver] = field(default_factory=list)
def subscribe(self, observer: NotificationObserver) -> None:
self.observers.append(observer)
def unsubscribe(self, observer: NotificationObserver) -> None:
self.observers.remove(observer)
def notify_observers(self, notification: Notification) -> None:
for observer in self.observers:
observer.on_event(notification)
@dataclass
class NotificationCenter:
user: RegularUser
notifications: List[Notification] = field(default_factory=list)
publisher: NotificationPublisher = field(default_factory=NotificationPublisher)
def __post_init__(self):
# Subscribe default services
self.publisher.subscribe(PushNotificationService())
self.publisher.subscribe(EmailNotificationService())
self.publisher.subscribe(InAppNotificationService())
def send_notification(self, notification: Notification) -> None:
self.notifications.append(notification)
self.publisher.notify_observers(notification)
def mark_as_read(self, notification_id: UUID) -> None:
for notif in self.notifications:
if notif.notification_id == notification_id:
notif.mark_as_read()
break
# ==================== User Classes ====================
class RegularUser(UserAccount):
def __init__(self, email: str, password: str, info: PersonalInfo):
super().__init__(email, password)
self.profile: UserProfile = UserProfile(info=info)
self.connections: SocialGraph = SocialGraph()
self.timeline: List[Post] = []
self.messages: List[Conversation] = []
self.notifications: NotificationCenter = NotificationCenter(user=self)
self.news_feed: NewsFeed = NewsFeed(user=self)
def create_post(self, post_type: str, data: Dict[str, Any]) -> Post:
data['author'] = self
factory = PostFactory()
post = factory.create_post(post_type, data)
self.timeline.append(post)
return post
def send_friend_request(self, target: RegularUser) -> None:
self.connections.send_friend_request(self, target)
# Notify target
notif = Notification(
notification_type=NotificationType.FRIEND_REQUEST,
recipient=target,
actor=self,
content=f"{self.profile.info.full_name} sent you a friend request"
)
target.notifications.send_notification(notif)
def send_message(self, recipient: RegularUser, text: str) -> None:
# Find or create conversation
conv = next((c for c in self.messages if c.has_participant(recipient)), None)
if not conv:
conv = Conversation(participants=[self, recipient])
self.messages.append(conv)
msg = Message(sender=self, content=text)
conv.send_message(msg)
class Administrator(UserAccount):
def __init__(self, email: str, password: str):
super().__init__(email, password)
self.permissions: Set[str] = {
'REVIEW_REPORTS', 'SUSPEND_ACCOUNTS',
'DELETE_CONTENT', 'BAN_USERS'
}
def review_report(self, report_id: UUID) -> None:
pass
def suspend_account(self, user_id: UUID) -> None:
pass
def delete_content(self, content_id: UUID) -> None:
pass
# ==================== Groups and Pages ====================
@dataclass
class GroupMember:
user: RegularUser
role: GroupRole
joined_at: datetime = field(default_factory=datetime.now)
def promote_to_admin(self) -> None:
self.role = GroupRole.ADMIN
def demote(self) -> None:
self.role = GroupRole.MEMBER
@dataclass
class Group:
group_id: UUID = field(default_factory=uuid4)
name: str = ""
description: str = ""
group_type: GroupType = GroupType.PUBLIC
creator: Optional[RegularUser] = None
members: List[GroupMember] = field(default_factory=list)
posts: List[Post] = field(default_factory=list)
created_at: datetime = field(default_factory=datetime.now)
def __post_init__(self):
if self.creator and not self.members:
self.members.append(GroupMember(user=self.creator, role=GroupRole.ADMIN))
def add_member(self, user: RegularUser, role: GroupRole) -> None:
self.members.append(GroupMember(user=user, role=role))
def remove_member(self, user: RegularUser) -> None:
self.members = [m for m in self.members if m.user != user]
def create_post(self, post: Post) -> None:
self.posts.append(post)
@dataclass
class PageReview:
review_id: UUID = field(default_factory=uuid4)
author: Optional[RegularUser] = None
rating: int = 5
text: str = ""
created_at: datetime = field(default_factory=datetime.now)
admin_response: str = ""
def __post_init__(self):
self.rating = max(1, min(5, self.rating))
def respond(self, response: str) -> None:
self.admin_response = response
@dataclass
class Page:
page_id: UUID = field(default_factory=uuid4)
name: str = ""
description: str = ""
category: PageCategory = PageCategory.BUSINESS
admins: List[RegularUser] = field(default_factory=list)
followers: Set[RegularUser] = field(default_factory=set)
posts: List[Post] = field(default_factory=list)
reviews: List[PageReview] = field(default_factory=list)
def publish_post(self, post: Post) -> None:
self.posts.append(post)
def add_follower(self, user: RegularUser) -> None:
self.followers.add(user)
def respond_to_review(self, review_id: UUID, response: str) -> None:
for review in self.reviews:
if review.review_id == review_id:
review.respond(response)
break
# ==================== Messaging ====================
@dataclass
class MediaAttachment:
attachment_id: UUID = field(default_factory=uuid4)
media_type: MediaType = MediaType.PHOTO
url: str = ""
size: int = 0
@dataclass
class Message:
message_id: UUID = field(default_factory=uuid4)
sender: Optional[RegularUser] = None
content: str = ""
sent_at: datetime = field(default_factory=datetime.now)
read_receipts: Dict[RegularUser, datetime] = field(default_factory=dict)
attachments: List[MediaAttachment] = field(default_factory=list)
def mark_as_read(self, user: RegularUser) -> None:
self.read_receipts[user] = datetime.now()
def delete(self) -> None:
pass # Soft delete
@dataclass
class Conversation:
conversation_id: UUID = field(default_factory=uuid4)
participants: List[RegularUser] = field(default_factory=list)
messages: List[Message] = field(default_factory=list)
created_at: datetime = field(default_factory=datetime.now)
last_activity: datetime = field(default_factory=datetime.now)
def send_message(self, message: Message) -> None:
self.messages.append(message)
self.last_activity = datetime.now()
def add_participant(self, user: RegularUser) -> None:
self.participants.append(user)
def remove_participant(self, user: RegularUser) -> None:
self.participants.remove(user)
def mark_as_read(self, user: RegularUser) -> None:
for msg in self.messages:
if msg.sender != user:
msg.mark_as_read(user)
def has_participant(self, user: RegularUser) -> bool:
return user in self.participants
# ==================== Facade Pattern ====================
class SearchIndex(ABC):
def __init__(self):
self.index: Dict[str, Set[UUID]] = defaultdict(set)
@abstractmethod
def index_document(self, doc: Any) -> None: ...
@abstractmethod
def search(self, query: str) -> List[Any]: ...
def remove_document(self, doc_id: UUID) -> None:
for uuid_set in self.index.values():
uuid_set.discard(doc_id)
@dataclass
class UserSearchIndex(SearchIndex):
users: Dict[UUID, RegularUser] = field(default_factory=dict)
def index_document(self, doc: RegularUser) -> None:
self.users[doc.account_id] = doc
name = doc.profile.info.full_name.lower()
for word in name.split():
self.index[word].add(doc.account_id)
def search(self, query: str) -> List[RegularUser]:
results = self.index.get(query.lower(), set())
return [self.users[uid] for uid in results if uid in self.users]
@dataclass
class PostSearchIndex(SearchIndex):
posts: Dict[UUID, Post] = field(default_factory=dict)
def index_document(self, doc: Post) -> None:
self.posts[doc.post_id] = doc
content = doc.content.lower()
for word in content.split():
self.index[word].add(doc.post_id)
def search(self, query: str) -> List[Post]:
results = self.index.get(query.lower(), set())
return [self.posts[pid] for pid in results if pid in self.posts]
@dataclass
class SearchFacade:
user_index: UserSearchIndex = field(default_factory=UserSearchIndex)
post_index: PostSearchIndex = field(default_factory=PostSearchIndex)
def search(self, query: str) -> Dict[str, List[Any]]:
return {
'users': self.user_index.search(query),
'posts': self.post_index.search(query)
}
def search_users(self, query: str) -> List[RegularUser]:
return self.user_index.search(query)
def search_posts(self, query: str) -> List[Post]:
return self.post_index.search(query)
# ==================== Graph Traversal ====================
@dataclass
class GraphTraversal:
def suggest_friends(self, user: RegularUser, limit: int) -> List[RegularUser]:
"""BFS to find friends of friends"""
visited: Set[RegularUser] = {user}
mutual_count: Dict[RegularUser, int] = defaultdict(int)
# Level 1: Direct friends
direct_friends = {f.get_other_user(user) for f in user.connections.friends
if f.get_other_user(user)}
visited.update(direct_friends)
# Level 2: Friends of friends
for friend in direct_friends:
if friend:
friends_of_friend = {f.get_other_user(friend)
for f in friend.connections.friends
if f.get_other_user(friend) and
f.get_other_user(friend) not in visited}
for candidate in friends_of_friend:
mutual_count[candidate] += 1
# Sort by mutual friend count
suggestions = sorted(mutual_count.items(),
key=lambda x: x[1],
reverse=True)
return [user for user, _ in suggestions[:limit]]
def find_shortest_path(self, user1: RegularUser, user2: RegularUser) -> int:
"""BFS to find shortest path between two users"""
if user1 == user2:
return 0
queue: deque = deque([(user1, 0)])
visited: Set[RegularUser] = {user1}
while queue:
current, distance = queue.popleft()
neighbors = {f.get_other_user(current)
for f in current.connections.friends
if f.get_other_user(current)}
for neighbor in neighbors:
if neighbor and neighbor not in visited:
if neighbor == user2:
return distance + 1
visited.add(neighbor)
queue.append((neighbor, distance + 1))
return -1 # No path found
# ==================== Demo ====================
def main():
# Create users
alice_info = PersonalInfo(full_name="Alice Smith", birth_date=date(1990, 5, 15))
bob_info = PersonalInfo(full_name="Bob Johnson", birth_date=date(1988, 8, 20))
alice = RegularUser(email="[email protected]", password="pass123", info=alice_info)
bob = RegularUser(email="[email protected]", password="pass456", info=bob_info)
# Alice sends friend request to Bob
alice.send_friend_request(bob)
# Alice creates a post
post = alice.create_post('text', {'content': 'Hello, world! First post.'})
# Bob reacts
post.react(bob, ReactionType.LIKE)
# Bob comments
comment = Comment(author=bob, text="Great post, Alice!")
post.add_comment(comment)
# Alice sends message to Bob
alice.send_message(bob, "Hey Bob, thanks for the like!")
# Create a group
developers = Group(
name="Java Developers",
description="A community for Java enthusiasts",
group_type=GroupType.PUBLIC,
creator=alice
)
developers.add_member(bob, GroupRole.MEMBER)
# Search
search = SearchFacade()
search.user_index.index_document(alice)
search.user_index.index_document(bob)
search.post_index.index_document(post)
results = search.search_users("Alice")
print(f"Found {len(results)} users matching 'Alice'")
# Friend suggestions
graph = GraphTraversal()
suggestions = graph.suggest_friends(alice, 10)
print(f"Friend suggestions for Alice: {len(suggestions)}")
print("\nSocial Network System demonstration completed!")
if __name__ == "__main__":
main()
Key Design Decisions
1. State Pattern for Account Management
Decision: Use the State pattern to manage account lifecycle (Active, Suspended, Deactivated, Deleted).
Rationale:
- Each state has different behavioral rules (login permissions, posting capabilities)
- State transitions are complex with conditional logic
- Future account states (e.g., Verified, Premium) can be added without modifying existing code
Trade-offs:
- Pro: Clean separation of state-specific behavior; easy to add new states
- Con: More classes to maintain; slight performance overhead from delegation
Example: A suspended account cannot post content but can view public content. The SuspendedState class encapsulates this behavior without polluting the UserAccount class with conditional statements.
2. Strategy Pattern for Feed Ranking
Decision: Implement multiple feed ranking algorithms (Chronological, EdgeRank, Engagement-based) using the Strategy pattern.
Rationale:
- Different users prefer different ranking methods
- Algorithm complexity varies greatly (simple timestamp sort vs. ML-based prediction)
- Need to A/B test different algorithms without code changes
- Real-time algorithm switching based on user preferences
Trade-offs:
- Pro: Algorithm swapping at runtime; easy to add new ranking strategies
- Con: All strategies must share the same interface, limiting flexibility
Example: During the News Feed load, the system can switch from EdgeRank to Chronological ranking based on user settings without recomputing the entire feed.
3. Observer Pattern for Notifications
Decision: Use Observer pattern with multiple notification channels (Push, Email, In-App).
Rationale:
- Single event (e.g., friend request) triggers multiple notification types
- Notification preferences vary by user
- Easy to add new channels (SMS, Webhook) without modifying event publishers
- Decouples event source from notification delivery
Trade-offs:
- Pro: Loose coupling; dynamic subscription management; parallel notification delivery
- Con: Debugging can be challenging with many observers; potential for notification storms
Example: When Alice sends a friend request to Bob, the NotificationPublisher notifies all registered observers (Push, Email, In-App services) simultaneously without Alice's code knowing about each channel.
4. Factory Pattern for Content Creation
Decision: Use Factory pattern to create different post types (Text, Photo, Video, Link).
Rationale:
- Post creation involves complex initialization (media upload, preview generation, metadata extraction)
- Each post type has different validation rules
- Centralized creation logic simplifies testing and maintenance
- Future content types (Poll, Event, Live Video) can be added easily
Trade-offs:
- Pro: Single point of creation; consistent initialization; type safety
- Con: Additional abstraction layer; factory becomes complex with many types
Example: Creating a LinkPost requires fetching URL metadata (title, image, description) from external sources. The PostFactory encapsulates this complexity, returning a fully-initialized LinkPost object.
5. Composite Pattern for Comment Threads
Decision: Implement nested comment replies as a tree structure using Composite pattern.
Rationale:
- Comments can have unlimited reply depth
- Operations (count reactions, search text) should work uniformly on comments and replies
- Simplifies rendering of threaded discussions
Trade-offs:
- Pro: Uniform treatment of comments and replies; recursive traversal; flexible depth
- Con: Can lead to very deep trees; performance concerns with excessive nesting
Example: Rendering a comment thread with 3 levels of replies uses the same traversal logic as a flat comment list, treating each node uniformly.
6. Facade Pattern for Search
Decision: Provide a unified SearchFacade over multiple specialized search indexes (Users, Posts, Groups, Pages).
Rationale:
- Each entity type requires different indexing strategies (name-based for users, full-text for posts)
- Client code should not know about multiple indexes
- Simplifies query routing and result aggregation
- Allows index implementation changes without affecting clients
Trade-offs:
- Pro: Simplified client interface; centralized search logic; easy to add new indexes
- Con: Can become a "god object"; may hide useful index-specific features
Example: A global search query "Java" is routed to both UserSearchIndex (finds users named Java) and PostSearchIndex (finds posts containing "Java"), with results aggregated in a single response.
7. Bidirectional vs. Asymmetric Relationships
Decision: Support both symmetric friendships (mutual consent required) and asymmetric following (one-way, no consent).
Rationale:
- Friendships imply reciprocal access and visibility
- Following allows users to subscribe to public figures without mutual relationship
- Matches real-world social dynamics (friends vs. followers)
- Privacy controls differ for each relationship type
Trade-offs:
- Pro: Flexibility for different use cases; aligns with user expectations
- Con: More complex access control logic; potential user confusion
Example: Bob can follow Celebrity Alice (asymmetric) to see her public posts, while Bob and Charlie are friends (symmetric) and share private content.
8. Privacy Settings Architecture
Decision: Implement granular, resource-specific privacy controls with custom privacy lists.
Rationale:
- Users need different visibility levels for profile, posts, photos, friend list
- Custom lists (Close Friends, Acquaintances, Restricted) enable fine-grained control
- Privacy decisions are context-dependent (work vs. personal content)
- Compliance with privacy regulations (GDPR, CCPA)
Trade-offs:
- Pro: User control; regulatory compliance; flexible visibility rules
- Con: Complex access control logic; potential performance impact on content delivery
Example: Alice shares vacation photos with "Close Friends" list, work updates with "Public" visibility, and personal thoughts with "Only Me" privacy.
9. Graph Traversal for Friend Suggestions
Decision: Use Breadth-First Search (BFS) with mutual friend counting for connection suggestions.
Rationale:
- Friends-of-friends are statistically likely to become friends
- BFS ensures shortest social distance
- Mutual friend count is a strong predictor of connection probability
- Efficient for limited search depth (2-3 levels)
Trade-offs:
- Pro: Simple implementation; interpretable results; good accuracy
- Con: Doesn't consider shared interests, location, or other signals; limited scalability
Example: The algorithm suggests Bob to Alice because they have 5 mutual friends (Charlie, David, Eve, Frank, Grace), even though they've never met.
10. Message Delivery with Read Receipts
Decision: Implement real-time message delivery with WebSocket and offline queuing with read receipt tracking.
Rationale:
- Users expect instant messaging experience
- WebSocket enables push-based delivery without polling
- Offline users should receive messages when they reconnect
- Read receipts provide sender confirmation
- Fallback to Push/Email notifications ensures message visibility
Trade-offs:
- Pro: Real-time experience; reliability; user awareness
- Con: Complex delivery infrastructure; privacy concerns with read receipts; increased server load
Example: When Alice sends a message to Bob at 2:00 PM, if Bob is online, he receives it via WebSocket within 100ms. If offline, the message queues and Bob receives a push notification. When Bob reads the message at 2:15 PM, Alice sees "Read at 2:15 PM."