An AI-powered quiz generation and learning application built with Next.js 15 and Convex. Uses Google Gemini for intelligent content generation and implements spaced repetition algorithms for optimized learning.
- AI-Powered Quiz Generation: Create personalized quizzes using Google Gemini
- Question Management: Edit, delete, and restore your questions with creator-only permissions
- Individual Question Tracking: Every generated question is persisted and tracked independently
- Interaction Analytics: Each answer attempt is recorded with timing and accuracy data
- Optimistic UI: Immediate feedback for all operations with automatic error rollback
- Pure FSRS Spaced Repetition: Unmodified FSRS algorithm without comfort features or daily limits
- Clerk Authentication: Secure, passwordless authentication with Clerk
- Real-time Updates: Built on Convex for instant data synchronization
- Responsive Design: Modern UI with Tailwind CSS and shadcn/ui components
- Keyboard Shortcuts: Power user shortcuts for efficient navigation and review
- Convex-Safe Bandwidth: Every backend query is paginated, indexed, and proven via >1,100 doc regression suites (see Convex Bandwidth Guardrails)
Scry respects the science of memory without compromise:
- No Daily Limits: If 300 cards are due, you see 300 cards
- No Comfort Features: The forgetting curve doesn't care about your comfort
- Natural Consequences: Generate 50 questions? Review 50 questions
- Brutal Honesty: Real counts, real progress, real learning debt
- Pure FSRS: The algorithm as designed, without "improvements"
Every "enhancement" that makes spaced repetition more comfortable makes it less effective. Scry chooses effectiveness.
- Node.js 20.0.0 or higher
- pnpm 10.0.0 or higher
- Convex account (free tier available)
- Google AI API key (for quiz generation)
git clone <repository-url>
cd scry
pnpm installScry uses Convex for the backend database and real-time features. You'll need to create a Convex account and project.
-
Sign up for Convex (free tier available):
# Visit https://convex.dev and create an account # Or sign up via CLI npx convex dev --new
-
Initialize Convex in your project:
# Install Convex CLI globally (recommended) npm install -g convex # Initialize Convex (follow prompts to create/link project) npx convex dev
-
Configure your Convex project:
- Follow the CLI prompts to create a new project or link an existing one
- Choose your team/organization
- The CLI will automatically generate your
NEXT_PUBLIC_CONVEX_URL
- Get your Convex Deployment Key (for production deployments):
- Go to Convex Dashboard
- Select your project
- Navigate to Settings → URL and Deploy Key
- Generate and copy your production deploy key
- For preview deployments, also generate a preview deploy key
# Copy the environment template
cp .env.example .env.local
# Edit .env.local with your configuration
# Your NEXT_PUBLIC_CONVEX_URL should already be set from the Convex setup
# Add the remaining required values (see "Environment Variables" section)
# Validate your environment
pnpm env:validate# In terminal 1: Start Next.js development server
pnpm dev
# In terminal 2: Start Convex development server
npx convex devOpen http://localhost:3000 to view the application.
| Variable | Description | Example |
|---|---|---|
GOOGLE_AI_API_KEY |
Google AI API key for quiz generation and embeddings | AIzaSy... |
NEXT_PUBLIC_CONVEX_URL |
Convex deployment URL | https://...convex.cloud |
CONVEX_DEPLOY_KEY |
Convex deploy key (for Vercel deployments) | prod:... |
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY |
Clerk publishable key | pk_live_... |
CLERK_SECRET_KEY |
Clerk secret key | sk_live_... |
| Variable | Description | Default |
|---|---|---|
NEXT_PUBLIC_APP_URL |
Application base URL for auth redirects | Auto-detected |
For detailed setup instructions, see docs/environment-setup.md.
# Development
pnpm dev # Start development server
pnpm build # Build for production
pnpm start # Start production server
pnpm lint # Run linting
pnpm qa # Lint + typecheck + test:ci
# Testing
pnpm test # Run unit tests
pnpm test:coverage # Run tests with coverage
pnpm test:e2e # Run end-to-end tests
# Environment Management
pnpm env:validate # Validate current environment
pnpm env:validate:prod # Validate production readiness
pnpm deploy:check # Full deployment readiness check
# Asset Generation
pnpm assets:generate # Generate static assets
pnpm assets:generate-all # Generate all assets (verbose)The project uses Vitest for unit and integration testing, with Playwright for end-to-end tests.
# Run all unit tests
pnpm test
# Run tests in watch mode for development
pnpm test:watch
# Run tests with coverage report
pnpm test:coverage
# Run specific test file
pnpm test lib/format-review-time.test.ts
# Run E2E tests
pnpm test:e2eTests are located alongside their source files using the .test.ts or .test.tsx suffix:
lib/
format-review-time.ts
format-review-time.test.ts
components/
Button.tsx
Button.test.tsx
convex/
fsrs.ts
fsrs.test.ts
After running pnpm test:coverage, coverage reports are available in:
- Terminal: Summary displayed after test run
- HTML Report: Open
coverage/index.htmlin your browser for detailed coverage - JSON:
coverage/coverage-final.jsonfor CI integration
Current coverage is intentionally low as we build up the test suite incrementally. Focus is on testing critical business logic first.
Example test structure:
import { describe, it, expect } from 'vitest'
import { yourFunction } from './your-module'
describe('yourFunction', () => {
it('should handle expected input', () => {
const result = yourFunction('input')
expect(result).toBe('expected output')
})
})This project uses separate Convex instances:
- Development:
amicable-lobster-935(local development) - Production:
uncommon-axolotl-639(production deployments)
Deployment Order: Convex Backend → Validation → Vercel Frontend
-
Vercel CLI: Install and authenticate
npm install -g vercel vercel login
-
Convex Deploy Key: Get production deploy key
- Visit Convex Dashboard
- Navigate to Settings → Deploy Keys
- Generate and copy production deploy key (starts with
prod:)
-
Environment Validation: Ensure all required variables are set
pnpm env:validate:prod pnpm deploy:check
The project uses automated atomic deployment via Vercel's build command:
-
Link Vercel Project (first time only):
vercel link
-
Configure Environment Variables in Vercel Dashboard:
GOOGLE_AI_API_KEY- Google AI API keyNEXT_PUBLIC_CONVEX_URL- Production Convex URLCONVEX_DEPLOY_KEY- Production deploy key (from step 2) - Production only
Important:
- Set all variables for both Production and Preview environments
- Exception:
CONVEX_DEPLOY_KEYis only needed for Production- Preview deployments use the already-deployed development Convex instance
- They do not trigger new Convex deployments, only Next.js builds
-
Update Build Command in Vercel Dashboard:
- Navigate to: Project Settings → Build & Development Settings
- Set "Build Command Override":
npx convex deploy --cmd 'pnpm build' - This is already configured in
vercel.jsonbut dashboard override provides redundancy
# Deploy to preview environment
vercel
# Deploy to production
vercel --prodWhat Happens Automatically:
- Vercel runs:
npx convex deploy --cmd 'pnpm build' - Convex functions deploy first using
CONVEX_DEPLOY_KEY - Schema version tracking validates compatibility
- Next.js application builds with deployed backend
- Frontend deploys to Vercel
For manual deployments or production hotfixes, use the atomic deployment script:
# Export production deploy key
export CONVEX_DEPLOY_KEY="prod:your-key-here"
# Run atomic deployment script
./scripts/deploy-production.shScript Steps:
- Deploys Convex backend functions
- Runs health check to verify critical functions exist
- Deploys Vercel frontend (only if backend healthy)
- Exits with error at first failure
Verify deployment health before and after deploying:
# Check that all critical functions are deployed
./scripts/check-deployment-health.shValidates:
- Convex deployment connectivity
- Critical functions exist:
generationJobs:getRecentJobs,createJob,cancelJobaiGeneration:processJobquestions:saveBatchspacedRepetition:getNextReview,scheduleReview
Exit codes: 0 = healthy, 1 = unhealthy with detailed error
The application automatically validates frontend/backend compatibility:
- Backend Version: Defined in
convex/schemaVersion.ts - Frontend Version: Defined in
lib/deployment-check.ts - Validation: Runs on every page load via
DeploymentVersionGuard
Backwards Compatibility:
- If backend doesn't have version checking function, check is silently skipped
- Allows gradual rollout without breaking existing deployments
- Console warning logged for debugging
On Version Mismatch:
- Error displayed to user with clear explanation
- Instructions provided for fixing the mismatch
- Prevents runtime errors from missing functions/fields
Feature Flag (Emergency Bypass):
Set NEXT_PUBLIC_DISABLE_VERSION_CHECK=true to disable version checking entirely.
# In Vercel dashboard or .env.local
NEXT_PUBLIC_DISABLE_VERSION_CHECK=trueUpdating Schema Version:
- Increment version in
convex/schemaVersion.ts(semantic versioning) - Update matching version in
lib/deployment-check.ts - Deploy backend first:
npx convex deploy - Deploy frontend second:
vercel --prod - Or use atomic script:
./scripts/deploy-production.sh
After deployment, verify functionality:
# View Vercel deployment logs
vercel logs --prod
vercel logs --prod --follow # Real-time streaming
# View Convex backend logs
npx convex logs
# Run health check
./scripts/check-deployment-health.shManual Verification:
- Visit production URL and check for "Server Error"
- Open browser console - should be clean except preload warnings
- Test question generation flow
- Test spaced repetition reviews
- Verify schema version check passes (no error modal)
"Function not found" errors in production:
- Cause: Frontend deployed before backend functions
- Fix: Run
npx convex deploythen redeploy frontend - Prevention: Use automated deployment or atomic script
Schema version mismatch errors:
- Cause: Backend and frontend versions don't match
- Fix: Ensure both
convex/schemaVersion.tsandlib/deployment-check.tshave same version - Deploy: Backend first, then frontend
Convex deploy fails in Vercel build:
- Cause:
CONVEX_DEPLOY_KEYnot set or invalid - Fix: Verify key exists in Vercel environment variables
- Scope: Must be set for both Production AND Preview
Health check fails:
- Cause: Critical functions missing from deployment
- Fix: Check Convex dashboard for deployment errors
- Retry:
npx convex deployto redeploy functions
Migration reports success but data unchanged:
- Cause: Deployed to wrong environment (DEV instead of PROD)
- Diagnosis: Check deployment URL in migration logs - should show production deployment
- Fix: Export
CONVEX_DEPLOY_KEYexplicitly (see CLAUDE.md), re-run migration - Prevention: Use
./scripts/run-migration.sh(validates deployment target)
Migration doesn't detect fields that exist:
- Cause: TypeScript type erasure removes runtime property checks for deleted schema fields
- Diagnosis: Migration code uses
doc.field !== undefined(compile-time check gets optimized away) - Fix: Use
'field' in (doc as any)for runtime property existence check - Prevention: Follow migration development guide (
docs/guides/writing-migrations.md)
- Always Use Atomic Deployment: Prefer automated Vercel deployment or manual script
- Validate Before Deploying: Run
./scripts/check-deployment-health.shbefore production deploy - Update Schema Versions: Keep frontend and backend versions in sync
- Monitor After Deploy: Check logs and run health check after every deployment
- Test Preview First: Deploy to preview environment before production
- Production: https://scry.study
- Health Check: https://scry.study/api/health
- Framework: Next.js 15 with App Router
- Backend: Convex for database and real-time features
- Database Model: Individual question persistence with separate interactions tracking
- AI Integration: Google Gemini via Vercel AI SDK
- Authentication: Clerk Authentication
- Styling: Tailwind CSS v4 with shadcn/ui components
- Sentry: Error tracking with PII scrubbing
- PostHog: Product analytics and feature flags
- Vercel Analytics: Web vitals
- Generates structured quizzes with 5 questions and 4 answer options
- Questions are persisted individually upon generation (not just quiz results)
- Each answer attempt is tracked with timing and accuracy data
- Supports difficulty levels: easy, medium, hard
- Uses JSON schema validation for consistent output
- API endpoint:
/api/generate-questions
- Clerk authentication and session management
- Protected routes and API endpoints
- Comprehensive error handling and logging
- Built-in performance monitoring dashboard
- Core Web Vitals tracking
- Database query performance monitoring
- Individual question and interaction analytics
- Custom metrics API at
/api/performance
- Every generated question is stored independently
- User interactions tracked with millisecond precision
- Denormalized stats for efficient querying (attemptCount, correctCount)
- Dashboard views for all questions and unattempted questions
- Historical quiz results linked to individual interactions
Scry uses an advanced spaced repetition system powered by the FSRS (Free Spaced Repetition Scheduler) algorithm to optimize your learning and retention.
- Automatic Scheduling: Every question you answer is automatically scheduled for review based on your performance
- Smart Review Queue: Questions appear for review at scientifically-optimized intervals to maximize retention
- No Manual Rating: Unlike traditional spaced repetition apps, Scry automatically determines review intervals based on whether you answered correctly or incorrectly
- Real-time Updates: Your review queue updates in real-time as questions become due
- Review Page: Click "Review" in the navigation menu to access your review queue
- Dashboard Indicator: See how many questions are due for review on your dashboard
- Quick Start: Use the "Start Review" button on the dashboard to jump right in
Traditional spaced repetition systems require you to rate your confidence (e.g., "Again", "Hard", "Good", "Easy") after each answer. Scry simplifies this:
- Correct Answer → Scheduled for review at a longer interval
- Incorrect Answer → Scheduled for immediate or short-term review
This approach:
- Saves Time: No need to think about rating your confidence
- Reduces Bias: Removes subjective self-assessment
- Mobile-Friendly: Single-tap answers work perfectly on phones
- Faster Reviews: Complete more reviews in less time
Scry uses the FSRS algorithm, which represents the current state-of-the-art in spaced repetition:
- Adaptive Intervals: Review intervals automatically adjust based on your performance history
- Optimal Retention: Maintains ~90% retention rate with minimal reviews
- Memory Modeling: Tracks stability and difficulty for each question individually
- Efficient Learning: Reduces total review time by 30-50% compared to traditional methods
- Create Quizzes: Generate quizzes on topics you want to learn
- Answer Questions: Complete quizzes at your own pace
- Check Reviews: Visit the Review page when questions become due
- Stay Consistent: Regular reviews lead to long-term retention
The review indicator on your dashboard will show when questions are ready for review. Questions you've never seen before are prioritized, followed by overdue questions that need reinforcement.
Scry provides comprehensive question management capabilities with creator-only permissions and optimistic UI for immediate feedback.
- Edit Questions: Modify question text, topic, and explanation while preserving spaced repetition data
- Soft Delete: Delete questions with ability to restore them later
- Creator Permissions: Only question creators can edit or delete their questions
- Optimistic Updates: Immediate UI feedback with automatic rollback on errors
- Real-time Sync: Changes sync instantly across all sessions using Convex
- FSRS Preservation: CRUD operations preserve spaced repetition scheduling data
Accessing Question Management:
- Navigate to "My Questions" from the dashboard or main menu
- View all your created questions in a searchable grid
- Use edit/delete buttons that appear only on questions you created
Editing Questions:
- Click the edit button (pencil icon) on any question you created
- Modify the question text, topic, or explanation
- Questions, options, and correct answers cannot be changed to preserve learning data
- Changes are saved instantly with immediate visual feedback
- Form validation ensures data integrity
Deleting Questions:
- Click the delete button (trash icon) with confirmation dialog
- Questions are soft-deleted (not permanently removed)
- Deleted questions are excluded from quiz generation and spaced repetition
- Your learning progress and interaction history are preserved
Restoring Questions:
- Use the
restoreQuestionAPI to recover accidentally deleted questions - All spaced repetition data and interaction history remain intact
- Restored questions immediately re-enter your review queue if due
Permission Model:
// Creator-only access enforced at the database level
const isOwner = question.userId === ctx.userId;
if (!isOwner) {
throw new Error("Only the question creator can edit this question");
}Optimistic Updates:
- Edit Operations: Immediate UI updates with automatic rollback on server errors
- Delete Operations: Questions disappear instantly with toast confirmation
- Error Handling: Failed operations revert UI state and show error messages
- Performance: <1ms perceived response time via optimistic state management
Data Integrity:
- FSRS Preservation: Spaced repetition scheduling data (stability, difficulty, review dates) remains unchanged during edits
- Interaction History: All previous answer attempts and timing data are preserved
- Soft Delete: Deleted questions retain all data and can be fully restored
- Audit Trail: All CRUD operations are logged with timestamps
API Endpoints:
questions.updateQuestion: Edit question with validation and permissionsquestions.softDeleteQuestion: Soft delete with creator verificationquestions.restoreQuestion: Restore deleted questions with full data recoveryquestions.getUserQuestions: Query with optionalincludeDeletedparameter
When to Edit:
- Fix typos or clarify question wording
- Update topic categorization for better organization
- Add or improve explanations for learning value
- Avoid changing the meaning or correct answer
When to Delete:
- Remove duplicate questions
- Clean up poorly generated content
- Remove questions that are no longer relevant
- Note: Deletion doesn't affect your learning statistics
Performance Considerations:
- CRUD operations use optimistic updates for instant feedback
- Large question libraries may benefit from pagination (implemented automatically)
- Search and filtering help manage extensive question collections
- Real-time sync ensures consistency across devices and sessions
Scry includes comprehensive keyboard shortcuts for power users to navigate and review efficiently.
| Shortcut | Action | Description |
|---|---|---|
? |
Show Help | Display keyboard shortcuts reference |
h |
Home | Navigate to home/review page |
Ctrl+S |
Settings | Open settings page |
n |
New Questions | Focus topic input for generation |
Esc |
Close/Cancel | Close modals or cancel editing |
| Shortcut | Action | Description |
|---|---|---|
1-4 |
Select Answer | Choose answer option by number |
Enter |
Submit/Next | Submit answer or go to next question |
Space |
Next Question | Advance when showing feedback |
→ |
Next Question | Alternative next navigation |
e |
Edit Question | Open edit mode for current question |
d or Delete |
Delete Question | Remove current question |
Ctrl+Z |
Undo | Undo last action (when available) |
s |
Skip Question | Mark as difficult and skip |
x |
Toggle Explanation | Show/hide answer explanation |
- Keyboard Icon: A pulsing keyboard icon appears in the bottom-right corner
- Help Modal: Press
?at any time to see all available shortcuts - Context Awareness: Shortcuts adapt based on current state (answering vs feedback)
- Speed Review: Use number keys for answers and Enter to submit rapidly
- Keyboard-Only Navigation: Complete entire review sessions without touching the mouse
- Quick Edits: Press
eto instantly edit questions inline - Efficient Skipping: Use
sto mark difficult questions for later review - Modal Management: Escape key consistently closes any open modal
The keyboard shortcuts system is designed to make reviewing fast and efficient, especially for users who prefer keyboard navigation over mouse interactions.
| Shortcut | Action | Description |
|---|---|---|
Cmd+Shift+D (Mac) / Ctrl+Shift+D (PC) |
Toggle Debug Panel | Shows performance metrics, render counts, and active timers |
The debug panel provides real-time performance monitoring during development:
- FPS counter and render tracking
- Component performance metrics
- Active timer monitoring
- State transition tracking
Note: Debug tools are automatically excluded from production builds.
Build failures:
- Run
pnpm env:validateto check environment variables - Ensure all required dependencies are installed
- Check Node.js version compatibility
Authentication issues:
- Verify Clerk configuration in dashboard and environment variables
- Check
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYandCLERK_SECRET_KEYare set - Ensure
NEXT_PUBLIC_APP_URLis set correctly in production - Ensure Clerk authentication integration is configured correctly
Convex connection issues:
- Verify
NEXT_PUBLIC_CONVEX_URLis correct from your Convex dashboard - Ensure Convex development server is running:
npx convex dev - Check that Convex functions are deployed:
npx convex deploy - Verify
CONVEX_DEPLOY_KEYis set for production deployments - Run
npx convex logsto check for backend errors - Ensure you're connected to the correct Convex project
Deployment issues:
- Check that both Convex and Vercel deployments succeed
- Verify all environment variables are set in Vercel dashboard
- Ensure
CONVEX_DEPLOY_KEYis configured for both Production and Preview environments - Run the deployment verification script:
node scripts/verify-deployment-setup.cjs
- Check the docs/ directory for detailed guides
- Run
pnpm deploy:checkfor deployment readiness - Monitor logs with
vercel logs <deployment-url> - Visit the health endpoint for system status
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests:
pnpm test - Validate environment:
pnpm env:validate - Submit a pull request
MIT License - see LICENSE file for details.