Notion Integration Guide

This document provides comprehensive documentation for the Notion backend integration in the AI Hackathon Assistant 2025 project.

Table of Contents


Overview

The Notion integration serves as the backend for the FAQ voting and statistics system. It provides:

  • Persistent FAQ Storage: Questions and answers stored in Notion database
  • Community Voting: Upvote/downvote tracking with real-time updates
  • View Analytics: Track question popularity via view counts
  • Graceful Fallback: Static questions when Notion is unavailable

Key Benefits

FeatureDescription
Content ManagementUpdate FAQ through Notion UI without code changes
Real-time StatsVote counts and views sync to Notion database
Privacy-FirstUser votes stored locally in browser
ResilientFalls back to static questions if Notion fails

Architecture

System Architecture Diagram

graph TB
    subgraph "Client Layer"
        UI[React Components]
        Hook[useFAQVoting Hook]
        LS[localStorage]
    end

    subgraph "API Layer"
        Q[/api/faq/questions]
        V[/api/faq/vote]
        W[/api/faq/view]
    end

    subgraph "Notion Backend"
        NC[Notion Client]
        DB[(FAQ Database)]
    end

    subgraph "Fallback"
        Static[Static Questions]
    end

    UI --> Hook
    Hook --> LS
    Hook --> Q
    Hook --> V
    Hook --> W

    Q --> NC
    V --> NC
    W --> NC
    NC --> DB

    Q -.-> Static

Data Flow Sequence

sequenceDiagram
    participant U as User
    participant C as Client
    participant LS as localStorage
    participant API as API Routes
    participant N as Notion DB

    Note over U,N: Page Load Flow
    U->>C: Open FAQ Page
    C->>LS: Check Cache (5min TTL)
    alt Cache Valid
        LS-->>C: Return Cached Data
    else Cache Expired/Missing
        C->>API: GET /api/faq/questions
        API->>N: Query Database (IsActive=true)
        N-->>API: FAQ Data + Stats
        API-->>C: Return Questions
        C->>LS: Update Cache
    end
    C-->>U: Display FAQ List

    Note over U,N: Vote Flow
    U->>C: Click Vote Button
    C->>LS: Save Vote Locally
    C-->>U: Update UI (Optimistic)
    C->>API: POST /api/faq/vote
    API->>N: Update Vote Count
    N-->>API: Confirm Update
    API-->>C: Success Response

    Note over U,N: View Tracking
    U->>C: Expand FAQ Card
    C->>API: POST /api/faq/view
    API->>N: Increment TotalViews
    Note right of C: Silent, non-blocking

Database Schema

Notion Database Properties

erDiagram
    FAQ_DATABASE {
        string Title PK "Question text (Title type)"
        string QuestionID UK "Unique identifier (Rich Text)"
        string Answer "Answer content (Rich Text)"
        string Category "8 categories (Select)"
        boolean IsActive "Filter flag (Checkbox)"
        number UpVotes "Upvote count (Number)"
        number DownVotes "Downvote count (Number)"
        number TotalViews "View count (Number)"
    }

Property Details

PropertyNotion TypeDescriptionExample
TitleTitleThe FAQ question text”When is the hackathon?”
QuestionIDRich TextUnique identifier for the question”event-info-1”
AnswerRich TextThe answer/explanation content”August 15-16, 2025…”
CategorySelectOne of 8 predefined categories”event-info”
IsActiveCheckboxFilter to show only active questionstrue
UpVotesNumberCount of helpful votes42
DownVotesNumberCount of not helpful votes3
TotalViewsNumberNumber of times viewed156

Available Categories

Category ValueDisplay Name
event-infoEvent Information
teamsTeam Formation
technicalTechnical Details
scheduleSchedule & Logistics
mentorsMentorship
awardsAwards & Judging
logisticsLogistics
generalGeneral

API Routes

GET /api/faq/questions

Fetches all active FAQ questions with their statistics.

Request: No body required

Response:

{
  success: boolean;
  questions: PresetQuestion[];  // FAQ content
  stats: FAQStats[];            // Vote/view statistics
  source: 'notion' | 'static' | 'static-fallback';
  timestamp: number;
}

Behavior:

  • Queries Notion with filter: IsActive = true
  • Returns fallback static questions if Notion fails
  • Calculates score as upVotes - downVotes

POST /api/faq/vote

Records an upvote or downvote for a question.

Request:

{
  questionId: string;
  voteType: 'up' | 'down';
  previousVote?: 'up' | 'down' | null;
}

Response:

{
  success: boolean;
  message: string;
}

Behavior:

  • Finds page by QuestionID
  • Removes previous vote if switching
  • Updates UpVotes or DownVotes property
  • Supports vote toggling (same vote = remove)

POST /api/faq/view

