This document outlines the implementation strategy for four new features in the ChainLearn API:
- #316: Batch quiz generation endpoint
- #317: Course progress sync with on-chain state
- #318: Public user profile endpoint
- #319: Course completion certificate generation (PDF)
Add an endpoint that generates quizzes for multiple modules in a single request.
- File:
src/modules/quizzes/quiz.routes.ts - Endpoint:
POST /api/v1/quizzes/generate-batch - Request Body:
{ courseId: string; moduleIds: string[]; difficulty?: string; numQuestions?: number; }
- File:
src/modules/quizzes/quiz.controller.ts - Method:
generateBatchQuizzes - Validate that all moduleIds belong to the specified courseId
- Enforce rate limiting to prevent AI service abuse
- File:
src/modules/quizzes/quiz.service.ts - Method:
generateBatchQuizzes - Sequential generation to avoid AI service overload
- Handle partial failures gracefully (return successful generations even if some fail)
- Return structure:
{ successful: Array<{ moduleId: string; quiz: Quiz }>; failed: Array<{ moduleId: string; error: string }>; }
- Apply strict rate limiting (e.g., 5 requests per minute per user)
- Leverage existing
src/middleware/rate-limit.tspatterns
Add a background job that periodically syncs course progress from the on-chain progress-tracker contract to the local database.
- File:
src/jobs/sync-progress.ts - Run every 15 minutes using cron or setInterval
- Query the progress-tracker contract for active users
- Fetch on-chain progress for each user with active enrollments
- Compare with local database state (enrollments, quiz submissions)
- Update local records if on-chain state differs
- Log discrepancies for monitoring
- Graceful failure handling (don't crash server on sync errors)
- Log failed syncs with user/course context
- Continue syncing other users even if one fails
- Add Prometheus metric to track:
- Total syncs performed
- Successful syncs
- Failed syncs
- Records updated
- Register job in
src/server.tsstartup - Ensure job doesn't conflict with existing jobs
Add a public profile endpoint that returns limited user information without requiring authentication.
- File:
src/modules/users/user.routes.ts - Endpoint:
GET /api/v1/users/:id/public-profile - Authentication: None (public endpoint)
- File:
src/modules/users/user.controller.ts - Method:
getPublicProfile - Return 404 if user doesn't have a displayName set
- File:
src/modules/users/user.service.ts - Method:
getPublicProfile - Return only:
displayNamecredentialsEarned(count)completedCourses(list of course IDs/names)totalQuizScore(aggregate)
- Exclude sensitive fields:
stellarAddresscreditslearningGoalemailisAdmin
- Cache response for 5 minutes using Redis
- Cache key:
public-profile:${userId} - Invalidate cache when user updates their profile
- Only expose profiles for users who have set a displayName (opt-in)
- Add documentation about what fields are public
Generate a downloadable PDF certificate when a user completes a course, in addition to the on-chain NFT credential.
- File:
src/services/certificate.ts - Use
pdfkitlibrary for PDF generation - Create certificate template with:
- Course title
- User name (displayName)
- Completion date
- QR code linking to public verification endpoint
- File:
src/modules/credentials/credential.routes.ts - Endpoint:
GET /api/v1/credentials/:id/certificate - Authentication: Required (user must own the credential)
- File:
src/modules/credentials/credential.controller.ts - Method:
getCertificate - Verify credential ownership
- Generate PDF on first request
- Cache PDF for subsequent requests
- Stream PDF as response with proper headers
- Store generated PDFs in Redis or filesystem
- Cache key:
certificate:${credentialId} - Invalidate cache if credential data changes (unlikely)
- Use
qrcodelibrary - QR links to:
https://api.chainlearn.com/api/v1/credentials/:id/verify(public endpoint) - Verification endpoint returns credential authenticity
- Add
pdfkitfor PDF generation - Add
qrcodefor QR code generation
- Test each new service method in isolation
- Mock external dependencies (database, Stellar client, AI service)
- Test complete request/response flow for each endpoint
- Verify rate limiting behavior (#316)
- Test partial failure handling (#316)
- Verify cache invalidation (#318)
- Test PDF generation and caching (#319)
- Generate batch quizzes with various module counts
- Verify on-chain sync accuracy
- Test public profile with/without displayName
- Download and verify PDF certificate appearance
No new migrations required for these features. All use existing schema.
-
Batch Quiz Generation (#316)
- Sequential processing prevents AI service overload
- Rate limiting prevents abuse
- Consider background job for large batches (future enhancement)
-
Progress Sync (#317)
- Run during off-peak hours if possible
- Batch Stellar queries to reduce RPC calls
- Add circuit breaker for Stellar client failures
-
Public Profile (#318)
- 5-minute cache reduces database load
- Consider adding pagination for completedCourses if list grows large
-
Certificate Generation (#319)
- Cache generated PDFs indefinitely (credentials don't change)
- Consider offloading to background job for async generation
- Monitor Redis memory usage for PDF storage
-
Batch Quiz Generation (#316)
- Strict rate limiting to prevent AI service abuse
- Validate user enrollment before generating quizzes
- Validate moduleIds belong to specified courseId
-
Progress Sync (#317)
- Read-only operation (safe)
- Log all sync operations for audit trail
-
Public Profile (#318)
- Only expose opt-in profiles (users with displayName)
- Never expose sensitive fields (stellarAddress, credits, etc.)
- Rate limit to prevent scraping
-
Certificate Generation (#319)
- Verify credential ownership before generating certificate
- Ensure QR verification endpoint is public and cacheable
- Consider adding watermark or signature to prevent forgery
- Implement #318 (Public Profile) - Low risk, no external dependencies
- Implement #316 (Batch Quiz Generation) - Medium complexity
- Implement #319 (Certificate Generation) - Requires new dependencies
- Implement #317 (Progress Sync) - Most complex, requires careful testing
- Deploy to staging environment
- Run integration tests
- Manual QA for each feature
- Deploy during off-peak hours
- Monitor error rates and performance metrics
- Enable progress sync job after verifying other features work
- #316: Should we add a maximum limit on moduleIds per request (e.g., max 10 modules)?
- #317: Should the sync job update local state even if on-chain is behind (e.g., on-chain shows less progress)?
- #318: Should we include course names or just course IDs in completedCourses?
- #319: Should certificate design be customizable per course, or use a single template?
- #318 (Public Profile): 4-6 hours
- #316 (Batch Quizzes): 6-8 hours
- #319 (Certificate): 8-10 hours
- #317 (Progress Sync): 10-12 hours
- Testing & QA: 6-8 hours
Total: 34-44 hours (~5-6 working days)
These four features enhance the ChainLearn API by:
- Improving user experience (batch quiz generation, public profiles, certificates)
- Ensuring data consistency (progress sync)
- Providing traditional proof of completion (PDF certificates)
All features leverage existing infrastructure and patterns, minimizing risk while delivering valuable functionality.