Skip to main content

Stories Feature

The Stories feature enables users to share temporary, ephemeral content that automatically expires after 24 hours, creating a more casual and spontaneous way to share moments.

What Stories Do in This Project​

The story system provides a temporary content sharing platform that encourages spontaneous, authentic sharing without the permanence of regular posts. It serves multiple critical purposes:

1. Spontaneous Content Sharing​

  • Encourages casual, in-the-moment sharing without pressure
  • Lower barrier to posting (temporary, less formal than posts)
  • Fosters authentic, unfiltered content
  • Creates urgency and FOMO (fear of missing out) due to 24-hour expiration

2. Enhanced User Engagement​

  • Stories appear at the top of feeds, increasing visibility
  • 24-hour expiration creates urgency to view content
  • Interactive features (reactions, replies) drive engagement
  • Story rings indicate who has new content, encouraging exploration

3. Real-Time Activity Updates​

  • Shows what friends are doing right now
  • Provides live, current updates from your network
  • Creates sense of connection and presence
  • Encourages frequent app usage to check stories

4. Privacy & Control​

  • Stories have separate privacy settings from posts
  • Can be more casual since they're temporary
  • Users can archive stories before expiration
  • View tracking provides insights into who's watching

5. Personalized Feed Algorithm​

  • ML-powered recommendation system ranks stories
  • Prioritizes stories from close friends and frequent interactions
  • Considers relationship strength and engagement history
  • Balances recency with personalization

6. Content Analytics​

  • Tracks story views with duration and quality metrics
  • Monitors reactions and replies
  • Provides insights into story performance
  • Helps users understand their audience

7. System Integration​

  • Automatically expires after 24 hours
  • Integrates with media processing for images/videos
  • Uses background workers for cleanup and analytics
  • Connects with recommendation system for personalized feeds

Overview​

Stories enable users to:

  • Share temporary photos and videos (24-hour expiration)
  • Add captions and text overlays
  • Control who can see stories (privacy settings)
  • Track who viewed their stories
  • React and reply to stories
  • View personalized story feeds
  • Archive stories before expiration

How Stories Work​

Story Lifecycle​

  1. Creation: User uploads media (image/video) with optional caption
  2. Media Processing: Background worker processes and optimizes media
  3. Storage: Story saved with 24-hour expiration timestamp
  4. Visibility: Story appears in feeds based on privacy settings
  5. Viewing: Users view stories, tracked with duration and quality
  6. Interactions: Users react, reply, or share stories
  7. Expiration: After 24 hours, story is automatically archived
  8. Cleanup: Background job archives expired stories and cleans up media

Story Storage​

Stories are stored with their media files and metadata. The system maintains:

  • Story entities with expiration timestamps
  • Media file references for images and videos
  • View tracking and interaction data
  • Privacy settings and visibility rules

Automatic Story Processing​

When a story is created:

  • Media file is uploaded and processed
  • Story entity is created with 24-hour expiration
  • Story appears in feeds based on privacy settings
  • Background workers handle media processing
  • Analytics track views and interactions

Creating Stories​

Upload a Story​

Purpose: Create a new story by uploading an image or video. This is the primary way users share temporary content that will expire after 24 hours.

Use Cases:

  • Share a moment from your day
  • Post a quick update or status
  • Share photos or videos casually
  • Create temporary content without permanence

When to Use:

  • User wants to share something temporary
  • Quick, casual content sharing
  • Real-time updates and moments
  • Content that doesn't need to be permanent

File Requirements:

  • Images: JPEG, PNG, GIF, WebP
  • Videos: MP4, WebM, MOV
  • Max File Size: 100MB
  • Processing: Media is processed in background after upload

Upload a story with media:

Upload a Story​

POST /api/Story/users/{userId}
Content-Type: multipart/form-data

{
"media": file, // image or video
"type": "image", // or "video"
"privacy": "friends" // or "public", "custom"
}

Response:

{
"success": true,
"data": {
"storyId": "story-guid",
"mediaFileId": "media-guid",
"tempUrl": "https://...",
"status": "Processing",
"expiresAt": "2024-01-16T10:00:00Z",
"message": "Story created successfully. Media is processing in background.",
"expiresInHours": 24
}
}

Note: Media processing happens in the background. The story may not be immediately viewable until processing completes.

Add Text to Story​

Purpose: Create a text-only story with custom background color. Useful for sharing thoughts, quotes, or announcements without media.

