Backend Architecture
Module overview
Section titled “Module overview”API layer (src/api/)
Section titled “API layer (src/api/)”The router is assembled in api/mod.rs with a layered middleware stack (outermost first):
Request → Security headers (CSP, X-Frame-Options, X-Content-Type-Options, HSTS, Referrer-Policy, Permissions-Policy) → Body limit (max_upload_bytes) → Timeout (30 seconds) → CORS → Compression (gzip + brotli) → Request tracing (trace_layer) → Route handlerCertain route groups have additional per-route middleware:
- Search, thumbnails, HLS — per-IP API rate limiting (configurable, default 60 req/min)
- TUS uploads — separate body limit
- Protected routes — JWT auth middleware
Each handler module owns its routes and is mounted on the appropriate prefix.
Services layer (src/services/)
Section titled “Services layer (src/services/)”Business logic lives here, separate from HTTP concerns:
- file_ops —
safe_resolvefor path validation,list_directory,file_info,read_text_content,atomic_write,delete_entry,rename_entry,detect_subtitles,check_blocked_extensionfor upload safety - cache —
DirCachewrapper around moka’s async cache with filesystem watcher integration - thumbnail — Decode, resize (Lanczos3 via fast_image_resize), encode to JPEG, disk-cache. Semaphore-limited to 4 concurrent generations
- transcoder — FFmpeg subprocess management, segment generation, disk caching. Max 2 concurrent processes
- search_index — SQLite FTS5-backed full-text filename search. Full reindex on startup, incremental updates via filesystem watcher notifications. Supports type/size/date filtering and path scoping
Database layer (src/db/)
Section titled “Database layer (src/db/)”- Connection pool via deadpool-sqlite (max 4 connections)
- WAL mode with
PRAGMA synchronous=NORMALfor concurrent reads - All database access goes through
db::interact(), which runs a closure on the pool - Migrations are applied at startup, tracked via a
schema_versionkey in thesettingstable
Key patterns
Section titled “Key patterns”Path safety
Section titled “Path safety”Every filesystem operation goes through safe_resolve:
pub fn safe_resolve(root: &Path, user_path: &str) -> Result<PathBuf, AppError>- Strips all non-Normal components (
.,.., prefix, root) - Joins onto the canonical root
- Canonicalizes the result
- Asserts the result starts with the canonical root
- Returns
AppError::Forbiddenon violation
Atomic writes
Section titled “Atomic writes”File saves use a write-then-rename pattern:
- Write to
{dir}/.rustyfile_tmp_{uuid} sync_all()to flush to diskrename()to the target path
This prevents partial writes from being visible if the process crashes mid-write.
Double-check cache pattern
Section titled “Double-check cache pattern”Thumbnail and HLS segment generation both use:
- Check if cached file exists → return if yes
- Acquire semaphore permit (limits concurrency)
- Check again (another request may have generated it while waiting)
- Generate and cache
This prevents thundering herd problems when many requests hit the same uncached resource.
Error handling
Section titled “Error handling”AppError is a single enum implementing IntoResponse. Internal errors (Database, Pool, Io, Json) are logged at error! level but return a generic “Internal server error” to clients — no stack traces or paths leak.
Dependencies (backend)
Section titled “Dependencies (backend)”| Category | Crate | Purpose |
|---|---|---|
| Web | axum, tower, tower-http | Routing, middleware |
| Async | tokio, tokio-util, futures-util | Runtime, streaming |
| Database | rusqlite (bundled), deadpool-sqlite | SQLite with pool |
| Auth | jsonwebtoken, argon2, rand | JWT + password hashing |
| Config | figment, clap | Layered config + CLI |
| Serialization | serde, serde_json | JSON handling |
| Caching | moka, dashmap | In-memory caches |
| Media | image, fast_image_resize, blake3 | Thumbnails, cache keys |
| Filesystem | notify, notify-debouncer-full | Change detection |
| Upload | base64, uuid | TUS protocol support |
| Rate limiting | governor | Login rate limiter |
| Error | thiserror, anyhow | Error types |
| Logging | tracing, tracing-subscriber | Structured logging |
| Embedding | rust-embed | Frontend in binary |