Data Export
Oak-Ed provides two export mechanisms: an Obsidian vault export for browsing your data as interlinked markdown notes, and database backups for disaster recovery.
Obsidian Vault Export
The export_obsidian management command exports all Oak-Ed data as an Obsidian-compatible vault. Each record becomes a markdown file with YAML frontmatter and [[wiki-link]] cross-references between related entities.
Running the Export
docker compose exec -T web uv run python manage.py export_obsidian --out-dir /path/to/vault
| Option | Description |
|---|---|
--out-dir |
Required. Output directory for the vault. Created if it doesn't exist. |
--clean |
Remove existing .md files from each subdirectory before writing. Useful for keeping the vault in sync. |
What Gets Exported
The command creates one folder per entity type:
| Folder | Contents | Notes |
|---|---|---|
| Learners | Profiles with learning style, strengths, weaknesses | Links to default persona and teachers |
| Teachers | Name, bio, teaching style | |
| Personas | Name and prompt instructions | Links to teachers |
| Tags | Name and slug | Only tags in use (referenced by at least one achievement, lesson, or inventory item) |
| Inventory | Items with type-specific fields (ISBN for books, player count for board games, etc.) | Links to tags and teachers |
| Lessons | Title, content, generation metadata | Only lessons with status generated. Links to learner, teacher, parent lesson |
| Achievements | Description, date, linked resources | Grouped by learner and date — multiple achievements on the same day become sections in one file |
| Reports | Period, content, learner link | Only reports with status complete |
Output Format
Each file follows this structure:
---
id: 42
name: Example Learner
teachers:
- "[[Teachers/jsmith (1)]]"
---
## Learning Style
Visual and kinaesthetic.
Filenames use the pattern Name (pk).md to ensure uniqueness. Special characters are replaced with hyphens.
Automated Export
In production, a systemd timer runs the export every four hours and commits changes to a git repository:
scripts/export-obsidian.sh # export script
scripts/oaked-obsidian.service # systemd service unit
scripts/oaked-obsidian.timer # runs at 00:00, 04:00, 08:00, 12:00, 16:00, 20:00
The script exports to ~/obsidian, then auto-commits and pushes if the output directory is a git repo. No action is needed if nothing changed since the last export.
Database Backups
The scripts/backup.sh script creates compressed backups of the PostgreSQL database and uploaded media files.
Running Manually
scripts/backup.sh
What Gets Backed Up
| Artifact | Format | Filename |
|---|---|---|
| Database | PostgreSQL custom dump (pg_dump -Fc) |
db_YYYYMMDD_HHMMSS.dump |
| Media files | Compressed tar archive | media_YYYYMMDD_HHMMSS.tar.gz |
Backups are written to /home/oaked/backups/ with 700 permissions. Files older than 30 days are automatically deleted.
Automated Schedule
A systemd timer runs the backup twice daily:
scripts/backup.sh # backup script
scripts/oaked-backup.service # systemd service unit
scripts/oaked-backup.timer # runs at 03:00 and 15:00
Restoring from Backup
To restore a database backup:
docker compose exec -T db pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists < /path/to/db_YYYYMMDD_HHMMSS.dump
To restore media files:
docker compose exec -T web tar xzf - -C /app/media < /path/to/media_YYYYMMDD_HHMMSS.tar.gz