Every Nexu lesson is a Firestore document stored under theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Stivenz3/Nexu/llms.txt
Use this file to discover all available pages before exploring further.
lessons/{lessonId} collection, with two subcollections — blocks and questions — holding all the content. Progress for each learner is tracked separately in users/{uid}/lessonProgress/{lessonId}, so the course content is read-only and shared while individual progress is private to each user.
Firestore layout
lessons, blocks, questions) is written once by the seed script and only read by the app. Progress (lessonProgress) is created and updated by the app as the learner advances.
Lesson 1 example — lesson_01_higiene_personal
The following is the actual lesson.json seed file for Lesson 1:
b01_video through b08_exam) and 23 questions — 8 inline questions embedded in theory blocks and 15 questions in the exam pool.
LessonDoc type
The sequential block model
Blocks unlock one at a time, in order. Block N becomes available only when block N-1 hascompleted: true in the user’s lessonProgress. The first block (index 0) is always unlocked.
The isBlockUnlocked function in progressService.ts encodes this rule directly:
canNavigateToBlock handles this case:
Exam unlock gate
The exam block only becomes interactive when every non-exam block has been completed.isExamUnlocked filters out the exam block itself and checks that all remaining blocks have completed: true:
LessonFlowPage calls isExamUnlocked to decide whether to enable the “Iniciar evaluación final” button. If the gate is not met, it shows the user which content block still needs to be completed.
Initial progress document — ensureLessonProgress
When a learner opens a lesson for the first time, ensureLessonProgress checks whether a lessonProgress document already exists. If it does not, it fetches the lesson’s blocks from Firestore and calls buildBlocksProgress to construct typed initial state for every block before writing the document:
buildBlocksProgress iterates over the blocks array and calls createInitialBlockProgress for each block, which returns the correct typed initial object based on block.type:
| Block type | Initial progress shape |
|---|---|
video | { completed: false, videoWatched: false, watchedPct: 0 } |
theory (single question) | { completed: false, questionAnswered: false, answeredCorrect: false } |
theory (multiple questions) | { completed: false, questionsAnswered: [false, false, …] } |
game | { completed: false, gameScore: 0, errorsFound: 0, hintsUsed: 0, timeSpentSec: 0 } |
exam | { completed: false, lastScore: 0, attempts: 0, passed: false } |
Learners who already had a
lessonProgress document from before this logic was introduced keep their existing document unchanged. Only new sessions generate the typed template from Firestore blocks.Progress status values
The top-levelstatus field on a LessonProgress document uses one of four string literals:
| Value | Meaning |
|---|---|
locked | Lesson not yet accessible (previous lesson not passed) |
in_progress | Learner has started but not yet passed the final exam |
passed | Learner scored ≥ passingScore on the final exam |
failed | Learner submitted the exam but scored below passingScore |
status is set to in_progress when the progress document is first created, and updated to passed or failed by saveExamResult after each exam submission.
Lesson service functions
The following functions insrc/services/lessonService.ts load lesson content from Firestore. Course content is read-only from the app’s perspective; only the seed script writes to these collections.
fetchActiveLessons is used by both LearningPathPage (to build the lesson list) and resolveEvalLessonId (to determine which lesson to target for the sidebar exam link). fetchLessonBlocks is called by LessonFlowPage on load and by several progress functions when the caller does not already have a blocks array in memory.
Progress write functions
The following functions insrc/services/progressService.ts write or update the learner’s lessonProgress document in Firestore.
updateBlockProgress
Partially updates the progress entry for a single block without marking it complete. Useful for recording incremental state (e.g. how far through a multi-question theory block the learner has reached).
markBlockCompleted
Sets completed: true on a block’s progress entry and updates lastBlockCompleted on the parent document. Accepts an optional extra object whose fields are merged into the block progress before marking complete (e.g. { videoWatched: true, watchedPct: 100 } for a video block).
resolveEvalLessonId
Returns the lessonId of the last lesson the learner has unlocked — used by the sidebar’s “Evaluación” link to point to the correct lesson regardless of which page the learner is on.
lesson_01_higiene_personal) is always returned as the fallback if no progress exists at all.
Learning path — /ruta
LearningPathPage calls fetchActiveLessons() to load all lessons where isActive: true, ordered by the order field. It then fetches the progress document for each lesson and computes a display status:
- Lesson 1 — always
available(orin-progress/completedif the user has started) - Lesson N+1 — only
availableonce lesson N hasstatus: 'passed'
isActive: true and assigning the correct order value in the lesson’s seed JSON — no frontend code changes are needed.