learnrTrackR provides a small SQLite layer for tutorial
attempt tracking, registered students, registered questions, gradebook
exports, and minimal learnr integration helpers.
Create a database
library(learnrTrackR)
db_path <- tempfile(fileext = ".sqlite")
con <- init_tracking_db(db_path, overwrite = TRUE)Register expected questions
Registered students provide a local roster for filtering and optional
student-id checks. Registered questions define the denominator used by
gradebook(). In this example, q3 is expected
but not answered.
register_students(
con,
data.frame(
student_id = c("student_001", "student_002"),
student_label = c("Student 1", "Student 2"),
group_id = c("A", "A")
)
)
#> # A tibble: 2 × 5
#> student_id student_label email group_id created_at
#> <chr> <chr> <chr> <chr> <chr>
#> 1 student_001 Student 1 NA A 2026-06-24T12:25:30Z
#> 2 student_002 Student 2 NA A 2026-06-24T12:25:30Z
register_questions(
con,
tutorial_id = "module_01",
questions = data.frame(
question_id = c("q1", "q2", "q3"),
max_score = c(1, 1, 1)
)
)
#> # A tibble: 3 × 6
#> question_id tutorial_id question_label question_type max_score created_at
#> <chr> <chr> <chr> <chr> <dbl> <chr>
#> 1 q1 module_01 q1 NA 1 2026-06-24T12:…
#> 2 q2 module_01 q2 NA 1 2026-06-24T12:…
#> 3 q3 module_01 q3 NA 1 2026-06-24T12:…Add simulated attempts
track_attempt(
con = con,
student_id = "student_001",
tutorial_id = "module_01",
question_id = "q1",
submitted_answer = "mean(x)",
grade_status = "correct",
score = 1,
max_score = 1,
feedback = "Correct.",
require_registered_student = TRUE
)
track_attempt(
con = con,
student_id = "student_001",
tutorial_id = "module_01",
question_id = "q2",
submitted_answer = "summarise(df, x = mean(x))",
grade_status = "partial",
score = 0.5,
max_score = 1,
feedback = "Good idea, but check grouping."
)Read attempts
get_attempts(con)
#> # A tibble: 2 × 12
#> attempt_id session_id student_id tutorial_id question_id attempt_number
#> <int> <chr> <chr> <chr> <chr> <int>
#> 1 1 session_student_… student_0… module_01 q1 1
#> 2 2 session_student_… student_0… module_01 q2 1
#> # ℹ 6 more variables: submitted_answer <chr>, grade_status <chr>, score <dbl>,
#> # max_score <dbl>, feedback <chr>, timestamp <chr>Compute scores
compute_scores() summarizes only observed attempts.
compute_scores(con, tutorial_id = "module_01", rule = "last")
#> student_id tutorial_id score max_score percent n_questions n_answered
#> 1 student_001 module_01 1.5 2 75 2 2gradebook() uses registered questions, so unanswered
questions are included.
gradebook(con, tutorial_id = "module_01", rule = "last")
#> # A tibble: 1 × 9
#> student_id tutorial_id score max_score percent n_questions n_answered
#> <chr> <chr> <dbl> <dbl> <dbl> <int> <int>
#> 1 student_001 module_01 1.5 3 50 3 2
#> # ℹ 2 more variables: n_unanswered <int>, completed <lgl>Export results
attempts_path <- tempfile(fileext = ".csv")
scores_path <- tempfile(fileext = ".csv")
gradebook_path <- tempfile(fileext = ".csv")
moodle_path <- tempfile(fileext = ".csv")
export_results(con, attempts_path, type = "attempts")
export_results(con, scores_path, type = "scores")
export_results(con, gradebook_path, type = "gradebook", tutorial_id = "module_01")
export_moodle_grades(
con,
moodle_path,
tutorial_id = "module_01",
grade_item = "Module 01 quiz"
)
export_canvas_grades(
con,
tempfile(fileext = ".csv"),
tutorial_id = "module_01",
assignment = "Module 01 quiz"
)
file.exists(c(attempts_path, scores_path, gradebook_path, moodle_path))
#> [1] TRUE TRUE TRUE TRUEExport a richer teaching bundle
bundle_dir <- tempfile()
bundle_paths <- export_tracking_bundle(
con,
bundle_dir,
tutorial_id = "module_01",
group_id = "A"
)
bundle_paths
#> # A tibble: 8 × 2
#> table path
#> <chr> <chr>
#> 1 summary /tmp/RtmpCDX4x7/file1e9220850936/module_01-group-A-summary.csv
#> 2 students /tmp/RtmpCDX4x7/file1e9220850936/module_01-group-A-students.csv
#> 3 attempts /tmp/RtmpCDX4x7/file1e9220850936/module_01-group-A-attempts.csv
#> 4 scores /tmp/RtmpCDX4x7/file1e9220850936/module_01-group-A-scores.csv
#> 5 gradebook /tmp/RtmpCDX4x7/file1e9220850936/module_01-group-A-gradebook.csv
#> 6 questions /tmp/RtmpCDX4x7/file1e9220850936/module_01-group-A-questions.csv
#> 7 moodle_grades /tmp/RtmpCDX4x7/file1e9220850936/module_01-group-A-moodle_grade…
#> 8 canvas_grades /tmp/RtmpCDX4x7/file1e9220850936/module_01-group-A-canvas_grade…