Channel Discovery System - nself-org/nchat GitHub Wiki

Channel Discovery & Browse System

Complete implementation of channel discovery, browsing, and recommendations for nself-chat

Version: 1.0.0 Date: February 1, 2026 Status: Production Ready


Overview

The Channel Discovery System provides a comprehensive solution for users to discover, browse, search, and join channels. It includes advanced filtering, sorting, categorization, recommendations, and invitation features.

Architecture

Components

Channel Discovery System
├── Components
│   ├── ChannelBrowser.tsx          - Main browsing interface
│   ├── ChannelDirectory.tsx        - Tree/grid/list directory view
│   ├── ChannelCard.tsx             - Channel display card
│   ├── ChannelPreview.tsx          - Channel preview modal
│   ├── ChannelInvite.tsx           - Invitation dialog
│   ├── ChannelSearch.tsx           - Search interface
│   ├── ChannelFilters.tsx          - Filter controls
│   ├── ChannelCategories.tsx       - Category navigation
│   ├── ChannelSuggestions.tsx      - AI recommendations
│   ├── FeaturedChannels.tsx        - Featured section
│   ├── PopularChannels.tsx         - Popular section
│   ├── TrendingChannels.tsx        - Trending section
│   └── RecentChannels.tsx          - Recent activity section
│
├── Hooks
│   └── use-channel-discovery.ts    - Discovery hook with filtering/sorting
│
├── Library Functions
│   ├── channel-discovery.ts        - Discovery logic
│   ├── channel-stats.ts            - Statistics calculation
│   ├── channel-categories.ts       - Category definitions
│   └── channel-suggestions.ts      - Recommendation engine
│
├── API Routes
│   └── /api/channels/discover      - RESTful discovery endpoint
│
└── GraphQL Queries
    └── channel-discovery.ts         - Discovery queries

Features

1. Channel Browser

File: /src/components/channels/ChannelBrowser.tsx

Comprehensive channel browsing interface with multiple views and features.

Features:

  • ✅ Tabbed interface (Discover, Browse All, Categories)
  • ✅ Grid and list layout toggle
  • ✅ Search integration
  • ✅ Filter integration
  • ✅ Category navigation
  • ✅ Featured channels section
  • ✅ Popular channels section
  • ✅ Trending channels section
  • ✅ Recent channels section
  • ✅ Personalized suggestions
  • ✅ Create channel button
  • ✅ Refresh functionality

Usage:

import { ChannelBrowser } from '@/components/channels/ChannelBrowser'
;<ChannelBrowser
  channels={channels}
  joinedChannelIds={joinedChannelIds}
  isLoading={false}
  showCreateButton={true}
  showSearch={true}
  showFilters={true}
  showCategories={true}
  showFeatured={true}
  showPopular={true}
  showRecent={true}
  showTrending={true}
  showSuggestions={true}
  defaultView="discover"
  onJoin={handleJoin}
  onLeave={handleLeave}
  onRefresh={handleRefresh}
/>

2. Channel Directory

File: /src/components/channels/ChannelDirectory.tsx

Hierarchical channel directory with tree, grid, and list views.

Features:

  • ✅ Tree view with collapsible categories
  • ✅ Grid view with category grouping
  • ✅ List view with flat display
  • ✅ Search channels
  • ✅ Sort by name, members, activity
  • ✅ Category filtering
  • ✅ Join/leave buttons
  • ✅ Member counts
  • ✅ Activity indicators

Usage:

import { ChannelDirectory } from '@/components/channels/ChannelDirectory'
;<ChannelDirectory
  channels={channels}
  joinedChannelIds={joinedChannelIds}
  showSearch={true}
  showSort={true}
  defaultExpanded={true}
  layout="tree" // or "grid" or "list"
  onJoin={handleJoin}
  onLeave={handleLeave}
/>

3. Channel Card

File: /src/components/channels/ChannelCard.tsx

Reusable channel display card with multiple variants.

Variants:

  • default: Full card with stats
  • compact: Condensed horizontal layout
  • featured: Highlighted with gradient background

Features:

  • ✅ Channel name, icon, description
  • ✅ Member count
  • ✅ Activity level badge
  • ✅ Trending indicator
  • ✅ New channel badge
  • ✅ Join/leave button
  • ✅ Featured star icon
  • ✅ Click to navigate

Usage:

import { ChannelCard } from '@/components/channels/ChannelCard'
;<ChannelCard
  channel={channel}
  isJoined={false}
  isFeatured={true}
  isTrending={false}
  isNew={false}
  showStats={true}
  showJoinButton={true}
  variant="default"
  onJoin={handleJoin}
  onLeave={handleLeave}
/>

4. Channel Invite

File: /src/components/channels/ChannelInvite.tsx

Complete invitation system with multiple invite methods.