Use Cases:

  • Share a quote or thought
  • Make an announcement
  • Create text-based content
  • Share status updates

When to Use:

  • User wants to share text without media
  • Creating announcements or quotes
  • Quick text-based updates
POST /api/Story/users/{userId}
Content-Type: application/json

{
"content": "Check out my day!",
"type": "text",
"backgroundColor": "#FF5733"
}

Viewing Stories​

Purpose: Get personalized story feed with ML-powered recommendations. Stories are ranked based on relationship strength, interaction history, recency, and popularity. This is the recommended endpoint for story feeds.

Use Cases:

  • Display personalized story feed
  • Show stories from close friends first
  • Prioritize content user engages with
  • Balance recency with personalization

When to Use:

  • Loading story feed on app startup
  • Refreshing story feed
  • Implementing infinite scroll
  • Displaying personalized story recommendations

Recommendation Algorithm:

  • Relationship Score: Close friends' stories ranked higher
  • Interaction Score: Stories from users you frequently engage with
  • Recency Score: Newer stories get priority
  • Popularity Score: Trending stories from your network
GET /api/story/feed/{userId}/recommended?limit=50&skip=0&includeScoreDetails=false
Authorization: Bearer {token}

Query Parameters:

  • userId (required) - Current user ID
  • limit (optional) - Stories per page (default: 50, max: 100)
  • skip (optional) - Stories to skip for pagination (default: 0)
  • includeScoreDetails (optional) - Include recommendation score breakdown (default: false)

Response:

{
"success": true,
"data": {
"stories": [
{
"storyId": "story-guid",
"userId": "user-guid",
"username": "johndoe",
"avatarUrl": "https://...",
"mediaUrl": "https://...",
"caption": "At the beach!",
"createdAt": "2024-01-15T10:30:00Z",
"expiresAt": "2024-01-16T10:30:00Z",
"recommendationScore": 87.5,
"scoreDetails": {
"recencyScore": 92.0,
"interactionScore": 85.0,
"relationshipScore": 90.0,
"popularityScore": 78.0
}
}
],
"totalCount": 25
}
}

Get Active Stories (Legacy)​

Purpose: Get active stories ordered by creation time. This endpoint is deprecated in favor of the recommended endpoint which provides personalized rankings.

Note: Use /feed/{userId}/recommended instead for better user experience.

GET /api/story/feed/{userId}?limit=50
Authorization: Bearer {token}

Get User's Active Stories​

Purpose: Get all active (non-expired) stories for a specific user. Used to display a user's story collection when viewing their profile or story ring.

Use Cases:

  • Display user's story collection
  • Show stories when clicking story ring
  • View all stories from a specific user
  • Check if user has active stories

When to Use:

  • User clicks on someone's story ring
  • Viewing user's profile stories
  • Checking if user has active stories
  • Displaying user's story timeline
GET /api/story/users/{userId}/active?requestingUserId={requestingUserId}
Authorization: Bearer {token}

Path Parameters:

  • userId - User ID whose stories to retrieve

Query Parameters:

  • requestingUserId (optional) - ID of user making request (for privacy checks)

Response:

{
"success": true,
"data": [
{
"storyId": "story-guid",
"mediaUrl": "https://...",
"caption": "My story",
"createdAt": "2024-01-15T10:00:00Z",
"expiresAt": "2024-01-16T10:00:00Z",
"viewCount": 25
}
]
}

Get Story by ID​

Purpose: Retrieve a specific story by its ID. Used when viewing a single story or navigating to a story from a notification or link.

Use Cases:

  • Viewing a specific story
  • Opening story from notification
  • Navigating to story from link
  • Validating story exists and user has access

When to Use:

  • User clicks on a story
  • Opening story from deep link
  • Validating story access
  • Loading story details

Security: Only returns stories the requesting user has permission to view based on privacy settings.

GET /api/story/{storyId}?requestingUserId={requestingUserId}
Authorization: Bearer {token}

Response:

{
"success": true,
"data": {
"storyId": "story-guid",
"userId": "user-guid",
"username": "johndoe",
"avatarUrl": "https://...",
"mediaUrl": "https://...",
"caption": "Check out my day!",
"createdAt": "2024-01-15T10:00:00Z",
"expiresAt": "2024-01-16T10:00:00Z",
"viewCount": 25,
"reactionCount": 5,
"replyCount": 2,
"isExpired": false,
"timeUntilExpiration": "18:30:00"
}
}

