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

  1. Article Collection Process:
  • News articles are sourced from external APIs and RSS feeds
  • Admin approves articles before they appear in newsfeed
  • Steps:
    1. Scheduled background job fetches articles from sources
    2. Natural language processing filters for AI relevance
    3. De-duplication algorithm removes duplicate stories
    4. Admin reviews and approves articles
    5. Approved articles appear in the newsfeed
  1. 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.

  1. Article Creation: News articles are created and managed through the admin panel or direct API interactions. There is no automated fetching from external sources.

  2. View Count: The NewsFeedView model is used to track when a user views a news article. The views_count on the NewsFeed model is incremented for each view.

  3. Favoriting: The FavoriteNewsFeed model and FavoriteNewsFeedViewSet handle 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:

  1. Indexing: The NewsFeed model has database indexes on the published_date and is_active fields to speed up filtering and sorting.

  2. Pagination: The API uses Django REST Framework’s standard PageNumberPagination to limit the number of results returned per request.

  3. 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))
    
  4. 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

  1. 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:
    1. Validate user authentication
    2. Check if favorite relationship already exists
    3. Create new UserFavorite record if not
    4. Return success response with favorite details
  1. Unfavorite Process:
  • Remove entry from UserFavorite table
  • Handle unfavoriting non-favorited articles gracefully
  • Update client state optimistically for responsive UI
  • Steps:
    1. Validate user authentication
    2. Find existing favorite relationship
    3. Delete UserFavorite record if found
    4. Return success response
  1. 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:
    1. Use React Context to share favorite state across components
    2. Update local state optimistically on favorite/unfavorite actions
    3. Sync with server on page load or at regular intervals

Performance and Optimization

Database Optimization

  1. Indexing Strategy:
  • Create index on published_date for efficient sorting
  • Create index on view_count for popular sorting
  • Create full-text search index on title and content
  • 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'])
    ]
    
  1. 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)
    
  1. Query Optimization:
  • Use select_related for 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'))
        )
      )
    
  1. 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

  1. 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>
  );
};
  1. 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" />
    
  1. 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

  1. 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
  1. 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
  1. 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

  1. Component Architecture:
  • Build reusable components:
    • NewsFeedCard: Main display component for news items
    • NewsFeedSidebar: Right sidebar showing saved articles
    • SidebarWithSearchAndFilter: Component for search and filter UI
  • Implement state management with MobX-State-Tree and useState
  • Ensure proper loading, error, and empty states
  1. 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
  1. 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

  1. 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
            )
    
  1. 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()
    
  1. 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

  1. Component Testing:
  • Unit tests for article card rendering
  • Test favorite functionality with mocked API
  • Snapshot tests for UI consistency
  • Implementation with Playwright
  1. 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
  1. 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

  1. 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
  1. 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
  1. 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

  1. 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
  1. 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
  1. 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
  1. 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
  1. 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

  1. News Feed Design:
  1. Content Aggregation Best Practices:
  1. Reading Experience:
  1. View Tracking Implementation:
  1. Reading Time Algorithms:
    - Medium’s Read Time Algorithm
    - Improving Read Time Estimates