Study Plans
Study Plans
Section titled “Study Plans”Admin-defined study plan templates resolve when a user creates a study. Steps are snapshotted into per-study rows so template edits do not change in-flight studies.
Terminology: use study step in API/DB (not “TODO”) to avoid confusion with deferred mentorship tasks (Product Scope).
Entities
Section titled “Entities”| Concept | Table | GraphQL |
|---|---|---|
| Plan template | study_plan_templates | StudyPlanTemplate (admin) |
| Template step | study_plan_template_steps | StudyPlanTemplateStep (admin) |
| Study step (instance) | study_steps | StudyStep |
Guided studies: published templates with study_method = guided are the catalog (title, description, spiritual phases). Users pick a template id as focus; see Study Methods.
Spiritual phases: each template has one or more spiritualPhases (pivot study_plan_template_spiritual_phases). Resolution matches when the user’s spiritual_phase is in that set (explicit allowlist, not a ladder).
Snapshot rule
Section titled “Snapshot rule”On createStudy:
- Resolve a published template from method, user
spiritual_phase, and focus. - Set
studies.plan_template_idandplan_applied_at. - Copy each template step into
study_steps(title, instructions, flow fields,step_keyfrozen). - All steps in wave 1 are
available; others remainpendinguntil their wave unlocks.
Template changes affect new studies only.
Step instructions (rich text)
Section titled “Step instructions (rich text)”Template and study step instructions are stored as the same rich text envelope JSON string used for note CRDT bodies (column type remains text). Admins edit instructions in the TipTap-based admin editor; clients render with RichTextPreview.
Filter blocks (filterBlock nodes) hold conditional content keyed by user personality and learning style. At step materialization (snapshot onto study_steps), the server evaluates filters against the creating user’s profile and strips non-matching blocks so each study step stores only the instructions that user should see.
Legacy markdown instructions import via fromMarkdown() on read; new content is always envelope JSON.
Resolution
Section titled “Resolution”| Method | Resolution order |
|---|---|
| Book (milk) | Published template for (book, user phase) — strict; create fails if missing. UI lists books via availableBookStudyBooks. |
| Book (meat) | Book-specific template if any → else generic meat template; if user already completed a study on the same book, variant=repeat template. |
| Book (transition) | Book-specific if any → else generic transition → phase fallback. |
| Guided | Published template for id in focus — strict if missing or phase-inaccessible. UI lists plans via availableGuidedStudyPlans. |
| Topical / word / character / hypothetical | Generic template for (method, phase) with phase fallback; create allowed without steps if unpublished (soft). |
Book focus is normalized to canonical USFM ids (e.g. Jn → Jhn) at create.
Step lifecycle
Section titled “Step lifecycle”Templates maintain separate step lists for mentored and individual participation (mentoredSteps / individualSteps in admin GraphQL). Materialization copies only the list matching the study’s participation_mode.
Each step declares:
| Field | Purpose |
|---|---|
wave | Steps in the same wave unlock together; the next wave opens when all steps in the current wave are completed |
completionMode | write_note, review_note, meet, acknowledge, assign_track, answer_quiz, grade_quiz, review_quiz, attest_outcomes, or promote_phase |
primaryActor | mentee, mentor, or pair — who must act to complete |
completionConfig | Mode-specific options (e.g. review reject target, meet stub note flags) |
Wave progression: wave 1 steps are available at create; others start pending. Completing every step in a wave unlocks the next wave. During parallel waves (e.g. meeting prep), mentor and mentee each see their own actionable step; the other party may see a waitingReason until the wave completes.
Review rejection: mentors can rejectStudyStepReview on a review_note step (when allowReject is true). A mentor note is required; the prior write_note step reopens for revision while the review step returns to pending.
Meet steps (stub): authored as meet; runtime behaves as acknowledge plus optional lane notes until study sessions ship.
Mentor private notes: optional per-step reminders on mentor_private_note_id — mentor read/write only, excluded from discipleship lane sharing.
- Visibility: clients query
study.nextSteps(limit)for viewer-actionable steps in the active wave (may return multiple during parallel work). - Complete:
completeStudyStepvalidates against snapshottedcompletionMode(optional lane note ids,quizAttemptId, oroutcomeChecks). - Mentorship: mentored studies use mentee and mentor note lanes per step; individual studies use the individual lane. See Mentorship.
- Study ended:
updateStudywithendedAtcancels pending/available steps (cancelled). Notes and log entries remain the source of truth.
Admin UI
Section titled “Admin UI”Curriculum designers and platform administrators manage templates at /admin/plans. Designer guide: Study plans. Platform-only routes (users, audit, feature flags, AI config) require a platform administrator.
| Route | Purpose |
|---|---|
/admin/plans | List, filters, resolution simulator |
/admin/plans/new, /admin/plans/[id] | Template form (dual mentored/individual steps, AI review) |
/admin/plans/new/assistant | AI wizard — platform admin + admin_study_plan_ai |
/admin/plans/rubric | Rubric dimension CRUD |
/admin/plans/outcomes | Learning outcome CRUD |
/admin/quizzes | Quiz bank list |
/admin/quizzes/[id] | Quiz authoring (questions, draw config, AI review) |
/admin/curriculum/reviews | Review queue — submit, approve, request changes |
GraphQL: adminStudyPlanTemplates, create/update/delete; learningOutcomes (authenticated catalog); admin createLearningOutcome / updateLearningOutcome / deleteLearningOutcome; adminQuizzes, adminQuiz, createQuiz, updateQuiz, deleteQuiz, question/variant CRUD, reviewQuiz; review mutations submitCurriculumReview, approveCurriculumReview, requestCurriculumChanges, withdrawCurriculumReview, mergeCurriculumRevision; queries curriculumReviewQueue, curriculumReviewRequest, curriculumRevision.
Editorial workflow (curriculum review)
Section titled “Editorial workflow (curriculum review)”Unpublished templates follow a draft → in review → approved → publish flow (editorial CMS pattern):
- Designer edits a draft (
is_published = false). - Designer calls
submitCurriculumReview— fingerprint snapshot stored on the review request. - A different curriculum designer or platform administrator calls
approveCurriculumReview(self-approval blocked). - Designer calls
updateStudyPlanTemplatewithisPublished: true— allowed only when an approved fingerprint matches the current entity state.
Published templates: live rows stay visible to learners. Attribute edits on a published template are staged in curriculum_revisions (JSON payload) until mergeCurriculumRevision applies them. StudyPlanTemplate exposes reviewStatus, hasStagedChanges, and activeRevisionId for admin UI.
Platform administrators may publish or merge without a prior review.
Local dev: StudyPlanTemplateSeeder — sample book plans, generic method plans, guided catalog templates, mentorship intro pairing plans. LearningOutcomesAndCheckupSeeder — Milk→Transition outcomes, promotion quiz, checkup template, and implicit outcomes on guided Foundations steps.
See Learning outcomes.
Quizzes
Section titled “Quizzes”Quiz bank rows live in quizzes with ordered quiz_questions (multiple choice, true/false, short answer, etc.). Study steps with completion_mode = answer_quiz reference a quiz id in completion_config; attempts are stored per study step (quiz_attempts / quiz_responses).
Admin: curriculum designers and platform administrators author quizzes at /admin/quizzes (list) and /admin/quizzes/{id} (metadata, questions, learning-style variants, random draw config, async AI review). Unpublished quizzes follow the same review-before-publish gate as templates. Plan template steps pick a quiz via dropdown and link out to the editor — questions are not edited inline on the plan form.
Runtime: mentees call startQuizAttempt to draw questions (respecting pool config and prior attempts on retry), then submitQuizAttempt. Snapshots and raw answers are purged after grading completes; scores and outcome evidence are retained. Passing score ratio is compared to the step or quiz threshold.
Subjective questions (essay and future types that return needs_review) trigger an automatic pipeline at study materialization: companion steps grade_quiz and review_quiz are injected after the answer_quiz step in the same wave. Flow: submit → async AI pre-grade (AnalyzeQuizAttemptJob) → analyzed → grader confirms (grade_quiz; mentor in mentored studies, study owner in individual) → graded → mentee acknowledges results (review_quiz) → reviewed. Auto-only quizzes skip injection and complete on pass as before.
Authoring rubric
Section titled “Authoring rubric”study_plan_rubric_dimensions holds the canonical checklist for template quality (seeded in dev and prod via StudyPlanRubricSeeder). Each dimension has a human-facing description and separate ai_instructions for agent prompts. Humans and AI agents share the same dimensions via StudyPlanRubric (forHumans(), forAgentPrompt()).
Public transparency (API): unauthenticated query studyPlanRubricDimensions { slug title description sortOrder } exposes rubric descriptions. aiInstructions is returned only for authenticated users with curriculum or platform admin access.
Admin AI assistance (platform administrator)
Section titled “Admin AI assistance (platform administrator)”Behind the admin_study_plan_ai feature flag (feature_flags.default_enabled). See AI Guidelines. External agents use the same flows via Study plan template MCP.
| Flow | Route / UI | GraphQL mutation | Poll query | Mutates draft? |
|---|---|---|---|---|
| Wizard draft | /admin/plans/new/assistant → prefills /admin/plans/new | generateStudyPlanTemplateDraft | studyPlanTemplateDraft(requestId) | Yes (once, unpublished) |
| Step instructions | Per-step actions in step editor | generateStudyPlanStepInstructions | studyPlanStepInstructions(requestId) | Yes, after diff + Apply; single-level undo |
| Plan review | Review plan on template form | reviewStudyPlanTemplate | studyPlanTemplateReview(requestId) | No — criticism only |
Async job pattern: each mutation returns a handle type (StudyPlanTemplateDraftRequest, StudyPlanTemplateReviewRequest, or StudyPlanStepInstructionsRequest) with requestId. The admin UI subscribes to Laravel Echo for progress, then polls the matching query until the job completes or fails. MCP tools mirror the same operations (kebab-case tool names on the study-plan-templates server).
Draft agent may fetch optional wizard referenceUrls via WebFetch and search public examples (capped). Review and step agents do not use web tools in v1. All agents load rubric dimensions into their prompts. Usage is logged to ai_usage.
Deferred
Section titled “Deferred”completion_ruleautomation (auto-complete from logs/notes).- Dynamic steps added after create.
- Non-linear prerequisites, skip.
- Template versioning (immutable publish versions) — partially addressed by staging revisions for published templates; full immutable version history remains in planning backlog.
- Track runtime is documented in Tracks (assignment, skip/noop, electives, inferred progress). Still deferred:
user_course_progresstable and programmatic prerequisite graphs beyond phase — Architecture Questions.