Check Users with Active Stories​

Purpose: Check which users from a list have active stories visible to the requesting user. Used to display story ring indicators in user lists, friend lists, or feeds.

Use Cases:

  • Display story ring indicators in user lists
  • Show which friends have new stories
  • Update story indicators in real-time
  • Filter users with active stories

When to Use:

  • Loading user list with story indicators
  • Refreshing story ring status
  • Displaying friend list with story indicators
  • Batch checking story availability

Performance: Optimized for batch queries (up to 1000 users).

POST /api/story/check-active?requestingUserId={requestingUserId}
Authorization: Bearer {token}
Content-Type: application/json

["user-guid-1", "user-guid-2", "user-guid-3"]

Response:

{
"success": true,
"data": {
"user-guid-1": true,
"user-guid-2": false,
"user-guid-3": true
}
}

Get User Story History​

Purpose: Get paginated history of all stories for a user (including expired). Only accessible by the story owner. Used for viewing past stories.

Use Cases:

  • View your own story history
  • Browse past stories you've shared
  • Review story archive
  • Access expired stories (owner only)

When to Use:

  • User wants to see their story history
  • Browsing past stories
  • Reviewing story archive
  • Accessing expired stories

Security: Only the story owner can access their history.

GET /api/story/users/{userId}/history?requestingUserId={userId}&page=1&pageSize=20
Authorization: Bearer {token}

Query Parameters:

  • requestingUserId (required) - Must match userId (owner only)
  • page (optional) - Page number (default: 1)
  • pageSize (optional) - Items per page (default: 20, max: 100)

Get Archived Stories​

Purpose: Get paginated list of archived stories for a user. Includes both manually archived and auto-archived (expired) stories.

Use Cases:

  • View archived stories
  • Browse expired stories
  • Review story archive
  • Access manually archived content

When to Use:

  • User wants to see archived stories
  • Browsing story archive
  • Reviewing past content

Security: Only the story owner can access their archived stories.

GET /api/story/users/{userId}/archived?requestingUserId={userId}&page=1&pageSize=20
Authorization: Bearer {token}

Story Interactions​

View Story​

Purpose: Track when a user views a story. Records view timestamp, duration, and view quality. Prevents duplicate view counts if user views the same story multiple times.

Use Cases:

  • Track story views for analytics
  • Record view duration for engagement metrics
  • Calculate view quality (how much of story was watched)
  • Prevent duplicate view counts

When to Use:

  • User opens a story
  • Story is displayed in viewer
  • Tracking story engagement
  • Updating view counts

