F6: Newsfeed Interaction Flow - Feature Analysis¶
Overview¶
The Newsfeed feature provides users with a curated collection of AI-focused news articles aggregated from verified external sources. This feature serves as a central hub for users to discover, engage with, and save relevant industry news. Each article is presented in a card format with metadata including source, publication date, read time, and view count. The news items are curated by admin approval to ensure quality and relevance. Users can search, filter, and sort articles based on various criteria, as well as save favorites for later reference. The newsfeed is designed to be responsive, accessible, and optimized for quick scanning while providing personalization features for authenticated users.
API Endpoints¶
1. Fetch Newsfeed Articles¶
GET /api/newsfeed/
search(string, optional): Text search query for article title or content.
Response:
{
"count": 245,
"next": "https://api.futrconnect.com/api/newsfeed/",
"previous": null,
"results": [
{
"id": "uuid-string",
"headline": "Breakthrough in Generative AI for Scientific Research",
"description": "A team of researchers has developed a new generative AI model that can assist in scientific hypothesis generation across multiple domains.",
"url": "https://www.technologyreview.com/article/123456",
"image_url": "https://storage.futrconnect.com/news/article-hero-image.jpg",
"published_date": "2025-05-15T09:30:00Z",
"is_favorited": false,
"views_count": 1205,
"minute_read": 4
}
// Additional news items...
]
}
2. Favorite News Article¶
POST /api/newsfeed-favorite/
Request Body:
{
"news_feed": "news-feed-uuid"
}
Response (201 Created):
{
"id": "uuid-string",
"news_feed": "news-feed-uuid"
}
3. Get User’s Favorited News Articles¶
GET /api/newsfeed-favorite/
Response:
{
"count": 18,
"next": "https://api.futrconnect.com/api/newsfeed-favorite/",
"previous": null,
"results": [
{
"id": "uuid-string",
"news_feed": {
"id": "uuid-string",
"headline": "Breakthrough in Generative AI for Scientific Research",
"description": "A team of researchers has developed a new generative AI model that can assist in scientific hypothesis generation across multiple domains.",
"url": "https://www.technologyreview.com/article/123456",
"published_date": "2025-05-15T09:30:00Z",
"interests": ["uuid-string"]
}
}
// Additional favorited news items...
]
}
4. Track Article View¶
POST /api/newsfeed-view-count/
Request Body:
{
"news_feed": "news-feed-uuid"
}
Response (201 Created):
{
"id": "uuid-string",
"news_feed": "news-feed-uuid"
}
State Management¶
React-query¶
interface NewsFeedData {
id: string;
created_on: string;
edited_on: string;
headline: string;
url: string;
published_date: string;
description: string;
image_url: string;
minute_read: number;
views_count: number;
is_active: boolean;
is_favourite: boolean;
is_viewed: boolean;
thumbnail_image: null | string;
}
interface SaveNews {
created_on: string;
edited_on: string;
headline: string;
id: string;
image_url: null | string;
news_feed: string;
url: string;
user: string;
views_count: number;
thumbnail_image: null | string;
}
MobX-State-Tree Models¶
NewsfeedStore¶
Model NewsfeedStore {
// Actions
updateNewsFavorite({newsId})
increaseViewCount({newsId})
}
Database Models¶
PostgreSQL Models¶
NewsFeed¶
id(UUID, primary key)headline(varchar, required)url(URLField, unique, required)description(text, nullable)image_url(URLField, nullable)thumbnail_image(ImageField, nullable)minute_read(PositiveIntegerField, default: 0)views_count(PositiveIntegerField, default: 0)is_active(boolean, default: false)
FavoriteNewsFeed¶
id(UUID, primary key)news_feed(ForeignKey to NewsFeed)user(ForeignKey to User)
NewsFeedView¶
id(UUID, primary key)news_feed(ForeignKey to NewsFeed)user(ForeignKey to User)
Algorithms¶
News Article Curation and Display¶
- Article Collection Process:
- News articles are sourced from external APIs and RSS feeds
- Admin approves articles before they appear in newsfeed
- Steps:
- Scheduled background job fetches articles from sources
- Natural language processing filters for AI relevance
- De-duplication algorithm removes duplicate stories
- Admin reviews and approves articles
- Approved articles appear in the newsfeed
- View Count Calculation Algorithm:
- View tracking uses a combination of strategies:- Count unique user views (for authenticated users)
- Use session/cookie tracking for anonymous users
- Implement cooldown period to prevent duplicate counts
- Implementation:
Backend Logic¶
News Article Management¶
The backend provides a simple system for managing news articles through the NewsFeedViewSet.
-
Article Creation: News articles are created and managed through the admin panel or direct API interactions. There is no automated fetching from external sources.
-
View Count: The
NewsFeedViewmodel is used to track when a user views a news article. Theviews_counton theNewsFeedmodel is incremented for each view. -
Favoriting: The
FavoriteNewsFeedmodel andFavoriteNewsFeedViewSethandle the logic for users favoriting and unfavoriting news articles.
Performance and Optimization¶
Database Query Optimization¶
The backend relies on the following to ensure efficient database queries:
-
Indexing: The
NewsFeedmodel has database indexes on thepublished_dateandis_activefields to speed up filtering and sorting. -
Pagination: The API uses Django REST Framework’s standard
PageNumberPaginationto limit the number of results returned per request. -
Read Time Estimation Algorithm:
- Calculate estimated reading time based on word count
- Consider language complexity and presence of technical terms
- Implementation:
def calculate_read_time(word_count, complexity_factor=1.0): """ Calculate estimated read time in minutes Average reading speed: ~200-250 words per minute complexity_factor: adjust for technical content """ # Base reading speed: 225 words per minute base_reading_speed = 225 # Adjust for content complexity (technical AI content) adjusted_speed = base_reading_speed / complexity_factor # Calculate minutes minutes = word_count / adjusted_speed # Round up to nearest minute, minimum 1 minute return max(1, math.ceil(minutes)) -
News Relevance Ranking:
- Default sorting by published date (newest first)
- Alternative sorting options:
- View count (most popular)
- Alphabetical by title
- Future: Personalized relevance based on user interests
- Implementation using Django ORM’s order_by and annotate
Favorite/Unfavorite Mechanism¶
- Favorite Process:
- Create an entry in UserFavorite table linking user to article
- Handle duplicate favorite attempts gracefully
- Update client state optimistically for responsive UI
- Steps:
- Validate user authentication
- Check if favorite relationship already exists
- Create new UserFavorite record if not
- Return success response with favorite details
- Unfavorite Process:
- Remove entry from UserFavorite table
- Handle unfavoriting non-favorited articles gracefully
- Update client state optimistically for responsive UI
- Steps:
- Validate user authentication
- Find existing favorite relationship
- Delete UserFavorite record if found
- Return success response
- Favorite Status Synchronization:
- Maintain consistent favorite status across different views
- Store favorite status in local state for quick access
- Sync with server periodically to handle multi-device scenarios
- Implementation:- Use React Context to share favorite state across components
- Update local state optimistically on favorite/unfavorite actions
- Sync with server on page load or at regular intervals
Performance and Optimization¶
Database Optimization¶
- Indexing Strategy:
- Create index on
published_datefor efficient sorting - Create index on
view_countfor popular sorting - Create full-text search index on
titleandcontent - Implementation:
# In Django model Meta class indexes = [ models.Index(fields=['published_date']), models.Index(fields=['view_count']), # For PostgreSQL full-text search GinIndex(fields=['search_vector']) ]
- Caching Implementation:
- Cache newsfeed results with reasonable TTL
- Implement separate cache for popular and recent articles
-
Example implementation:
# Cache keys with varying TTLs based on content freshness cache_key = f"newsfeed:{sort_by}:{sort_order}:{filter_hash}" # Recent news (short TTL) if sort_by == 'published_date': cache_ttl = 60 * 15 # 15 minutes # Popular news (longer TTL) elif sort_by == 'view_count': cache_ttl = 60 * 60 # 1 hour # Default else: cache_ttl = 60 * 30 # 30 minutes cached_data = cache.get(cache_key) if not cached_data: # Fetch from database queryset = NewsArticle.objects.filter(**filters) serializer = NewsArticleSerializer(queryset, many=True) cached_data = serializer.data cache.set(cache_key, cached_data, timeout=cache_ttl)
- Query Optimization:
- Use
select_relatedfor related data - Implement materialized views for complex aggregations
- Batch load favorite status for authenticated users:
# Annotate articles with favorited status for current user if request.user.is_authenticated: user_favorites = UserFavorite.objects.filter(user_id=request.user.id) articles = articles.annotate( is_favorited=Exists( user_favorites.filter(article_id=OuterRef('pk')) ) )
- Read/View Tracking Optimization:
- Use background tasks for view count updates
- Implement write-behind caching for view tracking
-
Batch update view counts periodically:
@background_task def update_view_counts(): """Update article view counts in batch""" # Get view counts from cache view_counts = cache.get_many(cache.keys('article_views:*')) # Update database in bulk with transaction.atomic(): for article_id, count in view_counts.items(): article_id = article_id.split(':')[1] NewsArticle.objects.filter(pk=article_id).update( view_count=F('view_count') + count ) # Clear the cache entries cache.delete_many(view_counts.keys())
Frontend Optimization¶
- Virtualized Lists and Infinite Scrolling:
- Implement virtualized rendering for large newsfeed lists - Load articles on-demand as user scrolls - Use React Virtualized or similar libraries:
const NewsFeedSidebar = () => {
const { userStore } = useStores();
const [openFeaturedModal, setOpenFeaturedModal] = useState(false);
const { submit } = useSubmitFeaturedData();
const [searchQuery, setSearchQuery] = useState("");
const [debounceSearch] = useDebounce(searchQuery, 1000);
const [filter, setFilter] = (useState < Filters) | (null > null);
// api for fetching save news feed data
const {
data: saveNewsFeedData,
hasNextPage,
isLoading: loadingSaveNewsFeed,
fetchNextPage,
isFetching: fetchingSaveNewsFeedData,
} = useInfiniteQuery({
queryKey: newsFeed.getFavoriteList(debounceSearch, filter),
queryFn: ({ pageParam }) => getFavoriteNewsList({ search: debounceSearch, page: pageParam, pageSize: 10, sort: filter?.ordering }),
getNextPageParam: (lastPage) => {
if (!lastPage.next) return undefined;
const url = new URL(lastPage.next);
const nextPage = url.searchParams.get("page");
return nextPage ? parseInt(nextPage, 10) : undefined;
},
initialPageParam: 1,
enabled: !!userStore.loggedInUserData?.user?.id || false,
});
const saveNewsFeedDataList = saveNewsFeedData?.pages?.flatMap((page) => page.results) || [];
console.log(JSON.stringify(saveNewsFeedDataList, null, 2));
const { lastElementRef } = useInfiniteScrollObserver({
hasNextPage: hasNextPage,
isLoading: fetchingSaveNewsFeedData,
fetchNextPage: fetchNextPage,
});
const getFeaturedButtonClick = () => {
if (userStore.loggedInUserData?.user?.id) {
setOpenFeaturedModal(true);
} else {
userStore.updateAuthModalState(true);
}
};
return (
<motion.div className="flex flex-col lg:gap-[48px]" initial="hidden" animate="visible" variants={containerVariants}>
<motion.div className="bg-white px-4 py-5 rounded-[4px]" variants={itemVariants}>
<motion.div variants={buttonVariants} whileHover="hover" whileTap="tap">
<GetFeaturedButtonWithTooltip onClick={getFeaturedButtonClick} />
</motion.div>
</motion.div>
<motion.div variants={itemVariants} className="mt-2">
<Sticky boundaryElement=".block" hideOnBoundaryHit={false}>
<SidebarWithSearchAndFilter
title="Saved AI News"
searchQuery={searchQuery}
setSearchQuery={setSearchQuery}
description="List of Saved AI News"
filter={
<DropdownMenu>
<DropdownMenuTrigger asChild>
<FilterIcon />
</DropdownMenuTrigger>
<DropdownMenuContent>
{sortBy.map((data, idx) => (
<DropdownMenuItem
key={idx}
onSelect={() => {
if (data.value === "reset") {
setFilter(null);
} else {
setFilter((e) => (e ? { ...e, ordering: data.value } : { ordering: data.value }));
}
}}>
{data.title}
{filter?.ordering == data.value && <Check />}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
}>
{loadingSaveNewsFeed &&
[1, 2, 3].map((val) => (
<motion.div key={val} initial={{ opacity: 0, y: 40 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.6, ease: "easeOut" }}>
<Skeleton className="h-[10vh] w-[100%] rounded-[10px]" />
</motion.div>
))}
{saveNewsFeedDataList.length == 0 && !loadingSaveNewsFeed && (
<Alert>
<AlertTitle>{debounceSearch ? "Don't have saved news for search query" : !userStore.loggedInUserData?.user?.id ? "Login for saved news" : "You haven’t saved any news yet."}</AlertTitle>
</Alert>
)}
{saveNewsFeedDataList.map((feed, idx) => {
if (idx + 1 == saveNewsFeedDataList.length) {
return (
<div key={feed.id} ref={lastElementRef}>
<Link href={feed.url} target="_blank" rel="noopener noreferrer">
<NewsFeedCard id={feed.news_feed} headline={feed.headline} feedImg={feed.image_url || feed?.thumbnail_image} views={feed.views_count} />
</Link>
</div>
);
} else {
return (
<div key={feed.id}>
<Link href={feed.url} target="_blank" rel="noopener noreferrer">
<NewsFeedCard id={feed.news_feed} headline={feed.headline} feedImg={feed.image_url} views={feed.views_count} />
</Link>
</div>
);
}
})}
</SidebarWithSearchAndFilter>
</Sticky>
</motion.div>
{openFeaturedModal && <GetFeaturedModal open={openFeaturedModal} onClose={() => setOpenFeaturedModal(false)} onFormSubmit={submit} />}
</motion.div>
);
};
- Image Optimization:
- Implement lazy loading for article images
- Use responsive images with appropriate sizes
- Leverage modern image formats (WebP with fallbacks)
-
Example component:
<Image src={feedImg ? feedImg : "/images/news-wallpaper-two.png"} alt="feed_img" width={150} height={70} className="w-[150px] flex-1 h-[70px] object-cover rounded-sm" />
- Content Delivery Network:
- Use CDN for delivering article images and source logos
- Implement cache headers for optimal delivery
- Leverage edge caching for global performance
Technical Considerations¶
Cross-Device Compatibility¶
- Implement responsive layout using Tailwind CSS grid system
- Adjust card sizes and layout based on viewport:
- Desktop: 3-column grid with sidebar
- Tablet: 2-column grid with collapsible sidebar
- Mobile: Single column with bottom drawer for saved articles
- Ensure touch targets are appropriately sized for mobile
Language Support¶
- Currently, the website is implemented in a single language (English)
- No language-switching capability in the current implementation
- All content, including article titles and content, is in English
- Data structures are designed to support future localization if needed
Authentication Integration¶
- Anonymous users can view and search articles
- Authentication required for favoriting articles
- Handle authentication states for favorite button:
- Unauthenticated: Prompt login when attempting to favorite
- Authenticated: Allow immediate interaction
- Maintain proper auth state during navigation
Potential Bottlenecks¶
- Search Performance:
- Challenge: Full-text search can become slow with large article database
- Solution: Implement caching for common search queries
- Solution: Consider dedicated search service (Elasticsearch) for large scale
- Solution: Use typeahead search with debouncing
- Image Loading Performance:
- Challenge: Multiple article images loading simultaneously
- Solution: Implement priority loading for visible content
- Solution: Use appropriate image sizes and formats
- Solution: Consider content-aware image loading strategies
- Database Load from Multiple Filters:
- Challenge: Complex filter combinations can lead to slow queries
- Solution: Cache common filter combinations
- Solution: Implement query optimization techniques
- Solution: Monitor and optimize slow queries
Implementation Considerations¶
Frontend Implementation¶
- Component Architecture:
- Build reusable components:
NewsFeedCard: Main display component for news itemsNewsFeedSidebar: Right sidebar showing saved articlesSidebarWithSearchAndFilter: Component for search and filter UI
- Implement state management with MobX-State-Tree and useState
- Ensure proper loading, error, and empty states
- User Interface Design:
- Create distinctive visual treatment for news articles:
- Clear hierarchy of information (title, source, date)
- Visual cues for read time and view count
- Consistent favorite button placement and states
- Implement engagement indicators:
- Favorite count or status
- View count with appropriate formatting
- Read time estimation
- Interaction Design:
- Design responsive hover and click states
- Implement micro-animations for favorite actions
- Create intuitive loading states and transitions
- Design infinite scroll with appropriate loading indicators
Backend Implementation¶
- API Design:
- Implement RESTful endpoints for CRUD operations
- Add caching headers for performance optimization
- Include proper error handling and validation
-
Example controller implementation:
class NewsArticleViewSet(viewsets.ModelViewSet): queryset = NewsArticle.objects.filter(is_approved=True) serializer_class = NewsArticleSerializer filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter] filterset_fields = ['tags', 'source'] search_fields = ['title', 'content'] ordering_fields = ['published_date', 'view_count', 'title'] ordering = ['-published_date'] def get_serializer_context(self): context = super().get_serializer_context() context['request'] = self.request return context @action(detail=True, methods=['post']) def favorite(self, request, pk=None): article = self.get_object() user = request.user if not user.is_authenticated: return Response( {"detail": "Authentication required"}, status=status.HTTP_401_UNAUTHORIZED ) favorite, created = UserFavorite.objects.get_or_create( user=user, article=article, defaults={'favorited_at': timezone.now()} ) if not created: return Response( {"detail": "Already favorited"}, status=status.HTTP_200_OK ) return Response( UserFavoriteSerializer(favorite).data, status=status.HTTP_201_CREATED )
- External News Integration:
- Create robust RSS and API integrators
- Implement proper error handling for external sources
- Add rate limiting and retries for API calls
-
Example news fetcher:
@shared_task def fetch_news_from_sources(): """Fetch news from all configured sources""" for source in NewsSources.objects.filter(active=True): try: if source.source_type == 'rss': fetch_news_from_rss(source) elif source.source_type == 'api': fetch_news_from_api(source) except Exception as e: logger.error(f"Error fetching from {source.name}: {str(e)}") continue def fetch_news_from_rss(source): """Fetch news from RSS feed""" feed = feedparser.parse(source.url) for entry in feed.entries[:50]: # Limit to latest 50 # Extract data published_date = parse_date(entry.published) # Skip if too old if published_date < (timezone.now() - timedelta(days=7)): continue # Check for duplicate by URL or title if NewsArticle.objects.filter( Q(source_url=entry.link) | Q(title=entry.title, source=source.name) ).exists(): continue # Create article (not yet approved) article = NewsArticle( title=entry.title, summary=entry.summary[:200] + '...', content=entry.content[0].value if 'content' in entry else entry.summary, source=source.name, source_url=entry.link, source_logo_url=source.logo_url, published_date=published_date, is_approved=False ) # Extract image if available if 'media_content' in entry and entry.media_content: article.image_url = entry.media_content[0]['url'] # Calculate word count and read time article.word_count = len(article.content.split()) article.estimated_read_minutes = calculate_read_time(article.word_count) # Generate preview article.content_preview = article.content[:300] + '...' # Save to database article.save()
- Admin Interface:
- Create dedicated admin panel for news approval
- Include filters for pending/approved articles
- Add bulk actions for approval/rejection
- Implement preview functionality
Testing Strategy¶
- Component Testing:
- Unit tests for article card rendering
- Test favorite functionality with mocked API
- Snapshot tests for UI consistency
- Implementation with Playwright
- API Testing:
- Test newsfeed endpoint with various filters
- Test favorite/unfavorite functionality
- Validate view count incrementation
- Implementation with pytest and Django Rest Framework test client
- Integration Testing:
- E2E tests for user flows (browse, search, favorite)
- Test external source integration with mocked responses
- Performance tests for article loading
- Implementation with Playwright
Creative Suggestions¶
Enhanced Content Consumption¶
- Reading Mode:
- Implement a distraction-free reading mode for articles
- Include text size adjustment and theme options
- Add text-to-speech functionality for accessibility
- Save reading progress for long articles
- Content Collections:
- Allow users to create themed collections of saved articles
- Implement tagging and organization of saved content
- Enable sharing of collections with other users
- Add notes or highlights to saved articles
- Related Articles Panel:
- Show contextually related articles based on content similarity
- Use NLP to find semantic relationships between articles
- Display “People also read” suggestions at the end of articles
- Implement a “reading path” for topic exploration
Feature Suggestions¶
Content Discovery Enhancements¶
- Personalized News Feed:
- Implement AI-based content recommendations
- Learn from user behavior (articles viewed, favorites)
- Allow explicit topic following
- Create a “For You” section with personalized content
- Advanced Filtering:
- Add advanced search with boolean operators
- Implement date range sliders for temporal filtering
- Create company-specific news filters
- Allow filtering by article length or complexity
- Content Digests:
- Send periodic email digests of top news (daily/weekly)
- Create topic-specific digests based on user interests
- Implement “weekend reading” compilations of longer articles
- Add “In case you missed it” section for popular content
- News Alerts:
- Allow users to set up keyword-based alerts
- Implement browser notifications for breaking news
- Create company-specific news alerts
- Send notifications for significant developments in followed topics
- Content Calendar:
- Create a calendar view of upcoming AI events mentioned in news
- Allow users to save events to personal calendars
- Highlight conference and product release dates
- Integrate with community event listings
Additional Considerations¶
Accessibility Enhancements¶
- Implement proper ARIA attributes for interactive elements
- Ensure keyboard navigability for article browsing
- Add screen reader descriptions for visual elements
- Support text scaling and contrast modes
- Implement focus management for favorite actions
- Test with lighthouse
Analytics and Measurements¶
- Track detailed engagement metrics:
- Read-through rate (estimated vs. actual time spent)
- Favorite conversion rate
- Click-through to source rate
- Search and filter usage patterns
- Implement A/B testing for article layout
- Monitor source performance and reader preferences
- Use analytics to guide content curation
Content Moderation¶
- Implement automated content screening
- Create guidelines for news approval
- Develop flagging system for problematic content
- Establish review process for user-reported issues
- Use AI content moderation tools to assist human reviewers
Mobile Considerations¶
- Optimize article layout for mobile reading:
- Readable font sizes and line heights
- Touch-friendly favorite and share buttons
- Swipe gestures for navigation
- Offline reading capability
- Implement mobile-specific search and filter UI
- Test on various mobile devices and network conditions
Further Reading & Best Practices¶
- News Feed Design:
- Content Aggregation Best Practices:
- Reading Experience:
- View Tracking Implementation:
- Reading Time Algorithms:
- Medium’s Read Time Algorithm
- Improving Read Time Estimates