Files
market-backOfficce/API.md

423 lines
8.8 KiB
Markdown
Raw Normal View History

2026-02-20 00:59:46 +04:00
# API Documentation
2026-01-19 23:17:07 +04:00
2026-02-20 00:59:46 +04:00
Endpoint reference for the Marketplace Backoffice.
Base URL: `https://your-api-domain.com/api`
---
2026-01-19 23:17:07 +04:00
## Projects
### Get All Projects
```
GET /api/projects
2026-02-20 00:59:46 +04:00
Response 200:
2026-01-19 23:17:07 +04:00
[
{
"id": "dexar",
"name": "dexar",
"displayName": "Dexar Marketplace",
"active": true,
"logoUrl": "https://..."
}
]
```
2026-02-20 00:59:46 +04:00
---
2026-01-19 23:17:07 +04:00
## Categories
### Get Categories for Project
```
GET /api/projects/:projectId/categories
2026-02-20 00:59:46 +04:00
Response 200:
2026-01-19 23:17:07 +04:00
[
{
"id": "cat1",
"name": "Electronics",
"visible": true,
"priority": 1,
"img": "https://...",
"projectId": "dexar",
2026-02-20 00:59:46 +04:00
"subcategories": [ ...Subcategory[] ]
2026-01-19 23:17:07 +04:00
}
]
```
### Get Single Category
```
GET /api/categories/:categoryId
2026-02-20 00:59:46 +04:00
Response 200:
2026-01-19 23:17:07 +04:00
{
"id": "cat1",
"name": "Electronics",
"visible": true,
"priority": 1,
"img": "https://...",
"projectId": "dexar",
2026-02-20 00:59:46 +04:00
"subcategories": [ ...Subcategory[] ]
2026-01-19 23:17:07 +04:00
}
```
### Create Category
```
POST /api/projects/:projectId/categories
Body:
{
2026-02-20 00:59:46 +04:00
"name": "New Category", // required
2026-01-19 23:17:07 +04:00
"visible": true,
"priority": 10,
"img": "https://..."
}
2026-02-20 00:59:46 +04:00
Response 201: (created category object)
2026-01-19 23:17:07 +04:00
```
### Update Category
```
PATCH /api/categories/:categoryId
2026-02-20 00:59:46 +04:00
Body: (any subset of fields)
2026-01-19 23:17:07 +04:00
{
"name": "Updated Name",
"visible": false,
"priority": 5
}
2026-02-20 00:59:46 +04:00
Response 200: (updated category object)
2026-01-19 23:17:07 +04:00
```
### Delete Category
```
DELETE /api/categories/:categoryId
2026-02-20 00:59:46 +04:00
Response 204 No Content
Note: Cascades and deletes all subcategories and items under this category
2026-01-19 23:17:07 +04:00
```
2026-02-20 00:59:46 +04:00
---
2026-01-19 23:17:07 +04:00
## Subcategories
2026-02-20 00:59:46 +04:00
Subcategories are **recursive** - they can be nested under a root `Category` or under
another `Subcategory`. The nesting depth is unlimited, with one constraint:
**a subcategory that already contains items cannot have child subcategories** (and vice versa).
### Subcategory Object
```json
{
"id": "sub1",
"name": "Smartphones",
"visible": true,
"priority": 1,
"img": "https://...",
"categoryId": "cat1", // always the ROOT category ID
"parentId": "cat1", // direct parent ID (category OR subcategory)
"itemCount": 15,
"hasItems": true,
"subcategories": [] // nested children (empty when hasItems = true)
}
2026-01-19 23:17:07 +04:00
```
2026-02-20 00:59:46 +04:00
> `categoryId` is always the **root-level category** this subtree belongs to.
> `parentId` is the **direct parent** - it can be either a category ID or a subcategory ID.
---
### Get Subcategories Under a Category
```
GET /api/categories/:categoryId/subcategories
2026-01-22 00:41:13 +04:00
2026-02-20 00:59:46 +04:00
Response 200: Subcategory[] (nested subcategories populated recursively)
2026-01-19 23:17:07 +04:00
```
### Get Single Subcategory
```
GET /api/subcategories/:subcategoryId
2026-02-20 00:59:46 +04:00
Response 200: Subcategory object (with nested subcategories if any)
2026-01-19 23:17:07 +04:00
```
2026-02-20 00:59:46 +04:00
### Create Subcategory Under a Category (level 1)
2026-01-19 23:17:07 +04:00
```
POST /api/categories/:categoryId/subcategories
Body:
{
2026-02-20 00:59:46 +04:00
"id": "custom-id", // optional, auto-generated if omitted (used in URL routing)
"name": "Smartphones", // required
2026-01-19 23:17:07 +04:00
"visible": true,
"priority": 10
}
2026-02-20 00:59:46 +04:00
Response 201: (created subcategory object)
Error 400: if category does not exist
```
2026-01-22 00:41:13 +04:00
2026-02-20 00:59:46 +04:00
### Create Subcategory Under a Parent Subcategory (level 2+, nested)
```
POST /api/subcategories/:parentSubcategoryId/subcategories
Body:
{
"id": "custom-id", // optional, auto-generated if omitted (used in URL routing)
"name": "Apple", // required
"visible": true,
"priority": 10
}
Response 201: (created subcategory object)
Error 400: if parent subcategory has items (hasItems = true)
Error 404: if parent subcategory does not exist
2026-01-19 23:17:07 +04:00
```
### Update Subcategory
```
PATCH /api/subcategories/:subcategoryId
2026-02-20 00:59:46 +04:00
Body: (any subset of fields)
2026-01-19 23:17:07 +04:00
{
2026-02-20 00:59:46 +04:00
"id": "new-slug", // ID is editable - used for marketplace URL routing
2026-01-19 23:17:07 +04:00
"name": "Updated Name",
2026-02-20 00:59:46 +04:00
"visible": false,
"priority": 3
2026-01-19 23:17:07 +04:00
}
2026-02-20 00:59:46 +04:00
Response 200: (updated subcategory object)
2026-01-19 23:17:07 +04:00
```
### Delete Subcategory
```
DELETE /api/subcategories/:subcategoryId
2026-02-20 00:59:46 +04:00
Response 204 No Content
Note: Cascades and deletes all nested subcategories and items under this subcategory
2026-01-19 23:17:07 +04:00
```
2026-02-20 00:59:46 +04:00
---
2026-01-19 23:17:07 +04:00
## Items
2026-02-20 00:59:46 +04:00
Items always belong to the **deepest subcategory** in the hierarchy (a leaf node).
A subcategory with at least one item has `hasItems: true` and cannot have child subcategories.
2026-01-19 23:17:07 +04:00
### Get Items (Paginated)
```
2026-02-20 00:59:46 +04:00
GET /api/subcategories/:subcategoryId/items
2026-01-19 23:17:07 +04:00
Query Params:
2026-02-20 00:59:46 +04:00
page number (default: 1)
limit number (default: 20)
search string optional - filters by name (case-insensitive)
visible boolean optional - filter by visibility
tags string optional - comma-separated tag list
2026-01-19 23:17:07 +04:00
2026-02-20 00:59:46 +04:00
Response 200:
2026-01-19 23:17:07 +04:00
{
"items": [
{
"id": "item1",
"name": "iPhone 15 Pro",
"visible": true,
"priority": 1,
"quantity": 50,
"price": 1299,
"currency": "USD",
"imgs": ["https://...", "https://..."],
"tags": ["new", "featured"],
"simpleDescription": "Latest iPhone...",
"description": [
{ "key": "Color", "value": "Black" },
{ "key": "Storage", "value": "256GB" }
],
"subcategoryId": "sub1",
2026-01-22 00:41:13 +04:00
"comments": [
{
"id": "c1",
"text": "Great product!",
"author": "John Doe",
"stars": 5,
"createdAt": "2024-01-10T10:30:00Z"
}
]
2026-01-19 23:17:07 +04:00
}
],
"total": 150,
"page": 1,
"limit": 20,
"hasMore": true
}
```
### Get Single Item
```
GET /api/items/:itemId
2026-02-20 00:59:46 +04:00
Response 200: (full item object)
2026-01-19 23:17:07 +04:00
```
### Create Item
```
POST /api/subcategories/:subcategoryId/items
Body:
{
2026-02-20 00:59:46 +04:00
"name": "New Product", // required
2026-01-19 23:17:07 +04:00
"visible": true,
"priority": 10,
"quantity": 100,
"price": 999,
2026-02-20 00:59:46 +04:00
"currency": "USD", // USD | EUR | RUB | GBP | UAH
2026-01-19 23:17:07 +04:00
"imgs": ["https://..."],
"tags": ["new"],
2026-02-20 00:59:46 +04:00
"simpleDescription": "Short description",
2026-01-19 23:17:07 +04:00
"description": [
{ "key": "Size", "value": "Large" }
]
}
2026-02-20 00:59:46 +04:00
Response 201: (created item object)
Side effect: Sets hasItems = true on the subcategory.
The subcategory can no longer receive child subcategories.
2026-01-19 23:17:07 +04:00
```
### Update Item
```
PATCH /api/items/:itemId
2026-02-20 00:59:46 +04:00
Body: (any subset of fields)
2026-01-19 23:17:07 +04:00
{
"name": "Updated Name",
"price": 899,
"quantity": 80,
"visible": false
}
2026-02-20 00:59:46 +04:00
Response 200: (updated item object)
2026-01-19 23:17:07 +04:00
```
2026-02-20 00:59:46 +04:00
**Updating images - always send the full array:**
2026-01-19 23:17:07 +04:00
```
2026-02-20 00:59:46 +04:00
PATCH /api/items/:itemId
2026-01-19 23:17:07 +04:00
Body:
{
2026-02-20 00:59:46 +04:00
"imgs": ["https://new1.jpg", "https://new2.jpg"]
2026-01-19 23:17:07 +04:00
}
2026-02-20 00:59:46 +04:00
Response 200: (updated item object)
2026-01-19 23:17:07 +04:00
```
### Delete Item
```
DELETE /api/items/:itemId
2026-02-20 00:59:46 +04:00
Response 204 No Content
Side effect: If no items remain in the subcategory, sets hasItems = false.
The subcategory can then receive child subcategories again.
2026-01-19 23:17:07 +04:00
```
### Bulk Update Items
```
PATCH /api/items/bulk
Body:
{
"itemIds": ["item1", "item2", "item3"],
"data": {
"visible": true
}
}
2026-02-20 00:59:46 +04:00
Response 204 No Content
2026-01-19 23:17:07 +04:00
```
2026-02-20 00:59:46 +04:00
---
2026-01-19 23:17:07 +04:00
## Upload
### Upload Image
```
POST /api/upload
Body: multipart/form-data
2026-02-20 00:59:46 +04:00
image: File
2026-01-19 23:17:07 +04:00
2026-02-20 00:59:46 +04:00
Response 201:
2026-01-19 23:17:07 +04:00
{
2026-02-20 00:59:46 +04:00
"url": "https://cdn.example.com/uploads/abc123.jpg"
2026-01-19 23:17:07 +04:00
}
```
2026-02-20 00:59:46 +04:00
---
2026-01-19 23:17:07 +04:00
## Notes
2026-02-20 00:59:46 +04:00
- All responses are JSON.
- Use `PATCH` for partial updates - send only the fields you want to change.
- `priority`: lower number = appears first in the list.
- `currency` supported values: `USD`, `EUR`, `RUB`, `GBP`, `UAH`.
- `imgs`: always send the **complete** array on update, not individual images.
- `description`: array of `{ key, value }` pairs - free-form attributes per item.
- Auto-save from the backoffice fires `PATCH` with a single field every ~500 ms.
---
## Business Rules
### Nested Subcategories
The hierarchy works like this:
```
Category (e.g. Electronics)
Subcategory L1 (e.g. Kitchen) <- can add more children OR items, not both
Subcategory L2 (e.g. Big Kitchen) <- same rule
Subcategory L3 (e.g. Ovens) <- if this has items, it is a leaf
Items...
```
Rules:
- A category can always receive new subcategories (categories never hold items directly).
- A subcategory that **has items** (`hasItems: true`) **cannot** receive child subcategories.
- `POST /api/subcategories/:id/subcategories` on a node with `hasItems: true` -> `400 Bad Request`.
- A subcategory that **has children** cannot have items added to it (items only go to leaf nodes).
- When the **first item** is created in a subcategory -> `hasItems` becomes `true`.
- When the **last item** is deleted -> `hasItems` becomes `false`; child subcategories can be added again.
### URL Structure (Marketplace Frontend)
Subcategory and item `id` fields are used directly in the marketplace URL path:
```
/{categoryId}/{sub1Id}/{sub2Id}/.../{itemId}
Examples:
/electronics/smartphones/iphone-15
/electronics/smartphones/apple/iphone-15-pro
/furniture/living-room/sofas/corner-sofa-modelo
```
The `id` field on subcategories is editable via `PATCH` to allow renaming slugs.
### Comments
- `stars` is optional, integer 1-5.
- `author` is optional (anonymous comments allowed).
- `createdAt` is ISO 8601 string.
### Cascade Deletes
| Delete target | Also deletes |
|---|---|
| Category | all subcategories (recursive) and their items |
| Subcategory | all nested subcategories (recursive) and their items |
| Item | nothing else |