docs: migrate legacy docs to official site

This commit is contained in:
Diocrafts
2026-04-22 07:50:41 +02:00
parent e10a908f07
commit c0cb86c273
63 changed files with 1646 additions and 10136 deletions
+120
View File
@@ -0,0 +1,120 @@
# Batch Operations
OxiCloud exposes batch endpoints for bulk file and folder operations under `/api/batch`. Batch requests reduce round-trips, run concurrently behind a semaphore, and return per-item success and failure details instead of aborting on the first error.
## What You Can Do
### File operations
| Method | Path | Description |
| --- | --- | --- |
| `POST` | `/api/batch/files/move` | Move multiple files into a target folder |
| `POST` | `/api/batch/files/copy` | Copy multiple files into a target folder |
| `POST` | `/api/batch/files/delete` | Delete multiple files |
| `POST` | `/api/batch/files/get` | Fetch metadata for multiple files |
### Folder operations
| Method | Path | Description |
| --- | --- | --- |
| `POST` | `/api/batch/folders/delete` | Delete multiple folders |
| `POST` | `/api/batch/folders/create` | Create multiple folders |
| `POST` | `/api/batch/folders/get` | Fetch metadata for multiple folders |
| `POST` | `/api/batch/folders/move` | Move multiple folders |
### Additional batch endpoints
| Method | Path | Description |
| --- | --- | --- |
| `POST` | `/api/batch/trash` | Trash multiple items in one request |
| `POST` | `/api/batch/download` | Build a batch download |
## Request Shapes
### File move or copy
```json
{
"file_ids": ["id-1", "id-2", "id-3"],
"target_folder_id": "folder-abc"
}
```
### Folder delete
```json
{
"folder_ids": ["folder-1", "folder-2"],
"recursive": true
}
```
### Folder create
```json
{
"folders": [
{ "name": "Documents", "parent_id": null },
{ "name": "Photos", "parent_id": "folder-abc" }
]
}
```
## Response Format
All batch endpoints return the same envelope:
```json
{
"successful": [
{ "id": "id-1" }
],
"failed": [
{ "id": "bad-id", "error": "File not found" }
],
"stats": {
"total": 5,
"successful": 4,
"failed": 1,
"execution_time_ms": 245
}
}
```
### Status codes
| Code | Meaning |
| --- | --- |
| `200 OK` or `201 Created` | Every operation succeeded |
| `206 Partial Content` | Some operations succeeded and some failed |
| `400 Bad Request` | Every operation failed |
## Concurrency Model
Batch work is coordinated by `BatchOperationService` and a `tokio::sync::Semaphore`. By default, OxiCloud caps concurrent work with `max_concurrent_files = 10` so large batches do not starve the rest of the application.
Individual failures are collected in the `failed` array. One bad item does not cancel the whole request unless the batch cannot start at all.
## Example
```bash
# Move three files into a folder
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"file_ids":["id-1","id-2","id-3"],"target_folder_id":"folder-abc"}' \
"https://oxicloud.example.com/api/batch/files/move"
# Delete multiple folders recursively
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"folder_ids":["old-1","old-2"],"recursive":true}' \
"https://oxicloud.example.com/api/batch/folders/delete"
```
## Related Pages
- [Search](/guide/search)
- [Trash & Recycle Bin](/guide/trash)
- [ZIP and Compression](/guide/zip-and-compression)
+56
View File
@@ -16,6 +16,33 @@ https://your-server:8086/caldav/
- RFC 5545 (iCalendar format)
- DAV capabilities: `1, 2, calendar-access`
### Route Structure
CalDAV is mounted at the top level, not under `/api`:
- `/caldav`
- `/caldav/`
- `/caldav/{*path}`
OxiCloud also exposes `/.well-known/caldav` and redirects it to `/caldav/`.
Typical resource shapes:
- `/caldav/` for the calendar home
- `/caldav/{calendar_id}/` for one calendar
- `/caldav/{calendar_id}/{ical_uid}.ics` for one event
### Supported Methods
- `OPTIONS`
- `PROPFIND`
- `REPORT`
- `MKCALENDAR`
- `PUT`
- `GET`
- `DELETE`
- `PROPPATCH`
### Client Setup
| Client | URL |
@@ -48,6 +75,31 @@ https://your-server:8086/carddav/
- RFC 6352 (CardDAV)
- RFC 6350 (vCard 4.0)
### Route Structure
CardDAV is also mounted at the top level:
- `/carddav`
- `/carddav/`
- `/carddav/{*path}`
Typical resource shapes:
- `/carddav/` for the address book home
- `/carddav/{addressBookId}/` for one address book
- `/carddav/{addressBookId}/{contactId}.vcf` for one contact
### Supported Methods
- `OPTIONS`
- `PROPFIND`
- `REPORT`
- `MKCOL`
- `PUT`
- `GET`
- `DELETE`
- `PROPPATCH`
### Client Setup
| Client | URL |
@@ -68,3 +120,7 @@ https://your-server:8086/carddav/
::: info
DAVx⁵ file sync works. CalDAV/CardDAV support on DAVx⁵ is still being refined.
:::
## Client Setup
For platform-specific instructions, see [DAV Client Setup](/guide/dav-client-setup).
+82 -38
View File
@@ -1,63 +1,107 @@
# Chunked Uploads
OxiCloud supports TUS-like chunked uploads for large files. Uploads are parallel, resumable, and have MD5 integrity checks.
OxiCloud exposes resumable chunked uploads under `/api/uploads`. The protocol is TUS-like in spirit, but the concrete API is OxiCloud-specific: create a session, stream chunks with `PATCH`, inspect progress with `HEAD`, then finalize the assembled file.
## How It Works
## Upload Flow
1. Client sends `POST /api/files/upload/init` with file metadata → receives an `upload_id`
2. Client splits the file into chunks and uploads them in parallel via `POST /api/files/upload/chunk`
3. Each chunk includes its index, MD5 hash, and the `upload_id`
4. When all chunks are uploaded, client calls `POST /api/files/upload/complete`
5. Server reassembles the file, verifies integrity, and runs deduplication
1. Create an upload session with `POST /api/uploads`
2. Upload each chunk with `PATCH /api/uploads/{upload_id}?chunk_index=N`
3. Optionally inspect progress with `HEAD /api/uploads/{upload_id}`
4. Finalize with `POST /api/uploads/{upload_id}/complete`
5. Cancel an in-flight upload with `DELETE /api/uploads/{upload_id}` if needed
## API Endpoints
### Initialize Upload
### Create upload session
```http
POST /api/files/upload/init
POST /api/uploads
Content-Type: application/json
{
"file_name": "large-video.mp4",
"filename": "large-video.mp4",
"folder_id": "folder-uuid",
"content_type": "video/mp4",
"total_size": 524288000,
"chunk_size": 8388608,
"total_chunks": 63
"chunk_size": 8388608
}
```
### Upload Chunk
```http
POST /api/files/upload/chunk
Content-Type: multipart/form-data
upload_id: "uuid"
chunk_index: 0
chunk_hash: "md5-hex"
file: <binary>
```
### Complete Upload
```http
POST /api/files/upload/complete
Content-Type: application/json
Typical response:
```json
{
"upload_id": "uuid"
"upload_id": "uuid",
"chunk_size": 8388608,
"total_chunks": 63,
"expires_at": 86400
}
```
## Configuration
### Upload a chunk
| Parameter | Default | Description |
|---|---|---|
| Max parallel chunks | 8 | Concurrent chunk uploads |
| Min size for chunking | 200 MB | Below this, single-shot upload is used |
| Chunk size | 8 MB | Default chunk size |
Chunks are sent as raw bytes, not multipart form uploads.
## Frontend Behaviour
```http
PATCH /api/uploads/{upload_id}?chunk_index=0&checksum=md5-hex
Content-Type: application/octet-stream
Content-MD5: md5-hex
The OxiCloud web UI automatically selects chunked upload for large files. A progress bar shows overall completion and current chunk status.
<binary chunk bytes>
```
Notes:
- `chunk_index` is required and zero-based
- `checksum` is optional and can also be supplied with the `Content-MD5` header
- Successful responses include progress headers such as `Upload-Offset`, `Upload-Progress`, and `Upload-Complete`
### Inspect upload status
```http
HEAD /api/uploads/{upload_id}
```
The response includes upload metadata in headers such as:
- `Upload-Offset`
- `Upload-Length`
- `Upload-Progress`
- `Upload-Chunks-Total`
- `Upload-Chunks-Complete`
### Finalize upload
```http
POST /api/uploads/{upload_id}/complete
```
Successful responses return the created file metadata:
```json
{
"file_id": "uuid",
"filename": "large-video.mp4",
"size": 524288000,
"path": "/Videos/large-video.mp4"
}
```
### Cancel upload
```http
DELETE /api/uploads/{upload_id}
```
This removes the in-progress session and temporary chunk data.
## Validation Rules
- `filename` is required
- `total_size` must be greater than zero
- `chunk_size` must be at least 1 MB when provided
- Storage quota checks can reject the session before upload starts
## Frontend Behavior
The OxiCloud web UI can switch to chunked uploads for larger files, track aggregate progress, and retry individual chunks without restarting the full transfer.
+101
View File
@@ -0,0 +1,101 @@
# DAV Client Setup
This page collects platform-specific connection steps for OxiCloud's WebDAV, CalDAV, and CardDAV endpoints.
## Connection Summary
| Use case | URL |
| --- | --- |
| WebDAV file access | `https://your-oxicloud-server/webdav/` |
| CalDAV calendar sync | `https://your-oxicloud-server/caldav` |
| CardDAV contact sync | `https://your-oxicloud-server/carddav` |
## WebDAV
### Windows Explorer
1. Open File Explorer
2. Right-click This PC and choose Add a network location or Map network drive
3. Enter `https://your-oxicloud-server/webdav/`
4. Provide your OxiCloud username and password
If Windows refuses the connection, check the `WebClient` service and verify these registry values under `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WebClient\Parameters`:
- `BasicAuthLevel = 2` when Basic auth is required
- `FileSizeLimitInBytes` if you need to allow larger transfers
### macOS Finder
1. Open Finder
2. Choose Go -> Connect to Server or press Cmd+K
3. Enter `https://your-oxicloud-server/webdav/`
4. Sign in with your OxiCloud credentials
### Linux
- GNOME Files: use `davs://your-oxicloud-server/webdav/`
- KDE Dolphin: use `webdavs://your-oxicloud-server/webdav/`
- `davfs2`: mount `https://your-oxicloud-server/webdav/` to a local directory
## CalDAV
### Apple Calendar
Use an advanced CalDAV account and point it at `https://your-oxicloud-server/caldav`.
### Thunderbird
Create a network calendar and use a CalDAV location such as:
```text
https://your-oxicloud-server/caldav/calendars/your-calendar-id
```
### Android with DAVx5
Use Login with URL and username, then point the base URL at `https://your-oxicloud-server/caldav`.
### Outlook on Windows
Use a CalDAV plugin such as CalDAV Synchronizer and register the calendar endpoint explicitly.
## CardDAV
### Apple Contacts
Create a CardDAV account using `https://your-oxicloud-server/carddav`.
### Thunderbird
Use a remote address book with a URL such as:
```text
https://your-oxicloud-server/carddav/address-books/your-address-book-id
```
### Android with DAVx5
Use the CardDAV base URL `https://your-oxicloud-server/carddav`.
### Outlook on Windows
Use a CardDAV-capable synchronizer and configure the remote address book endpoint explicitly.
## Troubleshooting
### WebDAV
- Make sure the URL includes `/webdav/`
- Use HTTPS in production
- Recheck credentials and the WebClient service on Windows
### CalDAV and CardDAV
- Use the full `/caldav` or `/carddav` base path
- Verify the calendar or address book identifier when the client asks for one
- If sync works on one client and not another, compare the exact URLs being used
## Related Pages
- [WebDAV](/guide/webdav)
- [CalDAV & CardDAV](/guide/caldav-carddav)
+50 -31
View File
@@ -1,46 +1,65 @@
# File Deduplication
OxiCloud uses **SHA-256 content-addressable storage** to avoid storing duplicate files. If two users upload the same file, only one copy is stored on disk.
OxiCloud uses **content-defined chunking (CDC)** with **FastCDC** and **BLAKE3** to deduplicate files at the sub-file level. Instead of storing only whole-file blobs, OxiCloud can split a file into variable-size chunks, reuse unchanged chunks across versions, and track the ordered chunk list in PostgreSQL.
## How It Works
1. When a file is uploaded, its SHA-256 hash is computed
2. The hash is checked against the blob store (`.blobs/{prefix}/{hash}.blob`)
3. If a blob with that hash already exists, the file metadata points to the existing blob (no extra disk usage)
4. If not, the content is saved as a new blob
5. A reference counter tracks how many files point to each blob
1. OxiCloud analyzes the uploaded file with FastCDC
2. The file is split into variable-size chunks from **64 KB** to **1 MB**, targeting an average of **256 KB**
3. Each chunk is hashed with **BLAKE3** and checked against the blob index
4. Only new chunks are written to the blob backend
5. A manifest in PostgreSQL maps the whole-file hash to the ordered chunk hash list
6. Reference counts are updated so identical chunks are stored once even across multiple files or edited versions
## Automatic Cleanup
## Storage Model
```text
storage.files -> metadata rows that reference content
chunk_manifests -> file_hash -> [chunk_hashes] + chunk_sizes + ref_count
storage.blobs -> per-chunk blob metadata and reference counts
blob backend -> actual chunk bytes on disk or remote storage
```
The manifest table is created in `migrations/20260414000000_chunk_manifests.sql` and keeps:
- `file_hash`
- ordered `chunk_hashes`
- `chunk_sizes`
- `total_size`
- `chunk_count`
- `ref_count`
## Why CDC Matters
Whole-file dedup only helps when two files are byte-for-byte identical. CDC helps when files are similar but not identical, for example:
- edited office documents
- versioned project archives
- large media files with partial changes
In those cases, unchanged chunks can be reused and only the modified portions need new storage.
## Backward Compatibility
Older uploads stored before CDC are still readable. When OxiCloud does not find a matching manifest row, it falls back to legacy whole-file blob reads.
## Cleanup Behavior
When a file is permanently deleted:
1. The blob's reference count is decremented
2. If the reference count reaches zero, the blob is removed from disk
1. OxiCloud decrements the manifest reference count
2. If the last manifest reference disappears, chunk refcounts are decremented
3. Chunks with `ref_count = 0` are removed from the blob index and then deleted from the backend
This means disk space is only freed when the **last** reference to a blob is removed.
## Storage Layout
```
storage/
├── .blobs/
│ ├── a1/
│ │ └── a1b2c3d4...sha256.blob
│ ├── f8/
│ │ └── f8e7d6c5...sha256.blob
│ └── ...
```
The first two hex characters of the hash are used as a directory prefix to avoid having millions of files in a single directory.
This keeps storage correct even when multiple files share the same chunk set.
## Benefits
- **Disk savings** — identical files across users consume storage only once
- **Instant uploads** — if the blob already exists, the upload completes immediately
- **Integrity** — SHA-256 ensures bit-for-bit correctness
- Better storage savings for edited and versioned files
- Faster repeat uploads when many chunks already exist
- BLAKE3 hashing for fast content verification
- PostgreSQL-backed manifests for durable indexing and cleanup
## Limitations
## Related Endpoints
- Deduplication is based on exact content match (byte-identical files)
- Near-duplicate files (e.g., a JPEG re-saved at slightly different quality) are stored separately
- Encryption at rest would require per-user keys, which breaks deduplication (planned as opt-in)
The dedup subsystem is also exposed through helper endpoints under `/api/dedup` for hash checks, deduplicated uploads, statistics, and maintenance operations.
+100
View File
@@ -0,0 +1,100 @@
# Favorites and Recent Items
OxiCloud includes two per-user tracking features backed by PostgreSQL:
- Favorites for pinning files and folders you want to reach quickly
- Recent items for tracking the files and folders you accessed most recently
Both features are enabled when the instance has a database connection.
## Favorites
### API
All routes live under `/api/favorites` and require authentication.
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/favorites/` | List all favorites for the current user |
| `POST` | `/api/favorites/{item_type}/{item_id}` | Add a file or folder to favorites |
| `DELETE` | `/api/favorites/{item_type}/{item_id}` | Remove a favorite |
`item_type` must be either `file` or `folder`.
### Behavior
- Adding the same item twice is idempotent
- Results are ordered by `created_at DESC`
- User identity comes from the JWT, not the request body
### Storage model
Favorites are stored in `auth.user_favorites` with a uniqueness constraint on `(user_id, item_id, item_type)`.
```sql
CREATE TABLE IF NOT EXISTS auth.user_favorites (
id SERIAL PRIMARY KEY,
user_id VARCHAR(36) NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
item_id TEXT NOT NULL,
item_type TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, item_id, item_type)
);
```
## Recent Items
### API
All routes live under `/api/recent` and require authentication.
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/recent/` | List recent items, optionally with `?limit=N` |
| `POST` | `/api/recent/{item_type}/{item_id}` | Record an access |
| `DELETE` | `/api/recent/{item_type}/{item_id}` | Remove one item from history |
| `DELETE` | `/api/recent/clear` | Clear all recent items |
### Behavior
- Default maximum per user: 50 items
- Re-accessing an item updates its `accessed_at` timestamp
- Old items are automatically pruned after inserts
- Results are ordered by `accessed_at DESC`
### Storage model
Recent items are stored in `auth.user_recent_files`.
```sql
CREATE TABLE IF NOT EXISTS auth.user_recent_files (
id SERIAL PRIMARY KEY,
user_id VARCHAR(36) NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
item_id TEXT NOT NULL,
item_type TEXT NOT NULL,
accessed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, item_id, item_type)
);
```
## Example
```bash
# Add a file to favorites
curl -X POST -H "Authorization: Bearer $TOKEN" \
"https://oxicloud.example.com/api/favorites/file/abc-123"
# List recent items
curl -H "Authorization: Bearer $TOKEN" \
"https://oxicloud.example.com/api/recent/?limit=10"
# Clear recent history
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
"https://oxicloud.example.com/api/recent/clear"
```
## Related Pages
- [Search](/guide/search)
- [Trash & Recycle Bin](/guide/trash)
- [Batch Operations](/guide/batch-operations)
+65
View File
@@ -0,0 +1,65 @@
# Internationalization
OxiCloud exposes a public translation API backed by JSON locale files on disk. Locales are loaded lazily, cached in memory, and served without authentication.
## Public API
All routes live under `/api/i18n`.
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/i18n/locales` | List available locales |
| `GET` | `/api/i18n/translate?key=...&locale=...` | Resolve a single key |
| `GET` | `/api/i18n/locales/{locale_code}` | Fetch all translations for one locale |
## Locale Files
Translations are stored as nested JSON files under `static/locales/`.
Example shape:
```json
{
"app": {
"title": "OxiCloud"
},
"nav": {
"files": "Files",
"trash": "Trash"
}
}
```
Keys are resolved with dot notation, so `nav.files` maps to `Files`.
## Fallback Rules
- If a key is missing in the requested locale, OxiCloud falls back to English
- If the key is missing there as well, the API returns a not-found error for that key
## Caching Model
Translations are cached in memory with an `RwLock<HashMap<Locale, serde_json::Value>>` and loaded on first use for each locale.
## Frontend Usage
Typical frontend flow:
1. Detect the preferred locale
2. Request `/api/i18n/locales/{code}`
3. Apply translated strings to UI elements
## Example
```bash
# List locales
curl "https://oxicloud.example.com/api/i18n/locales"
# Fetch one translation
curl "https://oxicloud.example.com/api/i18n/translate?key=app.title&locale=es"
```
## Related Pages
- [Internal Architecture](/architecture/)
- [Environment Variables](/config/env)
+27 -16
View File
@@ -3,8 +3,8 @@
## Docker (recommended)
```bash
git clone https://github.com/DioCrafts/oxicloud.git
cd oxicloud
git clone https://github.com/DioCrafts/OxiCloud.git
cd OxiCloud
cp example.env .env
docker compose up -d
```
@@ -16,14 +16,15 @@ Open **http://localhost:8086**. That's it.
```yaml
services:
postgres:
image: postgres:17.4-alpine
image: postgres:18.2-alpine3.23
environment:
POSTGRES_DB: oxicloud
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
volumes:
- pg_data:/var/lib/postgresql/data
- ./db/schema.sql:/docker-entrypoint-initdb.d/schema.sql
- pg_data:/var/lib/postgresql/
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
@@ -32,6 +33,9 @@ services:
oxicloud:
image: diocrafts/oxicloud:latest
build:
context: .
dockerfile: Dockerfile
ports:
- "8086:8086"
env_file:
@@ -52,13 +56,19 @@ volumes:
Requires **Rust 1.93+** and **PostgreSQL 13+**.
```bash
git clone https://github.com/DioCrafts/oxicloud.git
cd oxicloud
echo "DATABASE_URL=postgres://user:pass@localhost/oxicloud" > .env
git clone https://github.com/DioCrafts/OxiCloud.git
cd OxiCloud
cp example.env .env
# Edit .env and set OXICLOUD_DB_CONNECTION_STRING for runtime
export DATABASE_URL=postgres://user:pass@localhost:5432/oxicloud
cargo build --release
cargo run --release
```
`OXICLOUD_DB_CONNECTION_STRING` is the runtime setting read by OxiCloud. `DATABASE_URL` is only needed for SQLx build-time checks.
## Kubernetes (Helm)
```bash
@@ -77,14 +87,14 @@ kubectl logs statefulset/oxicloud -n oxicloud
| Client | Protocol | URL |
|--------|----------|-----|
| Windows Explorer | WebDAV | `http://host:8086/webdav/` |
| macOS Finder | WebDAV | `http://host:8086/webdav/` |
| Nautilus / Dolphin | WebDAV | `dav://host:8086/webdav/` |
| Thunderbird (calendar) | CalDAV | `http://host:8086/caldav/` |
| Thunderbird (contacts) | CardDAV | `http://host:8086/carddav/` |
| DAVx⁵ (Android) | CalDAV + CardDAV | `http://host:8086/` |
| GNOME Calendar | CalDAV | `http://host:8086/caldav/` |
| GNOME Contacts | CardDAV | `http://host:8086/carddav/` |
| Windows Explorer | WebDAV | `https://host/webdav/` |
| macOS Finder | WebDAV | `https://host/webdav/` |
| Nautilus / Dolphin | WebDAV | `davs://host/webdav/` |
| Thunderbird (calendar) | CalDAV | `https://host/caldav/` |
| Thunderbird (contacts) | CardDAV | `https://host/carddav/` |
| DAVx⁵ (Android) | CalDAV + CardDAV | `https://host/` |
| GNOME Calendar | CalDAV | `https://host/caldav/` |
| GNOME Contacts | CardDAV | `https://host/carddav/` |
| Collabora / OnlyOffice | WOPI | See [WOPI configuration](/config/wopi) |
## What's Next?
@@ -92,3 +102,4 @@ kubectl logs statefulset/oxicloud -n oxicloud
- [Environment Variables →](/config/env)
- [OIDC / SSO Setup →](/config/oidc)
- [WebDAV Guide →](/guide/webdav)
- [DAV Client Setup →](/guide/dav-client-setup)
+50 -27
View File
@@ -1,43 +1,66 @@
# Search
OxiCloud provides full-text search across your files with multiple filter options.
OxiCloud provides authenticated file and folder search with simple query parameters, advanced JSON criteria, pagination, recursive traversal, and in-memory result caching.
## Endpoint
## Endpoints
```http
GET /api/search?q=report&type_filter=pdf,docx&recursive=true
```
| Method | Endpoint | Description |
| --- | --- | --- |
| `GET` | `/api/search/` | Simple search using query parameters |
| `POST` | `/api/search/advanced` | Advanced search with a JSON body |
| `GET` | `/api/search/suggest` | Lightweight autocomplete suggestions |
| `DELETE` | `/api/search/cache` | Clear the search results cache |
## Query Parameters
All search endpoints require authentication.
## Simple Search Parameters
| Parameter | Description |
|---|---|
| `q` | Search query (matches file name) |
| `type_filter` | Comma-separated file extensions to filter by |
| `folder_id` | Restrict search to a specific folder |
| `recursive` | `true` to search subfolders |
| `date_from` / `date_to` | Filter by modification date |
| `size_min` / `size_max` | Filter by file size (bytes) |
| `limit` | Maximum results to return |
| --- | --- |
| `query` | Text to search in file and folder names |
| `type` | Comma-separated file extensions |
| `created_after` / `created_before` | Filter by creation time |
| `modified_after` / `modified_before` | Filter by modification time |
| `min_size` / `max_size` | Filter by file size in bytes |
| `folder_id` | Restrict search scope to one folder |
| `recursive` | Search subfolders, defaults to `true` |
| `limit` | Maximum results, defaults to `100` |
| `offset` | Pagination offset |
| `sort_by` | `relevance`, `name`, `name_desc`, `date`, `date_desc`, `size`, or `size_desc` |
## How It Works
### Example
OxiCloud stores file metadata in PostgreSQL with an `ltree` path column, enabling efficient recursive subtree queries:
```sql
SELECT * FROM storage.files
WHERE path <@ 'root.folder_id'
AND LOWER(name) LIKE '%query%'
AND LOWER(extension) = ANY('{pdf,docx}')
ORDER BY updated_at DESC
LIMIT 50;
```bash
curl -H "Authorization: Bearer $TOKEN" \
"https://oxicloud.example.com/api/search/?query=report&type=pdf,docx&recursive=true&limit=20"
```
## Frontend
## Advanced Search
The web UI includes a search bar in the toolbar. Results appear instantly with file name, path, size, and type. Clicking a result navigates to the file's location.
```json
{
"name_contains": "report",
"file_types": ["pdf", "docx"],
"min_size": 1024,
"folder_id": "folder-uuid",
"recursive": true,
"limit": 50,
"offset": 0
}
```
## Suggestions
Use `/api/search/suggest?query=rep&limit=10` for quick autocomplete-style results. Suggestions can also be scoped to a folder with `folder_id`.
## Result Caching
Search results are cached in memory using the search criteria and user ID as the cache key.
- Cache TTL: 5 minutes
- Max entries: 1000
- Manual invalidation: `DELETE /api/search/cache`
## Feature Flag
Search can be disabled via `OXICLOUD_ENABLE_SEARCH=false`.
Search can be disabled with `OXICLOUD_ENABLE_SEARCH=false`.
+96
View File
@@ -0,0 +1,96 @@
# Thumbnails and Transcoding
OxiCloud optimizes image delivery with two complementary features:
- WebP thumbnail generation in three sizes
- On-the-fly image transcoding for browsers that advertise WebP support
Both features use a memory cache plus a persistent disk cache and are designed to stay off the request hot path whenever possible.
## Thumbnails
### Supported sizes
| Size | Dimensions | Directory |
| --- | --- | --- |
| `icon` | 150 x 150 | `.thumbnails/icon/` |
| `preview` | 400 x 400 | `.thumbnails/preview/` |
| `large` | 800 x 800 | `.thumbnails/large/` |
### Supported inputs
`image/jpeg`, `image/jpg`, `image/png`, `image/gif`, and `image/webp`
All thumbnail outputs are stored as WebP.
### API
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/files/{id}/thumbnail/{size}` | Fetch a thumbnail |
| `POST` | `/api/files/upload` | Upload a file and pre-generate thumbnails for supported images |
Thumbnail responses include:
- `Content-Type: image/webp`
- `Cache-Control: public, max-age=31536000, immutable`
- `ETag: "thumb-{id}-{size}"`
### Generation flow
1. Upload succeeds through the file API
2. If the MIME type is supported, OxiCloud starts thumbnail generation in a background task
3. If a thumbnail is requested before pre-generation completes, the request can generate it lazily
4. Future requests are served from memory or disk cache
## Image Transcoding
OxiCloud can serve a smaller WebP version of uploaded JPEG, PNG, or GIF files when the client advertises WebP support in the `Accept` header.
### Rules
- Files over 5 MB skip transcoding
- Existing WebP files are not transcoded again
- SVG and BMP are not transcoded
- If the WebP output is larger than the original, OxiCloud serves the original file instead
### Storage layout
```text
<storage_path>/
.transcoded/
webp/
<file_id>.webp
```
### Statistics tracked by the service
- Cache hits
- Disk hits
- Successful transcodes
- Bytes saved
- Transcode errors
## Caching
Both thumbnail and transcode services use:
- An in-memory LRU cache for hot assets
- A disk cache for persistent reuse across restarts
- Fire-and-forget background writes for cache warmup
For the broader cache model across metadata and listings, see [Caching Architecture](/architecture/caching).
## Example
```text
Client: GET /api/files/abc-123/download
Accept: image/webp, image/png, */*
Server: checks cache -> transcodes if needed -> returns the smaller asset
```
## Related Pages
- [Caching Architecture](/architecture/caching)
- [ZIP and Compression](/guide/zip-and-compression)
+12 -1
View File
@@ -9,12 +9,21 @@ OxiCloud provides a trash system that soft-deletes files and folders, allowing u
3. Users can browse the trash, restore items, or permanently delete them
4. Items older than the retention period (default: **30 days**) are automatically purged
## Storage Model
- files and folders keep their original rows in PostgreSQL
- deletion into trash only flips soft-delete state and records the original parent location for restore
- blob content is not moved when an item enters the trash
- the unified `storage.trash_items` view is used to list trashed files and folders together
## API Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/trash` | List trashed items |
| POST | `/api/trash/restore/{id}` | Restore a trashed item |
| DELETE | `/api/trash/files/{id}` | Move a file to the trash |
| DELETE | `/api/trash/folders/{id}` | Move a folder to the trash |
| POST | `/api/trash/{id}/restore` | Restore a trashed item |
| DELETE | `/api/trash/{id}` | Permanently delete |
| DELETE | `/api/trash/empty` | Empty the entire trash |
@@ -25,3 +34,5 @@ Permanent deletion decrements the blob reference count. If no other file points
## Feature Flag
Trash can be disabled via `OXICLOUD_ENABLE_TRASH=false`. When disabled, deletions are permanent.
Retention is controlled by `OXICLOUD_TRASH_RETENTION_DAYS`.
+72
View File
@@ -33,6 +33,65 @@ Always use HTTPS in production — Basic auth sends credentials in every request
| `DELETE` | Delete a file/folder |
| `LOCK` / `UNLOCK` | File locking |
## Common Operations
### List a directory
Use `PROPFIND` with a `Depth` header:
```http
PROPFIND /webdav/projects/ HTTP/1.1
Depth: 1
Content-Type: application/xml
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:allprop/>
</D:propfind>
```
Successful directory listings return `207 Multi-Status`.
### Download a file
```http
GET /webdav/projects/document.pdf HTTP/1.1
Authorization: Basic base64(username:password)
```
### Upload or replace a file
```http
PUT /webdav/projects/document.pdf HTTP/1.1
Content-Type: application/pdf
<file bytes>
```
### Create a folder
```http
MKCOL /webdav/projects/new-folder HTTP/1.1
```
### Move or copy
```http
MOVE /webdav/old-location.pdf HTTP/1.1
Destination: https://your-server/webdav/new-location.pdf
```
```http
COPY /webdav/original.pdf HTTP/1.1
Destination: https://your-server/webdav/copy.pdf
```
### Delete a resource
```http
DELETE /webdav/projects/document.pdf HTTP/1.1
```
## Client Setup
### Windows Explorer
@@ -78,3 +137,16 @@ curl -u user:pass -X MKCOL https://your-server:8086/webdav/new-folder/
## Streaming PROPFIND
OxiCloud streams PROPFIND responses, so listing directories with thousands of files doesn't consume excessive memory.
## Integration Notes
- the WebDAV handler is only an HTTP adapter; file and folder operations still go through the same application services used by the REST API
- HTTP Basic Authentication is supported for DAV clients, while authorization rules remain the same as the rest of OxiCloud
- delete operations integrate with trash when the trash feature is enabled
## Troubleshooting
- Always use the `/webdav/` base path
- Prefer HTTPS because WebDAV uses Basic Authentication
- On Windows, make sure the `WebClient` service is enabled
- OxiCloud rejects path traversal segments such as `.` and `..` at the HTTP boundary
+67
View File
@@ -0,0 +1,67 @@
# ZIP and Compression
OxiCloud ships two compression-related features:
- ZIP download for folders
- Gzip compression for suitable file responses
## ZIP Download
### Endpoint
| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/api/folders/{id}/download` | Download a folder as a ZIP archive |
### How it works
- The ZIP archive is built in memory
- Folder traversal uses an iterative queue rather than recursive async calls
- Cycle detection prevents loops while walking nested folders
- Entries are written with UNIX mode `0o755`
- Compression uses the `Deflated` method from the `zip` crate
### Example
```bash
curl -H "Authorization: Bearer $TOKEN" \
"https://oxicloud.example.com/api/folders/abc-123/download" \
-o my-folder.zip
```
## Gzip Compression
OxiCloud can compress responses when it is worth doing so.
### Compression threshold
Files below 50 KB are skipped.
### Compression levels
| Level | Value |
| --- | --- |
| `None` | `0` |
| `Fast` | `1` |
| `Default` | `6` |
| `Best` | `9` |
### Skip list
These types are not gzipped because they are already compressed or because compression provides poor returns:
- `image/*` except SVG and BMP
- `audio/*`
- `video/*`
- archive formats such as ZIP, gzip, 7z, RAR, bzip2, and XZ
### Runtime behavior
- Compression and decompression run in `spawn_blocking`
- The implementation uses `flate2`
- Optional buffer pooling reduces allocation churn under load
## Related Pages
- [Batch Operations](/guide/batch-operations)
- [Thumbnails and Transcoding](/guide/thumbnails-and-transcoding)