Archiving Subsystem for Moodle

Long-term Archiving of Quizzes, Assignments, and More


Niels Gandraß

Niels.Gandrass@haw-hamburg.de mail
https://gandrass.de globe

BjΓΆrn Dittmann

mail Bjoern.Dittmann@haw-hamburg.de


Moodle.NRW Community Conference 2026

Ruhr University Bochum

2026-11-12

Imagine it's 2029

A student misses some score for final graduation
and contests the grade of an exam from the winter term 2026/27

Can you prove exactly what was answered
and how it was graded?

Let's have a look into our Moodle!

restart_alt  The course was reset for the next semester – twice
delete_sweep  Existing attempts were deleted during roll-over
edit_note  Three questions were edited
person_off  The teacher with their private archives left the university
extension_off  That fancy question type plugin is no longer installed
upgrade  Moodle had a breaking major update since then

Moodle is a learning platform, not an archive system

How do we archive today?

print  "Print to PDF" (by hand) for every single attempt
fax  Or actually print it ... on paper ... and put it in a cabinet
gpp_bad  Or keep course backups forever and hope Moodle can restore them in 2029
sentiment_stressed  Or simply don't, because it's cumbersome

celebration  Or maybe already using the Quiz Archiver?

A real archive must be ...

inventory_2 Complete

Everything that was graded: answers, attachments, feedback, metadata

Assignment, Quiz, ...
verified Trustworthy

Identical to exam and provably unaltered since the time of archiving

SHA256 & TSP
visibility Independent

Readable for 10+ years, without requiring an ancient Moodle instance

PDF/A, HTML & ZIP
security Compliant

Kept safe according to legal requirements but deleted once the period is over

Policies & GDPR

… and all of that without constantly having to worry about it!

From Quiz Archiver to the
Archiving Subsystem


Similar but tackling the bigger picture!

The journey so far

How we actually got where we are today ...

2023 Quiz Archiver First public release of the Quiz Archiver plugin – still actively maintained
2024 Stakeholder Workshop Requirements and user stories from 58 people representing 46 universities
2025 Prototype Release Public prototype release of the Archiving Subsystem, presented at MoodleMoot DACH and the Moodle University Conference
2025 v1.0.0 Release First stable release with quiz support, Moodle data and local dir storage, simple triggers
2026 v1.1.0 Release Adds assignment archiving, S3 object storage, Moodle 5.3 support, and various core improvements
Today v1.2.0 Release Event-based archiving, single-user archives, reworked archiving UI, searchable archives ... Submitted to Moodle Marketplace πŸŽ‰

What's new

All compatible features we developed in the last year also landed in the Quiz Archiver

picture_as_pdf  PDF/A-3b compliant reports
speed  Parallel archive job processing
filter_alt  Latest attempts only exports
function  MathJax 4 & JACK questions
tune  More report options
sell  Question ID, version, tags, ...
folder_zip  Archive structure customization
badge  New filename variables
update  Live job status updates
cloud_upload  Chunked uploads
change_circle  Moodle 5.3+ (LTS) support
engineering  Moodle Archiving Worker
Everything you love about the Quiz Archiver
is also part of the Archiving Subsystem!

Quiz Archiver vs. Archiving Subsystem

Everything Quiz Archiver can do ... and a lot more

Quiz Archiver Archiving Subsystem
description PDF/A report generation ✓ ✓ (same worker service)
folder_zip ZIP Archive creation with attachments ✓ ✓ (same worker service)
security Checksums, TSP signing, job policies, ... ✓ ✓
dashboard Scope Single quiz Course-wide overview of all activities
school Activities Quiz Quiz, Assignment, ... Extendable
bolt Triggers Manual Manual, Scheduled, Event-based, ... Extendable
database Storage Moodle Moodle, Local directory, SMB, NFS, S3, ... Extendable
hub Integration – Flexible API Extendable

Walkthrough

Archiving an activity with the new Archiving Subsystem

Where to find it

Each course gets its own archiving overview
accessible via More → Archiving

Course archiving overview

widgets  Lists all activities in the course
label  Archiving status per activity
history  Detects changes since last archive

list_alt  Lists all created archive jobs
person  Shows who / what created a job
touch_app  Access files, details, and logs

search  Search by activity or file name
filter_alt  Filter by trigger or status
article_person  Find archives with target user data

Creating an archive