Increments the view count for a question.

Request:

{
  questionId: string;
}

Response:

{
  success: boolean;
  message: string;
}

Behavior:

  • Silent failure (doesn’t throw on error)
  • Non-blocking to user experience
  • Increments TotalViews property

Client-Side Implementation

Key Files

FilePurpose
lib/notion-faq.tsNotion client, server operations, client utilities
hooks/use-faq-voting.tsReact hook for FAQ state and voting
components/chatbot/types.tsTypeScript interfaces

Type Definitions

// From components/chatbot/types.ts
 
interface PresetQuestion {
  id: string;
  question: string;
  answer: string;
  category: 'event-info' | 'teams' | 'technical' | 'schedule'
          | 'mentors' | 'awards' | 'logistics' | 'general';
}
 
interface FAQStats {
  questionId: string;
  upVotes: number;
  downVotes: number;
  totalViews: number;
  score: number;  // Calculated: upVotes - downVotes
}
 
interface FAQVote {
  questionId: string;
  vote: 'up' | 'down' | null;
  timestamp: number;
}
 
interface EnhancedPresetQuestion extends PresetQuestion {
  stats: FAQStats;
  userVote?: 'up' | 'down' | null;
}

useFAQVoting Hook

const {
  isLoading,           // Loading state
  error,               // Error message if any
  enhancedQuestions,   // Questions with stats and user votes
  voteOnQuestion,      // Function to vote
  incrementViews,      // Function to track view
  getUserVote,         // Get user's vote for a question
  stats                // Raw stats data
} = useFAQVoting();

Optimistic Updates

The voting system uses optimistic updates for instant UI feedback:

  1. User clicks vote button
  2. UI updates immediately (optimistic)
  3. Vote saved to localStorage (privacy)
  4. API call made in background
  5. No rollback on failure (best effort)

Caching Strategy

Client-Side Caching

CacheDurationStoragePurpose
FAQ Questions5 minutesMemoryReduce API calls
FAQ Stats5 minutesMemoryReduce API calls
User VotesPermanentlocalStoragePrivacy, persistence

Cache Invalidation

  • Cache expires after 5 minutes (TTL)
  • Manual invalidation via clearFAQCache()
  • Fresh fetch on vote submission

Implementation

// From lib/notion-faq.ts
 
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
 
let questionsCache: { data: PresetQuestion[]; timestamp: number } | null = null;
 
export async function fetchFAQQuestions(): Promise<PresetQuestion[]> {
  if (questionsCache && Date.now() - questionsCache.timestamp < CACHE_DURATION) {
    return questionsCache.data;
  }
 
  const response = await fetch('/api/faq/questions');
  const data = await response.json();
 
  questionsCache = { data: data.questions, timestamp: Date.now() };
  return data.questions;
}

Setup Instructions

1. Create Notion Integration

  1. Go to Notion Integrations
  2. Click “New integration”
  3. Name it (e.g., “AI Hackathon FAQ”)
  4. Select the workspace
  5. Copy the Internal Integration Token

2. Create FAQ Database

  1. Create a new Notion database
  2. Add the following properties:
Property NameTypeRequired
TitleTitleYes
QuestionIDTextYes
AnswerTextYes
CategorySelectYes
IsActiveCheckboxYes
UpVotesNumberYes
DownVotesNumberYes
TotalViewsNumberYes
  1. Add select options for Category:

    • event-info, teams, technical, schedule, mentors, awards, logistics, general
  2. Share the database with your integration

3. Get Database ID

  1. Open the database in Notion
  2. Copy the URL: notion.so/{workspace}/{database_id}?v=xxx
  3. Extract the database_id part

4. Configure Environment Variables

Add to .env.local:

NOTION_TOKEN=secret_xxxxxxxxxxxxxxxxxxxx
NOTION_FAQ_DATABASE_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

5. Populate Initial Data

Add FAQ entries to the Notion database:

  • Set IsActive to true for visible questions
  • Use unique QuestionID values
  • Initialize vote counts to 0

Troubleshooting

Common Issues

IssueCauseSolution
”Notion not configured”Missing env varsAdd NOTION_TOKEN and NOTION_FAQ_DATABASE_ID
Empty FAQ listNo active questionsSet IsActive=true in Notion
Votes not persistingAPI errorCheck server logs, verify Notion permissions
Static questions showingNotion errorCheck NOTION_TOKEN validity

Debug Mode

Enable debug logging by checking the API response:

const response = await fetch('/api/faq/questions');
const data = await response.json();
console.log('Source:', data.source);  // 'notion' or 'static-fallback'

Verify Notion Connection

# Test API endpoint
curl http://localhost:3000/api/faq/questions

Expected response should include "source": "notion".



Last updated: December 2024