# 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 stay `cargo fmt` + `cargo clippy --all-targets --all-features -- -D warnings` + `cargo test` clean.  
- 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

1. `studip-sync init-config` writes a config template (optionally overriding `download_root` and guarded by `--force`).
2. `studip-sync auth` collects credentials (CL flags, env, or interactive prompts), Base64-encodes `username:password`, and persists it in the active profile.
3. `studip-sync list-courses` builds a `StudipClient`, resolves/caches the user ID via `/users/me`, paginates `/users/{id}/courses`, fetches missing semesters, upserts course metadata into `state.toml`, and prints a table sorted by semester/title.
4. `studip-sync sync`:
   - Resolves download root (`config.download_root` or `$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 by `fetch_all_pages`.
   - Normalizes path components and uses `NameRegistry` to avoid collisions, guaranteeing human-readable yet unique names.
   - Checks file state (size, modified timestamp, checksum) against `state.toml` to skip unchanged files; downloads stream to `*.part` before rename.
   - Records remote metadata + local path hints in state. `--dry-run` reports actions without touching disk; `--prune` (plus non–dry-run) deletes stray files/dirs with `walkdir`.
   - `--since <ISO8601>` is accepted for future incremental sync work; at the moment it is recorded in logs/state but no API filters are issued.
5. HTTP errors propagate via `anyhow`, but 401/403 currently surface as generic failures—production UX should point users to `studip-sync auth`.

## Configuration & State

- Config path: `${XDG_CONFIG_HOME:-~/.config}/studip-sync/config.toml`. Override with `--config-dir` when 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-dir` relocates this tree (and the default `downloads/` folder). Explicitly setting `download_root` decouples downloads from the data dir; otherwise it defaults to `<data-dir>/downloads`.  
  - `profiles.<name>.user_id` caches `/users/me`.  
  - `profiles.<name>.semesters.<key>` stores semester IDs/titles/keys.  
  - `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; `--profile` switches, otherwise the config’s `default_profile` is used.

## Development Workflow

1. Install a recent Rust toolchain (`rustup toolchain install stable` if needed).
2. Lint/test loop:
   ```bash
   cargo fmt --all -- --check
   cargo clippy --all-targets --all-features -- -D warnings
   cargo test
   ```
3. Use `cargo run -- <subcommand>` for manual verification (e.g., `cargo run -- auth`, `cargo run -- list-courses --refresh`, `cargo run -- sync --dry-run`).
4. Keep dependencies minimal; avoid logging sensitive strings (`basic_auth_b64`, plaintext passwords).

## Known Gaps / Backlog

- `ConfigProfile::max_concurrent_downloads` is defined but unused; downloads happen sequentially. Introduce a bounded task queue if concurrency is needed.
- `SyncArgs::since` exists but is not wired into any API calls; ideal future work would leverage Stud.IP filters or local timestamps.
- 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.
