AI-Powered Vendor Questionnaire Automation for EduVault SaaS
Answer vendor assessment questionnaires in minutes, not hours. AlmaAssist uses AI (via OpenRouter) to read your reference documents and generate accurate, citation-backed answers automatically.
- About
- Live Demo
- Tech Stack
- Features
- Getting Started
- Usage
- Project Structure
- Troubleshooting
- Assumptions
- Trade-offs
- Future Improvements
- Deployment
- Security
- Scripts
- Contributing
- License
- Credits
AlmaAssist automates the tedious process of answering vendor assessment questionnaires sent by university procurement teams. Instead of spending hours manually searching through security policies, compliance documents, and technical specifications, users can:
- Upload a questionnaire PDF and reference documents
- Let AI analyze the documents and generate grounded answers
- Review, edit, and export a professional PDF
EduVault SaaS is a fictional cloud-based student data management platform for universities. The app helps EduVault's GTM team automatically answer vendor assessment questionnaires sent by universities using their internal reference documents.
This is a real problem that university vendors face — procurement teams send long security, compliance, and operational questionnaires that take hours to answer manually. AlmaAssist automates this entire workflow using RAG (Retrieval-Augmented Generation).
Production URL: https://alma-assist-new.vercel.app/
A pre-loaded demo account is available for reviewers:
| Field | Value |
|---|---|
| demo@gmail.com | |
| Password | Hello@1234 |
The account is pre-loaded with:
- EduVault vendor assessment questionnaire (15 questions)
- 2 reference documents (Security Policy + Technical Specs & SLA)
- AI-generated answers with confidence scores and citations
Recommended flow:
- Log in with demo credentials above
- Open the pre-loaded questionnaire
- View AI-generated answers with evidence snippets
- Try editing an answer inline
- Export the completed questionnaire as PDF
| Category | Technology | Version |
|---|---|---|
| Frontend | Next.js (App Router) | 14.x |
| Language | TypeScript | 5.x |
| Styling | Tailwind CSS | 3.4.x |
| Authentication | Firebase Auth | 10.x |
| Database | Cloud Firestore | - |
| AI | Nvidia Nemotron Nano 9B (via OpenRouter) | Free |
| PDF Parsing | pdf-parse | 1.x |
| PDF Export | jsPDF | 2.x |
All services used offer free tiers with no credit card required:
| Service | Cost | Limits |
|---|---|---|
| Firebase Spark | Free | 50K reads/day, 20K writes/day, 1GB storage |
| OpenRouter (Nemotron Nano Free) | Free | $0/token, rate-limited (~20 req/min) |
| Vercel Hosting | Free | 100GB bandwidth, unlimited deployments |
- ✅ User Authentication — Email/password signup and login via Firebase Auth
- ✅ PDF Upload & Parsing — Upload questionnaire PDF + up to 8 reference document PDFs
- ✅ AI Question Extraction — AI automatically identifies individual questions from the questionnaire
- ✅ RAG Answer Generation — Full-context RAG generates answers grounded in your reference documents
- ✅ Confidence Scores — Visual indicator of answer reliability (High / Medium / Low, color-coded)
- ✅ Evidence Snippets — See the exact passage from reference docs that supports each answer
- ✅ Inline Editing — Review and edit any answer before export
- ✅ Coverage Summary — At-a-glance stats on how many questions were answered
- ✅ PDF Export — Download the completed questionnaire as a formatted PDF
- ✅ Questionnaire Management — Rename and delete questionnaires from the dashboard
- ✅ Animated Landing Page — 3D interactive mockup with CSS-only animations
- ✅ Bring Your Own Key (BYOK) — Users can enter their own OpenRouter API key from the dashboard, with test/save/remove functionality. Keys are stored securely in Firestore and used in place of the default server key.
- ✅ Context Mode Toggle — Switch between Compact (~10K tokens) and Full (~50K tokens) context modes when generating answers, giving control over token usage vs. answer quality
- ✅ Token Warning Banner — Amber warning notification when answer generation fails due to token or credit limitations, with clear guidance on next steps
- ✅ Partial Regeneration — Select specific questions to re-generate without redoing the entire questionnaire
- ✅ Server-side Auth on All Routes — All API endpoints verify Firebase ID tokens
- ✅ Input Validation — 10MB file size limit, 500KB text limit, 20 question cap
Before you begin, ensure you have:
| Requirement | Version | Check | Link |
|---|---|---|---|
| Node.js | 18.x or higher | node --version |
nodejs.org |
| npm | 9.x or higher | npm --version |
Comes with Node.js |
| Git | 2.x or higher | git --version |
git-scm.com |
| Firebase Account | - | - | firebase.google.com |
| OpenRouter API Key | - | - | openrouter.ai |
# Clone via HTTPS
git clone https://github.com/JoelJosephPhilip/AlmaAssist.git
# Navigate to project directory
cd AlmaAssist# Install all dependencies
npm installThis will install:
- Next.js and React
- Firebase SDK (Client + Admin)
- pdf-parse for PDF extraction
- jsPDF for PDF generation
- Tailwind CSS and its dependencies
# Copy the example environment file
cp .env.example .env.localOpen .env.local in your text editor and add your values:
# ===========================================
# FIREBASE CLIENT SDK (PUBLIC)
# ===========================================
# These are safe to expose to the client (NEXT_PUBLIC_ prefix)
NEXT_PUBLIC_FIREBASE_API_KEY=your-firebase-api-key-here
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project-id.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-sender-id
NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id
# ===========================================
# FIREBASE ADMIN SDK (PRIVATE - SERVER ONLY)
# ===========================================
FIREBASE_ADMIN_PROJECT_ID=your-project-id
FIREBASE_ADMIN_CLIENT_EMAIL=firebase-adminsdk-xxxxx@your-project.iam.gserviceaccount.com
FIREBASE_ADMIN_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
# ===========================================
# OPENROUTER API (PRIVATE - SERVER ONLY)
# ===========================================
# This is NOT exposed to the client - keep it secret
OPENROUTER_API_KEY=your-openrouter-api-keyImportant:
- Never commit
.env.localto Git (it's already in.gitignore) - Replace placeholder values with your actual keys
- The
NEXT_PUBLIC_prefix makes variables accessible in the browser - Variables without the prefix are server-side only
# Start the development server
npm run devNavigate to: http://localhost:3000
You should see the AlmaAssist landing page.
- Go to Firebase Console
- Click "Create a project"
- Enter project name:
alma-assist(or any name you prefer) - Disable Google Analytics (not needed for this project)
- Click "Create project"
- Wait ~30 seconds for project creation
- Click "Continue"
- In Firebase Console, click "Authentication" in the left sidebar
- Click "Get Started"
- Click "Email/Password" under Sign-in providers
- Toggle "Enable" to ON
- Click "Save"
- Click "Firestore Database" in the left sidebar
- Click "Create database"
- Select "Start in test mode" (for development)
- Select region: Choose closest to your location
- Click "Enable"
- Wait for database creation (~10 seconds)
- Click the gear icon (⚙️) next to "Project Overview"
- Select "Project settings"
- Scroll down to "Your apps" section
- Click the Web icon (
</>) - Enter app nickname:
alma-assist-web - Click "Register app"
- Copy the config values from the displayed code:
const firebaseConfig = {
apiKey: "AIzaSy...", // → NEXT_PUBLIC_FIREBASE_API_KEY
authDomain: "...", // → NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN
projectId: "...", // → NEXT_PUBLIC_FIREBASE_PROJECT_ID
storageBucket: "...", // → NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET
messagingSenderId: "...", // → NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID
appId: "..." // → NEXT_PUBLIC_FIREBASE_APP_ID
};- Go to Project Settings → Service accounts
- Click "Generate new private key"
- Download the JSON file
- Copy the values into
.env.local:project_id→FIREBASE_ADMIN_PROJECT_IDclient_email→FIREBASE_ADMIN_CLIENT_EMAILprivate_key→FIREBASE_ADMIN_PRIVATE_KEY
- Go to Firestore Database → Rules tab
- Replace the default rules with:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
match /questionnaires/{questionnaireId} {
allow read, write: if request.auth != null &&
resource.data.userId == request.auth.uid;
allow create: if request.auth != null;
}
match /questions/{questionId} {
allow read: if request.auth != null;
allow create: if request.auth != null;
allow update: if request.auth != null;
}
match /documents/{documentId} {
allow read, write: if request.auth != null &&
resource.data.userId == request.auth.uid;
allow create: if request.auth != null;
}
}
}
- Click "Publish"
- Go to OpenRouter
- Sign up or log in
- Go to API Keys
- Click "Create Key"
- Copy the generated API key
Add your OpenRouter API key to .env.local:
OPENROUTER_API_KEY=sk-or-v1-...your-actual-key-hereThe app uses the nvidia/nemotron-nano-9b-v2:free model via OpenRouter by default. This is a free model ($0 per token) with 128K context window. Users can also bring their own OpenRouter API key and use any model. OpenRouter works globally (unlike the direct Gemini API which is blocked in some regions).
-
Sign Up
- Click "Get Started" on landing page
- Enter email and password (min 6 characters)
- Click "Create account"
-
Upload Questionnaire
- On dashboard, click "New Questionnaire"
- Upload a questionnaire PDF (max 10MB)
- Only PDF format supported
-
Upload Reference Documents
- Upload 1–8 reference PDFs
- These are your company's internal documents:
- Security policies
- Compliance documentation
- Technical specifications
- Support SLAs
-
Configure & Generate Answers
- Questions are automatically extracted from the questionnaire
- Choose context mode: Compact (faster, less tokens) or Full (more thorough)
- Optionally add your own OpenRouter API key from the dashboard (BYOK)
- Click "Generate Answers"
- Wait for AI processing (~10–30 seconds)
-
Review & Edit
- See all generated answers with confidence scores
- View evidence snippets for each answer
- Edit any answer inline if needed
- Select specific questions for partial regeneration
-
Export PDF
- Click "Export PDF"
- Professional document with all Q&As
- Ready for submission
-
Manage
- Rename or delete questionnaires from the dashboard
The Sample Questionnaire/ folder contains ready-to-use PDF files for testing:
| File | Description | Use As |
|---|---|---|
questionnaire.pdf |
Vendor assessment questionnaire | Questionnaire |
questionnaire-completed.pdf |
Example of a completed questionnaire | Reference |
security-policy.pdf |
EduVault security documentation | Reference |
privacy-compliance.pdf |
FERPA/GDPR compliance policies | Reference |
technical-specs.pdf |
Technical specifications | Reference |
support-sla.pdf |
Support SLA documentation | Reference |
api-documentation.pdf |
API documentation | Reference |
backup-procedures.pdf |
Backup & recovery procedures | Reference |
mfa-policy.pdf |
Multi-factor authentication policy | Reference |
accessibility-compliance.pdf |
Accessibility compliance docs | Reference |
| File | Description | Use As |
|---|---|---|
questionnaire.pdf |
Vendor assessment questionnaire | Questionnaire |
security-policy.pdf |
Security documentation | Reference |
privacy-compliance.pdf |
Compliance policies | Reference |
technical-specs.pdf |
Technical specifications | Reference |
support-sla.pdf |
Support SLA documentation | Reference |
To test the app:
- Upload
questionnaire.pdffrom either folder as the questionnaire - Upload the remaining PDFs as reference documents
- Click "Generate Answers" and review the AI-generated responses
alma-assist/
├── Sample Questionnaire/ # Demo PDF files for testing
│ ├── LARGE-PDFS/ # Full set (10 PDFs)
│ └── SMALL-PDFS/ # Quick test set (5 PDFs)
│
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── api/ # API routes
│ │ │ ├── documents/parse/ # PDF text extraction (auth + 10MB limit)
│ │ │ ├── generate/ # RAG answer generation (auth + ownership)
│ │ │ ├── questionnaire/process/ # Question extraction (auth + 500KB limit)
│ │ │ └── test-key/ # BYOK API key test/save/remove
│ │ ├── dashboard/
│ │ │ ├── new/ # Upload page
│ │ │ └── questionnaire/[id]/ # Review/edit page
│ │ ├── login/ # Login page
│ │ ├── signup/ # Signup page
│ │ ├── layout.tsx # Root layout with AuthProvider
│ │ ├── page.tsx # Landing page (animated 3D mockup)
│ │ └── globals.css # Global styles + CSS animations
│ │
│ ├── components/ # React components
│ │ ├── Header.tsx # Navigation header
│ │ └── ProtectedRoute.tsx # Auth guard wrapper
│ │
│ ├── contexts/ # React contexts
│ │ └── AuthContext.tsx # Firebase auth state
│ │
│ ├── lib/ # Utility libraries
│ │ ├── firebase.ts # Firebase client SDK (lazy init)
│ │ ├── firebase-admin.ts # Firebase Admin SDK (lazy init)
│ │ ├── auth-helpers.ts # Token verification helper
│ │ ├── gemini.ts # OpenRouter AI client (context truncation, BYOK support)
│ │ ├── resolve-api-key.ts # Resolves user or default OpenRouter API key
│ │ └── pdf-export.ts # jsPDF export utility
│ │
│ └── types/ # TypeScript types
│ └── index.ts # All type definitions
│
├── .env.example # Environment template
├── .env.local # Your local config (not committed)
├── .gitignore # Git ignore rules
├── tailwind.config.ts # Tailwind configuration
├── tsconfig.json # TypeScript config
├── next.config.mjs # Next.js configuration
├── package.json # Dependencies
└── README.md # This file
# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
npm install- Verify
.env.localexists and has correct values - Check
NEXT_PUBLIC_FIREBASE_API_KEYis set correctly - Restart development server after creating
.env.local
- Ensure file is a valid PDF
- Check file size is under 10MB
- Verify PDF is not password-protected
- Some scanned PDFs may not have extractable text
- Verify
OPENROUTER_API_KEYin.env.local - Check API key is valid on OpenRouter
- Ensure you haven't exceeded rate limits
- Try again after a few seconds
- The free model (
nvidia/nemotron-nano-9b-v2:free) requires no credits - If using a paid model, add credits at OpenRouter Credits
- Try switching to Compact context mode to reduce token usage
- Or use BYOK — add your own API key from the dashboard
- Your reference documents are too large for the model's context window
- Switch to Compact context mode on the questionnaire page
- Or reduce the number/size of reference documents
# Kill process on port 3000 (Windows)
netstat -ano | findstr :3000
taskkill /PID <PID> /F
# Or use a different port
npm run dev -- -p 3001- Ensure you're logged in before making API calls
- Check that Firebase Auth is properly configured
- Clear browser cookies and log in again
- Users have PDF questionnaires from universities or procurement teams
- Reference documents contain relevant information for answering questions
- Questions follow standard vendor assessment format (numbered questions)
- Users can verify and edit AI-generated answers before submission
- PDFs contain extractable text (not scanned images without OCR)
- Full-context RAG is sufficient — all reference doc text passed in a single prompt (no vector DB / chunking)
- 20 questions per questionnaire — capped to keep AI calls manageable
- 8 reference documents max — sufficient for typical use while staying within model context limits
- Users have stable internet connection for AI processing
| Decision | Benefit | Trade-off |
|---|---|---|
| Full-context RAG (no vector DB) | Simpler architecture, no embedding pipeline, no vector store costs | Won't scale beyond ~100 pages of reference text; higher per-request token usage |
| OpenRouter instead of direct Gemini API | Works globally (direct API blocked in India); easy model switching | Adds a proxy hop; slight latency increase |
| Firebase Auth + Firestore | Fast to set up, free tier generous, real-time capable | Vendor lock-in; Firestore's document model requires denormalization |
| Server-side PDF parsing | Simple pdf-parse integration, no client-side complexity |
Can't handle scanned/image PDFs; large PDFs block the API route |
| CSS-only landing page animations | Zero JS bundle cost, no animation library dependency | Limited to CSS transforms/keyframes; less interactive than Framer Motion |
| Client-side PDF Export (jsPDF) | No server round-trip, instant download | Limited formatting control compared to server-side generation (Puppeteer, etc.) |
| Email-only Auth | Faster to implement, sufficient for B2B | No social login (Google, GitHub) |
- Vector-based RAG with chunking — Replace full-context RAG with a proper embedding pipeline (e.g., OpenAI embeddings + Pinecone/ChromaDB) to handle large document sets and improve retrieval precision
- OCR support — Add Tesseract.js or a cloud OCR API to support scanned PDF questionnaires
- Rate limiting & abuse prevention — Add per-user rate limits on API routes (e.g., using Upstash Redis) to prevent AI endpoint abuse
- Streaming responses — Stream AI responses token-by-token instead of waiting for the full response, improving perceived latency
- Batch processing — Handle multiple questionnaires in parallel with a job queue
- Answer history & versioning — Track edits over time so users can revert or compare answer versions
- Team collaboration — Share questionnaires across team members with role-based access (viewer, editor, admin)
- Template system — Save and reuse answers for frequently asked questions across different questionnaires
- Better PDF export — Use server-side rendering (Puppeteer or React-PDF) for richer formatting, tables, and branding
- E2E tests — Add Playwright or Cypress tests covering the full upload → generate → review → export workflow
- More formats — Support Word, Excel questionnaires
- API integrations — Direct submission to procurement portals
- Analytics dashboard — Track time saved, answer accuracy
Vercel is the easiest deployment option for Next.js:
-
Push to GitHub (already done)
-
Connect to Vercel
- Go to vercel.com
- Sign in with GitHub
- Click "Add New" → "Project"
- Import
AlmaAssistrepository
-
Configure Environment Variables
In Vercel dashboard, add these environment variables:
Variable Value NEXT_PUBLIC_FIREBASE_API_KEYYour Firebase API key NEXT_PUBLIC_FIREBASE_AUTH_DOMAINyour-project.firebaseapp.com NEXT_PUBLIC_FIREBASE_PROJECT_IDyour-project-id NEXT_PUBLIC_FIREBASE_STORAGE_BUCKETyour-project.appspot.com NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_IDyour-sender-id NEXT_PUBLIC_FIREBASE_APP_IDyour-app-id FIREBASE_ADMIN_PROJECT_IDyour-project-id FIREBASE_ADMIN_CLIENT_EMAILyour-admin-client-email FIREBASE_ADMIN_PRIVATE_KEYyour-admin-private-key OPENROUTER_API_KEYYour OpenRouter API key -
Deploy
- Click "Deploy"
- Wait ~2 minutes
- Get live URL
- ✅ All API keys stored in environment variables (never committed to Git)
- ✅ Firebase Security Rules enforce user isolation (users can only access own data)
- ✅ Server-side authentication on ALL API routes (Firebase ID token verification)
- ✅ No secrets in client-side code (
NEXT_PUBLIC_prefix only for safe values) - ✅ Input validation on all API routes (file size, text length limits)
- ✅ PDF file size validation (10MB max)
- ✅ Questionnaire text length validation (500KB max)
- ✅ Question count cap (20 per questionnaire)
- ✅
.env.localexcluded from Git via.gitignore - ✅ Ownership verification on answer generation (users can only generate for their own questionnaires)
| Collection | Rule |
|---|---|
users/{userId} |
User can only read/write own data |
questionnaires/{id} |
User can only access own questionnaires |
questions/{id} |
Authenticated users can read/create/update |
documents/{id} |
User can only access own documents |
- Never commit
.env.localto Git - Regenerate API keys if exposed
- Use environment-specific Firebase projects for production
- Enable Firebase App Check in production
- Review Firestore rules before production deployment
# Development
npm run dev # Start development server (port 3000)
# Build
npm run build # Create production build
npm run start # Start production server
# Quality
npm run lint # Run ESLint- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open a Pull Request
This project is for demonstration purposes.
Built with:
- Next.js — The React Framework
- Firebase — App development platform
- OpenRouter AI — AI model gateway (Nvidia Nemotron Nano free model)
- Tailwind CSS — Utility-first CSS framework
- jsPDF — PDF generation library
- pdf-parse — PDF text extraction
If you encounter any issues or have questions:
- Check the Troubleshooting section
- Open an issue on GitHub
AlmaAssist — Answer vendor questionnaires in minutes, not hours.