6.4 KiB
6.4 KiB
StudIP Sync Agent
This document equips future agents with the current mental model for the studip-sync CLI so new work can focus on real gaps instead of rediscovering context.
Mission & Constraints
- Goal: one-way sync of documents from Stud.IP’s JSON:API (Uni Trier) to the local filesystem using Rust (async
tokio,reqwest,serde, TOML config/state). - Target platform: Linux (Arch) following the XDG base directory spec.
- Binary name must stay
studip-sync; code must staycargo fmt+cargo clippy --all-targets --all-features -- -D warnings+cargo testclean. - All configuration/state is TOML. The config file (mode
0600) stores the Base64-encoded Basic auth string; state caches user/semester/course/file metadata. - Directory layout requirement:
<download_root>/<semester_key>/<course>/<studip-folder-hierarchy>/<files>. Never upload to Stud.IP; pruning is opt-in via--prune.
Rust edition note: The crate currently targets Rust 2024 even though the original brief called for 2021. Keep this divergence in mind if MSRV compatibility matters.
Repository Map
| Path | Purpose |
|---|---|
src/main.rs |
Minimal entry point that parses CLI args and drives async runtime. |
src/cli.rs |
All subcommand implementations plus sync logic, prompt helpers, pruning, naming utilities, and state updates. |
src/config.rs |
Multi-profile TOML config loader/saver; enforces 0600 perms on write. |
src/state.rs |
TOML cache schema for user/semesters/courses/files plus helpers to read/write/mutate per profile. |
src/paths.rs |
Resolves XDG-compliant config/data dirs with optional overrides. |
src/studip_client.rs |
Thin JSON:API client (Basic auth header, pagination helper, download streaming). |
src/semesters.rs |
Converts human semester titles (“WiSe 2024/25”) into stable keys (ws2425). |
src/logging.rs |
Tracing subscriber setup with quiet/debug/json/verbosity knobs. |
docs/studip/ |
Offline copy of Stud.IP JSON:API docs for reference (no code). |
Runtime Flow
studip-sync init-configwrites a config template (optionally overridingdownload_rootand guarded by--force).studip-sync authcollects credentials (CL flags, env, or interactive prompts), Base64-encodesusername:password, and persists it in the active profile.studip-sync list-coursesbuilds aStudipClient, resolves/caches the user ID via/users/me, paginates/users/{id}/courses, fetches missing semesters (including start/end timestamps and re-fetching cached semesters that lack them), upserts course metadata intostate.toml, and prints a table sorted by semester/title.studip-sync sync:- Resolves download root (
config.download_rootor$XDG_DATA_HOME/studip-sync/downloads) and ensures directories exist unless--dry-run. - Refreshes course + semester info, then for each course performs a depth-first walk:
/courses/{id}/folders➜/folders/{id}/file-refs➜/folders/{id}/folders. Pagination is handled byfetch_all_pages. - Normalizes path components and uses
NameRegistryto avoid collisions, guaranteeing human-readable yet unique names. - Checks file state (size, modified timestamp, checksum) against
state.tomlto skip unchanged files; downloads stream to*.partbefore rename. - Records remote metadata + local path hints in state.
--dry-runreports actions without touching disk;--prune(plus non–dry-run) deletes stray files/dirs withwalkdir. --since <semester|date>now resolves either a semester key (e.g.,ws2526) to its cached start timestamp or a date string (DDMMYY,DDMMYYYY, RFC3339) and skips remote files whosechdateprecedes that cutoff.
- Resolves download root (
- HTTP errors propagate via
anyhow, but 401/403 currently surface as generic failures—production UX should point users tostudip-sync auth.
Configuration & State
- Config path:
${XDG_CONFIG_HOME:-~/.config}/studip-sync/config.toml. Override with--config-dirwhen needed. Example keys:base_url,jsonapi_path,basic_auth_b64,download_root,max_concurrent_downloads. - State path:
${XDG_DATA_HOME:-~/.local/share}/studip-sync/state.toml.--data-dirrelocates this tree (and the defaultdownloads/folder). Explicitly settingdownload_rootdecouples downloads from the data dir; otherwise it defaults to<data-dir>/downloads.profiles.<name>.user_idcaches/users/me.profiles.<name>.semesters.<key>stores semester IDs/titles/keys plusstart/endtimestamps (needed for--since ws2526). Runninglist-courses --refreshwill also refresh already-known semesters missing those timestamps sosync --since …can resolve properly.profiles.<name>.courses.<id>keeps display names +last_sync.profiles.<name>.files.<file_ref_id>remembers size, checksum, timestamps, and the last local path to avoid redundant downloads.
- Multiple profiles are supported;
--profileswitches, otherwise the config’sdefault_profileis used.
Development Workflow
- Install a recent Rust toolchain (
rustup toolchain install stableif needed). - Lint/test loop:
cargo fmt --all -- --check cargo clippy --all-targets --all-features -- -D warnings cargo test - Use
cargo run -- <subcommand>for manual verification (e.g.,cargo run -- auth,cargo run -- list-courses --refresh,cargo run -- sync --dry-run). - Keep dependencies minimal; avoid logging sensitive strings (
basic_auth_b64, plaintext passwords).
Known Gaps / Backlog
ConfigProfile::max_concurrent_downloadsis defined but unused; downloads happen sequentially. Introduce a bounded task queue if concurrency is needed.- Server-side filtering (
filter[since], if supported) is not used yet. Local cutoff logic relies on Stud.IP timestamps; future work could add conditional API query parameters once officially documented. - No automated tests (unit/integration) are present; critical helpers like
semesters::infer_key,normalize_component, and state transitions should gain coverage. - Error UX for auth failures could be clearer (detect 401/403 and prompt users to re-run
auth). - There is no CI config; if one is added, ensure it runs fmt/clippy/test.
- Verify long-term compatibility with Rust 2024 or document the minimum supported version explicitly.
Keep this guide updated whenever major flow or architecture changes land so that future agents can jump straight into implementation work.