View Tracking:

  • First view: Creates new view record
  • Subsequent views: Updates duration if longer (doesn't create duplicate)
  • View quality: Calculated based on duration vs. story length
  • Analytics: Used for recommendation algorithm
POST /api/story/{storyId}/views?userId={userId}
Authorization: Bearer {token}
Content-Type: application/json

{
"viewDurationSeconds": 15
}

Request Body:

  • viewDurationSeconds (required) - How long user viewed the story in seconds

Response:

{
"success": true,
"message": "Story view tracked successfully"
}

React to Story​

Purpose: Add a reaction to a story (like, love, haha, dislike, share). Reactions allow users to express their feelings about story content.

Use Cases:

  • User likes a story
  • Express emotions about story content
  • Quick engagement without commenting
  • Show appreciation for story

When to Use:

  • User taps reaction button on story
  • Quick engagement gesture
  • Expressing feelings about content

Reaction Types: like, love, haha, dislike, share

POST /api/story/{storyId}/reactions?userId={userId}
Authorization: Bearer {token}
Content-Type: application/json

{
"reaction": "like"
}

Response:

{
"success": true,
"message": "Reaction added successfully"
}

Reply to Story​

Purpose: Send a direct message reply to a story. Replies are sent as private messages to the story owner, not displayed publicly on the story.

Use Cases:

  • Comment on someone's story privately
  • Ask questions about story content
  • Engage in conversation about story
  • Provide feedback privately

When to Use:

  • User wants to comment on a story
  • Asking questions about content
  • Private engagement with story owner

Note: Replies are sent as direct messages, not displayed on the story itself.

POST /api/story/{storyId}/replies
Authorization: Bearer {token}
Content-Type: application/json

{
"content": "Great story!"
}

Story Viewers​

Get Story Viewers​

Purpose: Get list of users who viewed a story with their view details. Only accessible by the story owner. Provides insights into who watched the story and how they engaged.

Use Cases:

  • See who viewed your story
  • Check view engagement metrics
  • Analyze story performance
  • Understand audience

When to Use:

  • Story owner wants to see viewers
  • Analyzing story engagement
  • Checking who watched content
  • Reviewing story analytics

Security: Only the story owner can access viewer list.

Response Includes:

  • User information (name, avatar)
  • View timestamp (when they viewed)
  • View duration (how long they watched)
  • View quality (engagement level)
  • Interaction status (reacted, replied)
GET /api/story/{storyId}/viewers?requestingUserId={userId}
Authorization: Bearer {token}

Response:

{
"success": true,
"data": [
{
"userId": "user-guid",
"username": "janedoe",
"fullName": "Jane Doe",
"avatarUrl": "https://...",
"viewedAt": "2024-01-15T10:05:00Z",
"viewDurationSeconds": 12,
"viewQuality": "High",
"hasReacted": true,
"hasReplied": false
}
],
"totalViewers": 25,
"totalReactions": 5,
"totalReplies": 2
}

Story Management​

Archive Story​

Purpose: Manually archive a story before it expires. Archived stories are removed from feeds but can still be accessed by the owner in their archive.

Use Cases:

  • Remove story from feed before expiration
  • Hide story from viewers
  • Keep story for personal archive
  • Control story visibility

When to Use:

  • User wants to remove story early
  • Story is no longer relevant
  • Hide story from public view
  • Archive story for later

Note: Archiving triggers cleanup of analytics data via domain events.

POST /api/story/{storyId}/archive?userId={userId}
Authorization: Bearer {token}

Security: Only the story owner can archive their stories.

Delete Story​

Purpose: Permanently delete a story. This action cannot be undone and removes the story and its media files.

Use Cases:

  • Permanently remove unwanted story
  • Delete story with sensitive content
  • Remove story that shouldn't have been posted
  • Complete story removal

When to Use:

  • User wants to permanently delete story
  • Story contains sensitive information
  • Complete removal needed

Warning: This action is permanent. Consider archiving instead if you might want to access it later.

DELETE /api/story/{storyId}?userId={userId}
Authorization: Bearer {token}

Security: Only the story owner can delete their stories.

Story Expiration​

Automatic Expiration​

Stories automatically expire after 24 hours from creation. The expiration system ensures temporary content is removed as intended.

Expiration Process:

  1. Background Job: StoryCleanupJob runs periodically (typically every hour)
  2. Detection: Finds stories where ExpiresAt <= DateTime.UtcNow and not archived
  3. Archiving: Automatically archives expired stories
  4. Cleanup: Triggers domain events for analytics cleanup
  5. Cache Clear: Clears story-related caches
  6. Media Cleanup: Media files may be deleted after archival period

What Happens When Story Expires:

  • Story is automatically archived
  • Removed from active story feeds
  • No longer visible to other users
  • Owner can still access in archive
  • Analytics data is cleaned up
  • Media files may be deleted after grace period

Time Until Expiration​

Each story tracks:

  • CreatedAt: When story was created
  • ExpiresAt: When story will expire (CreatedAt + 24 hours)
  • TimeUntilExpiration: Calculated remaining time

Display: UI typically shows countdown or "X hours left" indicator.

Privacy Settings​

Stories have privacy settings that control who can see them:

SettingDescriptionWho Can See
PublicVisible to everyoneAll users, including non-friends
FriendsVisible to friends onlyOnly confirmed friends (default)
OnlyMePrivate storyOnly the story owner

Privacy Behavior:

  • Privacy is checked when fetching story feeds
  • Story rings only show for stories user can view
  • View tracking respects privacy settings
  • Recommendations consider privacy when ranking

Setting Privacy:

POST /api/story/users/{userId}
{
"media": file,
"caption": "My story",
"visibility": "Friends" // "Public", "Friends", "OnlyMe"
}

Story Architecture​

System Components​

  1. Domain Layer (Domain/Modules/Story)

    • Story aggregate with expiration logic
    • Story value objects (StoryId, Visibility)
    • Domain events for story lifecycle
  2. Application Layer (Application/Modules/Story)

    • Commands: Create, archive, delete, react, view
    • Queries: Get feed, get by ID, get viewers, get history
    • Event handlers for story events
  3. Infrastructure Layer

    • PostgreSQL: Story entities and relationships
    • Media Storage: S3 or local storage for media files
    • Redis: Caching for story feeds and active stories
    • Background Jobs: Story cleanup and expiration
  4. Background Workers

    • StoryCleanupJob: Archives expired stories
    • MediaProcessingWorker: Processes story media
    • Recommendation Workers: Calculate story scores

Story Flow​

User Creates Story
↓
Upload Media File
↓
Create Story Entity (24h expiration)
↓
Publish StoryCreatedEvent
↓
Background: Process Media
↓
Story Appears in Feeds
↓
Users View Story (tracked)
↓
Users React/Reply
↓
24 Hours Pass
↓
StoryCleanupJob Archives Story
↓
Publish StoryArchivedEvent
↓
Cleanup Analytics Data
↓
Media May Be Deleted

API Endpoints Summary​

Create Story​

Endpoint: POST /api/story/users/{userId}
Purpose: Upload and create a new story with media.

Key Features:

  • Supports images and videos
  • Optional caption
  • Privacy settings
  • Background media processing

When to Use: User wants to share a temporary story


Endpoint: GET /api/story/feed/{userId}/recommended
Purpose: Get personalized story feed with ML-powered rankings.

Key Features:

  • Personalized recommendations
  • Relationship-based ranking
  • Interaction history considered
  • Pagination support

When to Use: Loading story feed, displaying personalized stories


Get User Active Stories​

Endpoint: GET /api/story/users/{userId}/active
Purpose: Get all active stories for a specific user.

Key Features:

  • Privacy-aware
  • Returns non-expired stories only
  • Used for story rings

When to Use: Displaying user's story collection, story rings


View Story​

Endpoint: POST /api/story/{storyId}/views
Purpose: Track story views with duration and quality metrics.

Key Features:

  • Prevents duplicate views
  • Tracks view duration
  • Calculates view quality
  • Updates analytics

When to Use: User views a story, tracking engagement


React to Story​

Endpoint: POST /api/story/{storyId}/reactions
Purpose: Add reactions to stories (like, love, haha, etc.).

Key Features:

  • Multiple reaction types
  • Quick engagement
  • Updates reaction counts

When to Use: User reacts to story content


Get Story Viewers​

Endpoint: GET /api/story/{storyId}/viewers
Purpose: Get list of users who viewed a story (owner only).

Key Features:

  • View details (timestamp, duration)
  • Interaction status
  • Engagement metrics

When to Use: Story owner wants to see who viewed


Archive Story​

Endpoint: POST /api/story/{storyId}/archive
Purpose: Manually archive a story before expiration.

Key Features:

  • Removes from feeds
  • Owner can still access
  • Triggers cleanup

When to Use: User wants to remove story early


Delete Story​

Endpoint: DELETE /api/story/{storyId}
Purpose: Permanently delete a story.

Key Features:

  • Permanent removal
  • Deletes media files
  • Cannot be undone

When to Use: Complete story removal needed

Best Practices​

For Users​

  1. Share Authentic Moments: Stories are perfect for casual, in-the-moment content
  2. Use Captions: Add captions to provide context and increase engagement
  3. Check Privacy: Review privacy settings before posting
  4. Engage with Stories: View, react, and reply to friends' stories
  5. Archive When Needed: Archive stories early if they're no longer relevant
  6. Check Viewers: Review who viewed your stories to understand your audience
  7. Post Regularly: Regular story updates keep you visible in friends' feeds

For Developers​

  1. Real-Time Updates: Use WebSocket for real-time story updates
  2. Caching: Cache story feeds for performance (with short TTL due to expiration)
  3. Media Processing: Handle media processing asynchronously
  4. Expiration Handling: Check expiration status before displaying stories
  5. Privacy Checks: Always validate privacy settings before returning stories
  6. View Tracking: Track views accurately without duplicates
  7. Background Jobs: Use background jobs for cleanup and expiration
  8. Recommendations: Use recommended endpoint for better UX
  9. Pagination: Always paginate story feeds for performance
  10. Error Handling: Handle expired stories gracefully in UI

Story Content Tips​

  1. Visual Content: Stories work best with photos and videos
  2. Keep It Short: Stories are meant to be quick, engaging content
  3. Use Text Overlays: Add text to images for context
  4. Timing Matters: Post when your audience is active
  5. Engage Back: Reply to story replies to build connections

Learn More​