feat: add VitePress docs site, music file picker modal, Dockerfile optimization, i18n keys for 14 locales

- Add docs/ with VitePress site (19 pages): guide, config, architecture, FAQ
- Add GitHub Actions workflow for auto-deploy to GitHub Pages
- Replace music 'Add Tracks' upload picker with in-app audio file browser modal
- Add music picker CSS styles with dark theme support
- Add missing i18n keys (search_audio, no_audio_files, etc.) to all 14 locales
- Optimize Dockerfile: shared base stage, COPY --chmod, consolidated RUN, HEALTHCHECK
- Improve README: docs links, updated stats (222+ tests, 14 languages), feature status
This commit is contained in:
Diocrafts
2026-04-11 20:58:34 +02:00
parent 1bb65e6448
commit f08cffc0e8
42 changed files with 4313 additions and 95 deletions
+37
View File
@@ -0,0 +1,37 @@
# Caching Architecture
OxiCloud uses **moka** (a lock-free, concurrent cache) for write-behind caching that delivers sub-millisecond hot reads.
## Cache Layers
| Cache | TTL | Max Entries | Purpose |
|---|---|---|---|
| File metadata | 60 s | 10 000 | Avoid re-querying PostgreSQL for file info |
| Directory listings | 120 s | 10 000 | Frequently accessed folder contents |
| Thumbnail cache | configurable | 1 000 | Generated WebP/AVIF thumbnails |
| Image transcode | configurable | 500 | On-the-fly image transcoding results |
| Blob hash | 30 s TTI | 5 000 | SHA-256 hashes for dedup lookups |
| Audio metadata | — | 2 000 | ID3 tags and duration |
## How It Works
1. **Read path:** check cache → if hit, return immediately (sub-ms); if miss, query PostgreSQL, populate cache, return
2. **Write path:** update PostgreSQL → invalidate relevant cache entries
3. **TTL expiry:** entries are evicted after their time-to-live, ensuring eventual consistency
## Why moka?
- **Lock-free** — no mutex contention under concurrent access
- **Bounded memory** — max entries prevent unbounded growth
- **TTL + TTI** — supports both time-to-live and time-to-idle eviction
- **Async-ready** — works natively with Tokio
## Configuration
Cache parameters are currently hardcoded in `src/common/config.rs`. Key defaults:
```rust
file_cache_ttl_ms: 60_000, // 1 minute
directory_cache_ttl_ms: 120_000, // 2 minutes
max_cache_entries: 10_000,
```
+63
View File
@@ -0,0 +1,63 @@
# Internal Architecture
OxiCloud follows a **hexagonal (ports & adapters) architecture** with four layers:
```
┌───────────────────────────────────────────────────────────────┐
│ Interfaces │ REST API, WebDAV, CalDAV, CardDAV, WOPI │
├───────────────────────────────────────────────────────────────┤
│ Application │ Use cases, DTOs, port definitions │
├───────────────────────────────────────────────────────────────┤
│ Domain │ Entities, business rules, repository traits │
├───────────────────────────────────────────────────────────────┤
│ Infrastructure│ PostgreSQL, filesystem, caching, auth │
└───────────────────────────────────────────────────────────────┘
```
All cross-layer dependencies point **inward** via trait-based ports. The DI container (`AppServiceFactory`) wires concrete implementations at startup.
## Storage Model: 100% Blob Storage
- **File metadata** (name, folder, size, user, timestamps, trash status) → PostgreSQL (`storage.files`)
- **File content** → content-addressed blobs via DedupService at `.blobs/{prefix}/{hash}.blob`
- **Folder structure** → purely virtual, rows in `storage.folders` (no filesystem directories per user)
- **Trash** → soft-delete flags on files/folders, exposed via `storage.trash_items` VIEW
## Dependency Injection
`AppServiceFactory` in `src/common/di.rs` builds all services in a defined order:
1. **Core services** — paths, content cache, thumbnails, chunked upload, transcode, dedup, compression
2. **Repositories** — `FolderDbRepository`, `FileBlobReadRepository`, `FileBlobWriteRepository`, `TrashDbRepository`
3. **Trash service** (if enabled)
4. **Application services** — folder, file upload/retrieval/management, search, i18n
5. **Share service** (if enabled)
6. **DB services** — favorites, recent, storage usage, auth
7. **CalDAV/CardDAV services**
8. **ZIP service** (last, depends on file & folder services)
9. **Assemble `AppState`**
## Project Structure
```
src/
├── common/ # Config, DI container, errors
├── domain/ # Entities, repository traits
├── application/ # Use cases, DTOs, port traits
├── infrastructure/ # PostgreSQL repos, filesystem, caching
└── interfaces/ # HTTP handlers, WebDAV, CalDAV, CardDAV
```
## Key Metrics
| Metric | Value |
|--------|-------|
| Rust source files | ~170 |
| Lines of code | ~50 000 |
| Automated tests | 222+ |
| Docker image | ~40 MB |
## Further Reading
- [Caching Architecture →](/architecture/caching)
- [Storage Quotas →](/architecture/storage-quotas)
+36
View File
@@ -0,0 +1,36 @@
# Storage Quotas
OxiCloud supports per-user storage quotas to limit disk usage.
## Enabling Quotas
```bash
OXICLOUD_ENABLE_USER_STORAGE_QUOTAS=true
```
## How It Works
1. Each user has a `storage_quota` field (in bytes, `0` = unlimited)
2. On every file upload, the current usage is checked against the quota
3. If the upload would exceed the quota, it's rejected with a `413 Payload Too Large` error
4. Admins can view and set quotas via the admin panel or API
## API
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/admin/users/{id}/quota` | Get user's quota and current usage |
| PUT | `/api/admin/users/{id}/quota` | Set user's quota |
## Admin Panel
The admin panel (`/admin.html`) shows each user's current usage vs. quota with a visual progress bar.
## Deduplication Interaction
Storage usage is calculated based on **logical file size** (what the user uploaded), not physical blob size. This means:
- If two users upload the same 100 MB file, each user's quota is charged 100 MB
- But on disk, only one 100 MB blob exists
This ensures fair quota accounting while maintaining dedup benefits.