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