Database-Driven Homepage - Complete Setup Guide
🎉 What You Now Have
✅ Fully database-driven homepage with automated cause/topic management:
- API Endpoint -
/api/trendingserves causes from database - Frontend Integration - Homepage fetches causes dynamically
- Image Generator - Creates images for ALL 235 causes automatically
- Three Data Sources:
- EveryOrg (39 popular causes like "Climate", "Education", "Health")
- NTEE Codes (196 IRS nonprofit categories like "E32: School-Based Health Care")
- Mixed (automatically combines both)
🚀 Quick Start
Step 1: Generate Images for ALL Causes
cd /home/developer/projects/open-navigator
source .venv/bin/activate
# First, add Gemini API key to .env:
# echo "GEMINI_API_KEY=your_key_here" >> .env
# Get key from: https://makersuite.google.com/app/apikey
# Generate ALL 235 cause images (takes ~10-15 minutes)
python scripts/media/generate_all_cause_images.py
# OR test with just 10 causes first
python scripts/media/generate_all_cause_images.py --limit 10
# OR generate only EveryOrg causes (39 causes)
python scripts/media/generate_all_cause_images.py --type everyorg
# OR generate only NTEE codes (196 causes)
python scripts/media/generate_all_cause_images.py --type ntee
Output:
data/media/causes/
├── everyorg_animals_banner.png (1200x600)
├── everyorg_animals_square.png (400x400)
├── everyorg_climate_banner.png
├── everyorg_climate_square.png
├── ntee_E_banner.png
├── ntee_E_square.png
├── ntee_E32_banner.png
├── ntee_E32_square.png
└── all_causes_metadata.json
Step 2: Copy Images to Frontend
# Make images accessible to frontend
mkdir -p frontend/public/images/causes
cp data/media/causes/*.png frontend/public/images/causes/
# OR use symlink
ln -s ../../../data/media/causes frontend/public/images/causes
Step 3: Test the API
# Start the API
./start-all.sh
# Or just API:
cd /home/developer/projects/open-navigator
source .venv/bin/activate
uvicorn api.main:app --reload --port 8000
# Test endpoints:
curl http://localhost:8000/api/trending?source=everyorg&limit=12
curl http://localhost:8000/api/trending?source=ntee&level=1
curl http://localhost:8000/api/trending?source=mixed&limit=12
curl http://localhost:8000/api/trending/stats
Step 4: See It Live
# Visit homepage
http://localhost:5173
# You should see:
# - Trending causes loaded from database (not hardcoded!)
# - Count showing: "(12 from database)"
# - Causes change based on what's in parquet files
📚 How It Works
Data Flow
┌─────────────────────────────────────────────────────────────┐
│ 1. CAUSES DATA (Parquet Files) │
├─────────────────────────────────────────────────────────────┤
│ data/gold/causes_everyorg_causes.parquet (39 rows) │
│ data/gold/causes_ntee_codes (196 rows) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 2. IMAGE GENERATOR (Python Script) │
├─────────────────────────────────────────────────────────────┤
│ scripts/media/generate_all_cause_images.py │
│ - Reads parquet files │
│ - Uses Gemini AI for color schemes │
│ - Generates banner (1200x600) + square (400x400) │
│ - Saves to data/media/causes/ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 3. API ENDPOINT (FastAPI) │
├─────────────────────────────────────────────────────────────┤
│ GET /api/trending?source=mixed&limit=12 │
│ - Reads parquet files │
│ - Returns causes with metadata │
│ - Includes image URLs │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 4. FRONTEND (React) │
├─────────────────────────────────────────────────────────────┤
│ Home.tsx - useQuery('trending-causes') │
│ - Fetches from API on page load │
│ - Renders trending topics bar │
│ - Shows cause icons, names, + buttons │
│ - Clickable → search that cause │
└─────────────────────────────────────────────────────────────┘
API Endpoints
GET /api/trending
Parameters:
source: "everyorg" | "ntee" | "mixed" (default: "everyorg")limit: Number of causes to return (default: 12, max: 100)level: NTEE level filter (1=major groups, 2=subcategories) - only for ntee source
Response:
{
"causes": [
{
"name": "Climate",
"icon": "🌍",
"category": "primary",
"description": "Climate change mitigation...",
"image_url": "/images/causes/everyorg_climate_square.png",
"popularity_rank": 4
},
{
"name": "Health",
"icon": "⚕️",
"category": "major_group",
"description": "NTEE Code E",
"image_url": "/images/causes/ntee_E_square.png",
"popularity_rank": null
}
],
"total": 12
}
GET /api/trending/stats
Response:
{
"everyorg_causes": 39,
"ntee_causes": 196,
"total_causes": 235,
"generated_images": 470
}
🎨 Image Generation Details
What Gets Generated
For each cause (e.g., "Climate"):
-
Banner image (1200x600px)
- Filename:
everyorg_climate_banner.png - Use: Hero banners, featured stories
- Has: Gradient background, large text overlay
- Filename:
-
Square thumbnail (400x400px)
- Filename:
everyorg_climate_square.png - Use: Topic cards, trending bar
- Has: Circular gradient, compact text
- Filename:
-
Color scheme (in metadata.json)
- AI-generated thematic colors
- Example: Climate → greens and blues
- Example: Health → calming medical blues
Filename Patterns
-
EveryOrg:
everyorg_{cause_id}_{type}.pngeveryorg_climate_banner.pngeveryorg_education_square.png
-
NTEE:
ntee_{code}_{type}.pngntee_E_banner.png(Health - major group)ntee_E32_square.png(School-Based Health Care - specific)
Generation Progress
The script shows:
[1/235] Processing: Climate
Category: everyorg | ID: climate
────────────────────────────────────────────────────────────
🎨 Generated color scheme: Calming greens and blues for environmental focus
🖼️ Creating banner image (1200x600)...
✅ Saved: data/media/causes/everyorg_climate_banner.png
🔲 Creating square image (400x400)...
✅ Saved: data/media/causes/everyorg_climate_square.png
✅ Success! (1/235 = 0.4% complete)
🔧 Customization
Change Source Mix
Homepage (frontend/src/pages/Home.tsx):
// Current: Mixed (6 everyorg + 6 ntee)
source: 'mixed',
limit: 12
// Only popular causes:
source: 'everyorg',
limit: 12
// Only IRS categories:
source: 'ntee',
limit: 12,
level: 1 // Only major groups (Arts, Health, Education, etc.)
Add Custom Causes
Option 1: Add to EveryOrg causes
import polars as pl
# Load existing
df = pl.read_parquet('data/gold/causes_everyorg_causes.parquet')
# Add new cause
new_cause = pl.DataFrame({
'cause_id': ['oral-health'],
'cause_name': ['Oral Health'],
'description': ['Dental care access and fluoride policy'],
'category': ['primary'],
'parent_id': [None],
'icon': ['🦷'],
'popularity_rank': [40],
'data_source': ['Manual'],
'download_date': [pl.datetime('now')],
'version': ['2026.1']
})
# Combine
df = pl.concat([df, new_cause])
# Save
df.write_parquet('data/gold/causes_everyorg_causes.parquet')
Option 2: Add to NTEE codes (Similar process with causes_ntee_codes)
Skip Existing Images
If you've already generated some images:
python scripts/media/generate_all_cause_images.py --skip-existing
This will only generate images for causes that don't have them yet.
📊 What Changed
Files Modified
-
API:
- ✅
api/routes/trending.py- New trending causes endpoint - ✅
api/main.py- Registered trending router
- ✅
-
Frontend:
- ✅
frontend/src/pages/Home.tsx- Database-driven causes - Added
useQueryto fetch from/api/trending - Shows count "(X from database)"
- ✅
-
Scripts:
- ✅
scripts/media/generate_all_cause_images.py- Batch generator - ✅
scripts/media/generate_topic_images.py- Base generator (already existed)
- ✅
Before vs After
Before (Hardcoded):
const TRENDING_TOPICS = [
{ name: 'World Press Freedom Day', icon: '📰', category: 'Global' },
{ name: 'Business & Markets', icon: '💼', category: 'Economics' },
// ... hardcoded list
]
After (Database-Driven):
const { data: trendingData } = useQuery({
queryKey: ['trending-causes'],
queryFn: async () => {
const response = await api.get('/trending', {
params: { source: 'mixed', limit: 12 }
})
return response.data
}
})
const trendingTopics = trendingData?.causes || []
🎯 Next Steps
Phase 1: Generate All Images (Do This First!)
# Get Gemini API key
https://makersuite.google.com/app/apikey
# Add to .env
echo "GEMINI_API_KEY=your_key" >> .env
# Generate all 235 cause images (~10-15 minutes)
python scripts/media/generate_all_cause_images.py
# Copy to frontend
cp data/media/causes/*.png frontend/public/images/causes/
Phase 2: Test Locally
./start-all.sh
# Visit http://localhost:5173
# Check that trending causes load from database
# Inspect network tab: should see /api/trending request
Phase 3: Deploy
# Standard deployment
./packages/hosting/scripts/huggingface/safe-deploy.sh
# Make sure to include generated images!
# Either:
# 1. Copy to frontend/public/images/causes before deploy
# 2. Or upload to CDN and update image_url in API
Phase 4: Track Popularity (Future)
Add analytics to track which causes users click:
CREATE TABLE cause_interactions (
cause_id VARCHAR,
interaction_type VARCHAR, -- click, follow, search
user_id VARCHAR,
timestamp TIMESTAMP
);
Then use this data to dynamically rank causes by popularity!
🐛 Troubleshooting
"GEMINI_API_KEY not found"
# Get key from Google
https://makersuite.google.com/app/apikey
# Add to .env
echo "GEMINI_API_KEY=your_actual_key_here" >> .env
# Verify
grep GEMINI_API_KEY .env
Images Don't Show on Homepage
-
Check API response:
curl http://localhost:8000/api/trending?source=mixed&limit=1# Look for "image_url" field -
Check images exist:
ls frontend/public/images/causes/ | head -10 -
Check browser console:
- Should see no 404 errors for images
- Network tab shows images loading
"No causes found" Error
Verify parquet files exist:
ls -lh data/gold/causes*.parquet
# Should show:
# causes_everyorg_causes.parquet (39 rows)
# causes_ntee_codes (196 rows)
Frontend Shows "(0 from database)"
-
Check API is running:
curl http://localhost:8000/api/trending -
Check for CORS errors in browser console
-
Verify .env has correct API URL
📝 Summary
You now have:
✅ 235 causes ready to generate images for
- 39 EveryOrg popular causes (Climate, Education, etc.)
- 196 NTEE codes (official IRS categories)
✅ Automated image generation script
- Reads causes from parquet files
- Uses Gemini AI for color schemes
- Generates banner + square for each
✅ Database-driven API endpoint
/api/trendingserves causes dynamically- Supports filtering by source, limit, level
- Includes image URLs and metadata
✅ Frontend integration
- Homepage fetches causes from API
- Shows "(X from database)" count
- Automatically updates when data changes
Your homepage is now 100% database-driven! 🎉
No more hardcoded causes - everything comes from your parquet files!