checklist  Select what to export
chevron_right Example solutions, attachments, backups, ...
home_storage  Choose storage location
chevron_right Moodle, local directory, network storage, ...
text_fields  Configurable file names
chevron_right attempt-${attemptid}-${username}
dynamic_form  Customize your archive
chevron_right Additional files, compression, directory layout, ...
auto_delete  Retention time

What's inside: Quizzes

Every attempt as PDF/A – rendered exactly as seen in Moodle


What's inside: Assignments

PDF/A Report, instructions, submissions, feedback, and annotated PDFs per submission


File attachments

assignment  Provided intro files
upload_file  Submitted student files
inventory  Feedback files
picture_as_pdf  Annotated PDF files

Archive structure

Example: Hierarchical archive of an assignment


assignment-archive.zip
β”œβ”€β”€ submissions/
β”‚   └── jdoe-17/
β”‚      β”œβ”€β”€ annotation/
β”‚      β”‚   β”œβ”€β”€ John Doe_17_0.pdf
β”‚      β”‚   └── John Doe_17_0.pdf.sha256
β”‚      β”œβ”€β”€ assignment/
β”‚      β”‚   β”œβ”€β”€ template.zip
β”‚      β”‚   └── template.zip.sha256
β”‚      β”œβ”€β”€ feedback/
β”‚      β”‚   β”œβ”€β”€ unit_test_log.txt
β”‚      β”‚   └── unit_test_log.txt.sha256
β”‚      β”œβ”€β”€ submission/
β”‚      β”‚   β”œβ”€β”€ solution.zip
β”‚      β”‚   └── solution.zip.sha256
β”‚      β”œβ”€β”€ submission-17-jdoe.pdf
β”‚      └── submission-17-jdoe.pdf.sha256
β”œβ”€β”€ submissions_metadata.csv
└── submissions_metadata.csv.sha256
picture_as_pdf  PDF/A-3b for long-term archiving
attach_file  All file attachments
html  Optional HTML sources
restore  Optional Moodle backups (.mbz)
table  CSV metadata for all objects
tag  SHA256 checksum for every file
account_tree  Hierarchical or flat layout
function  File and folder names configurable

Archive job details

Inspect archive job metadata and see what's inside

person_search  All users with data inside this archive are searchable

File download & integrity

cloud_download  Easy access via Moodle
chevron_right Transparent file retrieval for all storage types
tag  SHA256 checksums of every archive
chevron_right Verifies integrity of archived data
chevron_right Re-validated on every retrieval
verified  Cryptographic signature (TSP / RFC 3161)
chevron_right Signed by a trusted Time-Stamp Authority
chevron_right Legally proves the archive existed unaltered at that time

Job logs

Every step of every job is logged for full traceability

Automatic deletion

delete  Automatic cleanup of old archives is supported out of the box
timer  Each archive can have a retention time set
chevron_right Expired archives are deleted automatically by a scheduled task
policy  Admins can enforce retention policies via locked job presets
event_repeat  Batch deletion is supported
chevron_right Example: Delete all expired archives on the first of January and July
receipt_long  Archive files with PII are deleted, job metadata and logs remain for traceability

Automation

Because nobody wants to click the "archive" button a thousand times

Archiving triggers

Archive jobs can be created in one of the following ways ...


touch_app
Manual
  • On demand by teachers / admins
  • Creates a single archive job
  • Full control over settings per job
  • Can also be disabled
   
calendar_clock
Scheduled
  • Periodic, e.g. every night
  • Archives all activities with new unarchived changes
  • Dry-run mode for testing
   
bolt
Event-based
  • Listens to Moodle events
  • Archives only the affected attempt / submission
  • Right when it happens

Scheduled archiving

fingerprint  Activity fingerprints detect changes since the last archive
science  Dry-run mode allows you to see what would be archived before going live

Event-based archiving

Admins select which Moodle events create archive jobs

Activity Event Archives
list_alt Quiz \mod_quiz\event\attempt_submitted The affected attempt
\mod_quiz\event\attempt_graded (Moodle 5.0+)
\mod_quiz\event\attempt_regraded
\mod_quiz\event\attempt_manual_grading_completed
file_upload Assignment \mod_assign\event\assessable_submitted The affected submission
\mod_assign\event\submission_graded
\mod_assign\event\submission_locked

Under the hood

filter_center_focus  Partial archiving
chevron_right Jobs can be scoped to specific attempts / submissions instead of the whole activity
fingerprint  Job fingerprints
chevron_right Identical jobs (same course, activity, settings, objects) are not queued twice
join  Combine triggers
chevron_right Archive each attempt individually on submission and full activities on a schedule / manually
manage_search  Traceability
chevron_right Trigger, source event, and targeted objects are recorded with each job

