This document traces the complete lifecycle of a learner's journey through ChainLearn, from account creation through credential minting. Each step identifies which service handles the operation and where data is stored.
Enroll -> Study -> Take Quiz -> Get Score -> Earn Reward -> Mint Credential
| | | | | |
API API+AI API+AI API API+Contracts API+Contracts
PG PG/Cache PG PG Stellar Stellar+PG
Service: chainlearn-api
- User opens
chainlearn-frontendand clicks "Sign In." - Frontend initiates SEP-10 challenge/response flow:
- Frontend requests a challenge transaction from
chainlearn-api(POST /auth/challenge). - User signs the challenge with their Stellar wallet (Freighter/Albedo).
- Frontend submits the signed challenge to
chainlearn-api(POST /auth/verify).
- Frontend requests a challenge transaction from
- API validates the signature against the Stellar network, issues a JWT.
- API creates or updates the user record in PostgreSQL.
Data stored:
| Location | Data |
|---|---|
| PostgreSQL | users table: id, stellar_address, display_name, created_at |
| Client | JWT in localStorage |
Service: chainlearn-api
- User browses the course catalog on the frontend.
- Frontend fetches courses from
GET /courses(paginated, filterable). - User selects a course and clicks "Enroll."
- Frontend calls
POST /courses/{id}/enroll. - API creates an enrollment record and calls the ProgressTracker contract to register enrollment on-chain.
- API calls
POST /courses/{id}/modulesto fetch the module list (content may be AI-generated on first access).
Data stored:
| Location | Data |
|---|---|
| PostgreSQL | enrollments table: id, user_id, course_id, status, enrolled_at |
| PostgreSQL | modules table: id, course_id, title, content, order |
| Stellar (ProgressTracker) | Enrollment event emitted with user, course_id, timestamp |
Service: chainlearn-api + chainlearn-ai
- User opens a module. Frontend fetches content from
GET /modules/{id}. - If module content exists in PostgreSQL, API returns it directly.
- If content needs generation (first access or refresh):
- API sends a request to
chainlearn-ai(POST /generate/course). - AI service generates structured content using Cohere's language model.
- AI service returns the content to the API.
- API persists the content in PostgreSQL and returns it to the frontend.
- API sends a request to
- User reads the content. Frontend tracks reading progress client-side.
- When the user completes a module, frontend calls
POST /modules/{id}/complete. - API updates the enrollment progress and calls ProgressTracker to log module completion on-chain.
Data stored:
| Location | Data |
|---|---|
| PostgreSQL | module_completions table: id, user_id, module_id, completed_at |
| PostgreSQL | modules.content |
| Redis | AI generation cache (TTL: 24h) |
| Stellar (ProgressTracker) | Module completion event |
Service: chainlearn-api + chainlearn-ai
- After completing all modules, user unlocks the course quiz.
- Frontend calls
POST /quizzes/generatewith the course ID. - API forwards the request to
chainlearn-ai(POST /generate/quiz). - AI service generates quiz questions based on the course content, calibrated to the course difficulty level.
- API stores the quiz in PostgreSQL and returns it to the frontend (answers omitted from response).
- User answers each question. Frontend calls
POST /quizzes/{id}/submitwith all answers. - API sends the submission to
chainlearn-ai(POST /evaluate/quiz). - AI service evaluates each answer, providing a score and per-question feedback.
- API stores the result and checks if the score meets the passing threshold (default: 70%).
Data stored:
| Location | Data |
|---|---|
| PostgreSQL | quizzes table: id, course_id, questions (JSONB), created_at |
| PostgreSQL | quiz_attempts table: id, quiz_id, user_id, score, answers (JSONB), feedback (JSONB), passed, submitted_at |
| Redis | Quiz cache (TTL: 1h) |
Service: chainlearn-api + chainlearn-contracts
- If the quiz score meets the passing threshold, the API initiates reward distribution.
- API calls the LearnToken contract's
transferfunction to send tokens to the learner's Stellar address. - The amount is determined by the course's reward configuration (e.g., 100 LEARN tokens per course).
- API records the reward transaction in PostgreSQL.
- Frontend displays the reward with a link to the Stellar transaction.
Data stored:
| Location | Data |
|---|---|
| PostgreSQL | rewards table: id, user_id, course_id, amount, tx_hash, distributed_at |
| Stellar (LearnToken) | Token transfer from platform treasury to learner |
| Stellar ledger | Transaction record with memo |
Service: chainlearn-api + chainlearn-contracts
- After reward distribution, API initiates credential minting.
- API calls the CredentialNFT contract's
mintfunction with:to: learner's Stellar addresscourse_id: the completed coursemetadata_uri: pointer to off-chain metadata (IPFS or API-hosted JSON)
- The NFT is non-transferable (soulbound). The contract enforces this at the code level.
- API records the credential in PostgreSQL with the mint transaction hash.
- Frontend shows the credential in the user's credential gallery.
Data stored:
| Location | Data |
|---|---|
| PostgreSQL | credentials table: id, user_id, course_id, nft_id, tx_hash, metadata_uri, minted_at |
| Stellar (CredentialNFT) | NFT minted to learner's address |
| IPFS / API | Credential metadata JSON: { course_title, completion_date, score, issuer } |
Service: chainlearn-api + chainlearn-indexer
- Anyone can verify a credential by querying the Stellar network.
- A verifier visits
chainlearn-frontend/verify/{credential_id}or queries the API directly. - API (or frontend via indexer) reads the CredentialNFT contract's
get_credentialfunction. - Indexer provides fast lookup of credential metadata by caching on-chain data in PostgreSQL.
- The verification result shows: holder address, course title, completion date, score, and issuer signature.
Data read:
| Location | Data |
|---|---|
| Stellar (CredentialNFT) | On-chain credential record (authoritative) |
| PostgreSQL (indexer) | Cached credential metadata for fast queries |
| Failure Point | Behavior |
|---|---|
| AI service unavailable | Course content falls back to pre-authored templates. Quiz generation retries 3x, then queues for later. |
| Smart contract call fails | Reward/credential is queued in a pending_rewards table. A background job retries every 5 minutes for 24 hours. |
| Stellar network congestion | Transactions use increasing fee bumps. After 3 retries, the operation is queued. |
| Indexer lag | API reads directly from Stellar RPC for real-time queries. Indexer data is eventually consistent (< 30s lag). |