Beam backfilled 11 library docs (CRUD, folders, visibility, browse, stats,
media-items) and re-attached frontmatter to create_collection.md — which had
silently lost its pilot version in cc893f75: the negative-test
'git checkout --' restored the OLD file because the pilot was never staged,
and a frontmatter-less doc is invisible to the gate. Claude restored the full
corrected pilot content (priority higher-wins, time.String() note, 409).
Claude registry: 11 entries + one inverted catch — DELETE /:id/folders DOES
bind {folder_path} (handler reuses AddLibraryFolderRequest); registry first
draft said bodyless. GET /:id/visibility returns joined
GetUserVisibleLibrariesRow (type_name etc.), not bare Libraries.
Gate-driven merges fixed create/get library response shapes (sqlc row keys:
created_by_admin_id, library_type_id, updated_at; dropped invented type/
folders/is_visible). Fixed invented request fields (user_id in
set-visibility; library_type_id in update). make test 9/9.
82 lines
2.6 KiB
Markdown
82 lines
2.6 KiB
Markdown
---
|
|
method: POST
|
|
path: /api/collections
|
|
auth: jwt
|
|
area: collections
|
|
---
|
|
<!-- source: internal/handlers/collections.go:94 CollectionHandler.CreateCollection -->
|
|
|
|
# Create Collection
|
|
|
|
Creates a new collection for the signed-in user. If any rules are present (or
|
|
`collection_type` is `"smart"`), the collection is a smart collection whose
|
|
membership is evaluated live; otherwise it is static.
|
|
|
|
Creating a collection whose name already exists for the user returns **409**.
|
|
|
|
## Example request
|
|
|
|
```json example-request
|
|
{
|
|
"name": "To Read",
|
|
"description": "Books I want to read soon",
|
|
"color": "#00FF00",
|
|
"icon": "📖",
|
|
"collection_type": "static",
|
|
"auto_assign_rules": [],
|
|
"view_settings": { "kobo": { "view_mode": "grid" } }
|
|
}
|
|
```
|
|
|
|
## Example response
|
|
|
|
```json example-response
|
|
{
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"user_id": "8f14e45f-ceea-467f-a429-0b21bfc0b1a2",
|
|
"name": "To Read",
|
|
"description": "Books I want to read soon",
|
|
"color": "#00FF00",
|
|
"icon": "📖",
|
|
"collection_type": "static",
|
|
"auto_assign_rules": null,
|
|
"view_settings": { "kobo": { "view_mode": "grid" } },
|
|
"book_count": 0,
|
|
"created_at": "2026-10-24 13:57:01.81234 +0000 UTC"
|
|
}
|
|
```
|
|
|
|
Note: `created_at` is serialized with Go's `time.String()` format, not
|
|
RFC3339. Treat it as display text; do not parse it as an ISO timestamp.
|
|
|
|
## Request fields
|
|
|
|
| Field | Type | Required | Notes |
|
|
| ----- | ---- | -------- | ----- |
|
|
| name | string | yes | unique per user |
|
|
| description | string | no | |
|
|
| color | string | no | hex color, e.g. `"#FF5733"` |
|
|
| icon | string | no | emoji |
|
|
| collection_type | string | no | `"static"` (default) or `"smart"`; also implied by non-empty `auto_assign_rules` |
|
|
| auto_assign_rules | array | no | rule objects, see below |
|
|
| view_settings | object | no | per-device display preferences |
|
|
|
|
### Auto-assign rule object
|
|
|
|
| Field | Type | Required | Notes |
|
|
| ----- | ---- | -------- | ----- |
|
|
| id | string | no | rule id |
|
|
| field | string | yes | one of `genre`, `series`, `author`, `language`, `publisher`, `copyright_year`, `tags` |
|
|
| operator | string | yes | one of `equals`, `not_equals`, `contains`, `not_contains`, `starts_with`, `ends_with`, `greater_than`, `less_than` |
|
|
| value | string | yes | value to compare against |
|
|
| priority | number | no | 1-10; higher values take precedence |
|
|
| enabled | boolean | no | absent = enabled (rules written before this field existed keep matching) |
|
|
|
|
## Errors
|
|
|
|
| Status | Body | When |
|
|
| ------ | ---- | ---- |
|
|
| 400 | `{"error": "..."}` | invalid JSON or validation failure |
|
|
| 409 | `{"error": "a collection with this name already exists"}` | name taken |
|
|
| 500 | `{"error": "..."}` | unexpected server error |
|