Features:

  • ✅ Invite users from directory
  • ✅ Generate invite links
  • ✅ Email invitations
  • ✅ Link expiry settings
  • ✅ Max uses tracking
  • ✅ Copy to clipboard
  • ✅ Search users
  • ✅ Bulk selection

Usage:

import { ChannelInvite } from '@/components/channels/ChannelInvite'
;<ChannelInvite channel={channel} open={isOpen} onOpenChange={setIsOpen} onInvite={handleInvite} />

5. Discovery Hook

File: /src/hooks/use-channel-discovery.ts

React hook for channel discovery with comprehensive state management.

Features:

  • ✅ Auto-fetch channels
  • ✅ Real-time updates (optional)
  • ✅ Advanced filtering
  • ✅ Multi-criteria sorting
  • ✅ Search functionality
  • ✅ Pagination support
  • ✅ Statistics calculation
  • ✅ Recommendation engine
  • ✅ Quick filters
  • ✅ Error handling
  • ✅ Loading states

Usage:

import { useChannelDiscovery } from '@/hooks/use-channel-discovery'

const {
  // State
  channels,
  filteredChannels,
  results,
  stats,
  filters,
  isLoading,
  error,
  hasMore,
  total,

  // Actions
  setFilters,
  resetFilters,
  applyQuickFilter,
  search,
  clearSearch,
  fetchChannels,
  fetchMore,
  refresh,
  getFeatured,
  getPopular,
  getTrending,
  getNew,
  getSuggested,
} = useChannelDiscovery({
  autoFetch: true,
  enableRealtime: false,
  limit: 50,
  includeJoined: true,
})

6. Discovery API

File: /src/app/api/channels/discover/route.ts

RESTful API endpoint for channel discovery.

Endpoint: GET /api/channels/discover

Query Parameters:

  • q - Search query
  • category - Category ID filter
  • type - Channel type (public, private, all)
  • sort - Sort by (name, memberCount, activity, created, trending)
  • order - Sort order (asc, desc)
  • limit - Results per page (default: 50)
  • offset - Pagination offset (default: 0)
  • excludeJoined - Exclude joined channels (boolean)
  • includeStats - Include statistics (boolean, default: true)
  • includeRecommendations - Include recommendations (boolean)

Response:

{
  "channels": [...],
  "total": 42,
  "limit": 50,
  "offset": 0,
  "hasMore": false,
  "stats": {
    "totalChannels": 42,
    "publicChannels": 35,
    "privateChannels": 7,
    "totalMembers": 250,
    "activeToday": 18,
    "newThisWeek": 3
  },
  "recommendations": {
    "featured": [...],
    "popular": [...],
    "trending": [...],
    "new": [...]
  }
}

Channel Categories

Predefined categories for channel organization:

Category Icon Color Description
General MessageSquare #6366f1 General discussion and announcements
Announcements Megaphone #f59e0b Important announcements and updates
Teams Users #10b981 Team-specific channels
Projects FolderKanban #8b5cf6 Project discussions and updates
Support HelpCircle #ef4444 Help and support channels
Social Coffee #ec4899 Casual conversations and social
Resources BookOpen #06b6d4 Shared resources and documentation
Archived Archive #64748b Archived and inactive channels

Filtering & Sorting

Filter Options

interface DiscoveryFilters {
  query?: string // Search text
  type?: 'public' | 'private' | 'all' // Channel type
  categoryId?: string // Category filter
  sortBy?: DiscoverySortOption // Sort field
  sortDirection?: 'asc' | 'desc' // Sort order
  hasActivity?: boolean // Active channels only
  memberCountMin?: number // Min members
  memberCountMax?: number // Max members
  createdAfter?: Date // Created after date
  createdBefore?: Date // Created before date
  excludeJoined?: boolean // Exclude joined
  excludePrivate?: boolean // Exclude private
}

Sort Options

  • name - Alphabetical by name
  • memberCount - By number of members
  • activity - By last message time
  • created - By creation date
  • trending - By recent activity and growth
  • relevance - By search relevance (when searching)

Quick Filters

Predefined filter combinations:

type QuickFilterType =
  | 'all' // All channels
  | 'public' // Public channels only
  | 'private' // Private channels only
  | 'active' // Recently active
  | 'new' // Recently created
  | 'popular' // Most members
  | 'trending' // Trending now

Recommendations

Featured Channels

Channels marked as default or with high member counts.

const featured = getFeaturedChannels(channels, limit)

Popular Channels

Sorted by member count descending.

const popular = getPopularChannels(channels, limit)

Trending Channels

Recently active with high engagement.

const trending = getTrending(limit)

New Channels

Recently created channels.

const newChannels = getNew(limit)

Suggested Channels

Personalized recommendations based on user context.

const suggestions = getSuggested(limit)

Statistics

The system tracks comprehensive channel statistics:

interface DiscoveryStats {
  totalChannels: number // Total channel count
  publicChannels: number // Public channel count
  privateChannels: number // Private channel count
  totalMembers: number // Total membership count
  activeToday: number // Active in last 24h
  newThisWeek: number // Created in last 7 days
}

