Operations Guide
Day-to-day server operations, monitoring, and maintenance.
Server Access
Section titled “Server Access”cd /home/rondoChecking Sync Status
Section titled “Checking Sync Status”The dashboard reports domain counts for People runs. People created, People updated, and People unchanged come from the Rondo Club submission result. Download and preparation volumes are shown as Processed in the run’s step table, so they do not look like newly created people.
View and Edit Sync Schedules
Section titled “View and Edit Sync Schedules”crontab -lView Recent Logs
Section titled “View Recent Logs”# List recent log filesls -lt logs/cron/ | head -20
# View latest people sync logcat logs/cron/$(ls -t logs/cron/ | grep sync-people | head -1)
# Tail a running synctail -f logs/cron/sync-people-*.logCheck if a Sync is Running
Section titled “Check if a Sync is Running”# Check for running Node processesps aux | grep "node sync-"
# Check lock filesls -la .sync-*.lockManual Sync Runs
Section titled “Manual Sync Runs”Individual Pipelines
Section titled “Individual Pipelines”scripts/sync.sh people # Members, parents, photos → Laposta + Rondo Clubscripts/sync.sh nikki # Nikki contributions → Rondo Clubscripts/sync.sh freescout # Rondo Club members → FreeScout customersscripts/sync.sh teams # Teams + work history → Rondo Clubscripts/sync.sh twelve --scheduled # Hourly due check; source login only inside club windowsscripts/sync.sh functions # Commissies + free fields (recent updates)scripts/sync.sh functions --all # Commissies + free fields (all members)scripts/sync.sh discipline # Discipline cases → Rondo Clubscripts/sync.sh all # All pipelines sequentiallySingle Member Sync
Section titled “Single Member Sync”Sync a specific member by KNVB ID:
node pipelines/sync-individual.js KNVB123456 --verbose # Full syncnode pipelines/sync-individual.js KNVB123456 --dry-run --verbose # Preview onlynode pipelines/sync-individual.js KNVB123456 --fetch --verbose # Fetch fresh data from Sportlink firstnode pipelines/sync-individual.js --search "Jan Jansen" # Search by nameDirect Script Execution
Section titled “Direct Script Execution”For debugging individual steps:
node steps/download-data-from-sportlink.js --verbose # Download onlynode steps/prepare-laposta-members.js --verbose # Prepare Laposta datanode steps/submit-laposta-list.js --verbose # Submit to Lapostanode steps/submit-rondo-club-sync.js --verbose # Submit to Rondo Club (includes birthdate)node steps/download-photos-from-api.js --verbose # Download photosnode steps/upload-photos-to-rondo-club.js --verbose # Upload photosDatabase Inspection
Section titled “Database Inspection”Member Lookups
Section titled “Member Lookups”# Find member in Sportlink data
# Find member in Laposta tracking
# Show pending Laposta changesnode tools/show-laposta-changes.js # Changes onlynode tools/show-laposta-changes.js --all # All members with diffsDirect SQLite Queries
Section titled “Direct SQLite Queries”# Member countsqlite3 data/rondo-sync.sqlite "SELECT COUNT(*) FROM rondo_club_members"
# Members needing sync (hash mismatch)sqlite3 data/rondo-sync.sqlite "SELECT COUNT(*) FROM rondo_club_members WHERE last_synced_hash IS NULL OR last_synced_hash != source_hash"
# Photo state distributionsqlite3 data/rondo-sync.sqlite "SELECT photo_state, COUNT(*) FROM rondo_club_members GROUP BY photo_state"
# Team countsqlite3 data/rondo-sync.sqlite "SELECT COUNT(*) FROM rondo_club_teams WHERE rondo_club_id IS NOT NULL"
# Commissie countsqlite3 data/rondo-sync.sqlite "SELECT COUNT(*) FROM rondo_club_commissies WHERE rondo_club_id IS NOT NULL"
# Recent Sportlink downloadssqlite3 data/laposta-sync.sqlite "SELECT id, created_at FROM sportlink_runs ORDER BY id DESC LIMIT 5"
# Nikki contributions with outstanding balancenode tools/show-nikki-contributions.js --outstanding
# FreeScout customer countsqlite3 data/freescout-sync.sqlite "SELECT COUNT(*) FROM freescout_customers WHERE freescout_id IS NOT NULL"Deploying Updates
Section titled “Deploying Updates”# On local machine: commit and pushgit add . && git commit -m "description" && git push
# On server: pull and installOnly run npm install if dependencies changed (check package.json diff).
Data Validation
Section titled “Data Validation”Verify Rondo Club ID Mappings
Section titled “Verify Rondo Club ID Mappings”Checks that all tracked rondo_club_id values still point to valid WordPress posts:
node tools/verify-rondo-club-data.js --verbose # Report onlynode tools/verify-rondo-club-data.js --fix --verbose # Fix invalid IDsRepopulate Missing Rondo Club IDs
Section titled “Repopulate Missing Rondo Club IDs”If IDs were lost (e.g., database restored from backup):
node tools/repopulate-rondo-club-ids.js --dry-run --verbose # Previewnode tools/repopulate-rondo-club-ids.js --verbose # ApplyValidate Photo Consistency
Section titled “Validate Photo Consistency”Check that photo files on disk match database state:
node tools/check-photo-consistency.js --verbose # Reportnode tools/check-photo-consistency.js --fix # Fix mismatchesCleanup Operations
Section titled “Cleanup Operations”Remove Duplicate Members
Section titled “Remove Duplicate Members”node tools/delete-duplicates.js --verbose # Dry runnode tools/delete-duplicates.js --apply # Delete duplicatesMerge Duplicate Person Records
Section titled “Merge Duplicate Person Records”When a parent and member record exist for the same person:
node tools/merge-duplicate-person.js --parent=123 --member=456Remove Orphaned Data
Section titled “Remove Orphaned Data”# Orphaned relationshipsnode tools/cleanup-orphan-relationships.js --verbosenode tools/cleanup-orphan-relationships.js --fix
# Duplicate relationshipsnode tools/cleanup-duplicate-relationships.jsDeduplicate Laposta Lists
Section titled “Deduplicate Laposta Lists”node tools/dedupe-laposta-list.js # Dry run, all listsnode tools/dedupe-laposta-list.js --apply # Delete duplicatesnode tools/dedupe-laposta-list.js 2 --apply # List 2 onlyLog Management
Section titled “Log Management”Logs accumulate in logs/cron/. Clean up old logs periodically:
# Delete logs older than 30 daysfind logs/cron/ -name "*.log" -mtime +30 -delete
# Check disk usagedu -sh logs/Monitoring Checklist
Section titled “Monitoring Checklist”GlitchTip collects filtered step errors, failed/partial runs, crashes and dashboard server errors. /health/sync checks aggregate schedule coverage: completed partial runs count as active, while their errors remain available for investigation. Keep external heartbeat monitoring for VPS outages. Private local logs retain the original messages that outgoing events omit.
Sync errors are grouped by pipeline, step and a safe error_code; unknown causes retain default stack grouping. Use the local logs for the original message. RunTracker also emits one performance transaction per completed run/step with full duration, a shared trace ID and aggregate created/updated/skipped/failed counts. No per-member spans or detail payloads leave the tracker. GLITCHTIP_PERFORMANCE=false disables these measurements while retaining errors; see performance measurements.
GlitchTip’s daily backup timer stores private local archives under /opt/glitchtip/backups, including credentials and the DuckDB performance cold-storage volume as cold-storage.tar. Restore cold storage alongside the database and uploads. Check systemctl status rondo-glitchtip-backup.timer and disk usage alongside the Sync checks below. These archives do not protect against loss of the VPS; see hosting and backups.
Daily checks:
- People sync email reports arrive at the configured cadence
- No errors in latest sync report
Weekly checks:
- Team sync ran at its configured slot (check
logs/cron/sync-teams-*) - Full functions sync ran at its configured slot (check
logs/cron/sync-functions-*) - Discipline sync ran at its configured slot (check
logs/cron/sync-discipline-*) - Disk usage reasonable (
du -sh /home/rondo/)
Monthly checks:
- Log files cleaned up (
find logs/cron/ -name "*.log" -mtime +30 | wc -l) - Photo directory size reasonable (
du -sh photos/) - Database sizes stable (
ls -lh data/*.sqlite)
Editable schedule operations
Section titled “Editable schedule operations”Use Beheer → Sync schedules to inspect saved timing, next runs and enable switches. See Editable Sync Schedules before installing or migrating cron. crontab -l shows the minute dispatcher and separate Twelve check, while data/sync-schedules.json holds the ten pipeline cadences. Run server commands as rondo; root-owned locks can prevent scheduled work.
Inspect logs/cron/scheduler.log when a due job is not dispatched. The dispatcher does not catch up missed slots after downtime. Dashboard overdue checks and watchdog stale budgets follow the saved schedule; disabled schedules also suppress automatic healing. Cadence changes reset previous-slot checks until the first eligible slot. Weekly/monthly checklists must follow the current saved timing rather than assume the initial default days.