Administration & Policies

Ensure archives meet your institutional requirements

Job presets and archiving scope

settings  Global configuration of all job parameters
tune  Configurable defaults for all jobs
lock  Lock settings to enforce institution-wide policies
school  Activity-specific presets per activity type
smart_toy  Automatic triggers always use presets
category  Archiving can be limited to some course categories

Storage

Various storage solutions are supported out of the box


DriverTierUse case
Moodle filestore hard_drive Local Default, zero configuration
Local directory database Hybrid Specific folder, NFS / SMB mounts, ...
S3-compatible cloud Remote DMS, Ceph, RustFS, AWS, …

file_download  Local files are directly accessible
cloud_download  Remote files are fetched asynchronously and cached
shield_locked  Allows connection of WORM storage

Permissions

Custom capabilities let you control who can work with archives and how

CapabilityAllows you to …Default roles
local/archiving:viewView and download archivesTeacher, Editing teacher, Manager
local/archiving:createCreate archive jobsEditing teacher, Manager
local/archiving:deleteDelete archivesNobody (Admins only)
local/archiving:bypasscourserestrictionsArchive outside of allowed categoriesNobody (Admins only)

shield  Archives must not disappear accidentally – deletion is denied by default

Archiving Subsystem
Architecture

One core, many pluggable components

The Archiving Subsystem

Sub-plugin types

Every component is a sub-plugin, allowing for easy extension!

Type Purpose Shipped implementations
school archivingmod Activity archiving drivers:
Extract and render activity data
Quiz, Assignment
database archivingstore Storage drivers:
Store, retrieve, and delete archives
Moodle, Local directory, S3 object store
bolt archivingtrigger Archiving triggers:
Decide when to create archive jobs
Manual, Scheduled, Event-based
hub archivingevent External event connectors:
Notify third-party systems
Flexible API

External services

A variety of external systems can interact with the Archiving Subsystem

The Moodle Archiving Worker

Handles the heavy lifting for both quizzes and assignments

screenshot_monitor  Archived exactly as seen in the browser
chevron_right Headless browser renders exactly what users saw (MathJax, STACK, GeoGebra, JSXGraph, …)
deployed_code  Rendering happens outside of Moodle
chevron_right No stress on Moodle, no blocked web requests, no PHP timeouts
speed  Asynchronous and parallel
chevron_right Archives are created in parallel and in the background
key  Security by design / Least privilege
chevron_right Short-lived web service tokens, scoped to a single task
package_2  Ready-to-use Docker image
chevron_right Docker Hub: ngandrass/moodle-archiving-worker

Back to 2029 ...

... but now with the Archiving Subsystem

restart_altCourse reset twice?
Archives live in an independent storage, not inside the course
edit_noteQuestions edited?
Questions and grades were snapshotted at archiving time
person_offTeacher left?
Archives are kept by the institution, not by a single person
extension_offPlugin uninstalled?
Everything was rendered to PDF/A exactly as seen
upgradeMoodle upgraded?
The archive opens without Moodle or custom plugins at all
gavelLawsuit ongoing?
SHA256 & TSP signature prove the data is unaltered
task_alt Yes, you can prove exactly what was answered and how it was graded

Getting Started

Interested? Here's how to try it yourself!

Quickstart

counter_1  Install the plugin local_archiving
chevron_right Supports Moodle 4.5 – 5.3, PHP 8.1 – 8.4
chevron_right All sub-plugins are bundled
counter_2  Spin up an archive worker
chevron_right docker run ngandrass/moodle-archiving-worker
chevron_right Or use the public demo worker for testing
counter_3  Archive!

Full documentation:
https://archiving.gandrass.de

Open source & community driven

bug_report

Test and give feedback

Found a bug or have an idea? Let us know!

extension

Build sub-plugins

New activities, storage systems, triggers, ...

forum

Join the discussion

Matrix: #archiving:gandrass.de

GPLv3 – free and open source

What's next?

rocket_launch  Final release in the Moodle Marketplace
school  Gathering your requirements and wishes
widgets  Support for more activities?
database  Additional storage systems?
hub  Standardized event connectors for CMS?
handshake  Ensuring long-term maintenance

Q&A Session

Now it's time for your questions!

You can find all slides of this talk at
globe https://gandrass.de