OpenAsk - AI-Powered Q&A Platform for Developers 🚀
💡 Inspiration
The inspiration for OpenAsk came from observing the challenges developers face when seeking help:
- Stack Overflow can be intimidating for beginners due to strict posting rules and sometimes harsh feedback
- Discord/Slack communities provide quick help but answers get lost in chat history
- Traditional forums lack modern features like AI-assisted responses and real-time collaboration
I envisioned a platform that combines the best of all worlds: community-driven Q&A with instant AI-generated draft answers to kickstart discussions, wrapped in a modern, friendly interface.
🎯 What It Does
OpenAsk is a full-stack Q&A platform that:
- Instant AI Assistance: When you post a question, Google's Gemini AI generates a draft answer immediately to get you started
- Community Engagement: Upvote/downvote questions and answers, fostering quality content through community moderation
- Smart Search & Tags: Find relevant questions quickly with full-text search and tag-based filtering
- Secure Authentication: Auth0-powered login with social providers (Google, GitHub) for seamless access
- Real-Time Updates: See vote counts and new answers instantly as the community engages
- Markdown Support: Rich text formatting for code snippets, lists, and formatted answers
Core Features:
- ✅ Ask questions with tags and receive AI-generated draft answers
- ✅ Browse, search, and filter questions by tags or votes
- ✅ Vote on questions and answers to surface quality content
- ✅ Edit your own questions and answers
- ✅ User profiles showing contribution history
- ✅ Trending tags sidebar for topic discovery
🛠️ How We Built It
Architecture
OpenAsk is built as a TypeScript monorepo using modern best practices:
openask/
├── apps/
│ ├── web/ # React + Vite + TypeScript frontend
│ └── api/ # Express + MongoDB backend
├── packages/
│ ├── sdk/ # Typed API client library
│ ├── ui/ # Reusable React components
│ └── config/ # Shared TypeScript/ESLint configs
Why Monorepo?
- Shared TypeScript types between frontend and backend prevent API contract mismatches
- Reusable component library ensures UI consistency
- Single source of truth for coding standards (ESLint, Prettier)
Technology Stack
Frontend (apps/web)
- React 18 with TypeScript for type-safe component development
- Vite for lightning-fast dev server and optimized production builds
- TailwindCSS for utility-first styling with custom design system
- Auth0 React SDK for secure authentication flows
- React Hook Form + Zod for form validation with type inference
- React Router v6 for client-side routing
- React Markdown for safe rendering of user-generated content
Backend (apps/api)
- Express.js with TypeScript for robust API development
- MongoDB + Mongoose for flexible document storage with schema validation
- Auth0 JWT middleware for stateless authentication
- Google Gemini AI (gemini-2.0-flash-exp) for generating draft answers
- Pino for structured JSON logging
- Helmet for security headers
- Express Rate Limit to prevent abuse (100 requests/15min)
Infrastructure & DevOps
- pnpm workspaces for efficient monorepo management
- Docker support for containerized deployment
- GitHub Actions CI/CD pipeline (lint, typecheck, test, build)
- Husky pre-commit hooks to enforce code quality
- Conventional Commits for semantic versioning
Key Implementation Details
1. Authentication Flow
// Frontend: Auth0 provider wraps app
<Auth0Provider domain={...} clientId={...} authorizationParams={{ audience: "https://openask-api" }}>
<App />
</Auth0Provider>
// SDK: Automatic token injection
const token = await getAccessTokenSilently({ cacheMode: 'off' });
fetch(url, { headers: { Authorization: `Bearer ${token}` } });
// Backend: JWT verification middleware
app.use('/api/v1', checkJwt); // Validates Auth0 JWT
2. AI Integration
// Gemini service with fallback
async function generateDraftAnswer({ title, body }) {
if (!GEMINI_API_KEY) return mockDraftAnswer(); // Deterministic mock
const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash-exp" });
const result = await model.generateContent(prompt);
return result.response.text();
}
3. Vote System
// MongoDB compound unique index prevents duplicate votes
VoteSchema.index({ targetType: 1, targetId: 1, userId: 1 }, { unique: true });
// Atomic vote updates
await Vote.findOneAndUpdate(
{ targetType, targetId, userId },
{ value }, // 1 or -1
{ upsert: true }
);
4. Full-Text Search
// MongoDB text index on question title/body
QuestionSchema.index({ title: 'text', body: 'text' });
// Search query
Question.find({ $text: { $search: query } })
.sort({ score: { $meta: 'textScore' } });
🧗 Challenges We Faced
1. Monorepo Configuration Complexity
Problem: Getting pnpm workspaces to work across TypeScript projects with shared dependencies was initially confusing.
Solution:
- Created
packages/configwith sharedtsconfig.base.json - Used
"workspace:*"protocol for internal dependencies - Set up proper
referencesin each workspace'stsconfig.json
Lesson: Spend time upfront on project structure—it pays dividends later.
2. Auth0 Token Audience Mismatch
Problem: Frontend was authenticated, but API returned 401 Unauthorized when posting questions.
Solution:
- Discovered token was issued for Auth0 Management API, not our custom API
- Created Auth0 API with identifier
https://openask-api - Updated frontend to pass
audienceingetAccessTokenSilently()
Code Fix:
// Before (wrong)
const token = await getAccessTokenSilently();
// After (correct)
const token = await getAccessTokenSilently({
audience: "https://openask-api",
cacheMode: 'off' // Force fresh token
});
Lesson: Auth0 requires explicit API audience—generic tokens won't work for custom APIs.
3. API Response Shape Mismatch
Problem: Frontend showed "No questions found" despite API returning data. Network tab showed {items: [...]} but SDK expected {questions: [...]}.
Solution:
- Traced through pagination helper (
createPaginationResult) returning wrong shape - Updated API routes to return SDK-compatible format: ```typescript // Changed from: return res.json(createPaginationResult(items, page, limit, total));
// To: return res.json({ questions: items, total, page, limit, totalPages: Math.ceil(total / limit) });
**Lesson**: Type-safe SDK prevents runtime errors—ensure API contracts match TypeScript interfaces.
---
### **4. Mongoose Validation Error on User Creation**
**Problem**: Creating questions failed with "User validation failed: email: Path `email` is required."
**Root Cause**: Auth0 JWT `sub` field doesn't include email by default.
**Solution**:
```typescript
// Made email optional in User schema
email: {
type: String,
required: false, // Changed from true
unique: true,
sparse: true // Allow multiple null emails
}
Lesson: Don't assume OAuth providers include all fields—make optional fields explicit.
5. Vote Route Conflict
Problem: Voting on answers returned "Question not found" error.
Root Cause: Both question and answer vote routes used same path /:id/vote, causing Express to always match question route first.
Solution: Consolidated into single smart route:
router.post('/:id/vote', async (req, res) => {
const isAnswer = req.baseUrl.includes('/answers');
const Model = isAnswer ? Answer : Question;
const targetType = isAnswer ? 'answer' : 'question';
// ... rest of vote logic
});
Lesson: Express matches routes in order—consolidate similar routes or use middleware to distinguish.
6. Vercel Deployment: pnpm Version Mismatch
Problem: Vercel used pnpm 6.35.1 but project required >=8.0.0.
Solution Attempts:
- ❌ Added
.npmrcwithuse-node-version→ Vercel rejected - ❌ Tried Corepack → Still used old pnpm
- ✅ Final fix: Custom install command:
json { "installCommand": "npm install -g pnpm@9.15.0 && cd ../.. && pnpm install --no-frozen-lockfile" }
Lesson: Vercel's Node.js environment has quirks—sometimes you need creative workarounds.
7. Gemini API Model Deprecation
Problem: AI draft answers failed with 404 errors.
Solution: Updated from deprecated gemini-1.5-flash to gemini-2.0-flash-exp:
const model = genAI.getGenerativeModel({
model: "gemini-2.0-flash-exp" // Was: gemini-1.5-flash
});
Lesson: Always check API documentation for latest model versions, especially in beta/preview stages.
📚 What We Learned
Technical Skills
- Monorepo Management: pnpm workspaces, TypeScript project references, shared configs
- OAuth2/OIDC: Deep understanding of JWT audience claims, token refresh, Auth0 configuration
- API Design: RESTful conventions, pagination strategies, error handling patterns
- Database Indexing: Text search indexes, compound unique indexes for data integrity
- AI Integration: Prompt engineering, fallback strategies, rate limiting AI requests
- DevOps: Docker multi-stage builds, CI/CD pipelines, deployment platform tradeoffs
Soft Skills
- Debugging Methodology: Read error messages carefully, use logging strategically, verify assumptions
- Documentation: Write for your future self—good docs save hours later
- Incremental Development: Build small, test often, commit frequently
- Resilience: When one approach fails (Corepack), try another (npm global install)
Best Practices Adopted
- ✅ Spec-first development:
ProjectScope.txtas single source of truth - ✅ Type safety everywhere: No
anytypes, strict TypeScript config - ✅ Separation of concerns: SDK abstracts API, UI package shares components
- ✅ Security by default: Rate limiting, CORS, Helmet, input sanitization
- ✅ Fail gracefully: Mock fallbacks for external services (Gemini AI)
🎓 Key Takeaways
For Future Hackathons
- Start with architecture: Spend 20% of time planning structure—saves 80% debugging later
- Use proven tools: Don't introduce too many new technologies at once
- Document as you go: README updates = progress checkpoints
- Test auth early: Authentication bugs are time sinks—verify flow before building features
- Deploy early: Don't wait until last minute—infrastructure surprises happen
Technical Insights
- Monorepos shine for full-stack projects with shared types
- JWT audience claims are critical for multi-API architectures
- Defensive programming (optional fields, fallbacks) prevents runtime errors
- Index your queries: MongoDB text indexes = 10x faster search
- Rate limiting is essential for AI API endpoints (cost control)
🚀 What's Next for OpenAsk
Immediate Improvements
- [ ] Real-time updates via WebSockets for live vote counts
- [ ] Notification system for answers to your questions
- [ ] Email digests of trending questions in followed tags
- [ ] Code syntax highlighting in markdown answers
Advanced Features
- [ ] AI-powered duplicate question detection
- [ ] Reputation system with badges (like Stack Overflow)
- [ ] Question bounties to incentivize answers
- [ ] Multi-language support (i18n)
- [ ] Advanced moderation tools (flag inappropriate content)
Technical Debt
- [ ] Add E2E tests (Playwright/Cypress)
- [ ] Implement caching layer (Redis) for hot questions
- [ ] GraphQL API for more efficient data fetching
- [ ] Performance monitoring (Sentry, DataDog)
🏆 Hackathon Accomplishments
We're proud to have built a production-ready platform with:
- ✅ 100% TypeScript - Type-safe from database to UI
- ✅ Comprehensive docs - README, CONTRIBUTING, CODE_OF_CONDUCT, SECURITY
- ✅ CI/CD pipeline - Automated testing and deployment
- ✅ Modern architecture - Monorepo, microservices-ready
- ✅ Security-first - Auth0, rate limiting, input sanitization, CORS
- ✅ Accessibility - Semantic HTML, keyboard navigation, ARIA labels
- ✅ Responsive design - Mobile-first, works on all devices
- ✅ Real AI integration - Not just a mock, actual Gemini API calls
Lines of Code: ~15,000+ (excluding dependencies)
Commits: 50+
Time Invested: 72 hours (3 days intensive development)
🙏 Acknowledgments
- Auth0 for excellent authentication documentation
- Google Gemini AI for powerful language model API
- Vercel & Railway for developer-friendly deployment platforms
- MongoDB for flexible document database
- Open Source Community for amazing tools (React, Express, Vite, etc.)
📖 Try It Out
- Live Demo: https://open-ask-web.vercel.app (update with actual URL)
- GitHub: https://github.com/9jaDevo/OpenAsk
- API Docs: See
POSTMAN_COLLECTION.jsonfor full API reference - Video Demo: (add YouTube/Loom link if you record one)
💻 Run It Locally
# Clone the repo
git clone https://github.com/9jaDevo/OpenAsk.git
cd OpenAsk
# Install dependencies
pnpm install
# Set up environment variables (see .env.example files)
cp apps/api/.env.example apps/api/.env
cp apps/web/.env.example apps/web/.env
# Start MongoDB (Docker)
docker-compose up -d
# Seed demo data
pnpm --filter api seed
# Run dev servers
pnpm dev
# Frontend: http://localhost:5173
# API: http://localhost:3001
📄 License
MIT © 2025 OpenAsk Contributors
Built with ❤️ during Opensource Hacfest 2025
"Empowering developers to help each other, one question at a time."
Built With
- auth0
- express.js
- gemini
- node.js
- react
- vite


Log in or sign up for Devpost to join the conversation.