2026-04-11 20:58:34 +02:00
|
|
|
|
# Search
|
|
|
|
|
|
|
2026-07-26 14:42:04 +02:00
|
|
|
|
OxiCloud provides authenticated file and folder search with a
|
|
|
|
|
|
cursor-paginated response, filter/sort query parameters, recursive
|
|
|
|
|
|
traversal, and in-memory result caching.
|
2026-04-11 20:58:34 +02:00
|
|
|
|
|
2026-04-22 07:50:41 +02:00
|
|
|
|
## Endpoints
|
2026-04-11 20:58:34 +02:00
|
|
|
|
|
2026-04-22 07:50:41 +02:00
|
|
|
|
| Method | Endpoint | Description |
|
|
|
|
|
|
| --- | --- | --- |
|
2026-07-26 14:42:04 +02:00
|
|
|
|
| `GET` | `/api/search` | Cursor-paginated search |
|
2026-04-22 07:50:41 +02:00
|
|
|
|
| `GET` | `/api/search/suggest` | Lightweight autocomplete suggestions |
|
2026-07-17 00:43:15 +02:00
|
|
|
|
| `DELETE` | `/api/admin/search/cache` | Flush the shared search results cache (admin only) |
|
2026-04-22 07:50:41 +02:00
|
|
|
|
|
2026-07-17 00:43:15 +02:00
|
|
|
|
All search endpoints require authentication. The cache flush is
|
|
|
|
|
|
additionally restricted to administrators — see [Result Caching](#result-caching).
|
2026-04-11 20:58:34 +02:00
|
|
|
|
|
2026-07-26 14:42:04 +02:00
|
|
|
|
## Query Parameters
|
2026-04-11 20:58:34 +02:00
|
|
|
|
|
|
|
|
|
|
| Parameter | Description |
|
2026-04-22 07:50:41 +02:00
|
|
|
|
| --- | --- |
|
2026-07-26 14:42:04 +02:00
|
|
|
|
| `query` | Text to search in file/folder names (and file content when the Tantivy index is enabled) |
|
|
|
|
|
|
| `type` | Comma-separated file extensions (files only) |
|
2026-04-22 07:50:41 +02:00
|
|
|
|
| `folder_id` | Restrict search scope to one folder |
|
|
|
|
|
|
| `recursive` | Search subfolders, defaults to `true` |
|
2026-07-26 14:42:04 +02:00
|
|
|
|
| `created_after` / `created_before` | Filter by creation time (unix seconds) |
|
|
|
|
|
|
| `modified_after` / `modified_before` | Filter by modification time |
|
|
|
|
|
|
| `min_size` / `max_size` | Filter by file size in bytes |
|
|
|
|
|
|
| `resource_types` | Comma-separated: `file`, `folder` (both by default) |
|
2026-07-26 17:22:00 +02:00
|
|
|
|
| `order_by` | Sort dimension: `relevance` (default), `name`, `size`, `updated_at`, `created_at` |
|
|
|
|
|
|
| `reverse` | Reverse sort direction (no-op for `relevance`) |
|
2026-07-26 14:42:04 +02:00
|
|
|
|
| `limit` | Page size (1–200, default 50) |
|
|
|
|
|
|
| `cursor` | Opaque cursor returned by the previous page |
|
2026-04-22 07:50:41 +02:00
|
|
|
|
|
2026-07-26 14:42:04 +02:00
|
|
|
|
## Response Shape
|
2026-04-11 20:58:34 +02:00
|
|
|
|
|
2026-07-26 14:42:04 +02:00
|
|
|
|
`/api/search` returns the same envelope as every other `/*/resources`
|
|
|
|
|
|
listing (folders, favorites, recent, trash, shared) so a single
|
|
|
|
|
|
client component can render all of them:
|
2026-04-11 20:58:34 +02:00
|
|
|
|
|
2026-04-22 07:50:41 +02:00
|
|
|
|
```json
|
|
|
|
|
|
{
|
2026-07-26 14:42:04 +02:00
|
|
|
|
"items": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"resource_type": "file",
|
|
|
|
|
|
"resource": { "id": "…", "name": "report.pdf", "size": 12345, "…": "…" },
|
|
|
|
|
|
"meta": {
|
|
|
|
|
|
"score": 0.82,
|
|
|
|
|
|
"snippet": "…quarterly <mark>report</mark>…",
|
|
|
|
|
|
"via": "content"
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"resource_type": "folder",
|
|
|
|
|
|
"resource": { "id": "…", "name": "Reports", "…": "…" },
|
|
|
|
|
|
"meta": { "score": 0.31, "via": "name" }
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
"next_cursor": "eyJvZmZzZXQiOjUwLCJvcmRlcl9ieSI6InJlbGV2YW5jZSJ9",
|
|
|
|
|
|
"query_time_ms": 12,
|
|
|
|
|
|
"total": 137
|
2026-04-22 07:50:41 +02:00
|
|
|
|
}
|
2026-04-11 20:58:34 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-07-26 14:42:04 +02:00
|
|
|
|
- `resource_type`: `"file"` or `"folder"` — tells the client which
|
|
|
|
|
|
variant of `resource` to render.
|
|
|
|
|
|
- `resource`: the same `FileDto` / `FolderDto` shape any other
|
|
|
|
|
|
endpoint would emit.
|
|
|
|
|
|
- `meta.score`: relevance in `[0, 1]`.
|
|
|
|
|
|
- `meta.snippet`: optional HTML-safe excerpt from the content index
|
|
|
|
|
|
(present only when the match came from file content).
|
|
|
|
|
|
- `meta.via`: `"name"`, `"content"`, or `"path"` — where the match
|
|
|
|
|
|
fired.
|
|
|
|
|
|
- `next_cursor`: opaque; present iff another page exists. Pass it
|
|
|
|
|
|
verbatim as `?cursor=…` for the next call.
|
|
|
|
|
|
- `total`: integer, approximate — reflects the caller-visible match
|
|
|
|
|
|
count (permission-filtered). Omitted when unknown; never leaks a
|
|
|
|
|
|
count for rows the caller cannot see.
|
|
|
|
|
|
|
|
|
|
|
|
### Example
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
|
|
|
|
"https://oxicloud.example.com/api/search?query=report&type=pdf,docx&limit=20"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-04-22 07:50:41 +02:00
|
|
|
|
## Suggestions
|
|
|
|
|
|
|
2026-07-26 14:42:04 +02:00
|
|
|
|
Use `/api/search/suggest?query=rep&limit=10` for quick
|
|
|
|
|
|
autocomplete-style results. Suggestions can also be scoped to a
|
|
|
|
|
|
folder with `folder_id`.
|
2026-04-22 07:50:41 +02:00
|
|
|
|
|
|
|
|
|
|
## Result Caching
|
|
|
|
|
|
|
2026-07-26 14:42:04 +02:00
|
|
|
|
Search results are cached in memory using the search criteria and
|
|
|
|
|
|
user ID as the cache key.
|
2026-04-11 20:58:34 +02:00
|
|
|
|
|
2026-04-22 07:50:41 +02:00
|
|
|
|
- Cache TTL: 5 minutes
|
|
|
|
|
|
- Max entries: 1000
|
2026-07-17 00:43:15 +02:00
|
|
|
|
- Manual invalidation: `DELETE /api/admin/search/cache` — admin-only.
|
|
|
|
|
|
The endpoint calls `invalidate_all()` on the shared moka cache, so
|
2026-07-26 14:42:04 +02:00
|
|
|
|
one call cold-starts every subsequent search for every tenant;
|
|
|
|
|
|
it's an operator debug lever, not a per-user affordance.
|
2026-04-11 20:58:34 +02:00
|
|
|
|
|
|
|
|
|
|
## Feature Flag
|
|
|
|
|
|
|
2026-04-22 07:50:41 +02:00
|
|
|
|
Search can be disabled with `OXICLOUD_ENABLE_SEARCH=false`.
|