A Next.js application for helping people with your knowledge, featuring a Google-style search interface and community-driven assistance.
- 🔍 Google-style Search Interface - Clean, minimal search with autocomplete suggestions
- 📚 Search History - Track and revisit previous searches
- 💡 Smart Suggestions - AI-powered search suggestions
- 🎨 Modern UI - Responsive design with smooth animations
- ⚡ Fast Performance - Built with Next.js 14 and TypeScript
- 🔒 Secure - Environment-based configuration
- Framework: Next.js 14 (App Router)
- Language: TypeScript
- Styling: CSS Modules + Global CSS
- Database: Supabase (PostgreSQL)
- Deployment: Vercel (recommended)
- Node.js 18+
- npm or yarn
- Supabase account (for database)
-
Clone the repository
git clone <your-repo-url> cd help-community-project
-
Install dependencies
npm install # or yarn install
-
Set up environment variables
cp env.local.example .env.local
Edit
.env.local
with your Supabase credentials:NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
-
Set up Supabase database
Create the following tables in your Supabase project:
-- Search history table CREATE TABLE search_history ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, query TEXT NOT NULL, user_id UUID REFERENCES auth.users(id), created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Search suggestions table CREATE TABLE search_suggestions ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, suggestion TEXT UNIQUE NOT NULL, frequency INTEGER DEFAULT 1, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Indexes for better performance CREATE INDEX idx_search_history_query ON search_history(query); CREATE INDEX idx_search_history_created_at ON search_history(created_at DESC); CREATE INDEX idx_search_suggestions_suggestion ON search_suggestions(suggestion); CREATE INDEX idx_search_suggestions_frequency ON search_suggestions(frequency DESC);
-
Run the development server
npm run dev # or yarn dev
-
Open your browser
Navigate to http://localhost:3000
├── app/ # Next.js App Router
│ ├── api/ # API routes
│ │ ├── suggest/ # Search suggestions
│ │ ├── history/ # Search history
│ │ └── log-query/ # Query logging
│ ├── search/ # Search results page
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home page
│ └── globals.css # Global styles
├── components/ # React components
│ └── SearchBox.tsx # Search input component
├── lib/ # Utility libraries
│ └── supabase.ts # Supabase client
├── styles/ # CSS modules
│ └── search.css # Search-specific styles
├── public/ # Static assets
│ └── assets/ # Images and icons
└── README.md
Returns search suggestions based on the query.
Response:
{
"suggestions": ["suggestion1", "suggestion2", ...]
}
Returns last 20 assists for a user (or all assists if no userId).
Response:
[
{
"id": "uuid",
"title": "Assist Title",
"url": "https://example.com",
"note": "Helpful note about the assist",
"userId": "user123",
"timestamp": "2024-01-01T00:00:00.000Z"
}
]
Adds a new assist to history.
Request:
{
"title": "Assist Title",
"url": "https://example.com",
"note": "Helpful note about the assist",
"userId": "user123"
}
Logs a search query for analytics.
Request:
{
"q": "search query"
}
The application supports multiple search providers through an adapter interface:
-
Google Programmable Search Engine (CSE)
- Most accurate and comprehensive results
- Requires API key and Custom Search Engine ID
- Free tier: 100 queries/day
- Get API Key
-
Bing Web Search API
- High-quality results from Microsoft Bing
- Requires Azure API key
- Free tier: 1,000 queries/month
- Get API Key
-
DuckDuckGo (Mocked for MVP)
- Privacy-focused search
- Currently uses mocked results (no API key required)
- Not suitable for production without proper API integration
- For production, consider third-party services like SerpAPI
-
Mock Provider
- For testing and development
- Returns static results
- No API key required
import { getSearchProvider } from '@/lib/search-providers'
// Get default provider (based on available API keys)
const provider = getSearchProvider()
const results = await provider.search('your query', { limit: 10 })
// Use a specific provider
const bingProvider = getSearchProvider('bing')
const results = await bingProvider.search('your query')
// Check which providers are available
import { getAvailableProviders, isProviderAvailable } from '@/lib/search-providers'
const available = getAvailableProviders() // ['bing', 'duck', 'mock']
const hasBing = isProviderAvailable('bing') // true/false
The default provider is selected in this order:
- Bing (if
BING_SEARCH_API_KEY
is set) - Google (if both
GOOGLE_SEARCH_API_KEY
andGOOGLE_SEARCH_ENGINE_ID
are set) - DuckDuckGo (mocked, always available)
- Mock (fallback)
You can override this by passing a provider name: ?provider=google|bing|duck|mock
- DuckDuckGo: Currently uses mocked results for MVP. Does not make real API calls.
- Rate Limits: Be aware of rate limits for Google (100/day free) and Bing (1000/month free)
- API Keys: Store API keys in
.env.local
file (never commit to git)
Use this utility function to record assists when users provide answers:
import { recordAssist } from '@/lib/recordAssist'
// Record an assist (logged in user)
await recordAssist({
title: "How to center a div in CSS",
url: "https://example.com/css-center-div",
note: "Explained three different methods: flexbox, grid, and absolute positioning"
}, "user123")
// Record an assist (anonymous user - saves to localStorage)
await recordAssist({
title: "JavaScript async/await best practices",
url: "https://example.com/js-async-await",
note: "Covered error handling and Promise.all patterns"
})
// Get local assists (for anonymous users)
import { getLocalAssists } from '@/lib/recordAssist'
const assists = getLocalAssists()
// Clear local assists
import { clearLocalAssists } from '@/lib/recordAssist'
clearLocalAssists()
npm run dev
- Start development servernpm run build
- Build for productionnpm run start
- Start production servernpm run lint
- Run ESLint
- TypeScript for type safety
- ESLint for code quality
- Prettier for code formatting (recommended)
- Semantic HTML and ARIA attributes for accessibility
- Push your code to GitHub
- Connect your repository to Vercel
- Add environment variables in Vercel dashboard
- Deploy!
The app can be deployed to any platform that supports Next.js:
- Netlify
- Railway
- DigitalOcean App Platform
- AWS Amplify
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
MIT License - see LICENSE file for details
The application uses Supabase Auth with the following providers:
- Google OAuth - Fast sign-in with Google account
- GitHub OAuth - Sign in with GitHub account
- Email Magic Link - Passwordless email authentication
- Go to Supabase Dashboard
- Select your project
- Navigate to Authentication → Providers
- In Supabase Dashboard, go to Authentication → Providers → Google
- Enable the Google provider
- Get OAuth credentials from Google Cloud Console:
- Create a new project or select existing
- Go to APIs & Services → Credentials
- Create OAuth 2.0 Client ID
- Add authorized redirect URI:
https://your-project.supabase.co/auth/v1/callback
- Copy Client ID and Client Secret to Supabase
- Set authorized domains in Supabase
- In Supabase Dashboard, go to Authentication → Providers → GitHub
- Enable the GitHub provider
- Get OAuth credentials from GitHub Developer Settings:
- Create a new OAuth App
- Set Homepage URL:
http://localhost:3000
(dev) or your domain (prod) - Set Authorization callback URL:
https://your-project.supabase.co/auth/v1/callback
- Copy Client ID and Client Secret to Supabase
- In Supabase Dashboard, go to Authentication → Providers → Email
- Enable Email provider
- Enable "Confirm email" (recommended)
- Configure email templates:
- Go to Authentication → Email Templates
- Customize Magic Link template
- Set up SMTP (optional):
- Go to Project Settings → Auth
- Configure custom SMTP settings (or use Supabase defaults)
- Go to Project Settings → Auth
- Set Site URL to:
- Development:
http://localhost:3000
- Production:
https://yourdomain.com
- Development:
- Add redirect URLs:
http://localhost:3000/auth/callback
https://yourdomain.com/auth/callback
Create a .env.local
file (copy from env.local.example
):
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key_here
NEXT_PUBLIC_SITE_URL=http://localhost:3000
- Rate Limiting - Auth actions are rate-limited (5 attempts per minute)
- Secure Cookies - HTTPOnly, Secure, SameSite cookies
- PKCE Flow - Proof Key for Code Exchange for OAuth
- Email Verification - Optional email confirmation
- Session Management - Automatic token refresh
- CSRF Protection - Built into Supabase Auth
- User clicks "Sign in" → Auth modal opens
- User selects provider:
- OAuth (Google/GitHub): Redirects to provider → Returns to
/auth/callback
→ Redirects to home - Magic Link: Email sent → User clicks link → Redirects to
/auth/callback
→ Redirects to home
- OAuth (Google/GitHub): Redirects to provider → Returns to
- Session created → User state updates globally
- Protected routes → Check session on server/client
// Get current user (client-side)
import { getCurrentUser } from '@/lib/auth'
const user = await getCurrentUser()
if (user) {
console.log(user.email, user.name)
}
// Sign out
import { signOut } from '@/lib/auth'
await signOut()
// Check if user is authenticated (server-side)
import { createServerSupabaseClient } from '@/lib/supabase'
const supabase = createServerSupabaseClient()
const { data: { user } } = await supabase.auth.getUser()
Edit components/AppsGrid.tsx
to add/remove quick links:
const apps: AppLink[] = [
{
name: 'Your App',
url: '/your-app',
icon: '🚀',
description: 'Description'
},
// ... more apps
]
Edit components/AuthModal.tsx
to modify:
- Sign-in methods
- UI/styling
- Error messages
- Success states
Adjust rate limits in lib/auth.ts
:
checkAuthRateLimit(identifier, maxAttempts, windowMs)
// Default: 5 attempts per 60 seconds
For questions and support, please open an issue on GitHub.