Channel Preview

File: /src/components/channels/ChannelPreview.tsx

Preview a channel before joining:

  • Channel information
  • Recent messages
  • Member list preview
  • Join button
  • Activity stats

Integration Guide

1. Basic Setup

import { ChannelBrowser } from '@/components/channels/ChannelBrowser'
import { useChannelDiscovery } from '@/hooks/use-channel-discovery'
import { useChannelMutations } from '@/hooks/use-channels'

export default function ChannelsPage() {
  const { channels, isLoading } = useChannelDiscovery()
  const { joinChannel, leaveChannel } = useChannelMutations()

  return (
    <ChannelBrowser
      channels={channels}
      isLoading={isLoading}
      onJoin={joinChannel}
      onLeave={leaveChannel}
    />
  )
}

2. With Custom Filters

const { channels, setFilters, applyQuickFilter } = useChannelDiscovery({
  initialFilters: {
    type: 'public',
    sortBy: 'activity',
  },
})

// Apply quick filter
applyQuickFilter('trending')

// Custom filter
setFilters({
  categoryId: 'engineering',
  memberCountMin: 10,
})

3. With Search

const { search, clearSearch, filteredChannels } = useChannelDiscovery()

<input
  onChange={(e) => search(e.target.value)}
  placeholder="Search channels..."
/>

Database Schema

The system expects the following Hasura tables:

nchat_channels

CREATE TABLE nchat_channels (
  id UUID PRIMARY KEY,
  name TEXT NOT NULL,
  slug TEXT UNIQUE NOT NULL,
  description TEXT,
  type TEXT NOT NULL, -- 'public', 'private', 'direct', 'group'
  category_id UUID,
  created_by UUID NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  topic TEXT,
  icon TEXT,
  color TEXT,
  is_archived BOOLEAN DEFAULT FALSE,
  is_default BOOLEAN DEFAULT FALSE,
  is_private BOOLEAN DEFAULT FALSE,
  last_message_at TIMESTAMPTZ,
  position INTEGER DEFAULT 0,
  owner_id UUID
);

nchat_channel_members

CREATE TABLE nchat_channel_members (
  channel_id UUID REFERENCES nchat_channels(id),
  user_id UUID NOT NULL,
  role TEXT DEFAULT 'member',
  joined_at TIMESTAMPTZ DEFAULT NOW(),
  is_muted BOOLEAN DEFAULT FALSE,
  is_pinned BOOLEAN DEFAULT FALSE,
  is_starred BOOLEAN DEFAULT FALSE,
  notifications_enabled BOOLEAN DEFAULT TRUE,
  last_read_at TIMESTAMPTZ,
  PRIMARY KEY (channel_id, user_id)
);

nchat_channel_invites

CREATE TABLE nchat_channel_invites (
  id UUID PRIMARY KEY,
  code TEXT UNIQUE NOT NULL,
  channel_id UUID REFERENCES nchat_channels(id),
  created_by UUID NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  expires_at TIMESTAMPTZ,
  max_uses INTEGER,
  uses INTEGER DEFAULT 0,
  is_active BOOLEAN DEFAULT TRUE,
  is_temporary BOOLEAN DEFAULT FALSE
);

Performance Considerations

Caching

The discovery API uses HTTP caching:

headers: {
  'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=300',
}

Pagination

Use offset-based pagination for large channel lists:

const { fetchMore, hasMore } = useChannelDiscovery({
  limit: 50,
  offset: 0,
})

if (hasMore) {
  await fetchMore()
}

Real-time Updates

Enable real-time updates for live data:

useChannelDiscovery({
  enableRealtime: true, // Uses GraphQL subscriptions
})

Testing

Unit Tests

npm test src/hooks/use-channel-discovery.test.ts
npm test src/lib/channels/channel-discovery.test.ts

Integration Tests

npm test src/components/channels/ChannelBrowser.test.tsx
npm test src/app/api/channels/discover/route.test.ts

E2E Tests

npm run test:e2e -- --grep "channel discovery"

Future Enhancements

Phase 1 (Current)

  • ✅ Basic discovery
  • ✅ Filtering and sorting
  • ✅ Categories
  • ✅ Search
  • ✅ Invitations

Phase 2 (Planned)

  • [ ] AI-powered recommendations
  • [ ] Channel analytics dashboard
  • [ ] Advanced search (boolean operators)
  • [ ] Saved searches
  • [ ] Channel collections

Phase 3 (Future)

  • [ ] Channel ratings/reviews
  • [ ] Channel verification badges
  • [ ] Cross-workspace discovery
  • [ ] Channel import/export
  • [ ] Discovery widgets

Related Documentation


Support

For issues or questions:


Last Updated: February 1, 2026 Version: 1.0.0 Status: Production Ready ✅